Compare commits
159 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
33d2577fb5 | ||
|
|
3be22bd43b | ||
|
|
094b876a38 | ||
|
|
97f8e9ce1c | ||
|
|
385be63126 | ||
|
|
7710528f01 | ||
|
|
c25462d924 | ||
|
|
9b45d240bb | ||
|
|
8bd27db727 | ||
|
|
83a7985a97 | ||
|
|
2d54a45a80 | ||
|
|
813a5f1e1f | ||
|
|
c7d7757dbd | ||
|
|
d7b6996bcf | ||
|
|
61705e4d22 | ||
|
|
6a1730956e | ||
|
|
df8a6529ac | ||
|
|
97a29f9c50 | ||
|
|
9395d58669 | ||
|
|
f9a0bbbc20 | ||
|
|
ccfd369a77 | ||
|
|
2ec1c3b56c | ||
|
|
dbeb626f32 | ||
|
|
8fd78d3819 | ||
|
|
b56b08387d | ||
|
|
34b16699fa | ||
|
|
75dfa5af7e | ||
|
|
e983032762 | ||
|
|
f5c5709cd9 | ||
|
|
fb874e1d65 | ||
|
|
6495508194 | ||
|
|
482626b9b8 | ||
|
|
9f01040d46 | ||
|
|
cdf298bafb | ||
|
|
a2f9f9320b | ||
|
|
0a48f613ec | ||
|
|
19f2d69be8 | ||
|
|
241de27c75 | ||
|
|
df8dafc5ca | ||
|
|
d01b7ac682 | ||
|
|
3161723c8b | ||
|
|
a907811b22 | ||
|
|
f1d298450d | ||
|
|
53eb66e5c4 | ||
|
|
907f576010 | ||
|
|
f24c2146e0 | ||
|
|
c342b58a87 | ||
|
|
be8feb7ee8 | ||
|
|
b32eb2bfc1 | ||
|
|
4375a03f38 | ||
|
|
ad9b7d700a | ||
|
|
460272291f | ||
|
|
f567dafe62 | ||
|
|
3c86c57765 | ||
|
|
dc2f77e019 | ||
|
|
80693d8338 | ||
|
|
72e5c4300c | ||
|
|
6e7168b3e9 | ||
|
|
31892e1d68 | ||
|
|
aa3099ce09 | ||
|
|
c6b90b9068 | ||
|
|
47fe5c201c | ||
|
|
f7d19f5a3a | ||
|
|
d42f7daef7 | ||
|
|
53363e6b80 | ||
|
|
7ba0573702 | ||
|
|
777a99fe07 | ||
|
|
3b392b2dd9 | ||
|
|
6009929a3b | ||
|
|
c1c9de4546 | ||
|
|
c08ae001a6 | ||
|
|
6c2c4d4428 | ||
|
|
e692e7cd9e | ||
|
|
f0a62e83c8 | ||
|
|
a01225db39 | ||
|
|
b36f6b67e6 | ||
|
|
782de8743f | ||
|
|
c42ac967ea | ||
|
|
e379fcf2cf | ||
|
|
89678fca47 | ||
|
|
e378f79d2b | ||
|
|
fba165408c | ||
|
|
dd168373a1 | ||
|
|
076e60378a | ||
|
|
526af777d4 | ||
|
|
f121558668 | ||
|
|
640ba7d69e | ||
|
|
bc4498e018 | ||
|
|
805d03125b | ||
|
|
7499f0811b | ||
|
|
37e0566957 | ||
|
|
1fbaff9f81 | ||
|
|
c3943d21d0 | ||
|
|
a7158ec69c | ||
|
|
f66906d54d | ||
|
|
85afef9981 | ||
|
|
bd463a038c | ||
|
|
eeb1a284a8 | ||
|
|
b38cc75f17 | ||
|
|
dd11528160 | ||
|
|
912d6f442a | ||
|
|
346621ed21 | ||
|
|
941f5a8ecb | ||
|
|
76e11e6f64 | ||
|
|
3c558ebbee | ||
|
|
eba7b16ccf | ||
|
|
466cd43277 | ||
|
|
47acbefa57 | ||
|
|
d9cf34ab8c | ||
|
|
9dc7d2a081 | ||
|
|
438708ea15 | ||
|
|
835840e8da | ||
|
|
d13e0762d3 | ||
|
|
ae8f6a6db5 | ||
|
|
608c5fd516 | ||
|
|
b5bd58b2b6 | ||
|
|
9785fd0333 | ||
|
|
b02a1ee037 | ||
|
|
5de43fca4e | ||
|
|
46fdbd629d | ||
|
|
2f4902a478 | ||
|
|
7e58c5009e | ||
|
|
39009dcfb9 | ||
|
|
a19ea4b662 | ||
|
|
63bc12d3f1 | ||
|
|
b9c2236885 | ||
|
|
450ae723cb | ||
|
|
2ac5ee4062 | ||
|
|
0d436b5f11 | ||
|
|
ca6983139e | ||
|
|
9f56c92497 | ||
|
|
113cecc4f0 | ||
|
|
7ac1176120 | ||
|
|
09c23a564d | ||
|
|
a969d3ff1d | ||
|
|
b6324d0007 | ||
|
|
ba27b4be69 | ||
|
|
7c3ef56332 | ||
|
|
7b9286b2c2 | ||
|
|
50d2b4e0b5 | ||
|
|
f1988a9e20 | ||
|
|
a24a3c565e | ||
|
|
20d87297b2 | ||
|
|
049df99afc | ||
|
|
6dcdf4ff45 | ||
|
|
00fd33b635 | ||
|
|
f2dc526fc8 | ||
|
|
e5491198f6 | ||
|
|
4cab45c759 | ||
|
|
5371268f8f | ||
|
|
1e080cc258 | ||
|
|
eba73f6844 | ||
|
|
cf45da33f6 | ||
|
|
fb7498a8ec | ||
|
|
574f9afa3d | ||
|
|
3751ac1784 | ||
|
|
af759dcf42 | ||
|
|
47426c28e1 | ||
|
|
49f7775d2d |
11
.npmignore
Normal file
@@ -0,0 +1,11 @@
|
||||
*.coffee
|
||||
*.html
|
||||
.DS_Store
|
||||
.git*
|
||||
Cakefile
|
||||
documentation/
|
||||
examples/
|
||||
extras/
|
||||
raw/
|
||||
src/
|
||||
test/
|
||||
65
Cakefile
@@ -73,7 +73,7 @@ task 'build:full', 'rebuild the source twice, and run the tests', ->
|
||||
|
||||
|
||||
task 'build:parser', 'rebuild the Jison parser (run build first)', ->
|
||||
extend global, require('utils')
|
||||
extend global, require('util')
|
||||
require 'jison'
|
||||
parser = require('./lib/grammar').parser
|
||||
fs.writeFile 'lib/parser.js', parser.generate()
|
||||
@@ -143,36 +143,78 @@ task 'loc', 'count the lines of source code in the CoffeeScript compiler', ->
|
||||
console.log stdout.trim()
|
||||
|
||||
|
||||
# Run the CoffeeScript test suite.
|
||||
runTests = (CoffeeScript) ->
|
||||
startTime = Date.now()
|
||||
passedTests = failedTests = 0
|
||||
startTime = Date.now()
|
||||
currentFile = null
|
||||
passedTests = 0
|
||||
failures = []
|
||||
|
||||
for name, func of require 'assert'
|
||||
# Mix in the assert module globally, to make it available for tests.
|
||||
addGlobal = (name, func) ->
|
||||
global[name] = ->
|
||||
passedTests += 1
|
||||
func arguments...
|
||||
|
||||
addGlobal name, func for name, func of require 'assert'
|
||||
|
||||
# Convenience aliases.
|
||||
global.eq = global.strictEqual
|
||||
global.CoffeeScript = CoffeeScript
|
||||
|
||||
# Our test helper function for delimiting different test cases.
|
||||
global.test = (description, fn) ->
|
||||
try
|
||||
fn()
|
||||
catch e
|
||||
e.description = description if description?
|
||||
e.source = fn.toString() if fn.toString?
|
||||
failures.push file: currentFile, error: e
|
||||
|
||||
# A recursive functional equivalence helper; uses egal for testing equivalence.
|
||||
# See http://wiki.ecmascript.org/doku.php?id=harmony:egal
|
||||
arrayEqual = (a, b) ->
|
||||
if a is b
|
||||
# 0 isnt -0
|
||||
a isnt 0 or 1/a is 1/b
|
||||
else if a instanceof Array and b instanceof Array
|
||||
return no unless a.length is b.length
|
||||
return no for el, idx in a when not arrayEqual el, b[idx]
|
||||
yes
|
||||
else
|
||||
# NaN is NaN
|
||||
a isnt a and b isnt b
|
||||
|
||||
global.arrayEq = (a, b, msg) -> ok arrayEqual(a,b), msg
|
||||
|
||||
# When all the tests have run, collect and print errors.
|
||||
# If a stacktrace is available, output the compiled function source.
|
||||
process.on 'exit', ->
|
||||
time = ((Date.now() - startTime) / 1000).toFixed(2)
|
||||
message = "passed #{passedTests} tests in #{time} seconds#{reset}"
|
||||
if failedTests
|
||||
log "failed #{failedTests} and #{message}", red
|
||||
else
|
||||
log message, green
|
||||
return log(message, green) unless failures.length
|
||||
log "failed #{failures.length} and #{message}", red
|
||||
for fail in failures
|
||||
{error, file} = fail
|
||||
jsFile = file.replace(/\.coffee$/,'.js')
|
||||
match = error.stack?.match(new RegExp(fail.file+":(\\d+):(\\d+)"))
|
||||
[match, line, col] = match if match
|
||||
log "\n #{error.toString()}", red
|
||||
log " #{error.description}", red if error.description
|
||||
log " #{jsFile}: line #{line or 'unknown'}, column #{col or 'unknown'}", red
|
||||
console.log " #{error.source}" if error.source
|
||||
|
||||
# Run every test in the `test` folder, recording failures.
|
||||
fs.readdir 'test', (err, files) ->
|
||||
files.forEach (file) ->
|
||||
return unless file.match(/\.coffee$/i)
|
||||
fileName = path.join 'test', file
|
||||
fs.readFile fileName, (err, code) ->
|
||||
currentFile = fileName
|
||||
try
|
||||
CoffeeScript.run code.toString(), {fileName}
|
||||
catch err
|
||||
failedTests += 1
|
||||
log "failed #{fileName}", red, '\n' + err.stack?.toString()
|
||||
catch e
|
||||
failures.push file: currentFile, error: e
|
||||
|
||||
|
||||
task 'test', 'run the CoffeeScript language test suite', ->
|
||||
@@ -182,5 +224,6 @@ task 'test', 'run the CoffeeScript language test suite', ->
|
||||
task 'test:browser', 'run the test suite against the merged browser script', ->
|
||||
source = fs.readFileSync 'extras/coffee-script.js', 'utf-8'
|
||||
result = {}
|
||||
global.testingBrowser = yes
|
||||
(-> eval source).call result
|
||||
runTests result.CoffeeScript
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
###
|
||||
CoffeeScript Compiler v0.9.6
|
||||
CoffeeScript Compiler v1.0.0
|
||||
Released under the MIT License
|
||||
###
|
||||
###
|
||||
|
||||
|
||||
|
||||
@@ -8,4 +8,6 @@ else
|
||||
|
||||
date = if friday then sue else jill
|
||||
|
||||
options or= defaults
|
||||
options or= defaults
|
||||
|
||||
|
||||
|
||||
4
documentation/coffee/do.coffee
Normal file
@@ -0,0 +1,4 @@
|
||||
for fileName in list
|
||||
do (fileName) ->
|
||||
fs.readFile fileName, (err, contents) ->
|
||||
compile fileName, contents.toString()
|
||||
@@ -1,6 +1,8 @@
|
||||
solipsism = true if mind? and not world?
|
||||
|
||||
speed ?= 140
|
||||
speed ?= 75
|
||||
|
||||
footprints = yeti ? "bear"
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1 +1,3 @@
|
||||
six = (one = 1) + (two = 2) + (three = 3)
|
||||
six = (one = 1) + (two = 2) + (three = 3)
|
||||
|
||||
|
||||
|
||||
@@ -3,4 +3,5 @@ alert(
|
||||
nonexistent / undefined
|
||||
catch error
|
||||
"And the error is ... " + error
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@@ -2,4 +2,6 @@ html = '''
|
||||
<strong>
|
||||
cup of coffeescript
|
||||
</strong>
|
||||
'''
|
||||
'''
|
||||
|
||||
|
||||
|
||||
@@ -6,4 +6,6 @@ OPERATOR = /// ^ (
|
||||
| ([&|<>])\2=? # logic / shift
|
||||
| \?\. # soak access
|
||||
| \.{2,3} # range or splat
|
||||
) ///
|
||||
) ///
|
||||
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ song = ["do", "re", "mi", "fa", "so"]
|
||||
|
||||
singers = {Jagger: "Rock", Elvis: "Roll"}
|
||||
|
||||
matrix = [
|
||||
bitlist = [
|
||||
1, 0, 1
|
||||
0, 0, 1
|
||||
1, 1, 0
|
||||
@@ -14,4 +14,6 @@ kids =
|
||||
age: 11
|
||||
sister:
|
||||
name: "Ida"
|
||||
age: 9
|
||||
age: 9
|
||||
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
$('.account').attr class: 'active'
|
||||
|
||||
log object.class
|
||||
log object.class
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
theBait = 1000
|
||||
theSwitch = 0
|
||||
|
||||
[theBait, theSwitch] = [theSwitch, theBait]
|
||||
[theBait, theSwitch] = [theSwitch, theBait]
|
||||
|
||||
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
String::dasherize = ->
|
||||
this.replace /_/g, "-"
|
||||
this.replace /_/g, "-"
|
||||
|
||||
|
||||
@@ -4,3 +4,4 @@ copy = numbers[0...numbers.length]
|
||||
|
||||
middle = copy[3..6]
|
||||
|
||||
|
||||
|
||||
@@ -22,4 +22,6 @@ awardMedals contenders...
|
||||
|
||||
alert "Gold: " + gold
|
||||
alert "Silver: " + silver
|
||||
alert "The Field: " + rest
|
||||
alert "The Field: " + rest
|
||||
|
||||
|
||||
|
||||
@@ -4,4 +4,5 @@ try
|
||||
catch error
|
||||
print error
|
||||
finally
|
||||
cleanUp()
|
||||
cleanUp()
|
||||
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
body {
|
||||
font-size: 13px;
|
||||
line-height: 20px;
|
||||
color: #191933;
|
||||
font-family: "Lucida Grande", "Lucida Sans Unicode", Helvetica, Arial, sans-serif !important;
|
||||
font-size: 14px;
|
||||
line-height: 21px;
|
||||
color: #333;
|
||||
background: #f6f6f6 url(../images/background.png);
|
||||
font-family: "Helvetica Neue", "Lucida Grande", "Lucida Sans Unicode", Helvetica, Arial, sans-serif !important;
|
||||
}
|
||||
.container {
|
||||
width: 950px;
|
||||
@@ -13,11 +14,14 @@ p, li {
|
||||
width: 625px;
|
||||
}
|
||||
a {
|
||||
color: #000055;
|
||||
color: #191933;
|
||||
}
|
||||
h1, h2, h3, h4, h5, h6, b.header {
|
||||
font-size: 18px;
|
||||
color: #000;
|
||||
margin-top: 40px;
|
||||
margin-bottom: 15px;
|
||||
text-shadow: #fff 0 1px 1px;
|
||||
}
|
||||
br.clear {
|
||||
height: 0;
|
||||
@@ -27,9 +31,7 @@ ul {
|
||||
padding-left: 20px;
|
||||
}
|
||||
b.header {
|
||||
color: #000055;
|
||||
display: block;
|
||||
font-size: 16px;
|
||||
}
|
||||
li {
|
||||
margin-bottom: 10px;
|
||||
@@ -47,7 +49,7 @@ table {
|
||||
table.definitions {
|
||||
width: auto;
|
||||
margin: 30px 0;
|
||||
border-left: 6px solid #ccccdd;
|
||||
border-left: 5px solid rgba(0,0,0,0.2);;
|
||||
}
|
||||
table.definitions td {
|
||||
text-align: center;
|
||||
@@ -57,17 +59,18 @@ code, pre, tt, textarea {
|
||||
font-family: Monaco, Consolas, "Lucida Console", monospace;
|
||||
font-size: 12px;
|
||||
line-height: 18px;
|
||||
color: #191955;
|
||||
color: #155;
|
||||
white-space: pre-wrap;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
tt {
|
||||
background: #f8f8ff;
|
||||
display: inline-block;
|
||||
background: #fff;
|
||||
border: 1px solid #dedede;
|
||||
padding: 0px 0.2em;
|
||||
}
|
||||
pre {
|
||||
border-left: 6px solid #ccccdd;
|
||||
border-left: 5px solid rgba(0,0,0,0.2);
|
||||
padding: 3px 0 3px 12px;
|
||||
font-size: 12px;
|
||||
}
|
||||
@@ -83,24 +86,28 @@ code, pre, tt, textarea {
|
||||
}
|
||||
div.code {
|
||||
position: relative;
|
||||
border: 1px solid #cacaca;
|
||||
background: #fafaff;
|
||||
padding: 7px 0 10px 0;
|
||||
-moz-border-radius: 5px; -webkit-border-radius: 5px; border-radius: 5px;
|
||||
-webkit-box-shadow: 0px 0px 7px #cacaca;
|
||||
background: #fff;
|
||||
border: 1px solid #d8d8d8;
|
||||
-webkit-box-shadow: 0px 0px 4px rgba(0,0,0,0.23);
|
||||
-moz-box-shadow: 0px 0px 4px rgba(0,0,0,0.23);
|
||||
box-shadow: 0px 0px 4px rgba(0,0,0,0.23);
|
||||
zoom: 1;
|
||||
}
|
||||
div.code button {
|
||||
div.code .minibutton {
|
||||
text-transform: none;
|
||||
position: absolute;
|
||||
right: 8px; bottom: 8px;
|
||||
}
|
||||
div.code .load {
|
||||
left: 8px; right: auto;
|
||||
}
|
||||
div.code pre, div.code textarea {
|
||||
float: left;
|
||||
width: 450px;
|
||||
background: #fafaff;
|
||||
border-left: 1px dotted #559;
|
||||
background: #fff;
|
||||
border-left: 1px dotted #d0d0d0;
|
||||
margin: 10px 0 15px 3px;
|
||||
padding: 0 0 0 12px;
|
||||
margin: 0;
|
||||
}
|
||||
div.code pre:first-child {
|
||||
border-left: 0;
|
||||
@@ -121,32 +128,38 @@ div.code {
|
||||
height: 50px;
|
||||
min-width: 490px;
|
||||
left: 40px; right: 40px; top: 25px;
|
||||
padding-left: 235px;
|
||||
padding-left: 252px;
|
||||
background: #eee;
|
||||
background: -webkit-gradient(linear, left top, left bottom, from(#f5f5f5), to(#d0d0d0));
|
||||
background: -moz-linear-gradient(top, #f5f5f5, #d0d0d0);
|
||||
background: -webkit-gradient(linear, left top, left bottom, from(#f8f8f8), to(#dadada));
|
||||
background: -moz-linear-gradient(top, #f8f8f8, #dadada);
|
||||
border: 1px solid #aaa;
|
||||
-webkit-border-radius: 20px; -moz-border-radius: 20px; border-radius: 20px;
|
||||
-webkit-box-shadow: 0 0 7px #aaa; -moz-box-shadow: 0 0 7px #aaa;
|
||||
border-top: 1px solid #bbb;
|
||||
border-bottom: 1px solid #888;
|
||||
-webkit-border-radius: 3px; -moz-border-radius: 3px; border-radius: 3px;
|
||||
-webkit-box-shadow: 0 3px 5px rgba(0,0,0,0.1);
|
||||
-moz-box-shadow: 0 3px 5px rgba(0,0,0,0.1);
|
||||
box-shadow: 0 3px 5px rgba(0,0,0,0.1);
|
||||
}
|
||||
#logo {
|
||||
display: block;
|
||||
width: 215px; height: 50px;
|
||||
width: 225px; height: 50px;
|
||||
background: url('../images/logo.png');
|
||||
position: absolute;
|
||||
top: 0px; left: 10px;
|
||||
}
|
||||
#error {
|
||||
position: absolute;
|
||||
-webkit-border-radius: 6px; -moz-border-radius: 6px; border-radius: 6px;
|
||||
right: 15px; top: 15px; left: 730px;
|
||||
height: 15px;
|
||||
padding: 2px 5px;
|
||||
-webkit-border-radius: 2px; -moz-border-radius: 2px; border-radius: 2px;
|
||||
-webkit-border-top-left-radius: 0; -moz-border-radius-topleft: 0; border-top-left-radius: 0;
|
||||
-webkit-border-bottom-left-radius: 0; -moz-border-radius-bottomleft: 0; border-bottom-left-radius: 0;
|
||||
right: 0px; top: 0px; left: 726px; bottom: 0;
|
||||
padding: 0 0 0 15px;
|
||||
background: #fdcdcc;
|
||||
color: #864544;
|
||||
border: 1px solid #864544;
|
||||
background: -webkit-gradient(linear, left top, left bottom, from(#ffedec), to(#ff9a95));
|
||||
background: -moz-linear-gradient(top, #f8f8f8, #dadada);
|
||||
color: #862322;
|
||||
font-size: 10px;
|
||||
line-height: 15px;
|
||||
line-height: 50px;
|
||||
overflow: hidden;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
@@ -158,91 +171,93 @@ div.code {
|
||||
position: relative;
|
||||
float: left;
|
||||
padding: 0 20px;
|
||||
border: 1px solid #bbb;
|
||||
border: 1px solid #aaa;
|
||||
border-top: 0; border-bottom: 0; border-left-width: 0;
|
||||
cursor: pointer;
|
||||
}
|
||||
body.full_screen .navigation {
|
||||
position: static;
|
||||
}
|
||||
.navigation.toc {
|
||||
border-left-width: 1px;
|
||||
}
|
||||
.navigation:hover,
|
||||
.navigation.active {
|
||||
background: #eee;
|
||||
background: -webkit-gradient(linear, left top, left bottom, from(#f0f0f0), to(#c0c0c0));
|
||||
background: -moz-linear-gradient(top, #f0f0f0, #c0c0c0);
|
||||
background: -webkit-gradient(linear, left top, left bottom, from(#eee), to(#f8f8f8));
|
||||
background: -moz-linear-gradient(top, #eee, #f8f8f8);
|
||||
}
|
||||
.navigation.active {
|
||||
height: 51px;
|
||||
color: #000;
|
||||
background: -webkit-gradient(linear, left top, left bottom, from(#e5e5e5), to(#fff));
|
||||
background: -moz-linear-gradient(top, #e5e5e5, #fff);
|
||||
}
|
||||
.navigation .button {
|
||||
font-weight: bold;
|
||||
}
|
||||
.navigation .button::selection {
|
||||
background: transparent;
|
||||
}
|
||||
.navigation .contents {
|
||||
display: none;
|
||||
position: absolute;
|
||||
background: #fff;
|
||||
opacity: 0.97;
|
||||
top: 51px; left: 0;
|
||||
padding: 5px 0;
|
||||
margin-left: -1px;
|
||||
border: 1px solid #aaa; border-top: 0;
|
||||
-webkit-border-radius: 5px; -moz-border-radius: 5px; border-radius: 5px;
|
||||
-webkit-border-top-left-radius: 0; -moz-border-radius-topleft: 0;
|
||||
-webkit-border-top-right-radius: 0; -moz-border-radius-topright: 0;
|
||||
-webkit-box-shadow: 0 5px 10px #999; -moz-box-shadow: 0 5px 10px #999;
|
||||
border: 1px solid #aaa;
|
||||
-webkit-border-radius: 3px; -moz-border-radius: 3px; border-radius: 3px;
|
||||
-webkit-box-shadow: 0 3px 5px rgba(0,0,0,0.2);
|
||||
-moz-box-shadow: 0 3px 5px rgba(0,0,0,0.2);
|
||||
box-shadow: 0 3px 5px rgba(0,0,0,0.2);
|
||||
}
|
||||
.navigation.active .contents {
|
||||
display: block;
|
||||
}
|
||||
.navigation .contents.repl_wrapper {
|
||||
left: -162px;
|
||||
width: 700px;
|
||||
padding: 0;
|
||||
}
|
||||
body.full_screen .navigation .contents.repl_wrapper {
|
||||
position: fixed;
|
||||
width: auto; height: auto;
|
||||
left: 60px; top: 77px; right: 60px; bottom: 30px;
|
||||
}
|
||||
.navigation .contents.repl_wrapper .code {
|
||||
-webkit-box-shadow: none; -moz-box-shadow: none;
|
||||
background: transparent;
|
||||
border: 0;
|
||||
position: static;
|
||||
}
|
||||
body.full_screen .navigation .contents.repl_wrapper .code {
|
||||
height: 100%;
|
||||
padding: 0; margin: 0;
|
||||
}
|
||||
.navigation .code button {
|
||||
bottom: 10px;
|
||||
text-transform: none;
|
||||
line-height: 14px;
|
||||
left: auto; right: auto;
|
||||
}
|
||||
.navigation .code .run {
|
||||
width: 40px;
|
||||
right: 10px;
|
||||
}
|
||||
.navigation .code .full_screen, .navigation .code .minimize {
|
||||
left: 10px;
|
||||
display: none;
|
||||
width: 90px;
|
||||
}
|
||||
body.minimized .code .full_screen, body.full_screen .code .minimize {
|
||||
display: inline;
|
||||
}
|
||||
.navigation .contents a {
|
||||
display: block;
|
||||
width: 290px;
|
||||
text-transform: none;
|
||||
text-decoration: none;
|
||||
font-weight: normal;
|
||||
height: 12px;
|
||||
line-height: 12px;
|
||||
padding: 4px 10px;
|
||||
border: 1px solid transparent;
|
||||
border-left: 0; border-right: 0;
|
||||
}
|
||||
.navigation .contents a:hover {
|
||||
background: #f0f0f0;
|
||||
border-color: #ddd;
|
||||
background: #eee;
|
||||
}
|
||||
.navigation.active .contents {
|
||||
display: block;
|
||||
}
|
||||
.navigation .contents.menu {
|
||||
border-top: 0;
|
||||
-webkit-border-top-left-radius: 0; -moz-border-radius-topleft: 0; border-top-left-radius: 0;
|
||||
-webkit-border-top-right-radius: 0; -moz-border-radius-topright: 0; border-top-right-radius: 0;
|
||||
}
|
||||
.navigation .contents.repl_wrapper {
|
||||
padding: 0;
|
||||
position: fixed;
|
||||
width: auto; height: auto;
|
||||
left: 40px; top: 90px; right: 40px; bottom: 30px;
|
||||
background: -webkit-gradient(linear, left top, left bottom, from(#fafafa), to(#eaeaea));
|
||||
}
|
||||
.navigation .repl_bridge {
|
||||
position: absolute;
|
||||
height: 12px;
|
||||
left: -1px; right: -1px;
|
||||
bottom: -14px;
|
||||
border: 1px solid #aaa;
|
||||
z-index: 5;
|
||||
background: #fff;
|
||||
display: none;
|
||||
border-top-color: #fff; border-bottom-color: #fff;
|
||||
}
|
||||
.navigation.active .repl_bridge {
|
||||
display: block;
|
||||
}
|
||||
.navigation .code .minibutton {
|
||||
top: 10px; right: 10px;
|
||||
width: 40px;
|
||||
text-transform: none;
|
||||
}
|
||||
|
||||
.bookmark {
|
||||
@@ -252,45 +267,108 @@ div.code {
|
||||
top: -90px;
|
||||
}
|
||||
|
||||
.navigation .contents.repl_wrapper .code {
|
||||
cursor: text;
|
||||
-webkit-box-shadow: none; -moz-box-shadow: none; box-shadow: none;
|
||||
background: #181a3a url(../images/banding.png);
|
||||
border: 2px solid #555;
|
||||
padding: 0;
|
||||
position: absolute;
|
||||
top: 15px; left: 15px; right: 15px; bottom: 15px;
|
||||
}
|
||||
.repl_wrapper .screenshadow {
|
||||
position: absolute;
|
||||
width: 200px; height: 150px;
|
||||
background: url(../images/screenshadow.png?2);
|
||||
}
|
||||
.repl_wrapper .screenshadow.tl {
|
||||
top: 0; left: 0;
|
||||
background-position: 0 0;
|
||||
}
|
||||
.repl_wrapper .screenshadow.tr {
|
||||
top: 0; right: 0;
|
||||
background-position: -200px 0;
|
||||
}
|
||||
.repl_wrapper .screenshadow.bl {
|
||||
bottom: 0; left: 0;
|
||||
background-position: 0 -150px;
|
||||
}
|
||||
.repl_wrapper .screenshadow.br {
|
||||
bottom: 0; right: 0;
|
||||
background-position: -200px -150px;
|
||||
}
|
||||
|
||||
#repl_source, #repl_results {
|
||||
background: transparent;
|
||||
outline: none;
|
||||
margin: 5px 0 20px;
|
||||
color: #def;
|
||||
}
|
||||
#repl_source_wrap {
|
||||
margin-left: 5px;
|
||||
height: 250px;
|
||||
width: 307px;
|
||||
position: relative;
|
||||
float: left;
|
||||
#repl_results, #repl_source_wrap {
|
||||
width: auto; height: auto;
|
||||
position: absolute;
|
||||
margin-bottom: 0;
|
||||
top: 10px; left: 10px; right: 10px; bottom: 15px;
|
||||
}
|
||||
#repl_source {
|
||||
width: 96%;
|
||||
height: 250px;
|
||||
border: 0;
|
||||
resize: none;
|
||||
#repl_source_wrap {
|
||||
margin-left: 5px;
|
||||
width: 47%; right: 50%;
|
||||
float: left;
|
||||
}
|
||||
#repl_results {
|
||||
font-family: Monaco, Consolas, "Lucida Console", monospace;
|
||||
text-transform: none;
|
||||
font-weight: normal;
|
||||
height: 260px;
|
||||
margin-bottom: 25px;
|
||||
overflow-y: auto;
|
||||
width: 370px;
|
||||
}
|
||||
body.full_screen #repl_results, body.full_screen #repl_source_wrap {
|
||||
width: auto; height: auto;
|
||||
position: absolute;
|
||||
margin-bottom: 0;
|
||||
top: 10px; left: 10px; right: 10px; bottom: 40px;
|
||||
}
|
||||
body.full_screen #repl_source {
|
||||
#repl_source {
|
||||
padding-left: 5px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: 0;
|
||||
overflow-y: auto;
|
||||
resize: none;
|
||||
}
|
||||
body.full_screen #repl_source_wrap {
|
||||
right: 50%;
|
||||
}
|
||||
body.full_screen #repl_results {
|
||||
#repl_results_wrap {
|
||||
white-space: pre;
|
||||
}
|
||||
#repl_results {
|
||||
text-transform: none;
|
||||
overflow-y: auto;
|
||||
left: 50%;
|
||||
border-left-color: #555;
|
||||
}
|
||||
|
||||
/*----------------------------- Mini Buttons ---------------------------------*/
|
||||
.minibutton {
|
||||
cursor: pointer;
|
||||
color: #333;
|
||||
text-shadow: #eee 0 1px 1px;
|
||||
font-weight: bold;
|
||||
font-size: 11px;
|
||||
line-height: 11px;
|
||||
padding: 5px 10px 6px;
|
||||
height: 11px;
|
||||
text-align: center;
|
||||
-webkit-border-radius: 3px; -moz-border-radius: 3px; border-radius: 3px;
|
||||
box-shadow: 0 1px 2px rgba(0,0,0,0.2); -webkit-box-shadow: 0 1px 2px rgba(0,0,0,0.2); -moz-box-shadow: 0 1px 2px rgba(0,0,0,0.2);
|
||||
border: 1px solid #b2b2b2; border-top-color: #c9c9c9; border-bottom-color: #9a9a9a;
|
||||
background: url(../images/button_bg.png) repeat-x left top;
|
||||
}
|
||||
.minibutton:active {
|
||||
border-color: #aaa;
|
||||
box-shadow: 0 1px 2px #e4e4e4; -webkit-box-shadow: 0 1px 2px #e4e4e4; -moz-box-shadow: 0 1px 2px #e4e4e4;
|
||||
}
|
||||
.minibutton::selection {
|
||||
background: transparent;
|
||||
}
|
||||
.minibutton ::-moz-selection {
|
||||
background: transparent;
|
||||
}
|
||||
.minibutton.ok {
|
||||
color: #fff;
|
||||
background-image: url(../images/button_bg_green.gif);
|
||||
border-color: #4ba47c; border-top-color: #53b388; border-bottom-color: #459671;
|
||||
text-shadow: #aaa 0 -1px 0;
|
||||
}
|
||||
.minibutton.dark {
|
||||
border: 0;
|
||||
color: #fff;
|
||||
box-shadow: none; -webkit-box-shadow: none; -moz-box-shadow: none;
|
||||
background-image: url(../images/button_bg_dark.gif);
|
||||
text-shadow: none;
|
||||
}
|
||||
@@ -4,38 +4,38 @@ contains the main entry functions for tokenizing, parsing, and compiling
|
||||
source CoffeeScript into JavaScript.</p>
|
||||
|
||||
<p>If included on a webpage, it will automatically sniff out, compile, and
|
||||
execute all scripts present in <code>text/coffeescript</code> tags.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">fs = </span><span class="nx">require</span> <span class="s1">'fs'</span>
|
||||
<span class="nv">path = </span><span class="nx">require</span> <span class="s1">'path'</span>
|
||||
<span class="p">{</span><span class="nx">Lexer</span><span class="p">}</span> <span class="o">=</span> <span class="nx">require</span> <span class="s1">'./lexer'</span>
|
||||
<span class="p">{</span><span class="nx">parser</span><span class="p">}</span> <span class="o">=</span> <span class="nx">require</span> <span class="s1">'./parser'</span></pre></div> </td> </tr> <tr id="section-2"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-2">¶</a> </div> <p>TODO: Remove registerExtension when fully deprecated.</p> </td> <td class="code"> <div class="highlight"><pre><span class="k">if</span> <span class="nx">require</span><span class="p">.</span><span class="nx">extensions</span>
|
||||
execute all scripts present in <code>text/coffeescript</code> tags.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">fs = </span><span class="nx">require</span> <span class="s1">'fs'</span>
|
||||
<span class="nv">path = </span><span class="nx">require</span> <span class="s1">'path'</span>
|
||||
<span class="p">{</span><span class="nx">Lexer</span><span class="p">,</span><span class="nx">RESERVED</span><span class="p">}</span> <span class="o">=</span> <span class="nx">require</span> <span class="s1">'./lexer'</span>
|
||||
<span class="p">{</span><span class="nx">parser</span><span class="p">}</span> <span class="o">=</span> <span class="nx">require</span> <span class="s1">'./parser'</span></pre></div> </td> </tr> <tr id="section-2"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-2">¶</a> </div> <p>TODO: Remove registerExtension when fully deprecated.</p> </td> <td class="code"> <div class="highlight"><pre><span class="k">if</span> <span class="nx">require</span><span class="p">.</span><span class="nx">extensions</span>
|
||||
<span class="nx">require</span><span class="p">.</span><span class="nx">extensions</span><span class="p">[</span><span class="s1">'.coffee'</span><span class="p">]</span> <span class="o">=</span> <span class="p">(</span><span class="nx">module</span><span class="p">,</span> <span class="nx">filename</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nv">content = </span><span class="nx">compile</span> <span class="nx">fs</span><span class="p">.</span><span class="nx">readFileSync</span> <span class="nx">filename</span><span class="p">,</span> <span class="s1">'utf8'</span>
|
||||
<span class="nx">module</span><span class="p">.</span><span class="nx">_compile</span> <span class="nx">content</span><span class="p">,</span> <span class="nx">filename</span>
|
||||
<span class="k">else</span> <span class="k">if</span> <span class="nx">require</span><span class="p">.</span><span class="nx">registerExtension</span>
|
||||
<span class="nx">require</span><span class="p">.</span><span class="nx">registerExtension</span> <span class="s1">'.coffee'</span><span class="p">,</span> <span class="p">(</span><span class="nx">content</span><span class="p">)</span> <span class="o">-></span> <span class="nx">compile</span> <span class="nx">content</span></pre></div> </td> </tr> <tr id="section-3"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-3">¶</a> </div> <p>The current CoffeeScript version number.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.VERSION = </span><span class="s1">'0.9.6'</span></pre></div> </td> </tr> <tr id="section-4"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-4">¶</a> </div> <p>Expose helpers for testing.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.helpers = </span><span class="nx">require</span> <span class="s1">'./helpers'</span></pre></div> </td> </tr> <tr id="section-5"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-5">¶</a> </div> <p>Compile a string of CoffeeScript code to JavaScript, using the Coffee/Jison
|
||||
<span class="nx">require</span><span class="p">.</span><span class="nx">registerExtension</span> <span class="s1">'.coffee'</span><span class="p">,</span> <span class="p">(</span><span class="nx">content</span><span class="p">)</span> <span class="o">-></span> <span class="nx">compile</span> <span class="nx">content</span></pre></div> </td> </tr> <tr id="section-3"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-3">¶</a> </div> <p>The current CoffeeScript version number.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.VERSION = </span><span class="s1">'1.0.0'</span></pre></div> </td> </tr> <tr id="section-4"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-4">¶</a> </div> <p>Words that cannot be used as identifiers in CoffeeScript code</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.RESERVED = </span><span class="nx">RESERVED</span></pre></div> </td> </tr> <tr id="section-5"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-5">¶</a> </div> <p>Expose helpers for testing.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.helpers = </span><span class="nx">require</span> <span class="s1">'./helpers'</span></pre></div> </td> </tr> <tr id="section-6"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-6">¶</a> </div> <p>Compile a string of CoffeeScript code to JavaScript, using the Coffee/Jison
|
||||
compiler.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.compile = compile = </span><span class="p">(</span><span class="nx">code</span><span class="p">,</span> <span class="nv">options = </span><span class="p">{})</span> <span class="o">-></span>
|
||||
<span class="k">try</span>
|
||||
<span class="p">(</span><span class="nx">parser</span><span class="p">.</span><span class="nx">parse</span> <span class="nx">lexer</span><span class="p">.</span><span class="nx">tokenize</span> <span class="nx">code</span><span class="p">).</span><span class="nx">compile</span> <span class="nx">options</span>
|
||||
<span class="k">catch</span> <span class="nx">err</span>
|
||||
<span class="nv">err.message = </span><span class="s2">"In #{options.fileName}, #{err.message}"</span> <span class="k">if</span> <span class="nx">options</span><span class="p">.</span><span class="nx">fileName</span>
|
||||
<span class="k">throw</span> <span class="nx">err</span></pre></div> </td> </tr> <tr id="section-6"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-6">¶</a> </div> <p>Tokenize a string of CoffeeScript code, and return the array of tokens.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.tokens = </span><span class="p">(</span><span class="nx">code</span><span class="p">,</span> <span class="nx">options</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nx">lexer</span><span class="p">.</span><span class="nx">tokenize</span> <span class="nx">code</span><span class="p">,</span> <span class="nx">options</span></pre></div> </td> </tr> <tr id="section-7"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-7">¶</a> </div> <p>Parse a string of CoffeeScript code or an array of lexed tokens, and
|
||||
<span class="k">throw</span> <span class="nx">err</span></pre></div> </td> </tr> <tr id="section-7"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-7">¶</a> </div> <p>Tokenize a string of CoffeeScript code, and return the array of tokens.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.tokens = </span><span class="p">(</span><span class="nx">code</span><span class="p">,</span> <span class="nx">options</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nx">lexer</span><span class="p">.</span><span class="nx">tokenize</span> <span class="nx">code</span><span class="p">,</span> <span class="nx">options</span></pre></div> </td> </tr> <tr id="section-8"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-8">¶</a> </div> <p>Parse a string of CoffeeScript code or an array of lexed tokens, and
|
||||
return the AST. You can then compile it by calling <code>.compile()</code> on the root,
|
||||
or traverse it by using <code>.traverse()</code> with a callback.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.nodes = </span><span class="p">(</span><span class="nx">source</span><span class="p">,</span> <span class="nx">options</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="k">if</span> <span class="k">typeof</span> <span class="nx">source</span> <span class="o">is</span> <span class="s1">'string'</span>
|
||||
<span class="nx">parser</span><span class="p">.</span><span class="nx">parse</span> <span class="nx">lexer</span><span class="p">.</span><span class="nx">tokenize</span> <span class="nx">source</span><span class="p">,</span> <span class="nx">options</span>
|
||||
<span class="k">else</span>
|
||||
<span class="nx">parser</span><span class="p">.</span><span class="nx">parse</span> <span class="nx">source</span></pre></div> </td> </tr> <tr id="section-8"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-8">¶</a> </div> <p>Compile and execute a string of CoffeeScript (on the server), correctly
|
||||
setting <code>__filename</code>, <code>__dirname</code>, and relative <code>require()</code>.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.run = </span><span class="p">(</span><span class="nx">code</span><span class="p">,</span> <span class="nx">options</span><span class="p">)</span> <span class="o">-></span></pre></div> </td> </tr> <tr id="section-9"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-9">¶</a> </div> <p>We want the root module.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">root = </span><span class="nx">module</span>
|
||||
<span class="nx">parser</span><span class="p">.</span><span class="nx">parse</span> <span class="nx">source</span></pre></div> </td> </tr> <tr id="section-9"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-9">¶</a> </div> <p>Compile and execute a string of CoffeeScript (on the server), correctly
|
||||
setting <code>__filename</code>, <code>__dirname</code>, and relative <code>require()</code>.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.run = </span><span class="p">(</span><span class="nx">code</span><span class="p">,</span> <span class="nx">options</span><span class="p">)</span> <span class="o">-></span></pre></div> </td> </tr> <tr id="section-10"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-10">¶</a> </div> <p>We want the root module.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">root = </span><span class="nx">module</span>
|
||||
<span class="k">while</span> <span class="nx">root</span><span class="p">.</span><span class="nx">parent</span>
|
||||
<span class="nv">root = </span><span class="nx">root</span><span class="p">.</span><span class="nx">parent</span></pre></div> </td> </tr> <tr id="section-10"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-10">¶</a> </div> <p>Set the filename.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">root.filename = </span><span class="nx">fs</span><span class="p">.</span><span class="nx">realpathSync</span> <span class="nx">options</span><span class="p">.</span><span class="nx">fileName</span> <span class="o">or</span> <span class="s1">'.'</span></pre></div> </td> </tr> <tr id="section-11"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-11">¶</a> </div> <p>Clear the module cache.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">root.moduleCache = </span><span class="p">{}</span> <span class="k">if</span> <span class="nx">root</span><span class="p">.</span><span class="nx">moduleCache</span></pre></div> </td> </tr> <tr id="section-12"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-12">¶</a> </div> <p>Compile.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="k">if</span> <span class="nx">path</span><span class="p">.</span><span class="nx">extname</span><span class="p">(</span><span class="nx">root</span><span class="p">.</span><span class="nx">filename</span><span class="p">)</span> <span class="o">isnt</span> <span class="s1">'.coffee'</span> <span class="o">or</span> <span class="nx">require</span><span class="p">.</span><span class="nx">extensions</span>
|
||||
<span class="nv">root = </span><span class="nx">root</span><span class="p">.</span><span class="nx">parent</span></pre></div> </td> </tr> <tr id="section-11"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-11">¶</a> </div> <p>Set the filename.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">root.filename = </span><span class="nx">fs</span><span class="p">.</span><span class="nx">realpathSync</span> <span class="nx">options</span><span class="p">.</span><span class="nx">fileName</span> <span class="o">or</span> <span class="s1">'.'</span></pre></div> </td> </tr> <tr id="section-12"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-12">¶</a> </div> <p>Clear the module cache.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">root.moduleCache = </span><span class="p">{}</span> <span class="k">if</span> <span class="nx">root</span><span class="p">.</span><span class="nx">moduleCache</span></pre></div> </td> </tr> <tr id="section-13"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-13">¶</a> </div> <p>Compile.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="k">if</span> <span class="nx">path</span><span class="p">.</span><span class="nx">extname</span><span class="p">(</span><span class="nx">root</span><span class="p">.</span><span class="nx">filename</span><span class="p">)</span> <span class="o">isnt</span> <span class="s1">'.coffee'</span> <span class="o">or</span> <span class="nx">require</span><span class="p">.</span><span class="nx">extensions</span>
|
||||
<span class="nx">root</span><span class="p">.</span><span class="nx">_compile</span> <span class="nx">compile</span><span class="p">(</span><span class="nx">code</span><span class="p">,</span> <span class="nx">options</span><span class="p">),</span> <span class="nx">root</span><span class="p">.</span><span class="nx">filename</span>
|
||||
<span class="k">else</span>
|
||||
<span class="nx">root</span><span class="p">.</span><span class="nx">_compile</span> <span class="nx">code</span><span class="p">,</span> <span class="nx">root</span><span class="p">.</span><span class="nx">filename</span></pre></div> </td> </tr> <tr id="section-13"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-13">¶</a> </div> <p>Compile and evaluate a string of CoffeeScript (in a Node.js-like environment).
|
||||
<span class="nx">root</span><span class="p">.</span><span class="nx">_compile</span> <span class="nx">code</span><span class="p">,</span> <span class="nx">root</span><span class="p">.</span><span class="nx">filename</span></pre></div> </td> </tr> <tr id="section-14"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-14">¶</a> </div> <p>Compile and evaluate a string of CoffeeScript (in a Node.js-like environment).
|
||||
The CoffeeScript REPL uses this to run the input.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.eval = </span><span class="p">(</span><span class="nx">code</span><span class="p">,</span> <span class="nx">options</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nv">__filename = </span><span class="nx">options</span><span class="p">.</span><span class="nx">fileName</span>
|
||||
<span class="nv">__dirname = </span><span class="nx">path</span><span class="p">.</span><span class="nx">dirname</span> <span class="nx">__filename</span>
|
||||
<span class="nb">eval</span> <span class="nx">compile</span> <span class="nx">code</span><span class="p">,</span> <span class="nx">options</span></pre></div> </td> </tr> <tr id="section-14"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-14">¶</a> </div> <p>Instantiate a Lexer for our use here.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">lexer = </span><span class="k">new</span> <span class="nx">Lexer</span></pre></div> </td> </tr> <tr id="section-15"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-15">¶</a> </div> <p>The real Lexer produces a generic stream of tokens. This object provides a
|
||||
<span class="nb">eval</span> <span class="nx">compile</span> <span class="nx">code</span><span class="p">,</span> <span class="nx">options</span></pre></div> </td> </tr> <tr id="section-15"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-15">¶</a> </div> <p>Instantiate a Lexer for our use here.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">lexer = </span><span class="k">new</span> <span class="nx">Lexer</span></pre></div> </td> </tr> <tr id="section-16"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-16">¶</a> </div> <p>The real Lexer produces a generic stream of tokens. This object provides a
|
||||
thin wrapper around it, compatible with the Jison API. We can then pass it
|
||||
directly as a "Jison lexer".</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">parser.lexer =</span>
|
||||
<span class="nx">lex</span><span class="o">:</span> <span class="o">-></span>
|
||||
|
||||
@@ -18,6 +18,7 @@ interactive REPL.</p> </td> <td class="code">
|
||||
<span class="p">[</span><span class="s1">'-c'</span><span class="p">,</span> <span class="s1">'--compile'</span><span class="p">,</span> <span class="s1">'compile to JavaScript and save as .js files'</span><span class="p">]</span>
|
||||
<span class="p">[</span><span class="s1">'-i'</span><span class="p">,</span> <span class="s1">'--interactive'</span><span class="p">,</span> <span class="s1">'run an interactive CoffeeScript REPL'</span><span class="p">]</span>
|
||||
<span class="p">[</span><span class="s1">'-o'</span><span class="p">,</span> <span class="s1">'--output [DIR]'</span><span class="p">,</span> <span class="s1">'set the directory for compiled JavaScript'</span><span class="p">]</span>
|
||||
<span class="p">[</span><span class="s1">'-j'</span><span class="p">,</span> <span class="s1">'--join'</span><span class="p">,</span> <span class="s1">'concatenate the scripts before compiling'</span><span class="p">]</span>
|
||||
<span class="p">[</span><span class="s1">'-w'</span><span class="p">,</span> <span class="s1">'--watch'</span><span class="p">,</span> <span class="s1">'watch scripts for changes, and recompile'</span><span class="p">]</span>
|
||||
<span class="p">[</span><span class="s1">'-p'</span><span class="p">,</span> <span class="s1">'--print'</span><span class="p">,</span> <span class="s1">'print the compiled JavaScript to stdout'</span><span class="p">]</span>
|
||||
<span class="p">[</span><span class="s1">'-l'</span><span class="p">,</span> <span class="s1">'--lint'</span><span class="p">,</span> <span class="s1">'pipe the compiled JavaScript through JSLint'</span><span class="p">]</span>
|
||||
@@ -27,33 +28,27 @@ interactive REPL.</p> </td> <td class="code">
|
||||
<span class="p">[</span><span class="s1">'-b'</span><span class="p">,</span> <span class="s1">'--bare'</span><span class="p">,</span> <span class="s1">'compile without the top-level function wrapper'</span><span class="p">]</span>
|
||||
<span class="p">[</span><span class="s1">'-t'</span><span class="p">,</span> <span class="s1">'--tokens'</span><span class="p">,</span> <span class="s1">'print the tokens that the lexer produces'</span><span class="p">]</span>
|
||||
<span class="p">[</span><span class="s1">'-n'</span><span class="p">,</span> <span class="s1">'--nodes'</span><span class="p">,</span> <span class="s1">'print the parse tree that Jison produces'</span><span class="p">]</span>
|
||||
<span class="p">[</span> <span class="s1">'--nodejs [ARGS]'</span><span class="p">,</span> <span class="s1">'pass options through to the "node" binary'</span><span class="p">]</span>
|
||||
<span class="p">[</span><span class="s1">'-v'</span><span class="p">,</span> <span class="s1">'--version'</span><span class="p">,</span> <span class="s1">'display CoffeeScript version'</span><span class="p">]</span>
|
||||
<span class="p">[</span><span class="s1">'-h'</span><span class="p">,</span> <span class="s1">'--help'</span><span class="p">,</span> <span class="s1">'display this help message'</span><span class="p">]</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-6"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-6">¶</a> </div> <p>Switches that are still supported, but will cause a warning message.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">DEPRECATED_SWITCHES = </span><span class="p">[</span>
|
||||
<span class="p">[</span><span class="s1">'--no-wrap'</span><span class="p">,</span> <span class="s1">'compile without the top-level function wrapper'</span><span class="p">]</span>
|
||||
<span class="p">]</span>
|
||||
|
||||
<span class="nv">ALL_SWITCHES = </span><span class="nx">SWITCHES</span><span class="p">.</span><span class="nx">concat</span> <span class="nx">DEPRECATED_SWITCHES</span></pre></div> </td> </tr> <tr id="section-7"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-7">¶</a> </div> <p>Top-level objects shared by all the functions.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">opts = </span><span class="p">{}</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-6"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-6">¶</a> </div> <p>Top-level objects shared by all the functions.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">opts = </span><span class="p">{}</span>
|
||||
<span class="nv">sources = </span><span class="p">[]</span>
|
||||
<span class="nv">optionParser = </span><span class="kc">null</span></pre></div> </td> </tr> <tr id="section-8"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-8">¶</a> </div> <p>Run <code>coffee</code> by parsing passed options and determining what action to take.
|
||||
<span class="nv">contents = </span><span class="p">[]</span>
|
||||
<span class="nv">optionParser = </span><span class="kc">null</span></pre></div> </td> </tr> <tr id="section-7"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-7">¶</a> </div> <p>Run <code>coffee</code> by parsing passed options and determining what action to take.
|
||||
Many flags cause us to divert before compiling anything. Flags passed after
|
||||
<code>--</code> will be passed verbatim to your script as arguments in <code>process.argv</code></p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.run = </span><span class="o">-></span>
|
||||
<span class="nx">parseOptions</span><span class="p">()</span>
|
||||
<span class="k">return</span> <span class="nx">usage</span><span class="p">()</span> <span class="k">if</span> <span class="nx">opts</span><span class="p">.</span><span class="nx">help</span>
|
||||
<span class="k">return</span> <span class="nx">version</span><span class="p">()</span> <span class="k">if</span> <span class="nx">opts</span><span class="p">.</span><span class="nx">version</span>
|
||||
<span class="k">return</span> <span class="nx">require</span> <span class="s1">'./repl'</span> <span class="k">if</span> <span class="nx">opts</span><span class="p">.</span><span class="nx">interactive</span>
|
||||
<span class="k">return</span> <span class="nx">compileStdio</span><span class="p">()</span> <span class="k">if</span> <span class="nx">opts</span><span class="p">.</span><span class="nx">stdio</span>
|
||||
<span class="k">return</span> <span class="nx">compileScript</span> <span class="kc">null</span><span class="p">,</span> <span class="nx">sources</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="k">if</span> <span class="nx">opts</span><span class="p">.</span><span class="nb">eval</span>
|
||||
<span class="k">return</span> <span class="nx">require</span> <span class="s1">'./repl'</span> <span class="nx">unless</span> <span class="nx">sources</span><span class="p">.</span><span class="nx">length</span>
|
||||
<span class="nv">separator = </span><span class="nx">sources</span><span class="p">.</span><span class="nx">indexOf</span> <span class="s1">'--'</span>
|
||||
<span class="nv">flags = </span><span class="p">[]</span>
|
||||
<span class="k">if</span> <span class="nx">separator</span> <span class="o">>=</span> <span class="mi">0</span>
|
||||
<span class="nv">flags = </span><span class="nx">sources</span><span class="p">.</span><span class="nx">splice</span> <span class="nx">separator</span> <span class="o">+</span> <span class="mi">1</span>
|
||||
<span class="nx">sources</span><span class="p">.</span><span class="nx">pop</span><span class="p">()</span>
|
||||
<span class="k">return</span> <span class="nx">forkNode</span><span class="p">()</span> <span class="k">if</span> <span class="nx">opts</span><span class="p">.</span><span class="nx">nodejs</span>
|
||||
<span class="k">return</span> <span class="nx">usage</span><span class="p">()</span> <span class="k">if</span> <span class="nx">opts</span><span class="p">.</span><span class="nx">help</span>
|
||||
<span class="k">return</span> <span class="nx">version</span><span class="p">()</span> <span class="k">if</span> <span class="nx">opts</span><span class="p">.</span><span class="nx">version</span>
|
||||
<span class="k">return</span> <span class="nx">require</span> <span class="s1">'./repl'</span> <span class="k">if</span> <span class="nx">opts</span><span class="p">.</span><span class="nx">interactive</span>
|
||||
<span class="k">return</span> <span class="nx">compileStdio</span><span class="p">()</span> <span class="k">if</span> <span class="nx">opts</span><span class="p">.</span><span class="nx">stdio</span>
|
||||
<span class="k">return</span> <span class="nx">compileScript</span> <span class="kc">null</span><span class="p">,</span> <span class="nx">sources</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="k">if</span> <span class="nx">opts</span><span class="p">.</span><span class="nb">eval</span>
|
||||
<span class="k">return</span> <span class="nx">require</span> <span class="s1">'./repl'</span> <span class="nx">unless</span> <span class="nx">sources</span><span class="p">.</span><span class="nx">length</span>
|
||||
<span class="k">if</span> <span class="nx">opts</span><span class="p">.</span><span class="nx">run</span>
|
||||
<span class="nv">flags = </span><span class="nx">sources</span><span class="p">.</span><span class="nx">splice</span><span class="p">(</span><span class="mi">1</span><span class="p">).</span><span class="nx">concat</span> <span class="nx">flags</span>
|
||||
<span class="nv">process.ARGV = process.argv = </span><span class="nx">flags</span>
|
||||
<span class="nx">compileScripts</span><span class="p">()</span></pre></div> </td> </tr> <tr id="section-9"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-9">¶</a> </div> <p>Asynchronously read in each CoffeeScript in a list of source files and
|
||||
<span class="nv">opts.literals = </span><span class="nx">sources</span><span class="p">.</span><span class="nx">splice</span><span class="p">(</span><span class="mi">1</span><span class="p">).</span><span class="nx">concat</span> <span class="nx">opts</span><span class="p">.</span><span class="nx">literals</span>
|
||||
<span class="nv">process.ARGV = process.argv = </span><span class="nx">process</span><span class="p">.</span><span class="nx">argv</span><span class="p">.</span><span class="nx">slice</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">2</span><span class="p">).</span><span class="nx">concat</span> <span class="nx">opts</span><span class="p">.</span><span class="nx">literals</span>
|
||||
<span class="nx">compileScripts</span><span class="p">()</span></pre></div> </td> </tr> <tr id="section-8"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-8">¶</a> </div> <p>Asynchronously read in each CoffeeScript in a list of source files and
|
||||
compile them. If a directory is passed, recursively compile all
|
||||
'.coffee' extension source files in it and all subdirectories.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">compileScripts = </span><span class="o">-></span>
|
||||
<span class="k">for</span> <span class="nx">source</span> <span class="k">in</span> <span class="nx">sources</span>
|
||||
@@ -67,9 +62,14 @@ compile them. If a directory is passed, recursively compile all
|
||||
<span class="k">for</span> <span class="nx">file</span> <span class="k">in</span> <span class="nx">files</span>
|
||||
<span class="nx">compile</span> <span class="nx">path</span><span class="p">.</span><span class="nx">join</span><span class="p">(</span><span class="nx">source</span><span class="p">,</span> <span class="nx">file</span><span class="p">)</span>
|
||||
<span class="k">else</span> <span class="k">if</span> <span class="nx">topLevel</span> <span class="o">or</span> <span class="nx">path</span><span class="p">.</span><span class="nx">extname</span><span class="p">(</span><span class="nx">source</span><span class="p">)</span> <span class="o">is</span> <span class="s1">'.coffee'</span>
|
||||
<span class="nx">fs</span><span class="p">.</span><span class="nx">readFile</span> <span class="nx">source</span><span class="p">,</span> <span class="p">(</span><span class="nx">err</span><span class="p">,</span> <span class="nx">code</span><span class="p">)</span> <span class="o">-></span> <span class="nx">compileScript</span><span class="p">(</span><span class="nx">source</span><span class="p">,</span> <span class="nx">code</span><span class="p">.</span><span class="nx">toString</span><span class="p">(),</span> <span class="nx">base</span><span class="p">)</span>
|
||||
<span class="nx">watch</span> <span class="nx">source</span><span class="p">,</span> <span class="nx">base</span> <span class="k">if</span> <span class="nx">opts</span><span class="p">.</span><span class="nx">watch</span>
|
||||
<span class="nx">compile</span> <span class="nx">source</span><span class="p">,</span> <span class="kc">true</span></pre></div> </td> </tr> <tr id="section-10"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-10">¶</a> </div> <p>Compile a single source script, containing the given code, according to the
|
||||
<span class="nx">fs</span><span class="p">.</span><span class="nx">readFile</span> <span class="nx">source</span><span class="p">,</span> <span class="p">(</span><span class="nx">err</span><span class="p">,</span> <span class="nx">code</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="k">if</span> <span class="nx">opts</span><span class="p">.</span><span class="nx">join</span>
|
||||
<span class="nx">contents</span><span class="p">[</span><span class="nx">sources</span><span class="p">.</span><span class="nx">indexOf</span> <span class="nx">source</span><span class="p">]</span> <span class="o">=</span> <span class="nx">code</span><span class="p">.</span><span class="nx">toString</span><span class="p">()</span>
|
||||
<span class="nx">compileJoin</span><span class="p">()</span> <span class="k">if</span> <span class="nx">helpers</span><span class="p">.</span><span class="nx">compact</span><span class="p">(</span><span class="nx">contents</span><span class="p">).</span><span class="nx">length</span> <span class="o">is</span> <span class="nx">sources</span><span class="p">.</span><span class="nx">length</span>
|
||||
<span class="k">else</span>
|
||||
<span class="nx">compileScript</span><span class="p">(</span><span class="nx">source</span><span class="p">,</span> <span class="nx">code</span><span class="p">.</span><span class="nx">toString</span><span class="p">(),</span> <span class="nx">base</span><span class="p">)</span>
|
||||
<span class="nx">watch</span> <span class="nx">source</span><span class="p">,</span> <span class="nx">base</span> <span class="k">if</span> <span class="nx">opts</span><span class="p">.</span><span class="nx">watch</span> <span class="o">and</span> <span class="o">not</span> <span class="nx">opts</span><span class="p">.</span><span class="nx">join</span>
|
||||
<span class="nx">compile</span> <span class="nx">source</span><span class="p">,</span> <span class="kc">true</span></pre></div> </td> </tr> <tr id="section-9"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-9">¶</a> </div> <p>Compile a single source script, containing the given code, according to the
|
||||
requested options. If evaluating the script directly sets <code>__filename</code>,
|
||||
<code>__dirname</code> and <code>module.filename</code> to be correct relative to the script's path.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">compileScript = </span><span class="p">(</span><span class="nx">file</span><span class="p">,</span> <span class="nx">input</span><span class="p">,</span> <span class="nx">base</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nv">o = </span><span class="nx">opts</span>
|
||||
@@ -93,14 +93,17 @@ requested options. If evaluating the script directly sets <code>__filename</code
|
||||
<span class="k">return</span> <span class="k">if</span> <span class="nx">CoffeeScript</span><span class="p">.</span><span class="nx">listeners</span><span class="p">(</span><span class="s1">'failure'</span><span class="p">).</span><span class="nx">length</span>
|
||||
<span class="k">return</span> <span class="nx">printLine</span> <span class="nx">err</span><span class="p">.</span><span class="nx">message</span> <span class="k">if</span> <span class="nx">o</span><span class="p">.</span><span class="nx">watch</span>
|
||||
<span class="nx">printWarn</span> <span class="nx">err</span><span class="p">.</span><span class="nx">stack</span>
|
||||
<span class="nx">process</span><span class="p">.</span><span class="nx">exit</span> <span class="mi">1</span></pre></div> </td> </tr> <tr id="section-11"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-11">¶</a> </div> <p>Attach the appropriate listeners to compile scripts incoming over <strong>stdin</strong>,
|
||||
<span class="nx">process</span><span class="p">.</span><span class="nx">exit</span> <span class="mi">1</span></pre></div> </td> </tr> <tr id="section-10"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-10">¶</a> </div> <p>Attach the appropriate listeners to compile scripts incoming over <strong>stdin</strong>,
|
||||
and write them back to <strong>stdout</strong>.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">compileStdio = </span><span class="o">-></span>
|
||||
<span class="nv">code = </span><span class="s1">''</span>
|
||||
<span class="nv">stdin = </span><span class="nx">process</span><span class="p">.</span><span class="nx">openStdin</span><span class="p">()</span>
|
||||
<span class="nx">stdin</span><span class="p">.</span><span class="kc">on</span> <span class="s1">'data'</span><span class="p">,</span> <span class="p">(</span><span class="nx">buffer</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nx">code</span> <span class="o">+=</span> <span class="nx">buffer</span><span class="p">.</span><span class="nx">toString</span><span class="p">()</span> <span class="k">if</span> <span class="nx">buffer</span>
|
||||
<span class="nx">stdin</span><span class="p">.</span><span class="kc">on</span> <span class="s1">'end'</span><span class="p">,</span> <span class="o">-></span>
|
||||
<span class="nx">compileScript</span> <span class="kc">null</span><span class="p">,</span> <span class="nx">code</span></pre></div> </td> </tr> <tr id="section-12"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-12">¶</a> </div> <p>Watch a source CoffeeScript file using <code>fs.watchFile</code>, recompiling it every
|
||||
<span class="nx">compileScript</span> <span class="kc">null</span><span class="p">,</span> <span class="nx">code</span></pre></div> </td> </tr> <tr id="section-11"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-11">¶</a> </div> <p>After all of the source files are done being read, concatenate and compile
|
||||
them together.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">compileJoin = </span><span class="o">-></span>
|
||||
<span class="nv">code = </span><span class="nx">contents</span><span class="p">.</span><span class="nx">join</span> <span class="s1">'\n'</span>
|
||||
<span class="nx">compileScript</span> <span class="s2">"concatenation"</span><span class="p">,</span> <span class="nx">code</span><span class="p">,</span> <span class="s2">"concatenation"</span></pre></div> </td> </tr> <tr id="section-12"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-12">¶</a> </div> <p>Watch a source CoffeeScript file using <code>fs.watchFile</code>, recompiling it every
|
||||
time the file is updated. May be used in combination with other options,
|
||||
such as <code>--lint</code> or <code>--print</code>.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">watch = </span><span class="p">(</span><span class="nx">source</span><span class="p">,</span> <span class="nx">base</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nx">fs</span><span class="p">.</span><span class="nx">watchFile</span> <span class="nx">source</span><span class="p">,</span> <span class="p">{</span><span class="nx">persistent</span><span class="o">:</span> <span class="kc">true</span><span class="p">,</span> <span class="nx">interval</span><span class="o">:</span> <span class="mi">500</span><span class="p">},</span> <span class="p">(</span><span class="nx">curr</span><span class="p">,</span> <span class="nx">prev</span><span class="p">)</span> <span class="o">-></span>
|
||||
@@ -112,7 +115,7 @@ are written out in <code>cwd</code> as <code>.js</code> files with the same name
|
||||
directory can be customized with <code>--output</code>.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">writeJs = </span><span class="p">(</span><span class="nx">source</span><span class="p">,</span> <span class="nx">js</span><span class="p">,</span> <span class="nx">base</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nv">filename = </span><span class="nx">path</span><span class="p">.</span><span class="nx">basename</span><span class="p">(</span><span class="nx">source</span><span class="p">,</span> <span class="nx">path</span><span class="p">.</span><span class="nx">extname</span><span class="p">(</span><span class="nx">source</span><span class="p">))</span> <span class="o">+</span> <span class="s1">'.js'</span>
|
||||
<span class="nv">srcDir = </span><span class="nx">path</span><span class="p">.</span><span class="nx">dirname</span> <span class="nx">source</span>
|
||||
<span class="nv">baseDir = </span><span class="nx">srcDir</span><span class="p">.</span><span class="nx">substring</span> <span class="nx">base</span><span class="p">.</span><span class="nx">length</span>
|
||||
<span class="nv">baseDir = </span><span class="k">if</span> <span class="nx">base</span> <span class="o">is</span> <span class="s1">'.'</span> <span class="k">then</span> <span class="nx">srcDir</span> <span class="k">else</span> <span class="nx">srcDir</span><span class="p">.</span><span class="nx">substring</span> <span class="nx">base</span><span class="p">.</span><span class="nx">length</span>
|
||||
<span class="nv">dir = </span><span class="k">if</span> <span class="nx">opts</span><span class="p">.</span><span class="nx">output</span> <span class="k">then</span> <span class="nx">path</span><span class="p">.</span><span class="nx">join</span> <span class="nx">opts</span><span class="p">.</span><span class="nx">output</span><span class="p">,</span> <span class="nx">baseDir</span> <span class="k">else</span> <span class="nx">srcDir</span>
|
||||
<span class="nv">jsPath = </span><span class="nx">path</span><span class="p">.</span><span class="nx">join</span> <span class="nx">dir</span><span class="p">,</span> <span class="nx">filename</span>
|
||||
<span class="nv">compile = </span><span class="o">-></span>
|
||||
@@ -135,17 +138,23 @@ any errors or warnings that arise.</p> </td> <td class="
|
||||
<span class="s2">"[#{tag} #{value}]"</span>
|
||||
<span class="nx">printLine</span> <span class="nx">strings</span><span class="p">.</span><span class="nx">join</span><span class="p">(</span><span class="s1">' '</span><span class="p">)</span></pre></div> </td> </tr> <tr id="section-16"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-16">¶</a> </div> <p>Use the <a href="optparse.html">OptionParser module</a> to extract all options from
|
||||
<code>process.argv</code> that are specified in <code>SWITCHES</code>.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">parseOptions = </span><span class="o">-></span>
|
||||
<span class="nv">optionParser = </span><span class="k">new</span> <span class="nx">optparse</span><span class="p">.</span><span class="nx">OptionParser</span> <span class="nx">ALL_SWITCHES</span><span class="p">,</span> <span class="nx">BANNER</span>
|
||||
<span class="nv">optionParser = </span><span class="k">new</span> <span class="nx">optparse</span><span class="p">.</span><span class="nx">OptionParser</span> <span class="nx">SWITCHES</span><span class="p">,</span> <span class="nx">BANNER</span>
|
||||
<span class="nv">o = opts = </span><span class="nx">optionParser</span><span class="p">.</span><span class="nx">parse</span> <span class="nx">process</span><span class="p">.</span><span class="nx">argv</span><span class="p">.</span><span class="nx">slice</span> <span class="mi">2</span>
|
||||
<span class="nx">o</span><span class="p">.</span><span class="nx">compile</span> <span class="o">or=</span> <span class="o">!!</span><span class="nx">o</span><span class="p">.</span><span class="nx">output</span>
|
||||
<span class="nv">o.run = </span><span class="o">not</span> <span class="p">(</span><span class="nx">o</span><span class="p">.</span><span class="nx">compile</span> <span class="o">or</span> <span class="nx">o</span><span class="p">.</span><span class="nx">print</span> <span class="o">or</span> <span class="nx">o</span><span class="p">.</span><span class="nx">lint</span><span class="p">)</span>
|
||||
<span class="nv">o.print = </span><span class="o">!!</span> <span class="p">(</span><span class="nx">o</span><span class="p">.</span><span class="nx">print</span> <span class="o">or</span> <span class="p">(</span><span class="nx">o</span><span class="p">.</span><span class="nb">eval</span> <span class="o">or</span> <span class="nx">o</span><span class="p">.</span><span class="nx">stdio</span> <span class="o">and</span> <span class="nx">o</span><span class="p">.</span><span class="nx">compile</span><span class="p">))</span>
|
||||
<span class="nv">sources = </span><span class="nx">o</span><span class="p">.</span><span class="nx">arguments</span>
|
||||
<span class="k">if</span> <span class="nx">opts</span><span class="p">[</span><span class="s1">'no-wrap'</span><span class="p">]</span>
|
||||
<span class="nx">printWarn</span> <span class="s1">'--no-wrap is deprecated; please use --bare instead.'</span></pre></div> </td> </tr> <tr id="section-17"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-17">¶</a> </div> <p>The compile-time options to pass to the CoffeeScript compiler.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">compileOptions = </span><span class="p">(</span><span class="nx">fileName</span><span class="p">)</span> <span class="o">-></span> <span class="p">{</span><span class="nx">fileName</span><span class="p">,</span> <span class="nx">bare</span><span class="o">:</span> <span class="nx">opts</span><span class="p">.</span><span class="nx">bare</span> <span class="o">or</span> <span class="nx">opts</span><span class="p">[</span><span class="s1">'no-wrap'</span><span class="p">]}</span></pre></div> </td> </tr> <tr id="section-18"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-18">¶</a> </div> <p>Print the <code>--help</code> usage message and exit. Deprecated switches are not
|
||||
<span class="nv">sources = </span><span class="nx">o</span><span class="p">.</span><span class="nx">arguments</span></pre></div> </td> </tr> <tr id="section-17"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-17">¶</a> </div> <p>The compile-time options to pass to the CoffeeScript compiler.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">compileOptions = </span><span class="p">(</span><span class="nx">fileName</span><span class="p">)</span> <span class="o">-></span> <span class="p">{</span><span class="nx">fileName</span><span class="p">,</span> <span class="nx">bare</span><span class="o">:</span> <span class="nx">opts</span><span class="p">.</span><span class="nx">bare</span><span class="p">}</span></pre></div> </td> </tr> <tr id="section-18"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-18">¶</a> </div> <p>Start up a new Node.js instance with the arguments in <code>--nodejs</code> passed to
|
||||
the <code>node</code> binary, preserving the other options.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">forkNode = </span><span class="o">-></span>
|
||||
<span class="nv">nodeArgs = </span><span class="nx">opts</span><span class="p">.</span><span class="nx">nodejs</span><span class="p">.</span><span class="nx">split</span> <span class="sr">/\s+/</span>
|
||||
<span class="nv">args = </span><span class="nx">process</span><span class="p">.</span><span class="nx">argv</span><span class="p">[</span><span class="mi">1</span><span class="p">..]</span>
|
||||
<span class="nx">args</span><span class="p">.</span><span class="nx">splice</span> <span class="nx">args</span><span class="p">.</span><span class="nx">indexOf</span><span class="p">(</span><span class="s1">'--nodejs'</span><span class="p">),</span> <span class="mi">2</span>
|
||||
<span class="nx">spawn</span> <span class="nx">process</span><span class="p">.</span><span class="nx">execPath</span><span class="p">,</span> <span class="nx">nodeArgs</span><span class="p">.</span><span class="nx">concat</span><span class="p">(</span><span class="nx">args</span><span class="p">),</span>
|
||||
<span class="nx">cwd</span><span class="o">:</span> <span class="nx">process</span><span class="p">.</span><span class="nx">cwd</span><span class="p">()</span>
|
||||
<span class="nx">env</span><span class="o">:</span> <span class="nx">process</span><span class="p">.</span><span class="nx">env</span>
|
||||
<span class="nx">customFds</span><span class="o">:</span> <span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">]</span></pre></div> </td> </tr> <tr id="section-19"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-19">¶</a> </div> <p>Print the <code>--help</code> usage message and exit. Deprecated switches are not
|
||||
shown.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">usage = </span><span class="o">-></span>
|
||||
<span class="nx">printLine</span> <span class="p">(</span><span class="k">new</span> <span class="nx">optparse</span><span class="p">.</span><span class="nx">OptionParser</span> <span class="nx">SWITCHES</span><span class="p">,</span> <span class="nx">BANNER</span><span class="p">).</span><span class="nx">help</span><span class="p">()</span>
|
||||
<span class="nx">process</span><span class="p">.</span><span class="nx">exit</span> <span class="mi">0</span></pre></div> </td> </tr> <tr id="section-19"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-19">¶</a> </div> <p>Print the <code>--version</code> message and exit.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">version = </span><span class="o">-></span>
|
||||
<span class="nx">process</span><span class="p">.</span><span class="nx">exit</span> <span class="mi">0</span></pre></div> </td> </tr> <tr id="section-20"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-20">¶</a> </div> <p>Print the <code>--version</code> message and exit.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">version = </span><span class="o">-></span>
|
||||
<span class="nx">printLine</span> <span class="s2">"CoffeeScript version #{CoffeeScript.VERSION}"</span>
|
||||
<span class="nx">process</span><span class="p">.</span><span class="nx">exit</span> <span class="mi">0</span>
|
||||
|
||||
|
||||
@@ -69,8 +69,8 @@ them somewhat circular.</p> </td> <td class="code">
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-13"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-13">¶</a> </div> <p>An indented block of expressions. Note that the <a href="rewriter.html">Rewriter</a>
|
||||
will convert some postfix forms into blocks for us, by adjusting the
|
||||
token stream.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">Block</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s1">'INDENT Body OUTDENT'</span><span class="p">,</span> <span class="o">-></span> <span class="nx">$2</span>
|
||||
<span class="nx">o</span> <span class="s1">'INDENT OUTDENT'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Expressions</span>
|
||||
<span class="nx">o</span> <span class="s1">'INDENT Body OUTDENT'</span><span class="p">,</span> <span class="o">-></span> <span class="nx">$2</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-14"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-14">¶</a> </div> <p>A literal identifier, a variable name or property.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">Identifier</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s1">'IDENTIFIER'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Literal</span> <span class="nx">$1</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-15"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-15">¶</a> </div> <p>Alphanumerics are separated from the other <strong>Literal</strong> matchers because
|
||||
@@ -185,10 +185,8 @@ and optional references to the superclass.</p> </td> <td
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-35"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-35">¶</a> </div> <p>Ordinary function invocation, or a chained series of calls.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">Invocation</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s1">'Value OptFuncExist Arguments'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Call</span> <span class="nx">$1</span><span class="p">,</span> <span class="nx">$3</span><span class="p">,</span> <span class="nx">$2</span>
|
||||
<span class="nx">o</span> <span class="s1">'Invocation OptFuncExist Arguments'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Call</span> <span class="nx">$1</span><span class="p">,</span> <span class="nx">$3</span><span class="p">,</span> <span class="nx">$2</span>
|
||||
<span class="nx">o</span> <span class="s1">'SUPER'</span><span class="p">,</span> <span class="o">-></span>
|
||||
<span class="k">new</span> <span class="nx">Call</span> <span class="s1">'super'</span><span class="p">,</span> <span class="p">[</span><span class="k">new</span> <span class="nx">Splat</span> <span class="k">new</span> <span class="nx">Literal</span> <span class="s1">'arguments'</span><span class="p">]</span>
|
||||
<span class="nx">o</span> <span class="s1">'SUPER Arguments'</span><span class="p">,</span> <span class="o">-></span>
|
||||
<span class="k">new</span> <span class="nx">Call</span> <span class="s1">'super'</span><span class="p">,</span> <span class="nx">$2</span>
|
||||
<span class="nx">o</span> <span class="s1">'SUPER'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Call</span> <span class="s1">'super'</span><span class="p">,</span> <span class="p">[</span><span class="k">new</span> <span class="nx">Splat</span> <span class="k">new</span> <span class="nx">Literal</span> <span class="s1">'arguments'</span><span class="p">]</span>
|
||||
<span class="nx">o</span> <span class="s1">'SUPER Arguments'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Call</span> <span class="s1">'super'</span><span class="p">,</span> <span class="nx">$2</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-36"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-36">¶</a> </div> <p>An optional existence check on a function.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">OptFuncExist</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s1">''</span><span class="p">,</span> <span class="o">-></span> <span class="kc">no</span>
|
||||
<span class="nx">o</span> <span class="s1">'FUNC_EXIST'</span><span class="p">,</span> <span class="o">-></span> <span class="kc">yes</span>
|
||||
@@ -262,14 +260,14 @@ or postfix, with a single expression. There is no do..while.</p> </t
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-53"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-53">¶</a> </div> <p>Array, object, and range comprehensions, at the most generic level.
|
||||
Comprehensions can either be normal, with a block of expressions to execute,
|
||||
or postfix, with a single expression.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">For</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s1">'Statement ForBody'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">For</span> <span class="nx">$1</span><span class="p">,</span> <span class="nx">$2</span><span class="p">,</span> <span class="nx">$2</span><span class="p">.</span><span class="nx">vars</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="nx">$2</span><span class="p">.</span><span class="nx">vars</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
|
||||
<span class="nx">o</span> <span class="s1">'Expression ForBody'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">For</span> <span class="nx">$1</span><span class="p">,</span> <span class="nx">$2</span><span class="p">,</span> <span class="nx">$2</span><span class="p">.</span><span class="nx">vars</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="nx">$2</span><span class="p">.</span><span class="nx">vars</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
|
||||
<span class="nx">o</span> <span class="s1">'ForBody Block'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">For</span> <span class="nx">$2</span><span class="p">,</span> <span class="nx">$1</span><span class="p">,</span> <span class="nx">$1</span><span class="p">.</span><span class="nx">vars</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="nx">$1</span><span class="p">.</span><span class="nx">vars</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
|
||||
<span class="nx">o</span> <span class="s1">'Statement ForBody'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">For</span> <span class="nx">$1</span><span class="p">,</span> <span class="nx">$2</span>
|
||||
<span class="nx">o</span> <span class="s1">'Expression ForBody'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">For</span> <span class="nx">$1</span><span class="p">,</span> <span class="nx">$2</span>
|
||||
<span class="nx">o</span> <span class="s1">'ForBody Block'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">For</span> <span class="nx">$2</span><span class="p">,</span> <span class="nx">$1</span>
|
||||
<span class="p">]</span>
|
||||
|
||||
<span class="nx">ForBody</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s1">'FOR Range'</span><span class="p">,</span> <span class="o">-></span> <span class="nx">source</span><span class="o">:</span> <span class="k">new</span> <span class="nx">Value</span><span class="p">(</span><span class="nx">$2</span><span class="p">),</span> <span class="nx">vars</span><span class="o">:</span> <span class="p">[]</span>
|
||||
<span class="nx">o</span> <span class="s1">'ForStart ForSource'</span><span class="p">,</span> <span class="o">-></span> <span class="nv">$2.own = </span><span class="nx">$1</span><span class="p">.</span><span class="nx">own</span><span class="p">;</span> <span class="nv">$2.vars = </span><span class="nx">$1</span><span class="p">;</span> <span class="nx">$2</span>
|
||||
<span class="nx">o</span> <span class="s1">'FOR Range'</span><span class="p">,</span> <span class="o">-></span> <span class="nx">source</span><span class="o">:</span> <span class="k">new</span> <span class="nx">Value</span><span class="p">(</span><span class="nx">$2</span><span class="p">)</span>
|
||||
<span class="nx">o</span> <span class="s1">'ForStart ForSource'</span><span class="p">,</span> <span class="o">-></span> <span class="nv">$2.own = </span><span class="nx">$1</span><span class="p">.</span><span class="nx">own</span><span class="p">;</span> <span class="nv">$2.name = </span><span class="nx">$1</span><span class="p">[</span><span class="mi">0</span><span class="p">];</span> <span class="nv">$2.index = </span><span class="nx">$1</span><span class="p">[</span><span class="mi">1</span><span class="p">];</span> <span class="nx">$2</span>
|
||||
<span class="p">]</span>
|
||||
|
||||
<span class="nx">ForStart</span><span class="o">:</span> <span class="p">[</span>
|
||||
@@ -313,17 +311,14 @@ in fixed-size increments.</p> </td> <td class="code">
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-58"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-58">¶</a> </div> <p>The most basic form of <em>if</em> is a condition and an action. The following
|
||||
if-related rules are broken up along these lines in order to avoid
|
||||
ambiguity.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">IfBlock</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s1">'IF Expression Block'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">If</span> <span class="nx">$2</span><span class="p">,</span> <span class="nx">$3</span>
|
||||
<span class="nx">o</span> <span class="s1">'UNLESS Expression Block'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">If</span> <span class="nx">$2</span><span class="p">,</span> <span class="nx">$3</span><span class="p">,</span> <span class="nx">invert</span><span class="o">:</span> <span class="kc">true</span>
|
||||
<span class="nx">o</span> <span class="s1">'IfBlock ELSE IF Expression Block'</span><span class="p">,</span> <span class="o">-></span> <span class="nx">$1</span><span class="p">.</span><span class="nx">addElse</span> <span class="k">new</span> <span class="nx">If</span> <span class="nx">$4</span><span class="p">,</span> <span class="nx">$5</span>
|
||||
<span class="nx">o</span> <span class="s1">'IF Expression Block'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">If</span> <span class="nx">$2</span><span class="p">,</span> <span class="nx">$3</span><span class="p">,</span> <span class="nx">type</span><span class="o">:</span> <span class="nx">$1</span>
|
||||
<span class="nx">o</span> <span class="s1">'IfBlock ELSE IF Expression Block'</span><span class="p">,</span> <span class="o">-></span> <span class="nx">$1</span><span class="p">.</span><span class="nx">addElse</span> <span class="k">new</span> <span class="nx">If</span> <span class="nx">$4</span><span class="p">,</span> <span class="nx">$5</span><span class="p">,</span> <span class="nx">type</span><span class="o">:</span> <span class="nx">$3</span>
|
||||
<span class="nx">o</span> <span class="s1">'IfBlock ELSE Block'</span><span class="p">,</span> <span class="o">-></span> <span class="nx">$1</span><span class="p">.</span><span class="nx">addElse</span> <span class="nx">$3</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-59"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-59">¶</a> </div> <p>The full complement of <em>if</em> expressions, including postfix one-liner
|
||||
<em>if</em> and <em>unless</em>.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">If</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s1">'IfBlock'</span>
|
||||
<span class="nx">o</span> <span class="s1">'Statement POST_IF Expression'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">If</span> <span class="nx">$3</span><span class="p">,</span> <span class="nx">Expressions</span><span class="p">.</span><span class="nx">wrap</span><span class="p">([</span><span class="nx">$1</span><span class="p">]),</span> <span class="nx">statement</span><span class="o">:</span> <span class="kc">true</span>
|
||||
<span class="nx">o</span> <span class="s1">'Expression POST_IF Expression'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">If</span> <span class="nx">$3</span><span class="p">,</span> <span class="nx">Expressions</span><span class="p">.</span><span class="nx">wrap</span><span class="p">([</span><span class="nx">$1</span><span class="p">]),</span> <span class="nx">statement</span><span class="o">:</span> <span class="kc">true</span>
|
||||
<span class="nx">o</span> <span class="s1">'Statement POST_UNLESS Expression'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">If</span> <span class="nx">$3</span><span class="p">,</span> <span class="nx">Expressions</span><span class="p">.</span><span class="nx">wrap</span><span class="p">([</span><span class="nx">$1</span><span class="p">]),</span> <span class="nx">statement</span><span class="o">:</span> <span class="kc">true</span><span class="p">,</span> <span class="nx">invert</span><span class="o">:</span> <span class="kc">true</span>
|
||||
<span class="nx">o</span> <span class="s1">'Expression POST_UNLESS Expression'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">If</span> <span class="nx">$3</span><span class="p">,</span> <span class="nx">Expressions</span><span class="p">.</span><span class="nx">wrap</span><span class="p">([</span><span class="nx">$1</span><span class="p">]),</span> <span class="nx">statement</span><span class="o">:</span> <span class="kc">true</span><span class="p">,</span> <span class="nx">invert</span><span class="o">:</span> <span class="kc">true</span>
|
||||
<span class="nx">o</span> <span class="s1">'Statement POST_IF Expression'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">If</span> <span class="nx">$3</span><span class="p">,</span> <span class="nx">Expressions</span><span class="p">.</span><span class="nx">wrap</span><span class="p">([</span><span class="nx">$1</span><span class="p">]),</span> <span class="nx">type</span><span class="o">:</span> <span class="nx">$2</span><span class="p">,</span> <span class="nx">statement</span><span class="o">:</span> <span class="kc">true</span>
|
||||
<span class="nx">o</span> <span class="s1">'Expression POST_IF Expression'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">If</span> <span class="nx">$3</span><span class="p">,</span> <span class="nx">Expressions</span><span class="p">.</span><span class="nx">wrap</span><span class="p">([</span><span class="nx">$1</span><span class="p">]),</span> <span class="nx">type</span><span class="o">:</span> <span class="nx">$2</span><span class="p">,</span> <span class="nx">statement</span><span class="o">:</span> <span class="kc">true</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-60"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-60">¶</a> </div> <p>Arithmetic and logical operators, working on one or more operands.
|
||||
Here they are grouped by order of precedence. The actual precedence rules
|
||||
are defined at the bottom of the page. It would be shorter if we could
|
||||
@@ -381,8 +376,8 @@ down. Following these rules is what makes <code>2 + 3 * 4</code> parse as:</p>
|
||||
<span class="p">[</span><span class="s1">'nonassoc'</span><span class="p">,</span> <span class="s1">'INDENT'</span><span class="p">,</span> <span class="s1">'OUTDENT'</span><span class="p">]</span>
|
||||
<span class="p">[</span><span class="s1">'right'</span><span class="p">,</span> <span class="s1">'='</span><span class="p">,</span> <span class="s1">':'</span><span class="p">,</span> <span class="s1">'COMPOUND_ASSIGN'</span><span class="p">,</span> <span class="s1">'RETURN'</span><span class="p">,</span> <span class="s1">'THROW'</span><span class="p">,</span> <span class="s1">'EXTENDS'</span><span class="p">]</span>
|
||||
<span class="p">[</span><span class="s1">'right'</span><span class="p">,</span> <span class="s1">'FORIN'</span><span class="p">,</span> <span class="s1">'FOROF'</span><span class="p">,</span> <span class="s1">'BY'</span><span class="p">,</span> <span class="s1">'WHEN'</span><span class="p">]</span>
|
||||
<span class="p">[</span><span class="s1">'right'</span><span class="p">,</span> <span class="s1">'IF'</span><span class="p">,</span> <span class="s1">'UNLESS'</span><span class="p">,</span> <span class="s1">'ELSE'</span><span class="p">,</span> <span class="s1">'FOR'</span><span class="p">,</span> <span class="s1">'WHILE'</span><span class="p">,</span> <span class="s1">'UNTIL'</span><span class="p">,</span> <span class="s1">'LOOP'</span><span class="p">,</span> <span class="s1">'SUPER'</span><span class="p">,</span> <span class="s1">'CLASS'</span><span class="p">]</span>
|
||||
<span class="p">[</span><span class="s1">'right'</span><span class="p">,</span> <span class="s1">'POST_IF'</span><span class="p">,</span> <span class="s1">'POST_UNLESS'</span><span class="p">]</span>
|
||||
<span class="p">[</span><span class="s1">'right'</span><span class="p">,</span> <span class="s1">'IF'</span><span class="p">,</span> <span class="s1">'ELSE'</span><span class="p">,</span> <span class="s1">'FOR'</span><span class="p">,</span> <span class="s1">'DO'</span><span class="p">,</span> <span class="s1">'WHILE'</span><span class="p">,</span> <span class="s1">'UNTIL'</span><span class="p">,</span> <span class="s1">'LOOP'</span><span class="p">,</span> <span class="s1">'SUPER'</span><span class="p">,</span> <span class="s1">'CLASS'</span><span class="p">]</span>
|
||||
<span class="p">[</span><span class="s1">'right'</span><span class="p">,</span> <span class="s1">'POST_IF'</span><span class="p">]</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-64"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-64">¶</a> </div> <h2>Wrapping Up</h2> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-65"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-65">¶</a> </div> <p>Finally, now what we have our <strong>grammar</strong> and our <strong>operators</strong>, we can create
|
||||
our <strong>Jison.Parser</strong>. We do this by processing all of our rules, recording all
|
||||
terminals (every symbol which does not appear as the name of a rule above)
|
||||
|
||||
@@ -4,9 +4,10 @@ arrays, count characters, that sort of thing.</p> </td>
|
||||
<span class="nx">literal</span> <span class="o">is</span> <span class="nx">string</span><span class="p">.</span><span class="nx">substr</span> <span class="nx">start</span><span class="p">,</span> <span class="nx">literal</span><span class="p">.</span><span class="nx">length</span></pre></div> </td> </tr> <tr id="section-3"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-3">¶</a> </div> <p>Peek at the end of a given string to see if it matches a sequence.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.ends = </span><span class="p">(</span><span class="nx">string</span><span class="p">,</span> <span class="nx">literal</span><span class="p">,</span> <span class="nx">back</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nv">len = </span><span class="nx">literal</span><span class="p">.</span><span class="nx">length</span>
|
||||
<span class="nx">literal</span> <span class="o">is</span> <span class="nx">string</span><span class="p">.</span><span class="nx">substr</span> <span class="nx">string</span><span class="p">.</span><span class="nx">length</span> <span class="o">-</span> <span class="nx">len</span> <span class="o">-</span> <span class="p">(</span><span class="nx">back</span> <span class="o">or</span> <span class="mi">0</span><span class="p">),</span> <span class="nx">len</span></pre></div> </td> </tr> <tr id="section-4"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-4">¶</a> </div> <p>Trim out all falsy values from an array.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.compact = </span><span class="p">(</span><span class="nx">array</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nx">item</span> <span class="k">for</span> <span class="nx">item</span> <span class="k">in</span> <span class="nx">array</span> <span class="k">when</span> <span class="nx">item</span></pre></div> </td> </tr> <tr id="section-5"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-5">¶</a> </div> <p>Count the number of occurrences of a character in a string.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.count = </span><span class="p">(</span><span class="nx">string</span><span class="p">,</span> <span class="nx">letter</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nx">item</span> <span class="k">for</span> <span class="nx">item</span> <span class="k">in</span> <span class="nx">array</span> <span class="k">when</span> <span class="nx">item</span></pre></div> </td> </tr> <tr id="section-5"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-5">¶</a> </div> <p>Count the number of occurrences of a string in a string.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.count = </span><span class="p">(</span><span class="nx">string</span><span class="p">,</span> <span class="nx">substr</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nv">num = pos = </span><span class="mi">0</span>
|
||||
<span class="nx">num</span><span class="o">++</span> <span class="k">while</span> <span class="nv">pos = </span><span class="mi">1</span> <span class="o">+</span> <span class="nx">string</span><span class="p">.</span><span class="nx">indexOf</span> <span class="nx">letter</span><span class="p">,</span> <span class="nx">pos</span>
|
||||
<span class="k">return</span> <span class="mi">1</span><span class="o">/</span><span class="mi">0</span> <span class="nx">unless</span> <span class="nx">substr</span><span class="p">.</span><span class="nx">length</span>
|
||||
<span class="nx">num</span><span class="o">++</span> <span class="k">while</span> <span class="nv">pos = </span><span class="mi">1</span> <span class="o">+</span> <span class="nx">string</span><span class="p">.</span><span class="nx">indexOf</span> <span class="nx">substr</span><span class="p">,</span> <span class="nx">pos</span>
|
||||
<span class="nx">num</span></pre></div> </td> </tr> <tr id="section-6"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-6">¶</a> </div> <p>Merge objects, returning a fresh copy with attributes from both sides.
|
||||
Used every time <code>Base#compile</code> is called, to allow properties in the
|
||||
options hash to propagate down the tree without polluting other branches.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.merge = </span><span class="p">(</span><span class="nx">options</span><span class="p">,</span> <span class="nx">overrides</span><span class="p">)</span> <span class="o">-></span>
|
||||
|
||||
@@ -14,12 +14,17 @@ option) list, and all subsequent arguments are left unparsed.</p> </
|
||||
<p>Along with an an optional banner for the usage help.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">constructor</span><span class="o">:</span> <span class="p">(</span><span class="nx">rules</span><span class="p">,</span> <span class="nx">@banner</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="vi">@rules = </span><span class="nx">buildRules</span> <span class="nx">rules</span></pre></div> </td> </tr> <tr id="section-3"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-3">¶</a> </div> <p>Parse the list of arguments, populating an <code>options</code> object with all of the
|
||||
specified options, and returning it. <code>options.arguments</code> will be an array
|
||||
containing the remaining non-option arguments. This is a simpler API than
|
||||
many option parsers that allow you to attach callback actions for every
|
||||
flag. Instead, you're responsible for interpreting the options object.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">parse</span><span class="o">:</span> <span class="p">(</span><span class="nx">args</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nv">options = </span><span class="nx">arguments</span><span class="o">:</span> <span class="p">[]</span>
|
||||
containing the remaining non-option arguments. <code>options.literals</code> will be
|
||||
an array of options that are meant to be passed through directly to the
|
||||
executing script. This is a simpler API than many option parsers that allow
|
||||
you to attach callback actions for every flag. Instead, you're responsible
|
||||
for interpreting the options object.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">parse</span><span class="o">:</span> <span class="p">(</span><span class="nx">args</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nv">options = </span><span class="nx">arguments</span><span class="o">:</span> <span class="p">[],</span> <span class="nx">literals</span><span class="o">:</span> <span class="p">[]</span>
|
||||
<span class="nv">args = </span><span class="nx">normalizeArguments</span> <span class="nx">args</span>
|
||||
<span class="k">for</span> <span class="nx">arg</span><span class="p">,</span> <span class="nx">i</span> <span class="k">in</span> <span class="nx">args</span>
|
||||
<span class="k">if</span> <span class="nx">arg</span> <span class="o">is</span> <span class="s1">'--'</span>
|
||||
<span class="nv">options.literals = </span><span class="nx">args</span><span class="p">[(</span><span class="nx">i</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)..]</span>
|
||||
<span class="k">break</span>
|
||||
<span class="nv">isOption = </span><span class="o">!!</span><span class="p">(</span><span class="nx">arg</span><span class="p">.</span><span class="nx">match</span><span class="p">(</span><span class="nx">LONG_FLAG</span><span class="p">)</span> <span class="o">or</span> <span class="nx">arg</span><span class="p">.</span><span class="nx">match</span><span class="p">(</span><span class="nx">SHORT_FLAG</span><span class="p">))</span>
|
||||
<span class="nv">matchedRule = </span><span class="kc">no</span>
|
||||
<span class="k">for</span> <span class="nx">rule</span> <span class="k">in</span> <span class="nx">@rules</span>
|
||||
|
||||
@@ -106,22 +106,22 @@ deal with them.</p> </td> <td class="code">
|
||||
<span class="nx">@tokens</span><span class="p">.</span><span class="nx">splice</span> <span class="nx">idx</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="p">[</span><span class="s1">'CALL_END'</span><span class="p">,</span> <span class="s1">')'</span><span class="p">,</span> <span class="nx">token</span><span class="p">[</span><span class="mi">2</span><span class="p">]]</span>
|
||||
<span class="nx">@scanTokens</span> <span class="p">(</span><span class="nx">token</span><span class="p">,</span> <span class="nx">i</span><span class="p">,</span> <span class="nx">tokens</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nv">tag = </span><span class="nx">token</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
|
||||
<span class="nv">noCall = </span><span class="kc">yes</span> <span class="k">if</span> <span class="nx">tag</span> <span class="k">in</span> <span class="p">[</span><span class="s1">'CLASS'</span><span class="p">,</span> <span class="s1">'IF'</span><span class="p">,</span> <span class="s1">'UNLESS'</span><span class="p">]</span>
|
||||
<span class="nv">noCall = </span><span class="kc">yes</span> <span class="k">if</span> <span class="nx">tag</span> <span class="k">in</span> <span class="p">[</span><span class="s1">'CLASS'</span><span class="p">,</span> <span class="s1">'IF'</span><span class="p">]</span>
|
||||
<span class="p">[</span><span class="nx">prev</span><span class="p">,</span> <span class="nx">current</span><span class="p">,</span> <span class="nx">next</span><span class="p">]</span> <span class="o">=</span> <span class="nx">tokens</span><span class="p">[</span><span class="nx">i</span> <span class="o">-</span> <span class="mi">1</span> <span class="p">..</span> <span class="nx">i</span> <span class="o">+</span> <span class="mi">1</span><span class="p">]</span>
|
||||
<span class="nv">callObject = </span><span class="o">not</span> <span class="nx">noCall</span> <span class="o">and</span> <span class="nx">tag</span> <span class="o">is</span> <span class="s1">'INDENT'</span> <span class="o">and</span>
|
||||
<span class="nx">next</span> <span class="o">and</span> <span class="nx">next</span><span class="p">.</span><span class="nx">generated</span> <span class="o">and</span> <span class="nx">next</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">is</span> <span class="s1">'{'</span> <span class="o">and</span>
|
||||
<span class="nx">prev</span> <span class="o">and</span> <span class="nx">prev</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="k">in</span> <span class="nx">IMPLICIT_FUNC</span>
|
||||
<span class="nv">seenSingle = </span><span class="kc">no</span>
|
||||
<span class="nv">noCall = </span><span class="kc">no</span> <span class="k">if</span> <span class="nx">tag</span> <span class="k">in</span> <span class="nx">LINEBREAKS</span>
|
||||
<span class="nv">noCall = </span><span class="kc">no</span> <span class="k">if</span> <span class="nx">tag</span> <span class="k">in</span> <span class="nx">LINEBREAKS</span>
|
||||
<span class="nv">token.call = </span><span class="kc">yes</span> <span class="k">if</span> <span class="nx">prev</span> <span class="o">and</span> <span class="o">not</span> <span class="nx">prev</span><span class="p">.</span><span class="nx">spaced</span> <span class="o">and</span> <span class="nx">tag</span> <span class="o">is</span> <span class="s1">'?'</span>
|
||||
<span class="k">return</span> <span class="mi">1</span> <span class="nx">unless</span> <span class="nx">callObject</span> <span class="o">or</span>
|
||||
<span class="nx">prev</span><span class="o">?</span><span class="p">.</span><span class="nx">spaced</span> <span class="o">and</span> <span class="p">(</span><span class="nx">prev</span><span class="p">.</span><span class="nx">call</span> <span class="o">or</span> <span class="nx">prev</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="k">in</span> <span class="nx">IMPLICIT_FUNC</span><span class="p">)</span> <span class="o">and</span>
|
||||
<span class="p">(</span><span class="nx">tag</span> <span class="k">in</span> <span class="nx">IMPLICIT_CALL</span> <span class="o">or</span> <span class="o">not</span> <span class="p">(</span><span class="nx">token</span><span class="p">.</span><span class="nx">spaced</span> <span class="o">or</span> <span class="nx">token</span><span class="p">.</span><span class="nx">newLine</span><span class="p">)</span> <span class="o">and</span> <span class="nx">tag</span> <span class="k">in</span> <span class="nx">IMPLICIT_UNSPACED_CALL</span><span class="p">)</span>
|
||||
<span class="nx">tokens</span><span class="p">.</span><span class="nx">splice</span> <span class="nx">i</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="p">[</span><span class="s1">'CALL_START'</span><span class="p">,</span> <span class="s1">'('</span><span class="p">,</span> <span class="nx">token</span><span class="p">[</span><span class="mi">2</span><span class="p">]]</span>
|
||||
<span class="nx">@detectEnd</span> <span class="nx">i</span> <span class="o">+</span> <span class="p">(</span><span class="k">if</span> <span class="nx">callObject</span> <span class="k">then</span> <span class="mi">2</span> <span class="k">else</span> <span class="mi">1</span><span class="p">),</span> <span class="p">(</span><span class="nx">token</span><span class="p">,</span> <span class="nx">i</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="k">return</span> <span class="kc">yes</span> <span class="k">if</span> <span class="o">not</span> <span class="nx">seenSingle</span> <span class="o">and</span> <span class="nx">token</span><span class="p">.</span><span class="nx">fromThen</span>
|
||||
<span class="nx">@detectEnd</span> <span class="nx">i</span> <span class="o">+</span> <span class="mi">1</span><span class="p">,</span> <span class="p">(</span><span class="nx">token</span><span class="p">,</span> <span class="nx">i</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="p">[</span><span class="nx">tag</span><span class="p">]</span> <span class="o">=</span> <span class="nx">token</span>
|
||||
<span class="nv">seenSingle = </span><span class="kc">yes</span> <span class="k">if</span> <span class="nx">tag</span> <span class="k">in</span> <span class="p">[</span><span class="s1">'IF'</span><span class="p">,</span> <span class="s1">'ELSE'</span><span class="p">,</span> <span class="s1">'UNLESS'</span><span class="p">,</span> <span class="s1">'->'</span><span class="p">,</span> <span class="s1">'=>'</span><span class="p">]</span>
|
||||
<span class="k">return</span> <span class="kc">yes</span> <span class="k">if</span> <span class="o">not</span> <span class="nx">seenSingle</span> <span class="o">and</span> <span class="nx">token</span><span class="p">.</span><span class="nx">fromThen</span>
|
||||
<span class="nv">seenSingle = </span><span class="kc">yes</span> <span class="k">if</span> <span class="nx">tag</span> <span class="k">in</span> <span class="p">[</span><span class="s1">'IF'</span><span class="p">,</span> <span class="s1">'ELSE'</span><span class="p">,</span> <span class="s1">'->'</span><span class="p">,</span> <span class="s1">'=>'</span><span class="p">]</span>
|
||||
<span class="k">return</span> <span class="kc">yes</span> <span class="k">if</span> <span class="nx">tag</span> <span class="k">in</span> <span class="p">[</span><span class="s1">'.'</span><span class="p">,</span> <span class="s1">'?.'</span><span class="p">,</span> <span class="s1">'::'</span><span class="p">]</span> <span class="o">and</span> <span class="nx">@tag</span><span class="p">(</span><span class="nx">i</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span> <span class="o">is</span> <span class="s1">'OUTDENT'</span>
|
||||
<span class="o">not</span> <span class="nx">token</span><span class="p">.</span><span class="nx">generated</span> <span class="o">and</span> <span class="nx">@tag</span><span class="p">(</span><span class="nx">i</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span> <span class="o">isnt</span> <span class="s1">','</span> <span class="o">and</span> <span class="nx">tag</span> <span class="k">in</span> <span class="nx">IMPLICIT_END</span> <span class="o">and</span>
|
||||
<span class="p">(</span><span class="nx">tag</span> <span class="o">isnt</span> <span class="s1">'INDENT'</span> <span class="o">or</span>
|
||||
@@ -163,7 +163,7 @@ but we need to make sure it's balanced.</p> </td> <td cl
|
||||
different precedence.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">tagPostfixConditionals</span><span class="o">:</span> <span class="o">-></span>
|
||||
<span class="nv">condition = </span><span class="p">(</span><span class="nx">token</span><span class="p">,</span> <span class="nx">i</span><span class="p">)</span> <span class="o">-></span> <span class="nx">token</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="k">in</span> <span class="p">[</span><span class="s1">'TERMINATOR'</span><span class="p">,</span> <span class="s1">'INDENT'</span><span class="p">]</span>
|
||||
<span class="nx">@scanTokens</span> <span class="p">(</span><span class="nx">token</span><span class="p">,</span> <span class="nx">i</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="k">return</span> <span class="mi">1</span> <span class="nx">unless</span> <span class="nx">token</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="k">in</span> <span class="p">[</span><span class="s1">'IF'</span><span class="p">,</span> <span class="s1">'UNLESS'</span><span class="p">]</span>
|
||||
<span class="k">return</span> <span class="mi">1</span> <span class="nx">unless</span> <span class="nx">token</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">is</span> <span class="s1">'IF'</span>
|
||||
<span class="nv">original = </span><span class="nx">token</span>
|
||||
<span class="nx">@detectEnd</span> <span class="nx">i</span> <span class="o">+</span> <span class="mi">1</span><span class="p">,</span> <span class="nx">condition</span><span class="p">,</span> <span class="p">(</span><span class="nx">token</span><span class="p">,</span> <span class="nx">i</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nx">original</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="s1">'POST_'</span> <span class="o">+</span> <span class="nx">original</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="k">if</span> <span class="nx">token</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">isnt</span> <span class="s1">'INDENT'</span>
|
||||
@@ -240,11 +240,11 @@ look things up from either end.</p> </td> <td class="cod
|
||||
<span class="nx">EXPRESSION_START</span><span class="p">.</span><span class="nx">push</span> <span class="nx">INVERSES</span><span class="p">[</span><span class="nx">rite</span><span class="p">]</span> <span class="o">=</span> <span class="nx">left</span>
|
||||
<span class="nx">EXPRESSION_END</span> <span class="p">.</span><span class="nx">push</span> <span class="nx">INVERSES</span><span class="p">[</span><span class="nx">left</span><span class="p">]</span> <span class="o">=</span> <span class="nx">rite</span></pre></div> </td> </tr> <tr id="section-22"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-22">¶</a> </div> <p>Tokens that indicate the close of a clause of an expression.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">EXPRESSION_CLOSE = </span><span class="p">[</span><span class="s1">'CATCH'</span><span class="p">,</span> <span class="s1">'WHEN'</span><span class="p">,</span> <span class="s1">'ELSE'</span><span class="p">,</span> <span class="s1">'FINALLY'</span><span class="p">].</span><span class="nx">concat</span> <span class="nx">EXPRESSION_END</span></pre></div> </td> </tr> <tr id="section-23"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-23">¶</a> </div> <p>Tokens that, if followed by an <code>IMPLICIT_CALL</code>, indicate a function invocation.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">IMPLICIT_FUNC = </span><span class="p">[</span><span class="s1">'IDENTIFIER'</span><span class="p">,</span> <span class="s1">'SUPER'</span><span class="p">,</span> <span class="s1">')'</span><span class="p">,</span> <span class="s1">'CALL_END'</span><span class="p">,</span> <span class="s1">']'</span><span class="p">,</span> <span class="s1">'INDEX_END'</span><span class="p">,</span> <span class="s1">'@'</span><span class="p">,</span> <span class="s1">'THIS'</span><span class="p">]</span></pre></div> </td> </tr> <tr id="section-24"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-24">¶</a> </div> <p>If preceded by an <code>IMPLICIT_FUNC</code>, indicates a function invocation.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">IMPLICIT_CALL = </span><span class="p">[</span>
|
||||
<span class="s1">'IDENTIFIER'</span><span class="p">,</span> <span class="s1">'NUMBER'</span><span class="p">,</span> <span class="s1">'STRING'</span><span class="p">,</span> <span class="s1">'JS'</span><span class="p">,</span> <span class="s1">'REGEX'</span><span class="p">,</span> <span class="s1">'NEW'</span><span class="p">,</span> <span class="s1">'PARAM_START'</span><span class="p">,</span> <span class="s1">'CLASS'</span>
|
||||
<span class="s1">'IF'</span><span class="p">,</span> <span class="s1">'UNLESS'</span><span class="p">,</span> <span class="s1">'TRY'</span><span class="p">,</span> <span class="s1">'SWITCH'</span><span class="p">,</span> <span class="s1">'THIS'</span><span class="p">,</span> <span class="s1">'BOOL'</span><span class="p">,</span> <span class="s1">'UNARY'</span><span class="p">,</span>
|
||||
<span class="s1">'IF'</span><span class="p">,</span> <span class="s1">'TRY'</span><span class="p">,</span> <span class="s1">'SWITCH'</span><span class="p">,</span> <span class="s1">'THIS'</span><span class="p">,</span> <span class="s1">'BOOL'</span><span class="p">,</span> <span class="s1">'UNARY'</span><span class="p">,</span> <span class="s1">'SUPER'</span>
|
||||
<span class="s1">'@'</span><span class="p">,</span> <span class="s1">'->'</span><span class="p">,</span> <span class="s1">'=>'</span><span class="p">,</span> <span class="s1">'['</span><span class="p">,</span> <span class="s1">'('</span><span class="p">,</span> <span class="s1">'{'</span><span class="p">,</span> <span class="s1">'--'</span><span class="p">,</span> <span class="s1">'++'</span>
|
||||
<span class="p">]</span>
|
||||
|
||||
<span class="nv">IMPLICIT_UNSPACED_CALL = </span><span class="p">[</span><span class="s1">'+'</span><span class="p">,</span> <span class="s1">'-'</span><span class="p">]</span></pre></div> </td> </tr> <tr id="section-25"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-25">¶</a> </div> <p>Tokens indicating that the implicit call must enclose a block of expressions.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">IMPLICIT_BLOCK = </span><span class="p">[</span><span class="s1">'->'</span><span class="p">,</span> <span class="s1">'=>'</span><span class="p">,</span> <span class="s1">'{'</span><span class="p">,</span> <span class="s1">'['</span><span class="p">,</span> <span class="s1">','</span><span class="p">]</span></pre></div> </td> </tr> <tr id="section-26"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-26">¶</a> </div> <p>Tokens that always mark the end of an implicit call for single-liners.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">IMPLICIT_END = </span><span class="p">[</span><span class="s1">'POST_IF'</span><span class="p">,</span> <span class="s1">'POST_UNLESS'</span><span class="p">,</span> <span class="s1">'FOR'</span><span class="p">,</span> <span class="s1">'WHILE'</span><span class="p">,</span> <span class="s1">'UNTIL'</span><span class="p">,</span> <span class="s1">'WHEN'</span><span class="p">,</span> <span class="s1">'BY'</span><span class="p">,</span> <span class="s1">'LOOP'</span><span class="p">,</span> <span class="s1">'TERMINATOR'</span><span class="p">,</span> <span class="s1">'INDENT'</span><span class="p">]</span></pre></div> </td> </tr> <tr id="section-27"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-27">¶</a> </div> <p>Single-line flavors of block expressions that have unclosed endings.
|
||||
<span class="nv">IMPLICIT_UNSPACED_CALL = </span><span class="p">[</span><span class="s1">'+'</span><span class="p">,</span> <span class="s1">'-'</span><span class="p">]</span></pre></div> </td> </tr> <tr id="section-25"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-25">¶</a> </div> <p>Tokens indicating that the implicit call must enclose a block of expressions.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">IMPLICIT_BLOCK = </span><span class="p">[</span><span class="s1">'->'</span><span class="p">,</span> <span class="s1">'=>'</span><span class="p">,</span> <span class="s1">'{'</span><span class="p">,</span> <span class="s1">'['</span><span class="p">,</span> <span class="s1">','</span><span class="p">]</span></pre></div> </td> </tr> <tr id="section-26"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-26">¶</a> </div> <p>Tokens that always mark the end of an implicit call for single-liners.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">IMPLICIT_END = </span><span class="p">[</span><span class="s1">'POST_IF'</span><span class="p">,</span> <span class="s1">'FOR'</span><span class="p">,</span> <span class="s1">'WHILE'</span><span class="p">,</span> <span class="s1">'UNTIL'</span><span class="p">,</span> <span class="s1">'WHEN'</span><span class="p">,</span> <span class="s1">'BY'</span><span class="p">,</span> <span class="s1">'LOOP'</span><span class="p">,</span> <span class="s1">'TERMINATOR'</span><span class="p">,</span> <span class="s1">'INDENT'</span><span class="p">]</span></pre></div> </td> </tr> <tr id="section-27"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-27">¶</a> </div> <p>Single-line flavors of block expressions that have unclosed endings.
|
||||
The grammar can't disambiguate them, so we insert the implicit indentation.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">SINGLE_LINERS = </span><span class="p">[</span><span class="s1">'ELSE'</span><span class="p">,</span> <span class="s1">'->'</span><span class="p">,</span> <span class="s1">'=>'</span><span class="p">,</span> <span class="s1">'TRY'</span><span class="p">,</span> <span class="s1">'FINALLY'</span><span class="p">,</span> <span class="s1">'THEN'</span><span class="p">]</span>
|
||||
<span class="nv">SINGLE_CLOSERS = </span><span class="p">[</span><span class="s1">'TERMINATOR'</span><span class="p">,</span> <span class="s1">'CATCH'</span><span class="p">,</span> <span class="s1">'FINALLY'</span><span class="p">,</span> <span class="s1">'ELSE'</span><span class="p">,</span> <span class="s1">'OUTDENT'</span><span class="p">,</span> <span class="s1">'LEADING_WHEN'</span><span class="p">]</span></pre></div> </td> </tr> <tr id="section-28"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-28">¶</a> </div> <p>Tokens that end a line.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">LINEBREAKS = </span><span class="p">[</span><span class="s1">'TERMINATOR'</span><span class="p">,</span> <span class="s1">'INDENT'</span><span class="p">,</span> <span class="s1">'OUTDENT'</span><span class="p">]</span>
|
||||
|
||||
|
||||
@@ -11,7 +11,8 @@ where it should declare its variables, and a reference to the function that
|
||||
it wraps.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">constructor</span><span class="o">:</span><span class="p">(</span><span class="nx">@parent</span><span class="p">,</span> <span class="nx">@expressions</span><span class="p">,</span> <span class="nx">@method</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="vi">@variables = </span><span class="p">[{</span><span class="nx">name</span><span class="o">:</span> <span class="s1">'arguments'</span><span class="p">,</span> <span class="nx">type</span><span class="o">:</span> <span class="s1">'arguments'</span><span class="p">}]</span>
|
||||
<span class="vi">@positions = </span><span class="p">{}</span>
|
||||
<span class="nv">Scope.root = </span><span class="k">this</span> <span class="nx">unless</span> <span class="nx">@parent</span></pre></div> </td> </tr> <tr id="section-5"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-5">¶</a> </div> <p>Adds a new variable or overrides an existing one.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">add</span><span class="o">:</span> <span class="p">(</span><span class="nx">name</span><span class="p">,</span> <span class="nx">type</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nv">Scope.root = </span><span class="k">this</span> <span class="nx">unless</span> <span class="nx">@parent</span></pre></div> </td> </tr> <tr id="section-5"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-5">¶</a> </div> <p>Adds a new variable or overrides an existing one.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">add</span><span class="o">:</span> <span class="p">(</span><span class="nx">name</span><span class="p">,</span> <span class="nx">type</span><span class="p">,</span> <span class="nx">immediate</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="k">return</span> <span class="nx">@parent</span><span class="p">.</span><span class="nx">add</span> <span class="nx">name</span><span class="p">,</span> <span class="nx">type</span><span class="p">,</span> <span class="nx">immediate</span> <span class="k">if</span> <span class="nx">@shared</span> <span class="o">and</span> <span class="o">not</span> <span class="nx">immediate</span>
|
||||
<span class="k">if</span> <span class="k">typeof</span> <span class="p">(</span><span class="nv">pos = </span><span class="nx">@positions</span><span class="p">[</span><span class="nx">name</span><span class="p">])</span> <span class="o">is</span> <span class="s1">'number'</span>
|
||||
<span class="nx">@variables</span><span class="p">[</span><span class="nx">pos</span><span class="p">].</span><span class="nv">type = </span><span class="nx">type</span>
|
||||
<span class="k">else</span>
|
||||
@@ -19,10 +20,9 @@ it wraps.</p> </td> <td class="code"> <div
|
||||
already exist.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">find</span><span class="o">:</span> <span class="p">(</span><span class="nx">name</span><span class="p">,</span> <span class="nx">options</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="k">return</span> <span class="kc">yes</span> <span class="k">if</span> <span class="nx">@check</span> <span class="nx">name</span><span class="p">,</span> <span class="nx">options</span>
|
||||
<span class="nx">@add</span> <span class="nx">name</span><span class="p">,</span> <span class="s1">'var'</span>
|
||||
<span class="vi">@hasDeclarations = </span><span class="kc">yes</span>
|
||||
<span class="kc">no</span></pre></div> </td> </tr> <tr id="section-7"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-7">¶</a> </div> <p>Reserve a variable name as originating from a function parameter for this
|
||||
scope. No <code>var</code> required for internal references.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">parameter</span><span class="o">:</span> <span class="p">(</span><span class="nx">name</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="k">return</span> <span class="k">if</span> <span class="nx">@shared</span> <span class="o">and</span> <span class="nx">@check</span> <span class="nx">name</span><span class="p">,</span> <span class="kc">yes</span>
|
||||
<span class="k">return</span> <span class="k">if</span> <span class="nx">@shared</span> <span class="o">and</span> <span class="nx">@parent</span><span class="p">.</span><span class="nx">check</span> <span class="nx">name</span><span class="p">,</span> <span class="kc">yes</span>
|
||||
<span class="nx">@add</span> <span class="nx">name</span><span class="p">,</span> <span class="s1">'param'</span></pre></div> </td> </tr> <tr id="section-8"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-8">¶</a> </div> <p>Just check to see if a variable has already been declared, without reserving,
|
||||
walks up to the root scope.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">check</span><span class="o">:</span> <span class="p">(</span><span class="nx">name</span><span class="p">,</span> <span class="nx">immediate</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nv">found = </span><span class="o">!!</span><span class="nx">@type</span><span class="p">(</span><span class="nx">name</span><span class="p">)</span>
|
||||
@@ -37,17 +37,17 @@ walks up to the root scope.</p> </td> <td class="code">
|
||||
compiler-generated variable. <code>_var</code>, <code>_var2</code>, and so on...</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">freeVariable</span><span class="o">:</span> <span class="p">(</span><span class="nx">type</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nv">index = </span><span class="mi">0</span>
|
||||
<span class="nx">index</span><span class="o">++</span> <span class="k">while</span> <span class="nx">@check</span><span class="p">((</span><span class="nv">temp = </span><span class="nx">@temporary</span> <span class="nx">type</span><span class="p">,</span> <span class="nx">index</span><span class="p">),</span> <span class="kc">true</span><span class="p">)</span>
|
||||
<span class="nx">@add</span> <span class="nx">temp</span><span class="p">,</span> <span class="s1">'var'</span>
|
||||
<span class="vi">@hasDeclarations = </span><span class="kc">yes</span>
|
||||
<span class="nx">@add</span> <span class="nx">temp</span><span class="p">,</span> <span class="s1">'var'</span><span class="p">,</span> <span class="kc">yes</span>
|
||||
<span class="nx">temp</span></pre></div> </td> </tr> <tr id="section-12"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-12">¶</a> </div> <p>Ensure that an assignment is made at the top of this scope
|
||||
(or at the top-level scope, if requested).</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">assign</span><span class="o">:</span> <span class="p">(</span><span class="nx">name</span><span class="p">,</span> <span class="nx">value</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nx">@add</span> <span class="nx">name</span><span class="p">,</span> <span class="nx">value</span><span class="o">:</span> <span class="nx">value</span><span class="p">,</span> <span class="nx">assigned</span><span class="o">:</span> <span class="kc">true</span>
|
||||
<span class="vi">@hasAssignments = </span><span class="kc">yes</span></pre></div> </td> </tr> <tr id="section-13"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-13">¶</a> </div> <p>Return the list of variables first declared in this scope.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">declaredVariables</span><span class="o">:</span> <span class="o">-></span>
|
||||
<span class="vi">@hasAssignments = </span><span class="kc">yes</span></pre></div> </td> </tr> <tr id="section-13"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-13">¶</a> </div> <p>Does this scope have any declared variables?</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">hasDeclarations</span><span class="o">:</span> <span class="o">-></span>
|
||||
<span class="o">!!</span><span class="nx">@declaredVariables</span><span class="p">().</span><span class="nx">length</span></pre></div> </td> </tr> <tr id="section-14"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-14">¶</a> </div> <p>Return the list of variables first declared in this scope.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">declaredVariables</span><span class="o">:</span> <span class="o">-></span>
|
||||
<span class="nv">realVars = </span><span class="p">[]</span>
|
||||
<span class="nv">tempVars = </span><span class="p">[]</span>
|
||||
<span class="k">for</span> <span class="nx">v</span> <span class="k">in</span> <span class="nx">@variables</span> <span class="k">when</span> <span class="nx">v</span><span class="p">.</span><span class="nx">type</span> <span class="o">is</span> <span class="s1">'var'</span>
|
||||
<span class="p">(</span><span class="k">if</span> <span class="nx">v</span><span class="p">.</span><span class="nx">name</span><span class="p">.</span><span class="nx">charAt</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span> <span class="o">is</span> <span class="s1">'_'</span> <span class="k">then</span> <span class="nx">tempVars</span> <span class="k">else</span> <span class="nx">realVars</span><span class="p">).</span><span class="nx">push</span> <span class="nx">v</span><span class="p">.</span><span class="nx">name</span>
|
||||
<span class="nx">realVars</span><span class="p">.</span><span class="nx">sort</span><span class="p">().</span><span class="nx">concat</span> <span class="nx">tempVars</span><span class="p">.</span><span class="nx">sort</span><span class="p">()</span></pre></div> </td> </tr> <tr id="section-14"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-14">¶</a> </div> <p>Return the list of assignments that are supposed to be made at the top
|
||||
<span class="nx">realVars</span><span class="p">.</span><span class="nx">sort</span><span class="p">().</span><span class="nx">concat</span> <span class="nx">tempVars</span><span class="p">.</span><span class="nx">sort</span><span class="p">()</span></pre></div> </td> </tr> <tr id="section-15"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-15">¶</a> </div> <p>Return the list of assignments that are supposed to be made at the top
|
||||
of this scope.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">assignedVariables</span><span class="o">:</span> <span class="o">-></span>
|
||||
<span class="s2">"#{v.name} = #{v.type.value}"</span> <span class="k">for</span> <span class="nx">v</span> <span class="k">in</span> <span class="nx">@variables</span> <span class="k">when</span> <span class="nx">v</span><span class="p">.</span><span class="nx">type</span><span class="p">.</span><span class="nx">assigned</span>
|
||||
|
||||
|
||||
BIN
documentation/images/background.png
Normal file
|
After Width: | Height: | Size: 123 B |
BIN
documentation/images/banding.png
Normal file
|
After Width: | Height: | Size: 132 B |
BIN
documentation/images/button_bg.png
Normal file
|
After Width: | Height: | Size: 138 B |
BIN
documentation/images/button_bg_dark.gif
Normal file
|
After Width: | Height: | Size: 148 B |
BIN
documentation/images/button_bg_green.gif
Normal file
|
After Width: | Height: | Size: 95 B |
|
Before Width: | Height: | Size: 5.9 KiB After Width: | Height: | Size: 7.8 KiB |
BIN
documentation/images/screenshadow.png
Normal file
|
After Width: | Height: | Size: 4.3 KiB |
@@ -1,4 +1,4 @@
|
||||
/*
|
||||
CoffeeScript Compiler v0.9.6
|
||||
CoffeeScript Compiler v1.0.0
|
||||
Released under the MIT License
|
||||
*/
|
||||
@@ -7,7 +7,7 @@ var __hasProp = Object.prototype.hasOwnProperty, __extends = function(child, par
|
||||
child.__super__ = parent.prototype;
|
||||
return child;
|
||||
};
|
||||
Animal = function() {
|
||||
Animal = (function() {
|
||||
function Animal(name) {
|
||||
this.name = name;
|
||||
}
|
||||
@@ -15,8 +15,8 @@ Animal = function() {
|
||||
return alert(this.name + " moved " + meters + "m.");
|
||||
};
|
||||
return Animal;
|
||||
}();
|
||||
Snake = function() {
|
||||
})();
|
||||
Snake = (function() {
|
||||
function Snake() {
|
||||
Snake.__super__.constructor.apply(this, arguments);
|
||||
}
|
||||
@@ -26,8 +26,8 @@ Snake = function() {
|
||||
return Snake.__super__.move.call(this, 5);
|
||||
};
|
||||
return Snake;
|
||||
}();
|
||||
Horse = function() {
|
||||
})();
|
||||
Horse = (function() {
|
||||
function Horse() {
|
||||
Horse.__super__.constructor.apply(this, arguments);
|
||||
}
|
||||
@@ -37,7 +37,7 @@ Horse = function() {
|
||||
return Horse.__super__.move.call(this, 45);
|
||||
};
|
||||
return Horse;
|
||||
}();
|
||||
})();
|
||||
sam = new Snake("Sammy the Python");
|
||||
tom = new Horse("Tommy the Palomino");
|
||||
sam.move();
|
||||
|
||||
10
documentation/js/do.js
Normal file
@@ -0,0 +1,10 @@
|
||||
var fileName, _fn, _i, _len;
|
||||
_fn = function(fileName) {
|
||||
return fs.readFile(fileName, function(err, contents) {
|
||||
return compile(fileName, contents.toString());
|
||||
});
|
||||
};
|
||||
for (_i = 0, _len = list.length; _i < _len; _i++) {
|
||||
fileName = list[_i];
|
||||
_fn(fileName);
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
var solipsism;
|
||||
var footprints, solipsism;
|
||||
if ((typeof mind != "undefined" && mind !== null) && !(typeof world != "undefined" && world !== null)) {
|
||||
solipsism = true;
|
||||
}
|
||||
typeof speed != "undefined" && speed !== null ? speed : speed = 140;
|
||||
typeof speed != "undefined" && speed !== null ? speed : speed = 75;
|
||||
footprints = typeof yeti != "undefined" && yeti !== null ? yeti : "bear";
|
||||
@@ -1,8 +1,9 @@
|
||||
var globals, name, _results;
|
||||
globals = (function() {
|
||||
var globals, name;
|
||||
globals = ((function() {
|
||||
var _results;
|
||||
_results = [];
|
||||
for (name in window) {
|
||||
_results.push(name);
|
||||
}
|
||||
return _results;
|
||||
}()).slice(0, 10);
|
||||
})()).slice(0, 10);
|
||||
@@ -1,7 +1,7 @@
|
||||
alert(function() {
|
||||
alert((function() {
|
||||
try {
|
||||
return nonexistent / void 0;
|
||||
} catch (error) {
|
||||
return "And the error is ... " + error;
|
||||
}
|
||||
}());
|
||||
})());
|
||||
@@ -1,14 +1,15 @@
|
||||
var age, ages, child, yearsOld, _results;
|
||||
var age, ages, child, yearsOld;
|
||||
yearsOld = {
|
||||
max: 10,
|
||||
ida: 9,
|
||||
tim: 11
|
||||
};
|
||||
ages = function() {
|
||||
ages = (function() {
|
||||
var _results;
|
||||
_results = [];
|
||||
for (child in yearsOld) {
|
||||
age = yearsOld[child];
|
||||
_results.push(child + " is " + age);
|
||||
}
|
||||
return _results;
|
||||
}();
|
||||
})();
|
||||
@@ -1,10 +1,10 @@
|
||||
var kids, matrix, singers, song;
|
||||
var bitlist, kids, singers, song;
|
||||
song = ["do", "re", "mi", "fa", "so"];
|
||||
singers = {
|
||||
Jagger: "Rock",
|
||||
Elvis: "Roll"
|
||||
};
|
||||
matrix = [1, 0, 1, 0, 0, 1, 1, 1, 0];
|
||||
bitlist = [1, 0, 1, 0, 0, 1, 1, 1, 0];
|
||||
kids = {
|
||||
brother: {
|
||||
name: "Max",
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
var cubes, list, math, num, number, opposite, race, square, _i, _len, _results;
|
||||
var cubes, list, math, num, number, opposite, race, square;
|
||||
var __slice = Array.prototype.slice;
|
||||
number = 42;
|
||||
opposite = true;
|
||||
@@ -25,10 +25,11 @@ if (typeof elvis != "undefined" && elvis !== null) {
|
||||
alert("I knew it!");
|
||||
}
|
||||
cubes = (function() {
|
||||
var _i, _len, _results;
|
||||
_results = [];
|
||||
for (_i = 0, _len = list.length; _i < _len; _i++) {
|
||||
num = list[_i];
|
||||
_results.push(math.cube(num));
|
||||
}
|
||||
return _results;
|
||||
}());
|
||||
})();
|
||||
@@ -1,8 +1,9 @@
|
||||
var countdown, num, _results;
|
||||
var countdown, num;
|
||||
countdown = (function() {
|
||||
var _results;
|
||||
_results = [];
|
||||
for (num = 10; num >= 1; num--) {
|
||||
_results.push(num);
|
||||
}
|
||||
return _results;
|
||||
}());
|
||||
})();
|
||||
@@ -1,4 +1,4 @@
|
||||
var copy, middle, numbers;
|
||||
numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
|
||||
copy = numbers.slice(0, numbers.length);
|
||||
middle = copy.slice(3, 6 + 1);
|
||||
middle = copy.slice(3, 7);
|
||||
@@ -1,3 +1,3 @@
|
||||
var numbers;
|
||||
var numbers, _ref;
|
||||
numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
|
||||
[].splice.apply(numbers, [3, 4].concat([-3, -4, -5, -6]));
|
||||
[].splice.apply(numbers, [3, 4].concat(_ref = [-3, -4, -5, -6])), _ref;
|
||||
@@ -1,4 +1,4 @@
|
||||
var lyrics, num, _results;
|
||||
var lyrics, num;
|
||||
if (this.studyingEconomics) {
|
||||
while (supply > demand) {
|
||||
buy();
|
||||
@@ -8,10 +8,11 @@ if (this.studyingEconomics) {
|
||||
}
|
||||
}
|
||||
num = 6;
|
||||
lyrics = function() {
|
||||
lyrics = (function() {
|
||||
var _results;
|
||||
_results = [];
|
||||
while (num -= 1) {
|
||||
_results.push(num + " little monkeys, jumping on the bed. One fell out and bumped his head.");
|
||||
}
|
||||
return _results;
|
||||
}();
|
||||
})();
|
||||
6240
documentation/vendor/jquery-1.4.2.js
vendored
Normal file
1293
index.html
@@ -1,8 +1,8 @@
|
||||
(function() {
|
||||
var Lexer, compile, fs, lexer, parser, path;
|
||||
var Lexer, RESERVED, compile, fs, lexer, parser, path, _ref;
|
||||
fs = require('fs');
|
||||
path = require('path');
|
||||
Lexer = require('./lexer').Lexer;
|
||||
_ref = require('./lexer'), Lexer = _ref.Lexer, RESERVED = _ref.RESERVED;
|
||||
parser = require('./parser').parser;
|
||||
if (require.extensions) {
|
||||
require.extensions['.coffee'] = function(module, filename) {
|
||||
@@ -15,7 +15,8 @@
|
||||
return compile(content);
|
||||
});
|
||||
}
|
||||
exports.VERSION = '0.9.6';
|
||||
exports.VERSION = '1.0.0';
|
||||
exports.RESERVED = RESERVED;
|
||||
exports.helpers = require('./helpers');
|
||||
exports.compile = compile = function(code, options) {
|
||||
if (options == null) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
(function() {
|
||||
var ALL_SWITCHES, BANNER, CoffeeScript, DEPRECATED_SWITCHES, EventEmitter, SWITCHES, compileOptions, compileScript, compileScripts, compileStdio, exec, fs, helpers, lint, optionParser, optparse, opts, parseOptions, path, printLine, printTokens, printWarn, sources, spawn, usage, util, version, watch, writeJs, _ref;
|
||||
var BANNER, CoffeeScript, EventEmitter, SWITCHES, compileJoin, compileOptions, compileScript, compileScripts, compileStdio, contents, exec, forkNode, fs, helpers, lint, optionParser, optparse, opts, parseOptions, path, printLine, printTokens, printWarn, sources, spawn, usage, util, version, watch, writeJs, _ref;
|
||||
fs = require('fs');
|
||||
path = require('path');
|
||||
util = require('util');
|
||||
@@ -16,15 +16,16 @@
|
||||
return process.binding('stdio').writeError(line + '\n');
|
||||
};
|
||||
BANNER = 'Usage: coffee [options] path/to/script.coffee';
|
||||
SWITCHES = [['-c', '--compile', 'compile to JavaScript and save as .js files'], ['-i', '--interactive', 'run an interactive CoffeeScript REPL'], ['-o', '--output [DIR]', 'set the directory for compiled JavaScript'], ['-w', '--watch', 'watch scripts for changes, and recompile'], ['-p', '--print', 'print the compiled JavaScript to stdout'], ['-l', '--lint', 'pipe the compiled JavaScript through JSLint'], ['-s', '--stdio', 'listen for and compile scripts over stdio'], ['-e', '--eval', 'compile a string from the command line'], ['-r', '--require [FILE*]', 'require a library before executing your script'], ['-b', '--bare', 'compile without the top-level function wrapper'], ['-t', '--tokens', 'print the tokens that the lexer produces'], ['-n', '--nodes', 'print the parse tree that Jison produces'], ['-v', '--version', 'display CoffeeScript version'], ['-h', '--help', 'display this help message']];
|
||||
DEPRECATED_SWITCHES = [['--no-wrap', 'compile without the top-level function wrapper']];
|
||||
ALL_SWITCHES = SWITCHES.concat(DEPRECATED_SWITCHES);
|
||||
SWITCHES = [['-c', '--compile', 'compile to JavaScript and save as .js files'], ['-i', '--interactive', 'run an interactive CoffeeScript REPL'], ['-o', '--output [DIR]', 'set the directory for compiled JavaScript'], ['-j', '--join', 'concatenate the scripts before compiling'], ['-w', '--watch', 'watch scripts for changes, and recompile'], ['-p', '--print', 'print the compiled JavaScript to stdout'], ['-l', '--lint', 'pipe the compiled JavaScript through JSLint'], ['-s', '--stdio', 'listen for and compile scripts over stdio'], ['-e', '--eval', 'compile a string from the command line'], ['-r', '--require [FILE*]', 'require a library before executing your script'], ['-b', '--bare', 'compile without the top-level function wrapper'], ['-t', '--tokens', 'print the tokens that the lexer produces'], ['-n', '--nodes', 'print the parse tree that Jison produces'], ['--nodejs [ARGS]', 'pass options through to the "node" binary'], ['-v', '--version', 'display CoffeeScript version'], ['-h', '--help', 'display this help message']];
|
||||
opts = {};
|
||||
sources = [];
|
||||
contents = [];
|
||||
optionParser = null;
|
||||
exports.run = function() {
|
||||
var flags, separator;
|
||||
parseOptions();
|
||||
if (opts.nodejs) {
|
||||
return forkNode();
|
||||
}
|
||||
if (opts.help) {
|
||||
return usage();
|
||||
}
|
||||
@@ -43,21 +44,17 @@
|
||||
if (!sources.length) {
|
||||
return require('./repl');
|
||||
}
|
||||
separator = sources.indexOf('--');
|
||||
flags = [];
|
||||
if (separator >= 0) {
|
||||
flags = sources.splice(separator + 1);
|
||||
sources.pop();
|
||||
}
|
||||
if (opts.run) {
|
||||
flags = sources.splice(1).concat(flags);
|
||||
opts.literals = sources.splice(1).concat(opts.literals);
|
||||
}
|
||||
process.ARGV = process.argv = flags;
|
||||
process.ARGV = process.argv = process.argv.slice(0, 2).concat(opts.literals);
|
||||
return compileScripts();
|
||||
};
|
||||
compileScripts = function() {
|
||||
var base, compile, source, _fn, _i, _len, _results;
|
||||
_fn = function(source) {
|
||||
var base, compile, source, _i, _len, _results;
|
||||
_results = [];
|
||||
for (_i = 0, _len = sources.length; _i < _len; _i++) {
|
||||
source = sources[_i];
|
||||
base = path.join(source);
|
||||
compile = function(source, topLevel) {
|
||||
return path.exists(source, function(exists) {
|
||||
@@ -77,21 +74,23 @@
|
||||
});
|
||||
} else if (topLevel || path.extname(source) === '.coffee') {
|
||||
fs.readFile(source, function(err, code) {
|
||||
return compileScript(source, code.toString(), base);
|
||||
if (opts.join) {
|
||||
contents[sources.indexOf(source)] = code.toString();
|
||||
if (helpers.compact(contents).length === sources.length) {
|
||||
return compileJoin();
|
||||
}
|
||||
} else {
|
||||
return compileScript(source, code.toString(), base);
|
||||
}
|
||||
});
|
||||
if (opts.watch) {
|
||||
if (opts.watch && !opts.join) {
|
||||
return watch(source, base);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
return _results.push(compile(source, true));
|
||||
};
|
||||
_results = [];
|
||||
for (_i = 0, _len = sources.length; _i < _len; _i++) {
|
||||
source = sources[_i];
|
||||
_fn(source);
|
||||
_results.push(compile(source, true));
|
||||
}
|
||||
return _results;
|
||||
};
|
||||
@@ -155,6 +154,11 @@
|
||||
return compileScript(null, code);
|
||||
});
|
||||
};
|
||||
compileJoin = function() {
|
||||
var code;
|
||||
code = contents.join('\n');
|
||||
return compileScript("concatenation", code, "concatenation");
|
||||
};
|
||||
watch = function(source, base) {
|
||||
return fs.watchFile(source, {
|
||||
persistent: true,
|
||||
@@ -175,7 +179,7 @@
|
||||
var baseDir, compile, dir, filename, jsPath, srcDir;
|
||||
filename = path.basename(source, path.extname(source)) + '.js';
|
||||
srcDir = path.dirname(source);
|
||||
baseDir = srcDir.substring(base.length);
|
||||
baseDir = base === '.' ? srcDir : srcDir.substring(base.length);
|
||||
dir = opts.output ? path.join(opts.output, baseDir) : srcDir;
|
||||
jsPath = path.join(dir, filename);
|
||||
compile = function() {
|
||||
@@ -211,8 +215,9 @@
|
||||
return jsl.stdin.end();
|
||||
};
|
||||
printTokens = function(tokens) {
|
||||
var strings, tag, token, value, _i, _len, _ref, _results;
|
||||
strings = function() {
|
||||
var strings, tag, token, value;
|
||||
strings = (function() {
|
||||
var _i, _len, _ref, _results;
|
||||
_results = [];
|
||||
for (_i = 0, _len = tokens.length; _i < _len; _i++) {
|
||||
token = tokens[_i];
|
||||
@@ -220,27 +225,35 @@
|
||||
_results.push("[" + tag + " " + value + "]");
|
||||
}
|
||||
return _results;
|
||||
}();
|
||||
})();
|
||||
return printLine(strings.join(' '));
|
||||
};
|
||||
parseOptions = function() {
|
||||
var o;
|
||||
optionParser = new optparse.OptionParser(ALL_SWITCHES, BANNER);
|
||||
optionParser = new optparse.OptionParser(SWITCHES, BANNER);
|
||||
o = opts = optionParser.parse(process.argv.slice(2));
|
||||
o.compile || (o.compile = !!o.output);
|
||||
o.run = !(o.compile || o.print || o.lint);
|
||||
o.print = !!(o.print || (o.eval || o.stdio && o.compile));
|
||||
sources = o.arguments;
|
||||
if (opts['no-wrap']) {
|
||||
return printWarn('--no-wrap is deprecated; please use --bare instead.');
|
||||
}
|
||||
return sources = o.arguments;
|
||||
};
|
||||
compileOptions = function(fileName) {
|
||||
return {
|
||||
fileName: fileName,
|
||||
bare: opts.bare || opts['no-wrap']
|
||||
bare: opts.bare
|
||||
};
|
||||
};
|
||||
forkNode = function() {
|
||||
var args, nodeArgs;
|
||||
nodeArgs = opts.nodejs.split(/\s+/);
|
||||
args = process.argv.slice(1);
|
||||
args.splice(args.indexOf('--nodejs'), 2);
|
||||
return spawn(process.execPath, nodeArgs.concat(args), {
|
||||
cwd: process.cwd(),
|
||||
env: process.env,
|
||||
customFds: [0, 1, 2]
|
||||
});
|
||||
};
|
||||
usage = function() {
|
||||
printLine((new optparse.OptionParser(SWITCHES, BANNER)).help());
|
||||
return process.exit(0);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
(function() {
|
||||
var Parser, alt, alternatives, grammar, name, o, operators, token, tokens, unwrap, _i, _j, _len, _len2, _ref, _results;
|
||||
var Parser, alt, alternatives, grammar, name, o, operators, token, tokens, unwrap;
|
||||
Parser = require('jison').Parser;
|
||||
unwrap = /^function\s*\(\)\s*\{\s*return\s*([\s\S]*);\s*\}/;
|
||||
o = function(patternString, action, options) {
|
||||
@@ -34,10 +34,10 @@
|
||||
],
|
||||
Expression: [o('Value'), o('Invocation'), o('Code'), o('Operation'), o('Assign'), o('If'), o('Try'), o('While'), o('For'), o('Switch'), o('Class')],
|
||||
Block: [
|
||||
o('INDENT Body OUTDENT', function() {
|
||||
return $2;
|
||||
}), o('INDENT OUTDENT', function() {
|
||||
o('INDENT OUTDENT', function() {
|
||||
return new Expressions;
|
||||
}), o('INDENT Body OUTDENT', function() {
|
||||
return $2;
|
||||
})
|
||||
],
|
||||
Identifier: [
|
||||
@@ -368,22 +368,22 @@
|
||||
],
|
||||
For: [
|
||||
o('Statement ForBody', function() {
|
||||
return new For($1, $2, $2.vars[0], $2.vars[1]);
|
||||
return new For($1, $2);
|
||||
}), o('Expression ForBody', function() {
|
||||
return new For($1, $2, $2.vars[0], $2.vars[1]);
|
||||
return new For($1, $2);
|
||||
}), o('ForBody Block', function() {
|
||||
return new For($2, $1, $1.vars[0], $1.vars[1]);
|
||||
return new For($2, $1);
|
||||
})
|
||||
],
|
||||
ForBody: [
|
||||
o('FOR Range', function() {
|
||||
return {
|
||||
source: new Value($2),
|
||||
vars: []
|
||||
source: new Value($2)
|
||||
};
|
||||
}), o('ForStart ForSource', function() {
|
||||
$2.own = $1.own;
|
||||
$2.vars = $1;
|
||||
$2.name = $1[0];
|
||||
$2.index = $1[1];
|
||||
return $2;
|
||||
})
|
||||
],
|
||||
@@ -474,13 +474,13 @@
|
||||
],
|
||||
IfBlock: [
|
||||
o('IF Expression Block', function() {
|
||||
return new If($2, $3);
|
||||
}), o('UNLESS Expression Block', function() {
|
||||
return new If($2, $3, {
|
||||
invert: true
|
||||
type: $1
|
||||
});
|
||||
}), o('IfBlock ELSE IF Expression Block', function() {
|
||||
return $1.addElse(new If($4, $5));
|
||||
return $1.addElse(new If($4, $5, {
|
||||
type: $3
|
||||
}));
|
||||
}), o('IfBlock ELSE Block', function() {
|
||||
return $1.addElse($3);
|
||||
})
|
||||
@@ -488,22 +488,14 @@
|
||||
If: [
|
||||
o('IfBlock'), o('Statement POST_IF Expression', function() {
|
||||
return new If($3, Expressions.wrap([$1]), {
|
||||
type: $2,
|
||||
statement: true
|
||||
});
|
||||
}), o('Expression POST_IF Expression', function() {
|
||||
return new If($3, Expressions.wrap([$1]), {
|
||||
type: $2,
|
||||
statement: true
|
||||
});
|
||||
}), o('Statement POST_UNLESS Expression', function() {
|
||||
return new If($3, Expressions.wrap([$1]), {
|
||||
statement: true,
|
||||
invert: true
|
||||
});
|
||||
}), o('Expression POST_UNLESS Expression', function() {
|
||||
return new If($3, Expressions.wrap([$1]), {
|
||||
statement: true,
|
||||
invert: true
|
||||
});
|
||||
})
|
||||
],
|
||||
Operation: [
|
||||
@@ -556,11 +548,12 @@
|
||||
})
|
||||
]
|
||||
};
|
||||
operators = [['left', '.', '?.', '::'], ['left', 'CALL_START', 'CALL_END'], ['nonassoc', '++', '--'], ['left', '?'], ['right', 'UNARY'], ['left', 'MATH'], ['left', '+', '-'], ['left', 'SHIFT'], ['left', 'RELATION'], ['left', 'COMPARE'], ['left', 'LOGIC'], ['nonassoc', 'INDENT', 'OUTDENT'], ['right', '=', ':', 'COMPOUND_ASSIGN', 'RETURN', 'THROW', 'EXTENDS'], ['right', 'FORIN', 'FOROF', 'BY', 'WHEN'], ['right', 'IF', 'UNLESS', 'ELSE', 'FOR', 'WHILE', 'UNTIL', 'LOOP', 'SUPER', 'CLASS'], ['right', 'POST_IF', 'POST_UNLESS']];
|
||||
operators = [['left', '.', '?.', '::'], ['left', 'CALL_START', 'CALL_END'], ['nonassoc', '++', '--'], ['left', '?'], ['right', 'UNARY'], ['left', 'MATH'], ['left', '+', '-'], ['left', 'SHIFT'], ['left', 'RELATION'], ['left', 'COMPARE'], ['left', 'LOGIC'], ['nonassoc', 'INDENT', 'OUTDENT'], ['right', '=', ':', 'COMPOUND_ASSIGN', 'RETURN', 'THROW', 'EXTENDS'], ['right', 'FORIN', 'FOROF', 'BY', 'WHEN'], ['right', 'IF', 'ELSE', 'FOR', 'DO', 'WHILE', 'UNTIL', 'LOOP', 'SUPER', 'CLASS'], ['right', 'POST_IF']];
|
||||
tokens = [];
|
||||
for (name in grammar) {
|
||||
alternatives = grammar[name];
|
||||
grammar[name] = function() {
|
||||
grammar[name] = (function() {
|
||||
var _i, _j, _len, _len2, _ref, _results;
|
||||
_results = [];
|
||||
for (_i = 0, _len = alternatives.length; _i < _len; _i++) {
|
||||
alt = alternatives[_i];
|
||||
@@ -577,7 +570,7 @@
|
||||
_results.push(alt);
|
||||
}
|
||||
return _results;
|
||||
}();
|
||||
})();
|
||||
}
|
||||
exports.parser = new Parser({
|
||||
tokens: tokens.join(' '),
|
||||
|
||||
@@ -19,10 +19,13 @@
|
||||
}
|
||||
return _results;
|
||||
};
|
||||
exports.count = function(string, letter) {
|
||||
exports.count = function(string, substr) {
|
||||
var num, pos;
|
||||
num = pos = 0;
|
||||
while (pos = 1 + string.indexOf(letter, pos)) {
|
||||
if (!substr.length) {
|
||||
return 1 / 0;
|
||||
}
|
||||
while (pos = 1 + string.indexOf(substr, pos)) {
|
||||
num++;
|
||||
}
|
||||
return num;
|
||||
|
||||
56
lib/lexer.js
@@ -8,7 +8,7 @@
|
||||
};
|
||||
Rewriter = require('./rewriter').Rewriter;
|
||||
_ref = require('./helpers'), count = _ref.count, starts = _ref.starts, compact = _ref.compact, last = _ref.last;
|
||||
exports.Lexer = Lexer = function() {
|
||||
exports.Lexer = Lexer = (function() {
|
||||
function Lexer() {}
|
||||
Lexer.prototype.tokenize = function(code, opts) {
|
||||
var i;
|
||||
@@ -51,12 +51,14 @@
|
||||
tag = 'LEADING_WHEN';
|
||||
} else if (tag === 'FOR') {
|
||||
this.seenFor = true;
|
||||
} else if (tag === 'UNLESS') {
|
||||
tag = 'IF';
|
||||
} else if (__indexOf.call(UNARY, tag) >= 0) {
|
||||
tag = 'UNARY';
|
||||
} else if (__indexOf.call(RELATION, tag) >= 0) {
|
||||
if (tag !== 'INSTANCEOF' && this.seenFor) {
|
||||
this.seenFor = false;
|
||||
tag = 'FOR' + tag;
|
||||
this.seenFor = false;
|
||||
} else {
|
||||
tag = 'RELATION';
|
||||
if (this.value() === '!') {
|
||||
@@ -79,7 +81,7 @@
|
||||
if (COFFEE_ALIASES.hasOwnProperty(id)) {
|
||||
id = COFFEE_ALIASES[id];
|
||||
}
|
||||
tag = function() {
|
||||
tag = (function() {
|
||||
switch (id) {
|
||||
case '!':
|
||||
return 'UNARY';
|
||||
@@ -101,7 +103,7 @@
|
||||
default:
|
||||
return tag;
|
||||
}
|
||||
}();
|
||||
})();
|
||||
}
|
||||
this.token(tag, id);
|
||||
if (colon) {
|
||||
@@ -128,7 +130,7 @@
|
||||
this.token('STRING', (string = match[0]).replace(MULTILINER, '\\\n'));
|
||||
break;
|
||||
case '"':
|
||||
if (!(string = this.balancedString(this.chunk, [['"', '"'], ['#{', '}']]))) {
|
||||
if (!(string = this.balancedString(this.chunk, '"'))) {
|
||||
return 0;
|
||||
}
|
||||
if (0 < string.indexOf('#{', 1)) {
|
||||
@@ -447,35 +449,32 @@
|
||||
Lexer.prototype.assignmentError = function() {
|
||||
throw SyntaxError("Reserved word \"" + (this.value()) + "\" on line " + (this.line + 1) + " can't be assigned");
|
||||
};
|
||||
Lexer.prototype.balancedString = function(str, delimited, options) {
|
||||
var i, open, pair, stack, _i, _len, _ref;
|
||||
if (options == null) {
|
||||
options = {};
|
||||
}
|
||||
stack = [delimited[0]];
|
||||
Lexer.prototype.balancedString = function(str, end) {
|
||||
var i, letter, prev, stack, _ref;
|
||||
stack = [end];
|
||||
for (i = 1, _ref = str.length; (1 <= _ref ? i < _ref : i > _ref); (1 <= _ref ? i += 1 : i -= 1)) {
|
||||
switch (str.charAt(i)) {
|
||||
switch (letter = str.charAt(i)) {
|
||||
case '\\':
|
||||
i++;
|
||||
continue;
|
||||
break;
|
||||
case stack[stack.length - 1][1]:
|
||||
case end:
|
||||
stack.pop();
|
||||
if (!stack.length) {
|
||||
return str.slice(0, i + 1);
|
||||
}
|
||||
end = stack[stack.length - 1];
|
||||
continue;
|
||||
}
|
||||
for (_i = 0, _len = delimited.length; _i < _len; _i++) {
|
||||
pair = delimited[_i];
|
||||
if ((open = pair[0]) === str.substr(i, open.length)) {
|
||||
stack.push(pair);
|
||||
i += open.length - 1;
|
||||
break;
|
||||
}
|
||||
if (end === '}' && (letter === '"' || letter === "'")) {
|
||||
stack.push(end = letter);
|
||||
} else if (end === '}' && letter === '{') {
|
||||
stack.push(end = '}');
|
||||
} else if (end === '"' && prev === '#' && letter === '{') {
|
||||
stack.push(end = '}');
|
||||
}
|
||||
prev = letter;
|
||||
}
|
||||
throw new Error("unterminated " + (stack.pop()[0]) + " on line " + (this.line + 1));
|
||||
throw new Error("missing " + (stack.pop()) + ", starting on line " + (this.line + 1));
|
||||
};
|
||||
Lexer.prototype.interpolateString = function(str, options) {
|
||||
var expr, heredoc, i, inner, interpolated, letter, nested, pi, regex, tag, tokens, value, _len, _ref, _ref2, _ref3;
|
||||
@@ -491,7 +490,7 @@
|
||||
i += 1;
|
||||
continue;
|
||||
}
|
||||
if (!(letter === '#' && str.charAt(i + 1) === '{' && (expr = this.balancedString(str.slice(i + 1), [['{', '}']])))) {
|
||||
if (!(letter === '#' && str.charAt(i + 1) === '{' && (expr = this.balancedString(str.slice(i + 1), '}')))) {
|
||||
continue;
|
||||
}
|
||||
if (pi < i) {
|
||||
@@ -580,8 +579,8 @@
|
||||
return quote + this.escapeLines(body, heredoc) + quote;
|
||||
};
|
||||
return Lexer;
|
||||
}();
|
||||
JS_KEYWORDS = ['true', 'false', 'null', 'this', 'new', 'delete', 'typeof', 'in', 'instanceof', 'return', 'throw', 'break', 'continue', 'debugger', 'if', 'else', 'switch', 'for', 'while', 'try', 'catch', 'finally', 'class', 'extends', 'super'];
|
||||
})();
|
||||
JS_KEYWORDS = ['true', 'false', 'null', 'this', 'new', 'delete', 'typeof', 'in', 'instanceof', 'return', 'throw', 'break', 'continue', 'debugger', 'if', 'else', 'switch', 'for', 'while', 'do', 'try', 'catch', 'finally', 'class', 'extends', 'super'];
|
||||
COFFEE_KEYWORDS = ['undefined', 'then', 'unless', 'until', 'loop', 'of', 'by', 'when'];
|
||||
for (op in COFFEE_ALIASES = {
|
||||
and: '&&',
|
||||
@@ -596,14 +595,15 @@
|
||||
}) {
|
||||
COFFEE_KEYWORDS.push(op);
|
||||
}
|
||||
RESERVED = ['case', 'default', 'function', 'var', 'void', 'with', 'do', 'const', 'let', 'enum', 'export', 'import', 'native', '__hasProp', '__extends', '__slice'];
|
||||
RESERVED = ['case', 'default', 'function', 'var', 'void', 'with', 'const', 'let', 'enum', 'export', 'import', 'native', '__hasProp', '__extends', '__slice', '__bind', '__indexOf'];
|
||||
JS_FORBIDDEN = JS_KEYWORDS.concat(RESERVED);
|
||||
exports.RESERVED = RESERVED.concat(JS_KEYWORDS).concat(COFFEE_KEYWORDS);
|
||||
IDENTIFIER = /^([$A-Za-z_][$\w]*)([^\n\S]*:(?!:))?/;
|
||||
NUMBER = /^0x[\da-f]+|^(?:\d+(\.\d+)?|\.\d+)(?:e[+-]?\d+)?/i;
|
||||
HEREDOC = /^("""|''')([\s\S]*?)(?:\n[^\n\S]*)?\1/;
|
||||
OPERATOR = /^(?:[-=]>|[-+*\/%<>&|^!?=]=|>>>=?|([-+:])\1|([&|<>])\2=?|\?\.|\.{2,3})/;
|
||||
WHITESPACE = /^[^\n\S]+/;
|
||||
COMMENT = /^###([^#][\s\S]*?)(?:###[^\n\S]*\n|(?:###)?$)|^(?:\s*#(?!##[^#]).*)+/;
|
||||
COMMENT = /^###([^#][\s\S]*?)(?:###[^\n\S]*|(?:###)?$)|^(?:\s*#(?!##[^#]).*)+/;
|
||||
CODE = /^[-=]>/;
|
||||
MULTI_DENT = /^(?:\n[^\n\S]*)+/;
|
||||
SIMPLESTR = /^'[^\\']*(?:\\.[^\\']*)*'/;
|
||||
@@ -618,7 +618,7 @@
|
||||
TRAILING_SPACES = /\s+$/;
|
||||
NO_NEWLINE = /^(?:[-+*&|\/%=<>!.\\][<>=&|]*|and|or|is(?:nt)?|n(?:ot|ew)|delete|typeof|instanceof)$/;
|
||||
COMPOUND_ASSIGN = ['-=', '+=', '/=', '*=', '%=', '||=', '&&=', '?=', '<<=', '>>=', '>>>=', '&=', '^=', '|='];
|
||||
UNARY = ['!', '~', 'NEW', 'TYPEOF', 'DELETE'];
|
||||
UNARY = ['!', '~', 'NEW', 'TYPEOF', 'DELETE', 'DO'];
|
||||
LOGIC = ['&&', '||', '&', '|', '^'];
|
||||
SHIFT = ['<<', '>>', '>>>'];
|
||||
COMPARE = ['==', '!=', '<', '>', '<=', '>='];
|
||||
|
||||
519
lib/nodes.js
@@ -1,6 +1,6 @@
|
||||
(function() {
|
||||
var LONG_FLAG, MULTI_FLAG, OPTIONAL, OptionParser, SHORT_FLAG, buildRule, buildRules, normalizeArguments;
|
||||
exports.OptionParser = OptionParser = function() {
|
||||
exports.OptionParser = OptionParser = (function() {
|
||||
function OptionParser(rules, banner) {
|
||||
this.banner = banner;
|
||||
this.rules = buildRules(rules);
|
||||
@@ -8,11 +8,16 @@
|
||||
OptionParser.prototype.parse = function(args) {
|
||||
var arg, i, isOption, matchedRule, options, rule, value, _i, _len, _len2, _ref;
|
||||
options = {
|
||||
arguments: []
|
||||
arguments: [],
|
||||
literals: []
|
||||
};
|
||||
args = normalizeArguments(args);
|
||||
for (i = 0, _len = args.length; i < _len; i++) {
|
||||
arg = args[i];
|
||||
if (arg === '--') {
|
||||
options.literals = args.slice(i + 1);
|
||||
break;
|
||||
}
|
||||
isOption = !!(arg.match(LONG_FLAG) || arg.match(SHORT_FLAG));
|
||||
matchedRule = false;
|
||||
_ref = this.rules;
|
||||
@@ -52,7 +57,7 @@
|
||||
return "\n" + (lines.join('\n')) + "\n";
|
||||
};
|
||||
return OptionParser;
|
||||
}();
|
||||
})();
|
||||
LONG_FLAG = /^(--\w[\w\-]+)/;
|
||||
SHORT_FLAG = /^(-\w)/;
|
||||
MULTI_FLAG = /^-(\w{2,})/;
|
||||
|
||||
452
lib/parser.js
@@ -6,7 +6,7 @@
|
||||
}
|
||||
return -1;
|
||||
}, __slice = Array.prototype.slice;
|
||||
exports.Rewriter = function() {
|
||||
exports.Rewriter = (function() {
|
||||
function Rewriter() {}
|
||||
Rewriter.prototype.rewrite = function(tokens) {
|
||||
this.tokens = tokens;
|
||||
@@ -113,7 +113,7 @@
|
||||
startIndent = 0;
|
||||
condition = function(token, i) {
|
||||
var one, tag, three, two, _ref, _ref2;
|
||||
_ref = this.tokens.slice(i + 1, i + 3 + 1), one = _ref[0], two = _ref[1], three = _ref[2];
|
||||
_ref = this.tokens.slice(i + 1, (i + 3 + 1) || 9e9), one = _ref[0], two = _ref[1], three = _ref[2];
|
||||
if ('HERECOMMENT' === (one != null ? one[0] : void 0)) {
|
||||
return false;
|
||||
}
|
||||
@@ -161,10 +161,10 @@
|
||||
return this.scanTokens(function(token, i, tokens) {
|
||||
var callObject, current, next, prev, seenSingle, tag, _ref, _ref2, _ref3;
|
||||
tag = token[0];
|
||||
if (tag === 'CLASS' || tag === 'IF' || tag === 'UNLESS') {
|
||||
if (tag === 'CLASS' || tag === 'IF') {
|
||||
noCall = true;
|
||||
}
|
||||
_ref = tokens.slice(i - 1, i + 1 + 1), prev = _ref[0], current = _ref[1], next = _ref[2];
|
||||
_ref = tokens.slice(i - 1, (i + 1 + 1) || 9e9), prev = _ref[0], current = _ref[1], next = _ref[2];
|
||||
callObject = !noCall && tag === 'INDENT' && next && next.generated && next[0] === '{' && prev && (_ref2 = prev[0], __indexOf.call(IMPLICIT_FUNC, _ref2) >= 0);
|
||||
seenSingle = false;
|
||||
if (__indexOf.call(LINEBREAKS, tag) >= 0) {
|
||||
@@ -177,13 +177,13 @@
|
||||
return 1;
|
||||
}
|
||||
tokens.splice(i, 0, ['CALL_START', '(', token[2]]);
|
||||
this.detectEnd(i + (callObject ? 2 : 1), function(token, i) {
|
||||
this.detectEnd(i + 1, function(token, i) {
|
||||
var post, _ref;
|
||||
tag = token[0];
|
||||
if (!seenSingle && token.fromThen) {
|
||||
return true;
|
||||
}
|
||||
tag = token[0];
|
||||
if (tag === 'IF' || tag === 'ELSE' || tag === 'UNLESS' || tag === '->' || tag === '=>') {
|
||||
if (tag === 'IF' || tag === 'ELSE' || tag === '->' || tag === '=>') {
|
||||
seenSingle = true;
|
||||
}
|
||||
if ((tag === '.' || tag === '?.' || tag === '::') && this.tag(i - 1) === 'OUTDENT') {
|
||||
@@ -244,8 +244,8 @@
|
||||
return (_ref = token[0]) === 'TERMINATOR' || _ref === 'INDENT';
|
||||
};
|
||||
return this.scanTokens(function(token, i) {
|
||||
var original, _ref;
|
||||
if ((_ref = token[0]) !== 'IF' && _ref !== 'UNLESS') {
|
||||
var original;
|
||||
if (token[0] !== 'IF') {
|
||||
return 1;
|
||||
}
|
||||
original = token;
|
||||
@@ -331,7 +331,7 @@
|
||||
return (_ref = this.tokens[i]) != null ? _ref[0] : void 0;
|
||||
};
|
||||
return Rewriter;
|
||||
}();
|
||||
})();
|
||||
BALANCED_PAIRS = [['(', ')'], ['[', ']'], ['{', '}'], ['INDENT', 'OUTDENT'], ['CALL_START', 'CALL_END'], ['PARAM_START', 'PARAM_END'], ['INDEX_START', 'INDEX_END']];
|
||||
INVERSES = {};
|
||||
EXPRESSION_START = [];
|
||||
@@ -343,10 +343,10 @@
|
||||
}
|
||||
EXPRESSION_CLOSE = ['CATCH', 'WHEN', 'ELSE', 'FINALLY'].concat(EXPRESSION_END);
|
||||
IMPLICIT_FUNC = ['IDENTIFIER', 'SUPER', ')', 'CALL_END', ']', 'INDEX_END', '@', 'THIS'];
|
||||
IMPLICIT_CALL = ['IDENTIFIER', 'NUMBER', 'STRING', 'JS', 'REGEX', 'NEW', 'PARAM_START', 'CLASS', 'IF', 'UNLESS', 'TRY', 'SWITCH', 'THIS', 'BOOL', 'UNARY', '@', '->', '=>', '[', '(', '{', '--', '++'];
|
||||
IMPLICIT_CALL = ['IDENTIFIER', 'NUMBER', 'STRING', 'JS', 'REGEX', 'NEW', 'PARAM_START', 'CLASS', 'IF', 'TRY', 'SWITCH', 'THIS', 'BOOL', 'UNARY', 'SUPER', '@', '->', '=>', '[', '(', '{', '--', '++'];
|
||||
IMPLICIT_UNSPACED_CALL = ['+', '-'];
|
||||
IMPLICIT_BLOCK = ['->', '=>', '{', '[', ','];
|
||||
IMPLICIT_END = ['POST_IF', 'POST_UNLESS', 'FOR', 'WHILE', 'UNTIL', 'WHEN', 'BY', 'LOOP', 'TERMINATOR', 'INDENT'];
|
||||
IMPLICIT_END = ['POST_IF', 'FOR', 'WHILE', 'UNTIL', 'WHEN', 'BY', 'LOOP', 'TERMINATOR', 'INDENT'];
|
||||
SINGLE_LINERS = ['ELSE', '->', '=>', 'TRY', 'FINALLY', 'THEN'];
|
||||
SINGLE_CLOSERS = ['TERMINATOR', 'CATCH', 'FINALLY', 'ELSE', 'OUTDENT', 'LEADING_WHEN'];
|
||||
LINEBREAKS = ['TERMINATOR', 'INDENT', 'OUTDENT'];
|
||||
|
||||
18
lib/scope.js
@@ -1,7 +1,7 @@
|
||||
(function() {
|
||||
var Scope, extend, last, _ref;
|
||||
_ref = require('./helpers'), extend = _ref.extend, last = _ref.last;
|
||||
exports.Scope = Scope = function() {
|
||||
exports.Scope = Scope = (function() {
|
||||
Scope.root = null;
|
||||
function Scope(parent, expressions, method) {
|
||||
this.parent = parent;
|
||||
@@ -18,8 +18,11 @@
|
||||
Scope.root = this;
|
||||
}
|
||||
}
|
||||
Scope.prototype.add = function(name, type) {
|
||||
Scope.prototype.add = function(name, type, immediate) {
|
||||
var pos;
|
||||
if (this.shared && !immediate) {
|
||||
return this.parent.add(name, type, immediate);
|
||||
}
|
||||
if (typeof (pos = this.positions[name]) === 'number') {
|
||||
return this.variables[pos].type = type;
|
||||
} else {
|
||||
@@ -34,11 +37,10 @@
|
||||
return true;
|
||||
}
|
||||
this.add(name, 'var');
|
||||
this.hasDeclarations = true;
|
||||
return false;
|
||||
};
|
||||
Scope.prototype.parameter = function(name) {
|
||||
if (this.shared && this.check(name, true)) {
|
||||
if (this.shared && this.parent.check(name, true)) {
|
||||
return;
|
||||
}
|
||||
return this.add(name, 'param');
|
||||
@@ -75,8 +77,7 @@
|
||||
while (this.check((temp = this.temporary(type, index)), true)) {
|
||||
index++;
|
||||
}
|
||||
this.add(temp, 'var');
|
||||
this.hasDeclarations = true;
|
||||
this.add(temp, 'var', true);
|
||||
return temp;
|
||||
};
|
||||
Scope.prototype.assign = function(name, value) {
|
||||
@@ -86,6 +87,9 @@
|
||||
});
|
||||
return this.hasAssignments = true;
|
||||
};
|
||||
Scope.prototype.hasDeclarations = function() {
|
||||
return !!this.declaredVariables().length;
|
||||
};
|
||||
Scope.prototype.declaredVariables = function() {
|
||||
var realVars, tempVars, v, _i, _len, _ref;
|
||||
realVars = [];
|
||||
@@ -112,5 +116,5 @@
|
||||
return _results;
|
||||
};
|
||||
return Scope;
|
||||
}();
|
||||
})();
|
||||
}).call(this);
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
"description": "Unfancy JavaScript",
|
||||
"keywords": ["javascript", "language", "coffeescript", "compiler"],
|
||||
"author": "Jeremy Ashkenas",
|
||||
"version": "0.9.6",
|
||||
"version": "1.0.0",
|
||||
"licenses": [{
|
||||
"type": "MIT",
|
||||
"url": "http://github.com/jashkenas/coffee-script/raw/master/LICENSE"
|
||||
}],
|
||||
"engines": {
|
||||
"node": ">=0.1.99"
|
||||
"node": ">=0.2.5"
|
||||
},
|
||||
"directories" : {
|
||||
"lib" : "./lib"
|
||||
|
||||
@@ -6,10 +6,10 @@
|
||||
# If included on a webpage, it will automatically sniff out, compile, and
|
||||
# execute all scripts present in `text/coffeescript` tags.
|
||||
|
||||
fs = require 'fs'
|
||||
path = require 'path'
|
||||
{Lexer} = require './lexer'
|
||||
{parser} = require './parser'
|
||||
fs = require 'fs'
|
||||
path = require 'path'
|
||||
{Lexer,RESERVED} = require './lexer'
|
||||
{parser} = require './parser'
|
||||
|
||||
# TODO: Remove registerExtension when fully deprecated.
|
||||
if require.extensions
|
||||
@@ -20,7 +20,10 @@ else if require.registerExtension
|
||||
require.registerExtension '.coffee', (content) -> compile content
|
||||
|
||||
# The current CoffeeScript version number.
|
||||
exports.VERSION = '0.9.6'
|
||||
exports.VERSION = '1.0.0'
|
||||
|
||||
# Words that cannot be used as identifiers in CoffeeScript code
|
||||
exports.RESERVED = RESERVED
|
||||
|
||||
# Expose helpers for testing.
|
||||
exports.helpers = require './helpers'
|
||||
|
||||
@@ -30,6 +30,7 @@ SWITCHES = [
|
||||
['-c', '--compile', 'compile to JavaScript and save as .js files']
|
||||
['-i', '--interactive', 'run an interactive CoffeeScript REPL']
|
||||
['-o', '--output [DIR]', 'set the directory for compiled JavaScript']
|
||||
['-j', '--join', 'concatenate the scripts before compiling']
|
||||
['-w', '--watch', 'watch scripts for changes, and recompile']
|
||||
['-p', '--print', 'print the compiled JavaScript to stdout']
|
||||
['-l', '--lint', 'pipe the compiled JavaScript through JSLint']
|
||||
@@ -39,20 +40,15 @@ SWITCHES = [
|
||||
['-b', '--bare', 'compile without the top-level function wrapper']
|
||||
['-t', '--tokens', 'print the tokens that the lexer produces']
|
||||
['-n', '--nodes', 'print the parse tree that Jison produces']
|
||||
[ '--nodejs [ARGS]', 'pass options through to the "node" binary']
|
||||
['-v', '--version', 'display CoffeeScript version']
|
||||
['-h', '--help', 'display this help message']
|
||||
]
|
||||
|
||||
# Switches that are still supported, but will cause a warning message.
|
||||
DEPRECATED_SWITCHES = [
|
||||
['--no-wrap', 'compile without the top-level function wrapper']
|
||||
]
|
||||
|
||||
ALL_SWITCHES = SWITCHES.concat DEPRECATED_SWITCHES
|
||||
|
||||
# Top-level objects shared by all the functions.
|
||||
opts = {}
|
||||
sources = []
|
||||
contents = []
|
||||
optionParser = null
|
||||
|
||||
# Run `coffee` by parsing passed options and determining what action to take.
|
||||
@@ -60,20 +56,16 @@ optionParser = null
|
||||
# `--` will be passed verbatim to your script as arguments in `process.argv`
|
||||
exports.run = ->
|
||||
parseOptions()
|
||||
return usage() if opts.help
|
||||
return version() if opts.version
|
||||
return require './repl' if opts.interactive
|
||||
return compileStdio() if opts.stdio
|
||||
return compileScript null, sources[0] if opts.eval
|
||||
return require './repl' unless sources.length
|
||||
separator = sources.indexOf '--'
|
||||
flags = []
|
||||
if separator >= 0
|
||||
flags = sources.splice separator + 1
|
||||
sources.pop()
|
||||
return forkNode() if opts.nodejs
|
||||
return usage() if opts.help
|
||||
return version() if opts.version
|
||||
return require './repl' if opts.interactive
|
||||
return compileStdio() if opts.stdio
|
||||
return compileScript null, sources[0] if opts.eval
|
||||
return require './repl' unless sources.length
|
||||
if opts.run
|
||||
flags = sources.splice(1).concat flags
|
||||
process.ARGV = process.argv = flags
|
||||
opts.literals = sources.splice(1).concat opts.literals
|
||||
process.ARGV = process.argv = process.argv.slice(0, 2).concat opts.literals
|
||||
compileScripts()
|
||||
|
||||
# Asynchronously read in each CoffeeScript in a list of source files and
|
||||
@@ -91,8 +83,13 @@ compileScripts = ->
|
||||
for file in files
|
||||
compile path.join(source, file)
|
||||
else if topLevel or path.extname(source) is '.coffee'
|
||||
fs.readFile source, (err, code) -> compileScript(source, code.toString(), base)
|
||||
watch source, base if opts.watch
|
||||
fs.readFile source, (err, code) ->
|
||||
if opts.join
|
||||
contents[sources.indexOf source] = code.toString()
|
||||
compileJoin() if helpers.compact(contents).length is sources.length
|
||||
else
|
||||
compileScript(source, code.toString(), base)
|
||||
watch source, base if opts.watch and not opts.join
|
||||
compile source, true
|
||||
|
||||
# Compile a single source script, containing the given code, according to the
|
||||
@@ -132,6 +129,12 @@ compileStdio = ->
|
||||
stdin.on 'end', ->
|
||||
compileScript null, code
|
||||
|
||||
# After all of the source files are done being read, concatenate and compile
|
||||
# them together.
|
||||
compileJoin = ->
|
||||
code = contents.join '\n'
|
||||
compileScript "concatenation", code, "concatenation"
|
||||
|
||||
# Watch a source CoffeeScript file using `fs.watchFile`, recompiling it every
|
||||
# time the file is updated. May be used in combination with other options,
|
||||
# such as `--lint` or `--print`.
|
||||
@@ -148,7 +151,7 @@ watch = (source, base) ->
|
||||
writeJs = (source, js, base) ->
|
||||
filename = path.basename(source, path.extname(source)) + '.js'
|
||||
srcDir = path.dirname source
|
||||
baseDir = srcDir.substring base.length
|
||||
baseDir = if base is '.' then srcDir else srcDir.substring base.length
|
||||
dir = if opts.output then path.join opts.output, baseDir else srcDir
|
||||
jsPath = path.join dir, filename
|
||||
compile = ->
|
||||
@@ -180,17 +183,26 @@ printTokens = (tokens) ->
|
||||
# Use the [OptionParser module](optparse.html) to extract all options from
|
||||
# `process.argv` that are specified in `SWITCHES`.
|
||||
parseOptions = ->
|
||||
optionParser = new optparse.OptionParser ALL_SWITCHES, BANNER
|
||||
optionParser = new optparse.OptionParser SWITCHES, BANNER
|
||||
o = opts = optionParser.parse process.argv.slice 2
|
||||
o.compile or= !!o.output
|
||||
o.run = not (o.compile or o.print or o.lint)
|
||||
o.print = !! (o.print or (o.eval or o.stdio and o.compile))
|
||||
sources = o.arguments
|
||||
if opts['no-wrap']
|
||||
printWarn '--no-wrap is deprecated; please use --bare instead.'
|
||||
|
||||
# The compile-time options to pass to the CoffeeScript compiler.
|
||||
compileOptions = (fileName) -> {fileName, bare: opts.bare or opts['no-wrap']}
|
||||
compileOptions = (fileName) -> {fileName, bare: opts.bare}
|
||||
|
||||
# Start up a new Node.js instance with the arguments in `--nodejs` passed to
|
||||
# the `node` binary, preserving the other options.
|
||||
forkNode = ->
|
||||
nodeArgs = opts.nodejs.split /\s+/
|
||||
args = process.argv[1..]
|
||||
args.splice args.indexOf('--nodejs'), 2
|
||||
spawn process.execPath, nodeArgs.concat(args),
|
||||
cwd: process.cwd()
|
||||
env: process.env
|
||||
customFds: [0, 1, 2]
|
||||
|
||||
# Print the `--help` usage message and exit. Deprecated switches are not
|
||||
# shown.
|
||||
|
||||
@@ -104,8 +104,8 @@ grammar =
|
||||
# will convert some postfix forms into blocks for us, by adjusting the
|
||||
# token stream.
|
||||
Block: [
|
||||
o 'INDENT Body OUTDENT', -> $2
|
||||
o 'INDENT OUTDENT', -> new Expressions
|
||||
o 'INDENT Body OUTDENT', -> $2
|
||||
]
|
||||
|
||||
# A literal identifier, a variable name or property.
|
||||
@@ -286,10 +286,8 @@ grammar =
|
||||
Invocation: [
|
||||
o 'Value OptFuncExist Arguments', -> new Call $1, $3, $2
|
||||
o 'Invocation OptFuncExist Arguments', -> new Call $1, $3, $2
|
||||
o 'SUPER', ->
|
||||
new Call 'super', [new Splat new Literal 'arguments']
|
||||
o 'SUPER Arguments', ->
|
||||
new Call 'super', $2
|
||||
o 'SUPER', -> new Call 'super', [new Splat new Literal 'arguments']
|
||||
o 'SUPER Arguments', -> new Call 'super', $2
|
||||
]
|
||||
|
||||
# An optional existence check on a function.
|
||||
@@ -417,14 +415,14 @@ grammar =
|
||||
# Comprehensions can either be normal, with a block of expressions to execute,
|
||||
# or postfix, with a single expression.
|
||||
For: [
|
||||
o 'Statement ForBody', -> new For $1, $2, $2.vars[0], $2.vars[1]
|
||||
o 'Expression ForBody', -> new For $1, $2, $2.vars[0], $2.vars[1]
|
||||
o 'ForBody Block', -> new For $2, $1, $1.vars[0], $1.vars[1]
|
||||
o 'Statement ForBody', -> new For $1, $2
|
||||
o 'Expression ForBody', -> new For $1, $2
|
||||
o 'ForBody Block', -> new For $2, $1
|
||||
]
|
||||
|
||||
ForBody: [
|
||||
o 'FOR Range', -> source: new Value($2), vars: []
|
||||
o 'ForStart ForSource', -> $2.own = $1.own; $2.vars = $1; $2
|
||||
o 'FOR Range', -> source: new Value($2)
|
||||
o 'ForStart ForSource', -> $2.own = $1.own; $2.name = $1[0]; $2.index = $1[1]; $2
|
||||
]
|
||||
|
||||
ForStart: [
|
||||
@@ -483,9 +481,8 @@ grammar =
|
||||
# if-related rules are broken up along these lines in order to avoid
|
||||
# ambiguity.
|
||||
IfBlock: [
|
||||
o 'IF Expression Block', -> new If $2, $3
|
||||
o 'UNLESS Expression Block', -> new If $2, $3, invert: true
|
||||
o 'IfBlock ELSE IF Expression Block', -> $1.addElse new If $4, $5
|
||||
o 'IF Expression Block', -> new If $2, $3, type: $1
|
||||
o 'IfBlock ELSE IF Expression Block', -> $1.addElse new If $4, $5, type: $3
|
||||
o 'IfBlock ELSE Block', -> $1.addElse $3
|
||||
]
|
||||
|
||||
@@ -493,10 +490,8 @@ grammar =
|
||||
# *if* and *unless*.
|
||||
If: [
|
||||
o 'IfBlock'
|
||||
o 'Statement POST_IF Expression', -> new If $3, Expressions.wrap([$1]), statement: true
|
||||
o 'Expression POST_IF Expression', -> new If $3, Expressions.wrap([$1]), statement: true
|
||||
o 'Statement POST_UNLESS Expression', -> new If $3, Expressions.wrap([$1]), statement: true, invert: true
|
||||
o 'Expression POST_UNLESS Expression', -> new If $3, Expressions.wrap([$1]), statement: true, invert: true
|
||||
o 'Statement POST_IF Expression', -> new If $3, Expressions.wrap([$1]), type: $2, statement: true
|
||||
o 'Expression POST_IF Expression', -> new If $3, Expressions.wrap([$1]), type: $2, statement: true
|
||||
]
|
||||
|
||||
# Arithmetic and logical operators, working on one or more operands.
|
||||
@@ -565,8 +560,8 @@ operators = [
|
||||
['nonassoc', 'INDENT', 'OUTDENT']
|
||||
['right', '=', ':', 'COMPOUND_ASSIGN', 'RETURN', 'THROW', 'EXTENDS']
|
||||
['right', 'FORIN', 'FOROF', 'BY', 'WHEN']
|
||||
['right', 'IF', 'UNLESS', 'ELSE', 'FOR', 'WHILE', 'UNTIL', 'LOOP', 'SUPER', 'CLASS']
|
||||
['right', 'POST_IF', 'POST_UNLESS']
|
||||
['right', 'IF', 'ELSE', 'FOR', 'DO', 'WHILE', 'UNTIL', 'LOOP', 'SUPER', 'CLASS']
|
||||
['right', 'POST_IF']
|
||||
]
|
||||
|
||||
# Wrapping Up
|
||||
|
||||
@@ -15,10 +15,11 @@ exports.ends = (string, literal, back) ->
|
||||
exports.compact = (array) ->
|
||||
item for item in array when item
|
||||
|
||||
# Count the number of occurrences of a character in a string.
|
||||
exports.count = (string, letter) ->
|
||||
# Count the number of occurrences of a string in a string.
|
||||
exports.count = (string, substr) ->
|
||||
num = pos = 0
|
||||
num++ while pos = 1 + string.indexOf letter, pos
|
||||
return 1/0 unless substr.length
|
||||
num++ while pos = 1 + string.indexOf substr, pos
|
||||
num
|
||||
|
||||
# Merge objects, returning a fresh copy with attributes from both sides.
|
||||
|
||||
@@ -89,12 +89,14 @@ exports.Lexer = class Lexer
|
||||
tag = 'LEADING_WHEN'
|
||||
else if tag is 'FOR'
|
||||
@seenFor = yes
|
||||
else if tag is 'UNLESS'
|
||||
tag = 'IF'
|
||||
else if tag in UNARY
|
||||
tag = 'UNARY'
|
||||
else if tag in RELATION
|
||||
if tag isnt 'INSTANCEOF' and @seenFor
|
||||
@seenFor = no
|
||||
tag = 'FOR' + tag
|
||||
@seenFor = no
|
||||
else
|
||||
tag = 'RELATION'
|
||||
if @value() is '!'
|
||||
@@ -139,7 +141,7 @@ exports.Lexer = class Lexer
|
||||
return 0 unless match = SIMPLESTR.exec @chunk
|
||||
@token 'STRING', (string = match[0]).replace MULTILINER, '\\\n'
|
||||
when '"'
|
||||
return 0 unless string = @balancedString @chunk, [['"', '"'], ['#{', '}']]
|
||||
return 0 unless string = @balancedString @chunk, '"'
|
||||
if 0 < string.indexOf '#{', 1
|
||||
@interpolateString string.slice 1, -1
|
||||
else
|
||||
@@ -387,22 +389,27 @@ exports.Lexer = class Lexer
|
||||
# a series of delimiters, all of which must be nested correctly within the
|
||||
# contents of the string. This method allows us to have strings within
|
||||
# interpolations within strings, ad infinitum.
|
||||
balancedString: (str, delimited, options = {}) ->
|
||||
stack = [delimited[0]]
|
||||
balancedString: (str, end) ->
|
||||
stack = [end]
|
||||
for i in [1...str.length]
|
||||
switch str.charAt i
|
||||
switch letter = str.charAt i
|
||||
when '\\'
|
||||
i++
|
||||
continue
|
||||
when stack[stack.length - 1][1]
|
||||
when end
|
||||
stack.pop()
|
||||
return str.slice 0, i + 1 unless stack.length
|
||||
unless stack.length
|
||||
return str.slice 0, i + 1
|
||||
end = stack[stack.length - 1]
|
||||
continue
|
||||
for pair in delimited when (open = pair[0]) is str.substr i, open.length
|
||||
stack.push pair
|
||||
i += open.length - 1
|
||||
break
|
||||
throw new Error "unterminated #{ stack.pop()[0] } on line #{ @line + 1 }"
|
||||
if end is '}' and letter in ['"', "'"]
|
||||
stack.push end = letter
|
||||
else if end is '}' and letter is '{'
|
||||
stack.push end = '}'
|
||||
else if end is '"' and prev is '#' and letter is '{'
|
||||
stack.push end = '}'
|
||||
prev = letter
|
||||
throw new Error "missing #{ stack.pop() }, starting on line #{ @line + 1 }"
|
||||
|
||||
|
||||
# Expand variables and expressions inside double-quoted strings using
|
||||
@@ -423,7 +430,7 @@ exports.Lexer = class Lexer
|
||||
i += 1
|
||||
continue
|
||||
unless letter is '#' and str.charAt(i+1) is '{' and
|
||||
(expr = @balancedString str.slice(i+1), [['{', '}']])
|
||||
(expr = @balancedString str.slice(i + 1), '}')
|
||||
continue
|
||||
tokens.push ['NEOSTRING', str.slice(pi, i)] if pi < i
|
||||
inner = expr.slice(1, -1)
|
||||
@@ -493,7 +500,7 @@ JS_KEYWORDS = [
|
||||
'true', 'false', 'null', 'this'
|
||||
'new', 'delete', 'typeof', 'in', 'instanceof'
|
||||
'return', 'throw', 'break', 'continue', 'debugger'
|
||||
'if', 'else', 'switch', 'for', 'while', 'try', 'catch', 'finally'
|
||||
'if', 'else', 'switch', 'for', 'while', 'do', 'try', 'catch', 'finally'
|
||||
'class', 'extends', 'super'
|
||||
]
|
||||
|
||||
@@ -514,15 +521,17 @@ COFFEE_KEYWORDS.push op for op of COFFEE_ALIASES =
|
||||
# used by CoffeeScript internally. We throw an error when these are encountered,
|
||||
# to avoid having a JavaScript error at runtime.
|
||||
RESERVED = [
|
||||
'case', 'default', 'function', 'var', 'void', 'with', 'do'
|
||||
'case', 'default', 'function', 'var', 'void', 'with'
|
||||
'const', 'let', 'enum', 'export', 'import', 'native'
|
||||
'__hasProp', '__extends', '__slice'
|
||||
'__hasProp', '__extends', '__slice', '__bind', '__indexOf'
|
||||
]
|
||||
|
||||
# The superset of both JavaScript keywords and reserved words, none of which may
|
||||
# be used as identifiers or properties.
|
||||
JS_FORBIDDEN = JS_KEYWORDS.concat RESERVED
|
||||
|
||||
exports.RESERVED = RESERVED.concat(JS_KEYWORDS).concat(COFFEE_KEYWORDS)
|
||||
|
||||
# Token matching regexes.
|
||||
IDENTIFIER = /// ^
|
||||
( [$A-Za-z_][$\w]* )
|
||||
@@ -548,7 +557,7 @@ OPERATOR = /// ^ (
|
||||
|
||||
WHITESPACE = /^[^\n\S]+/
|
||||
|
||||
COMMENT = /^###([^#][\s\S]*?)(?:###[^\n\S]*\n|(?:###)?$)|^(?:\s*#(?!##[^#]).*)+/
|
||||
COMMENT = /^###([^#][\s\S]*?)(?:###[^\n\S]*|(?:###)?$)|^(?:\s*#(?!##[^#]).*)+/
|
||||
|
||||
CODE = /^[-=]>/
|
||||
|
||||
@@ -600,7 +609,7 @@ COMPOUND_ASSIGN = [
|
||||
]
|
||||
|
||||
# Unary tokens.
|
||||
UNARY = ['!', '~', 'NEW', 'TYPEOF', 'DELETE']
|
||||
UNARY = ['!', '~', 'NEW', 'TYPEOF', 'DELETE', 'DO']
|
||||
|
||||
# Logical tokens.
|
||||
LOGIC = ['&&', '||', '&', '|', '^']
|
||||
|
||||
234
src/nodes.coffee
@@ -40,7 +40,7 @@ exports.Base = class Base
|
||||
o.level = lvl if lvl
|
||||
node = @unfoldSoak(o) or this
|
||||
node.tab = o.indent
|
||||
if o.level is LEVEL_TOP or node.isPureStatement() or not node.isStatement(o)
|
||||
if o.level is LEVEL_TOP or not node.isStatement(o)
|
||||
node.compileNode o
|
||||
else
|
||||
node.compileClosure o
|
||||
@@ -48,9 +48,9 @@ exports.Base = class Base
|
||||
# Statements converted into expressions via closure-wrapping share a scope
|
||||
# object with their parent closure, to preserve the expected lexical scope.
|
||||
compileClosure: (o) ->
|
||||
if @containsPureStatement()
|
||||
throw SyntaxError 'cannot include a pure statement in an expression.'
|
||||
o.sharedScope = o.scope
|
||||
if @jumps()
|
||||
throw SyntaxError 'cannot use a pure statement in an expression.'
|
||||
o.sharedScope = yes
|
||||
Closure.wrap(this).compileNode o
|
||||
|
||||
# If the code generation wishes to use the result of a complex expression
|
||||
@@ -94,10 +94,11 @@ exports.Base = class Base
|
||||
containsType: (type) ->
|
||||
this instanceof type or @contains (node) -> node instanceof type
|
||||
|
||||
# Convenience for the most common use of contains. Does the node contain
|
||||
# a pure statement?
|
||||
containsPureStatement: ->
|
||||
@isPureStatement() or @contains (node) -> node.isPureStatement()
|
||||
# Pull out the last non-comment node of a node list.
|
||||
lastNonComment: (list) ->
|
||||
i = list.length
|
||||
return list[i] while i-- when list[i] not instanceof Comment
|
||||
null
|
||||
|
||||
# `toString` representation of the node, for inspecting the parse tree.
|
||||
# This is what `coffee --nodes` prints out.
|
||||
@@ -133,7 +134,7 @@ exports.Base = class Base
|
||||
children: []
|
||||
|
||||
isStatement : NO
|
||||
isPureStatement : NO
|
||||
jumps : NO
|
||||
isComplex : YES
|
||||
isChainable : NO
|
||||
isAssignable : NO
|
||||
@@ -179,10 +180,14 @@ exports.Expressions = class Expressions extends Base
|
||||
not @expressions.length
|
||||
|
||||
isStatement: (o) ->
|
||||
for exp in @expressions when exp.isPureStatement() or exp.isStatement o
|
||||
for exp in @expressions when exp.isStatement o
|
||||
return yes
|
||||
no
|
||||
|
||||
jumps: (o) ->
|
||||
for exp in @expressions
|
||||
return exp if exp.jumps o
|
||||
|
||||
# An Expressions node does not return its entire body, rather it
|
||||
# ensures that the final expression is returned.
|
||||
makeReturn: ->
|
||||
@@ -237,7 +242,7 @@ exports.Expressions = class Expressions extends Base
|
||||
for exp, i in @expressions
|
||||
exp = exp.unwrap()
|
||||
break unless exp instanceof Comment or exp instanceof Literal
|
||||
o.level = LEVEL_TOP
|
||||
o = merge(o, level: LEVEL_TOP)
|
||||
if i
|
||||
rest = @expressions.splice i, @expressions.length
|
||||
code = @compileNode o
|
||||
@@ -245,7 +250,7 @@ exports.Expressions = class Expressions extends Base
|
||||
post = @compileNode o
|
||||
{scope} = o
|
||||
if scope.expressions is this
|
||||
if not o.globals and o.scope.hasDeclarations
|
||||
if not o.globals and o.scope.hasDeclarations()
|
||||
code += "#{@tab}var #{ scope.declaredVariables().join(', ') };\n"
|
||||
if scope.hasAssignments
|
||||
code += "#{@tab}var #{ multident scope.assignedVariables().join(', '), @tab };\n"
|
||||
@@ -266,23 +271,26 @@ exports.Literal = class Literal extends Base
|
||||
constructor: (@value) ->
|
||||
|
||||
makeReturn: ->
|
||||
if @isPureStatement() then this else new Return this
|
||||
|
||||
# Break and continue must be treated as pure statements -- they lose their
|
||||
# meaning when wrapped in a closure.
|
||||
isPureStatement: ->
|
||||
@value in ['break', 'continue', 'debugger']
|
||||
if @isStatement() then this else new Return this
|
||||
|
||||
isAssignable: ->
|
||||
IDENTIFIER.test @value
|
||||
|
||||
isStatement: ->
|
||||
@value in ['break', 'continue', 'debugger']
|
||||
|
||||
isComplex: NO
|
||||
|
||||
assigns: (name) ->
|
||||
name is @value
|
||||
|
||||
compile: ->
|
||||
if @value.reserved then "\"#{@value}\"" else @value
|
||||
jumps: (o) ->
|
||||
return no unless @isStatement()
|
||||
if not (o and (o.loop or o.block and (@value isnt 'continue'))) then this else no
|
||||
|
||||
compileNode: (o) ->
|
||||
code = if @value.reserved then "\"#{@value}\"" else @value
|
||||
if @isStatement() then "#{@tab}#{code};" else code
|
||||
|
||||
toString: ->
|
||||
' "' + @value + '"'
|
||||
@@ -297,16 +305,15 @@ exports.Return = class Return extends Base
|
||||
children: ['expression']
|
||||
|
||||
isStatement: YES
|
||||
isPureStatement: YES
|
||||
makeReturn: THIS
|
||||
jumps: THIS
|
||||
|
||||
compile: (o, level) ->
|
||||
expr = @expression?.makeReturn()
|
||||
if expr and expr not instanceof Return then expr.compile o, level else super o, level
|
||||
|
||||
compileNode: (o) ->
|
||||
o.level = LEVEL_PAREN
|
||||
@tab + "return#{ if @expression then ' ' + @expression.compile o else '' };"
|
||||
@tab + "return#{ if @expression then ' ' + @expression.compile(o, LEVEL_PAREN) else '' };"
|
||||
|
||||
#### Value
|
||||
|
||||
@@ -342,6 +349,7 @@ exports.Value = class Value extends Base
|
||||
|
||||
isStatement : (o) -> not @properties.length and @base.isStatement o
|
||||
assigns : (name) -> not @properties.length and @base.assigns name
|
||||
jumps : (o) -> not @properties.length and @base.jumps o
|
||||
|
||||
isObject: (onlyGenerated) ->
|
||||
return no if @properties.length
|
||||
@@ -411,7 +419,6 @@ exports.Value = class Value extends Base
|
||||
exports.Comment = class Comment extends Base
|
||||
constructor: (@comment) ->
|
||||
|
||||
isPureStatement: YES
|
||||
isStatement: YES
|
||||
makeReturn: THIS
|
||||
|
||||
@@ -550,6 +557,7 @@ exports.Extends = class Extends extends Base
|
||||
# an access into the object's prototype.
|
||||
exports.Access = class Access extends Base
|
||||
constructor: (@name, tag) ->
|
||||
@name.asKey = yes
|
||||
@proto = if tag is 'proto' then '.prototype' else ''
|
||||
@soak = tag is 'soak'
|
||||
|
||||
@@ -657,12 +665,21 @@ exports.Slice = class Slice extends Base
|
||||
constructor: (@range) ->
|
||||
super()
|
||||
|
||||
# We have to be careful when trying to slice through the end of the array,
|
||||
# `9e9` is used because not all implementations respect `undefined` or `1/0`.
|
||||
# `9e9` should be safe because `9e9` > `2**32`, the max array length.
|
||||
compileNode: (o) ->
|
||||
from = if @range.from then @range.from.compile(o) else '0'
|
||||
to = if @range.to then @range.to.compile(o) else ''
|
||||
to += if not to or @range.exclusive then '' else ' + 1'
|
||||
to = ', ' + to if to
|
||||
".slice(#{from}#{to})"
|
||||
{to, from} = @range
|
||||
fromStr = from and from.compile(o, LEVEL_PAREN) or '0'
|
||||
compiled = to and to.compile o, LEVEL_PAREN
|
||||
if to and not (not @range.exclusive and +compiled is -1)
|
||||
toStr = ', ' + if @range.exclusive
|
||||
compiled
|
||||
else if SIMPLENUM.test compiled
|
||||
(+compiled + 1).toString()
|
||||
else
|
||||
"(#{compiled} + 1) || 9e9"
|
||||
".slice(#{ fromStr }#{ toStr or '' })"
|
||||
|
||||
#### Obj
|
||||
|
||||
@@ -677,8 +694,7 @@ exports.Obj = class Obj extends Base
|
||||
props = @properties
|
||||
return (if @front then '({})' else '{}') unless props.length
|
||||
idt = o.indent += TAB
|
||||
nonComments = (prop for prop in @properties when prop not instanceof Comment)
|
||||
lastNoncom = last nonComments
|
||||
lastNoncom = @lastNonComment @properties
|
||||
props = for prop, i in props
|
||||
join = if i is props.length - 1
|
||||
''
|
||||
@@ -689,8 +705,10 @@ exports.Obj = class Obj extends Base
|
||||
indent = if prop instanceof Comment then '' else idt
|
||||
if prop instanceof Value and prop.this
|
||||
prop = new Assign prop.properties[0].name, prop, 'object'
|
||||
else if prop not instanceof Assign and prop not instanceof Comment
|
||||
prop = new Assign prop, prop, 'object'
|
||||
if prop not instanceof Comment
|
||||
if prop not instanceof Assign
|
||||
prop = new Assign prop, prop, 'object'
|
||||
(prop.variable.base or prop.variable).asKey = yes
|
||||
indent + prop.compile(o, LEVEL_TOP) + join
|
||||
props = props.join ''
|
||||
obj = "{#{ props and '\n' + props + '\n' + @tab }}"
|
||||
@@ -731,6 +749,7 @@ exports.Arr = class Arr extends Base
|
||||
exports.Class = class Class extends Base
|
||||
constructor: (@variable, @parent, @body = new Expressions) ->
|
||||
@boundFuncs = []
|
||||
@body.classBody = yes
|
||||
|
||||
children: ['variable', 'parent', 'body']
|
||||
|
||||
@@ -747,6 +766,7 @@ exports.Class = class Class extends Base
|
||||
# `this` is the Class being constructed.
|
||||
setContext: (name) ->
|
||||
@body.traverseChildren false, (node) ->
|
||||
return false if node.classBody
|
||||
if node instanceof Literal and node.value is 'this'
|
||||
node.value = name
|
||||
else if node instanceof Code
|
||||
@@ -823,7 +843,7 @@ exports.Class = class Class extends Base
|
||||
@body.expressions.push lname
|
||||
@addBoundFunctions o
|
||||
|
||||
klass = new Parens new Call(new Code [], @body), true
|
||||
klass = new Parens Closure.wrap(@body), true
|
||||
klass = new Assign @variable, klass if @variable
|
||||
klass.compile o
|
||||
|
||||
@@ -832,7 +852,8 @@ exports.Class = class Class extends Base
|
||||
# The **Assign** is used to assign a local variable to value, or to set the
|
||||
# property of an object -- including within object literals.
|
||||
exports.Assign = class Assign extends Base
|
||||
constructor: (@variable, @value, @context) ->
|
||||
constructor: (@variable, @value, @context, options) ->
|
||||
@param = options and options.param
|
||||
|
||||
# Matchers for detecting class/method names
|
||||
METHOD_DEF: /^(?:(\S+)\.prototype\.|\S+?)?\b([$A-Za-z_][$\w]*)$/
|
||||
@@ -862,8 +883,11 @@ exports.Assign = class Assign extends Base
|
||||
return "#{name}: #{val}" if @context is 'object'
|
||||
unless @variable.isAssignable()
|
||||
throw SyntaxError "\"#{ @variable.compile o }\" cannot be assigned."
|
||||
o.scope.find name unless @context or
|
||||
isValue and (@variable.namespaced or @variable.hasProperties())
|
||||
unless @context or isValue and (@variable.namespaced or @variable.hasProperties())
|
||||
if @param
|
||||
o.scope.add name, 'var'
|
||||
else
|
||||
o.scope.find name
|
||||
val = name + " #{ @context or '=' } " + val
|
||||
if o.level <= LEVEL_LIST then val else "(#{val})"
|
||||
|
||||
@@ -932,7 +956,7 @@ exports.Assign = class Assign extends Base
|
||||
else
|
||||
acc = isObject and IDENTIFIER.test idx.unwrap().value or 0
|
||||
val = new Value new Literal(vvar), [new (if acc then Access else Index) idx]
|
||||
assigns.push new Assign(obj, val).compile o, LEVEL_TOP
|
||||
assigns.push new Assign(obj, val, null, param: @param).compile o, LEVEL_TOP
|
||||
assigns.push vvar unless top
|
||||
code = assigns.join ', '
|
||||
if o.level < LEVEL_LIST then code else "(#{code})"
|
||||
@@ -947,18 +971,21 @@ exports.Assign = class Assign extends Base
|
||||
# Compile the assignment from an array splice literal, using JavaScript's
|
||||
# `Array#splice` method.
|
||||
compileSplice: (o) ->
|
||||
{range} = @variable.properties.pop()
|
||||
name = @variable.compile o
|
||||
plus = if range.exclusive then '' else ' + 1'
|
||||
from = if range.from then range.from.compile(o) else '0'
|
||||
to = "#{name}.length" unless range.to
|
||||
unless to
|
||||
if range.from and range.from.isSimpleNumber() and range.to.isSimpleNumber()
|
||||
to = (+range.to.compile(o)) - +from + +plus
|
||||
{range: {from, to, exclusive}} = @variable.properties.pop()
|
||||
name = @variable.compile o
|
||||
[fromDecl, fromRef] = from?.cache(o, LEVEL_OP) or ['0', '0']
|
||||
if to
|
||||
if from?.isSimpleNumber() and to.isSimpleNumber()
|
||||
to = +to.compile(o) - +fromRef
|
||||
to += 1 unless exclusive
|
||||
else
|
||||
to = range.to.compile(o) + ' - ' + from + plus
|
||||
val = @value.compile(o)
|
||||
"[].splice.apply(#{name}, [#{from}, #{to}].concat(#{val}))"
|
||||
to = to.compile(o) + ' - ' + fromRef
|
||||
to += ' + 1' unless exclusive
|
||||
else
|
||||
to = "9e9"
|
||||
[valDef, valRef] = @value.cache o, LEVEL_LIST
|
||||
code = "[].splice.apply(#{name}, [#{fromDecl}, #{to}].concat(#{valDef})), #{valRef}"
|
||||
if o.level > LEVEL_TOP then "(#{code})" else code
|
||||
|
||||
#### Code
|
||||
|
||||
@@ -976,15 +1003,16 @@ exports.Code = class Code extends Base
|
||||
|
||||
isStatement: -> !!@ctor
|
||||
|
||||
jumps: NO
|
||||
|
||||
# Compilation creates a new scope unless explicitly asked to share with the
|
||||
# outer scope. Handles splat parameters in the parameter list by peeking at
|
||||
# the JavaScript `arguments` objects. If the function is bound with the `=>`
|
||||
# arrow, generates a wrapper that saves the current value of `this` through
|
||||
# a closure.
|
||||
compileNode: (o) ->
|
||||
sharedScope = del o, 'sharedScope'
|
||||
o.scope = sharedScope or new Scope o.scope, @body, this
|
||||
o.scope.shared = yes if sharedScope
|
||||
o.scope = new Scope o.scope, @body, this
|
||||
o.scope.shared = del o, 'sharedScope'
|
||||
o.indent += TAB
|
||||
delete o.bare
|
||||
delete o.globals
|
||||
@@ -998,7 +1026,7 @@ exports.Code = class Code extends Base
|
||||
if param.isComplex()
|
||||
val = ref = param.asReference o
|
||||
val = new Op '?', ref, param.value if param.value
|
||||
exprs.push new Assign new Value(param.name), val, '='
|
||||
exprs.push new Assign new Value(param.name), val, '=', param: yes
|
||||
else
|
||||
ref = param
|
||||
if param.value
|
||||
@@ -1019,7 +1047,7 @@ exports.Code = class Code extends Base
|
||||
code += '}'
|
||||
return @tab + code if @ctor
|
||||
return utility('bind') + "(#{code}, #{@context})" if @bound
|
||||
if @front then "(#{code})" else code
|
||||
if @front or (o.level >= LEVEL_ACCESS) then "(#{code})" else code
|
||||
|
||||
# Short-circuit `traverseChildren` method to prevent it from crossing scope boundaries
|
||||
# unless `crossScope` is `true`.
|
||||
@@ -1114,13 +1142,12 @@ exports.While = class While extends Base
|
||||
addBody: (@body) ->
|
||||
this
|
||||
|
||||
containsPureStatement: ->
|
||||
jumps: ->
|
||||
{expressions} = @body
|
||||
i = expressions.length
|
||||
return true if expressions[--i]?.containsPureStatement()
|
||||
ret = (node) -> node instanceof Return
|
||||
return true while i-- when expressions[i].contains ret
|
||||
false
|
||||
return no unless expressions.length
|
||||
for node in expressions
|
||||
return node if node.jumps loop: yes
|
||||
no
|
||||
|
||||
# The main difference from a JavaScript *while* is that the CoffeeScript
|
||||
# *while* can be used as a part of a larger expression -- while loops may
|
||||
@@ -1140,8 +1167,7 @@ exports.While = class While extends Base
|
||||
body = "\n#{ body.compile o, LEVEL_TOP }\n#{@tab}"
|
||||
code = set + @tab + "while (#{ @condition.compile o, LEVEL_PAREN }) {#{body}}"
|
||||
if @returns
|
||||
o.indent = @tab
|
||||
code += '\n' + new Return(new Literal rvar).compile o
|
||||
code += "\n#{@tab}return #{rvar};"
|
||||
code
|
||||
|
||||
#### Op
|
||||
@@ -1151,6 +1177,7 @@ exports.While = class While extends Base
|
||||
exports.Op = class Op extends Base
|
||||
constructor: (op, first, second, flip) ->
|
||||
return new In first, second if op is 'in'
|
||||
return new Call first, first.params or [] if op is 'do'
|
||||
if op is 'new'
|
||||
return first.newInstance() if first instanceof Call
|
||||
first = new Parens first if first instanceof Code and first.bound
|
||||
@@ -1173,6 +1200,8 @@ exports.Op = class Op extends Base
|
||||
|
||||
children: ['first', 'second']
|
||||
|
||||
isSimpleNumber: NO
|
||||
|
||||
isUnary: ->
|
||||
not @second
|
||||
|
||||
@@ -1228,7 +1257,6 @@ exports.Op = class Op extends Base
|
||||
compileChain: (o) ->
|
||||
[@first.second, shared] = @first.second.cache o
|
||||
fst = @first.compile o, LEVEL_OP
|
||||
fst = fst.slice 1, -1 if @first.unwrap() instanceof Op and @first.isChainable() and fst.charAt(0) is '('
|
||||
code = "#{fst} #{if @invert then '&&' else '||'} #{ shared.compile o } #{@operator} #{ @second.compile o, LEVEL_OP }"
|
||||
"(#{code})"
|
||||
|
||||
@@ -1296,6 +1324,8 @@ exports.Try = class Try extends Base
|
||||
|
||||
isStatement: YES
|
||||
|
||||
jumps: (o) -> @attempt.jumps(o) or @recovery?.jumps(o)
|
||||
|
||||
makeReturn: ->
|
||||
@attempt = @attempt .makeReturn() if @attempt
|
||||
@recovery = @recovery.makeReturn() if @recovery
|
||||
@@ -1325,6 +1355,7 @@ exports.Throw = class Throw extends Base
|
||||
children: ['expression']
|
||||
|
||||
isStatement: YES
|
||||
jumps: NO
|
||||
|
||||
# A **Throw** is already a return, of sorts...
|
||||
makeReturn: THIS
|
||||
@@ -1377,8 +1408,9 @@ exports.Parens = class Parens extends Base
|
||||
if expr instanceof Value and expr.isAtomic()
|
||||
expr.front = @front
|
||||
return expr.compile o
|
||||
bare = o.level < LEVEL_OP and (expr instanceof Op or expr instanceof Call)
|
||||
code = expr.compile o, LEVEL_PAREN
|
||||
bare = o.level < LEVEL_OP and (expr instanceof Op or expr instanceof Call or
|
||||
(expr instanceof For and expr.returns))
|
||||
if bare then code else "(#{code})"
|
||||
|
||||
#### For
|
||||
@@ -1391,8 +1423,8 @@ exports.Parens = class Parens extends Base
|
||||
# the current index of the loop as a second parameter. Unlike Ruby blocks,
|
||||
# you can map and filter in a single pass.
|
||||
exports.For = class For extends Base
|
||||
constructor: (body, source, @name, @index) ->
|
||||
{@source, @guard, @step} = source
|
||||
constructor: (body, source) ->
|
||||
{@source, @guard, @step, @name, @index} = source
|
||||
@body = Expressions.wrap [body]
|
||||
@own = !!source.own
|
||||
@object = !!source.object
|
||||
@@ -1408,28 +1440,29 @@ exports.For = class For extends Base
|
||||
|
||||
isStatement: YES
|
||||
|
||||
jumps: While::jumps
|
||||
|
||||
makeReturn: ->
|
||||
@returns = yes
|
||||
this
|
||||
|
||||
containsPureStatement: While::containsPureStatement
|
||||
|
||||
# Welcome to the hairiest method in all of CoffeeScript. Handles the inner
|
||||
# loop, filtering, stepping, and result saving for array, object, and range
|
||||
# comprehensions. Some of the generated code can be shared in common, and
|
||||
# some cannot.
|
||||
compileNode: (o) ->
|
||||
body = Expressions.wrap [@body]
|
||||
hasCode = body.contains (node) -> node instanceof Code
|
||||
hasPure = last(body.expressions)?.containsPureStatement()
|
||||
lastJumps = last(body.expressions)?.jumps()
|
||||
@returns = no if lastJumps and lastJumps instanceof Return
|
||||
source = if @range then @source.base else @source
|
||||
scope = o.scope
|
||||
name = @name and @name.compile o, LEVEL_LIST
|
||||
index = @index and @index.compile o, LEVEL_LIST
|
||||
scope.find(name, immediate: yes) if name and not @pattern
|
||||
scope.find(index, immediate: yes) if index
|
||||
rvar = scope.freeVariable 'results' if @returns and not hasPure
|
||||
rvar = scope.freeVariable 'results' if @returns
|
||||
ivar = (if @range then name else index) or scope.freeVariable 'i'
|
||||
name = ivar if @pattern
|
||||
varPart = ''
|
||||
guardPart = ''
|
||||
defPart = ''
|
||||
@@ -1437,38 +1470,36 @@ exports.For = class For extends Base
|
||||
if @range
|
||||
forPart = source.compile merge(o, {index: ivar, @step})
|
||||
else
|
||||
svar = @source.compile o, LEVEL_TOP
|
||||
svar = @source.compile o, LEVEL_LIST
|
||||
if (name or @own) and not IDENTIFIER.test svar
|
||||
defPart = "#{@tab}#{ref = scope.freeVariable 'ref'} = #{svar};\n"
|
||||
svar = ref
|
||||
namePart = if @pattern
|
||||
new Assign(@name, new Literal "#{svar}[#{ivar}]").compile o, LEVEL_TOP
|
||||
else if name
|
||||
"#{name} = #{svar}[#{ivar}]"
|
||||
if name and not @pattern
|
||||
namePart = "#{name} = #{svar}[#{ivar}]"
|
||||
unless @object
|
||||
lvar = scope.freeVariable 'len'
|
||||
stepPart = if @step then "#{ivar} += #{ @step.compile(o, LEVEL_OP) }" else "#{ivar}++"
|
||||
forPart = "#{ivar} = 0, #{lvar} = #{svar}.length; #{ivar} < #{lvar}; #{stepPart}"
|
||||
if @returns and not hasPure
|
||||
if @returns
|
||||
resultPart = "#{@tab}#{rvar} = [];\n"
|
||||
returnResult = '\n' + (new Return(new Literal(rvar)).compile o, LEVEL_PAREN)
|
||||
returnResult = "\n#{@tab}return #{rvar};"
|
||||
body = Push.wrap rvar, body
|
||||
if @guard
|
||||
body = Expressions.wrap [new If @guard, body]
|
||||
if hasCode
|
||||
body = Closure.wrap(body, yes)
|
||||
if @pattern
|
||||
body.expressions.unshift new Assign @name, new Literal "#{svar}[#{ivar}]"
|
||||
defPart += @pluckDirectCall o, body
|
||||
varPart = "\n#{idt1}#{namePart};" if namePart
|
||||
if @object
|
||||
forPart = "#{ivar} in #{svar}"
|
||||
guardPart = "\n#{idt1}if (!#{utility('hasProp')}.call(#{svar}, #{ivar})) continue;" if @own
|
||||
defPart += @pluckDirectCall o, body, name, index unless @pattern
|
||||
body = body.compile merge(o, indent: idt1), LEVEL_TOP
|
||||
body = '\n' + body + '\n' if body
|
||||
"""
|
||||
#{defPart}#{resultPart or ''}#{@tab}for (#{forPart}) {#{guardPart}#{varPart}#{body}#{@tab}}#{returnResult or ''}
|
||||
"""
|
||||
|
||||
pluckDirectCall: (o, body, name, index) ->
|
||||
pluckDirectCall: (o, body) ->
|
||||
defs = ''
|
||||
for expr, idx in body.expressions
|
||||
expr = expr.unwrapAll()
|
||||
@@ -1482,15 +1513,10 @@ exports.For = class For extends Base
|
||||
fn = val.base?.unwrapAll() or val
|
||||
ref = new Literal o.scope.freeVariable 'fn'
|
||||
base = new Value ref
|
||||
args = compact [name, index]
|
||||
args.reverse() if @object
|
||||
for arg, i in args
|
||||
fn.params.push new Param args[i] = new Literal arg
|
||||
if val.base
|
||||
[val.base, base] = [base, val]
|
||||
args.unshift new Literal 'this'
|
||||
body.expressions[idx] = new Call base, args
|
||||
o.sharedScope = o.scope
|
||||
body.expressions[idx] = new Call base, expr.args
|
||||
defs += @tab + new Assign(ref, fn).compile(o, LEVEL_TOP) + ';\n'
|
||||
defs
|
||||
|
||||
@@ -1504,6 +1530,11 @@ exports.Switch = class Switch extends Base
|
||||
|
||||
isStatement: YES
|
||||
|
||||
jumps: (o = {block: yes}) ->
|
||||
for [conds, block] in @cases
|
||||
return block if block.jumps o
|
||||
@otherwise?.jumps o
|
||||
|
||||
makeReturn: ->
|
||||
pair[1].makeReturn() for pair in @cases
|
||||
@otherwise?.makeReturn()
|
||||
@@ -1519,10 +1550,11 @@ exports.Switch = class Switch extends Base
|
||||
code += idt1 + "case #{ cond.compile o, LEVEL_PAREN }:\n"
|
||||
code += body + '\n' if body = block.compile o, LEVEL_TOP
|
||||
break if i is @cases.length - 1 and not @otherwise
|
||||
for expr in block.expressions by -1 when expr not instanceof Comment
|
||||
code += idt2 + 'break;\n' unless expr instanceof Return
|
||||
break
|
||||
code += idt1 + "default:\n#{ @otherwise.compile o, LEVEL_TOP }\n" if @otherwise
|
||||
expr = @lastNonComment block.expressions
|
||||
jumper = expr.jumps()
|
||||
if not expr or not jumper or (jumper instanceof Literal and jumper.value is 'debugger')
|
||||
code += idt2 + 'break;\n'
|
||||
code += idt1 + "default:\n#{ @otherwise.compile o, LEVEL_TOP }\n" if @otherwise and @otherwise.expressions.length
|
||||
code + @tab + '}'
|
||||
|
||||
#### If
|
||||
@@ -1534,7 +1566,7 @@ exports.Switch = class Switch extends Base
|
||||
# because ternaries are already proper expressions, and don't need conversion.
|
||||
exports.If = class If extends Base
|
||||
constructor: (condition, @body, options = {}) ->
|
||||
@condition = if options.invert then condition.invert() else condition
|
||||
@condition = if options.type is 'unless' then condition.invert() else condition
|
||||
@elseBody = null
|
||||
@isChain = false
|
||||
{@soak} = options
|
||||
@@ -1559,6 +1591,8 @@ exports.If = class If extends Base
|
||||
o?.level is LEVEL_TOP or
|
||||
@bodyNode().isStatement(o) or @elseBodyNode()?.isStatement(o)
|
||||
|
||||
jumps: (o) -> @body.jumps(o) or @elseBody?.jumps(o)
|
||||
|
||||
compileNode: (o) ->
|
||||
if @isStatement o then @compileStatement o else @compileExpression o
|
||||
|
||||
@@ -1610,7 +1644,7 @@ exports.If = class If extends Base
|
||||
# which is helpful for recording the result arrays from comprehensions.
|
||||
Push =
|
||||
wrap: (name, exps) ->
|
||||
return exps if exps.isEmpty() or last(exps.expressions).containsPureStatement()
|
||||
return exps if exps.isEmpty() or last(exps.expressions).jumps()
|
||||
exps.push new Call new Value(new Literal(name), [new Access new Literal 'push']), [exps.pop()]
|
||||
|
||||
#### Closure
|
||||
@@ -1622,7 +1656,7 @@ Closure =
|
||||
# in which case, no dice. If the body mentions `this` or `arguments`,
|
||||
# then make sure that the closure wrapper preserves the original values.
|
||||
wrap: (expressions, statement, noReturn) ->
|
||||
return expressions if expressions.containsPureStatement()
|
||||
return expressions if expressions.jumps()
|
||||
func = new Code [], Expressions.wrap [expressions]
|
||||
args = []
|
||||
if (mentionsArgs = expressions.contains @literalArgs) or
|
||||
@@ -1631,13 +1665,15 @@ Closure =
|
||||
args = [new Literal 'this']
|
||||
args.push new Literal 'arguments' if mentionsArgs
|
||||
func = new Value func, [new Access meth]
|
||||
func.noReturn = noReturn
|
||||
func.noReturn = noReturn
|
||||
call = new Call func, args
|
||||
if statement then Expressions.wrap [call] else call
|
||||
|
||||
literalArgs: (node) -> node instanceof Literal and node.value is 'arguments'
|
||||
literalThis: (node) -> node instanceof Literal and node.value is 'this' or
|
||||
node instanceof Code and node.bound
|
||||
literalArgs: (node) ->
|
||||
node instanceof Literal and node.value is 'arguments' and not node.asKey
|
||||
literalThis: (node) ->
|
||||
(node instanceof Literal and node.value is 'this' and not node.asKey) or
|
||||
(node instanceof Code and node.bound)
|
||||
|
||||
# Unfold a node's child if soak, then tuck the node under created `If`
|
||||
unfoldSoak = (o, parent, name) ->
|
||||
|
||||
@@ -18,13 +18,18 @@ exports.OptionParser = class OptionParser
|
||||
|
||||
# Parse the list of arguments, populating an `options` object with all of the
|
||||
# specified options, and returning it. `options.arguments` will be an array
|
||||
# containing the remaining non-option arguments. This is a simpler API than
|
||||
# many option parsers that allow you to attach callback actions for every
|
||||
# flag. Instead, you're responsible for interpreting the options object.
|
||||
# containing the remaining non-option arguments. `options.literals` will be
|
||||
# an array of options that are meant to be passed through directly to the
|
||||
# executing script. This is a simpler API than many option parsers that allow
|
||||
# you to attach callback actions for every flag. Instead, you're responsible
|
||||
# for interpreting the options object.
|
||||
parse: (args) ->
|
||||
options = arguments: []
|
||||
options = arguments: [], literals: []
|
||||
args = normalizeArguments args
|
||||
for arg, i in args
|
||||
if arg is '--'
|
||||
options.literals = args[(i + 1)..]
|
||||
break
|
||||
isOption = !!(arg.match(LONG_FLAG) or arg.match(SHORT_FLAG))
|
||||
matchedRule = no
|
||||
for rule in @rules
|
||||
|
||||
@@ -135,22 +135,22 @@ class exports.Rewriter
|
||||
@tokens.splice idx, 0, ['CALL_END', ')', token[2]]
|
||||
@scanTokens (token, i, tokens) ->
|
||||
tag = token[0]
|
||||
noCall = yes if tag in ['CLASS', 'IF', 'UNLESS']
|
||||
noCall = yes if tag in ['CLASS', 'IF']
|
||||
[prev, current, next] = tokens[i - 1 .. i + 1]
|
||||
callObject = not noCall and tag is 'INDENT' and
|
||||
next and next.generated and next[0] is '{' and
|
||||
prev and prev[0] in IMPLICIT_FUNC
|
||||
seenSingle = no
|
||||
noCall = no if tag in LINEBREAKS
|
||||
noCall = no if tag in LINEBREAKS
|
||||
token.call = yes if prev and not prev.spaced and tag is '?'
|
||||
return 1 unless callObject or
|
||||
prev?.spaced and (prev.call or prev[0] in IMPLICIT_FUNC) and
|
||||
(tag in IMPLICIT_CALL or not (token.spaced or token.newLine) and tag in IMPLICIT_UNSPACED_CALL)
|
||||
tokens.splice i, 0, ['CALL_START', '(', token[2]]
|
||||
@detectEnd i + (if callObject then 2 else 1), (token, i) ->
|
||||
return yes if not seenSingle and token.fromThen
|
||||
@detectEnd i + 1, (token, i) ->
|
||||
[tag] = token
|
||||
seenSingle = yes if tag in ['IF', 'ELSE', 'UNLESS', '->', '=>']
|
||||
return yes if not seenSingle and token.fromThen
|
||||
seenSingle = yes if tag in ['IF', 'ELSE', '->', '=>']
|
||||
return yes if tag in ['.', '?.', '::'] and @tag(i - 1) is 'OUTDENT'
|
||||
not token.generated and @tag(i - 1) isnt ',' and tag in IMPLICIT_END and
|
||||
(tag isnt 'INDENT' or
|
||||
@@ -198,7 +198,7 @@ class exports.Rewriter
|
||||
tagPostfixConditionals: ->
|
||||
condition = (token, i) -> token[0] in ['TERMINATOR', 'INDENT']
|
||||
@scanTokens (token, i) ->
|
||||
return 1 unless token[0] in ['IF', 'UNLESS']
|
||||
return 1 unless token[0] is 'IF'
|
||||
original = token
|
||||
@detectEnd i + 1, condition, (token, i) ->
|
||||
original[0] = 'POST_' + original[0] if token[0] isnt 'INDENT'
|
||||
@@ -305,7 +305,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', 'UNLESS', 'TRY', 'SWITCH', 'THIS', 'BOOL', 'UNARY',
|
||||
'IF', 'TRY', 'SWITCH', 'THIS', 'BOOL', 'UNARY', 'SUPER'
|
||||
'@', '->', '=>', '[', '(', '{', '--', '++'
|
||||
]
|
||||
|
||||
@@ -315,7 +315,7 @@ IMPLICIT_UNSPACED_CALL = ['+', '-']
|
||||
IMPLICIT_BLOCK = ['->', '=>', '{', '[', ',']
|
||||
|
||||
# Tokens that always mark the end of an implicit call for single-liners.
|
||||
IMPLICIT_END = ['POST_IF', 'POST_UNLESS', 'FOR', 'WHILE', 'UNTIL', 'WHEN', 'BY', 'LOOP', 'TERMINATOR', 'INDENT']
|
||||
IMPLICIT_END = ['POST_IF', 'FOR', 'WHILE', 'UNTIL', 'WHEN', 'BY', 'LOOP', 'TERMINATOR', 'INDENT']
|
||||
|
||||
# Single-line flavors of block expressions that have unclosed endings.
|
||||
# The grammar can't disambiguate them, so we insert the implicit indentation.
|
||||
|
||||
@@ -23,7 +23,8 @@ exports.Scope = class Scope
|
||||
Scope.root = this unless @parent
|
||||
|
||||
# Adds a new variable or overrides an existing one.
|
||||
add: (name, type) ->
|
||||
add: (name, type, immediate) ->
|
||||
return @parent.add name, type, immediate if @shared and not immediate
|
||||
if typeof (pos = @positions[name]) is 'number'
|
||||
@variables[pos].type = type
|
||||
else
|
||||
@@ -34,13 +35,12 @@ exports.Scope = class Scope
|
||||
find: (name, options) ->
|
||||
return yes if @check name, options
|
||||
@add name, 'var'
|
||||
@hasDeclarations = yes
|
||||
no
|
||||
|
||||
# Reserve a variable name as originating from a function parameter for this
|
||||
# scope. No `var` required for internal references.
|
||||
parameter: (name) ->
|
||||
return if @shared and @check name, yes
|
||||
return if @shared and @parent.check name, yes
|
||||
@add name, 'param'
|
||||
|
||||
# Just check to see if a variable has already been declared, without reserving,
|
||||
@@ -67,8 +67,7 @@ exports.Scope = class Scope
|
||||
freeVariable: (type) ->
|
||||
index = 0
|
||||
index++ while @check((temp = @temporary type, index), true)
|
||||
@add temp, 'var'
|
||||
@hasDeclarations = yes
|
||||
@add temp, 'var', yes
|
||||
temp
|
||||
|
||||
# Ensure that an assignment is made at the top of this scope
|
||||
@@ -77,6 +76,10 @@ exports.Scope = class Scope
|
||||
@add name, value: value, assigned: true
|
||||
@hasAssignments = yes
|
||||
|
||||
# Does this scope have any declared variables?
|
||||
hasDeclarations: ->
|
||||
!!@declaredVariables().length
|
||||
|
||||
# Return the list of variables first declared in this scope.
|
||||
declaredVariables: ->
|
||||
realVars = []
|
||||
|
||||
127
test/arguments.coffee
Normal file
@@ -0,0 +1,127 @@
|
||||
# Arguments
|
||||
# ---------
|
||||
|
||||
# shared identity function
|
||||
id = (_) -> if arguments.length is 1 then _ else Array::slice.call(arguments)
|
||||
|
||||
test "basic argument passing tests", ->
|
||||
a = {}
|
||||
b = {}
|
||||
c = {}
|
||||
eq 1, (id 1)
|
||||
eq 2, (id 1, 2)[1]
|
||||
eq a, (id a)
|
||||
eq c, (id a, b, c)[2]
|
||||
|
||||
test "passing arguments on separate lines", ->
|
||||
a = {}
|
||||
b = {}
|
||||
c = {}
|
||||
ok(id(
|
||||
a
|
||||
b
|
||||
c
|
||||
)[1] is b)
|
||||
eq(0, id(
|
||||
0
|
||||
10
|
||||
)[0])
|
||||
eq(a,id(
|
||||
a
|
||||
))
|
||||
eq b,
|
||||
(id b)
|
||||
|
||||
test "reference `arguments` inside of functions", ->
|
||||
sumOfArgs = ->
|
||||
sum = (a,b) -> a + b
|
||||
sum = 0
|
||||
sum += num for num in arguments
|
||||
sum
|
||||
|
||||
eq 10, sumOfArgs(0, 1, 2, 3, 4)
|
||||
|
||||
|
||||
#### Parameter List Features
|
||||
|
||||
test "splats", ->
|
||||
arrayEq [0, 1, 2], (((splat...) -> splat) 0, 1, 2)
|
||||
arrayEq [2, 3], (((_, _, splat...) -> splat) 0, 1, 2, 3)
|
||||
arrayEq [0, 1], (((splat..., _, _) -> splat) 0, 1, 2, 3)
|
||||
arrayEq [2], (((_, _, splat..., _) -> splat) 0, 1, 2, 3)
|
||||
|
||||
test "@-parameters: automatically assign an argument's value to a property of the context", ->
|
||||
nonce = {}
|
||||
|
||||
((@prop) ->).call context = {}, nonce
|
||||
eq nonce, context.prop
|
||||
|
||||
# allow splats along side the special argument
|
||||
((splat..., @prop) ->).apply context = {}, [0, 0, nonce]
|
||||
eq nonce, context.prop
|
||||
|
||||
# allow the argument itself to be a splat
|
||||
((@prop...) ->).call context = {}, 0, nonce, 0
|
||||
eq nonce, context.prop[1]
|
||||
|
||||
# the argument should still be able to be referenced normally
|
||||
eq nonce, (((@prop) -> prop).call {}, nonce)
|
||||
|
||||
test "@-parameters and splats with constructors", ->
|
||||
a = {}
|
||||
b = {}
|
||||
class Klass
|
||||
constructor: (@first, splat..., @last) ->
|
||||
|
||||
obj = new Klass a, 0, 0, b
|
||||
eq a, obj.first
|
||||
eq b, obj.last
|
||||
|
||||
test "destructuring in function definition", ->
|
||||
(([{a: [b], c}]...) ->
|
||||
eq 1, b
|
||||
eq 2, c
|
||||
) {a: [1], c: 2}
|
||||
|
||||
test "default values", ->
|
||||
nonceA = {}
|
||||
nonceB = {}
|
||||
a = (_,_,arg=nonceA) -> arg
|
||||
eq nonceA, a()
|
||||
eq nonceA, a(0)
|
||||
eq nonceB, a(0,0,nonceB)
|
||||
eq nonceA, a(0,0,undefined)
|
||||
eq nonceA, a(0,0,null)
|
||||
eq false , a(0,0,false)
|
||||
eq nonceB, a(undefined,undefined,nonceB,undefined)
|
||||
b = (_,arg=nonceA,_,_) -> arg
|
||||
eq nonceA, b()
|
||||
eq nonceA, b(0)
|
||||
eq nonceB, b(0,nonceB)
|
||||
eq nonceA, b(0,undefined)
|
||||
eq nonceA, b(0,null)
|
||||
eq false , b(0,false)
|
||||
eq nonceB, b(undefined,nonceB,undefined)
|
||||
c = (arg=nonceA,_,_) -> arg
|
||||
eq nonceA, c()
|
||||
eq 0, c(0)
|
||||
eq nonceB, c(nonceB)
|
||||
eq nonceA, c(undefined)
|
||||
eq nonceA, c(null)
|
||||
eq false , c(false)
|
||||
eq nonceB, c(nonceB,undefined,undefined)
|
||||
|
||||
test "default values with @-parameters", ->
|
||||
a = {}
|
||||
b = {}
|
||||
obj = f: (q = a, @p = b) -> q
|
||||
eq a, obj.f()
|
||||
eq b, obj.p
|
||||
|
||||
test "default values with splatted arguments", ->
|
||||
withSplats = (a = 2, b..., c = 3, d = 5) -> a * (b.length + 1) * c * d
|
||||
eq 30, withSplats()
|
||||
eq 15, withSplats(1)
|
||||
eq 5, withSplats(1,1)
|
||||
eq 1, withSplats(1,1,1)
|
||||
eq 2, withSplats(1,1,1,1)
|
||||
98
test/assignment.coffee
Normal file
@@ -0,0 +1,98 @@
|
||||
# Assignment
|
||||
# ----------
|
||||
|
||||
test "context property assignment (using @)", ->
|
||||
nonce = {}
|
||||
addMethod = ->
|
||||
@method = -> nonce
|
||||
this
|
||||
eq nonce, addMethod.call({}).method()
|
||||
|
||||
test "unassignable values", ->
|
||||
nonce = {}
|
||||
for nonref in ['', '""', '0', 'f()'].concat CoffeeScript.RESERVED
|
||||
eq nonce, (try CoffeeScript.compile "#{nonref} = v" catch e then nonce)
|
||||
|
||||
test "compound assignments should not declare", ->
|
||||
# TODO: make description more clear
|
||||
# TODO: remove reference to Math
|
||||
eq Math, (-> Math or= 0)()
|
||||
|
||||
|
||||
#### Statements as Expressions
|
||||
|
||||
test "assign the result of a try/catch block", ->
|
||||
# multiline
|
||||
result = try
|
||||
nonexistent * missing
|
||||
catch error
|
||||
true
|
||||
eq true, result
|
||||
|
||||
# single line
|
||||
result = try nonexistent * missing catch error then true
|
||||
eq true, result
|
||||
|
||||
test "conditionals", ->
|
||||
# assign inside the condition of a conditional statement
|
||||
nonce = {}
|
||||
if a = nonce then 1
|
||||
eq nonce, a
|
||||
1 if b = nonce
|
||||
eq nonce, b
|
||||
|
||||
# assign the result of a conditional statement
|
||||
c = if true then nonce
|
||||
eq nonce, c
|
||||
|
||||
test "assign inside the condition of a `while` loop", ->
|
||||
nonce = {}
|
||||
count = 1
|
||||
a = nonce while count--
|
||||
eq nonce, a
|
||||
count = 1
|
||||
while count--
|
||||
b = nonce
|
||||
eq nonce, b
|
||||
|
||||
|
||||
#### Compound Assignment
|
||||
|
||||
test "compound assignment (math operators)", ->
|
||||
num = 10
|
||||
num -= 5
|
||||
eq 5, num
|
||||
|
||||
num *= 10
|
||||
eq 50, num
|
||||
|
||||
num /= 10
|
||||
eq 5, num
|
||||
|
||||
num %= 3
|
||||
eq 2, num
|
||||
|
||||
test "more compound assignment", ->
|
||||
a = {}
|
||||
val = undefined
|
||||
val ||= a
|
||||
val ||= true
|
||||
eq a, val
|
||||
|
||||
b = {}
|
||||
val &&= true
|
||||
eq val, true
|
||||
val &&= b
|
||||
eq b, val
|
||||
|
||||
c = {}
|
||||
val = null
|
||||
val ?= c
|
||||
val ?= true
|
||||
eq c, val
|
||||
|
||||
|
||||
#### Destructuring Assignment
|
||||
|
||||
# NO TESTS?!
|
||||
# TODO: make tests for destructuring assignment
|
||||
18
test/break.coffee
Normal file
@@ -0,0 +1,18 @@
|
||||
# Break
|
||||
# -----
|
||||
|
||||
test "break at the top level", ->
|
||||
for i in [1,2,3]
|
||||
result = i
|
||||
if i == 2
|
||||
break
|
||||
eq 2, result
|
||||
|
||||
test "break *not* at the top level", ->
|
||||
someFunc = () ->
|
||||
i = 0
|
||||
while ++i < 3
|
||||
result = i
|
||||
break if i > 1
|
||||
result
|
||||
eq 2, someFunc()
|
||||
201
test/comments.coffee
Normal file
@@ -0,0 +1,201 @@
|
||||
# Comments
|
||||
# --------
|
||||
|
||||
# Note: awkward spacing seen in some tests is likely intentional.
|
||||
|
||||
test "comments in objects", ->
|
||||
obj1 = {
|
||||
# comment
|
||||
# comment
|
||||
# comment
|
||||
one: 1
|
||||
# comment
|
||||
two: 2
|
||||
# comment
|
||||
}
|
||||
|
||||
ok Object::hasOwnProperty.call(obj1,'one')
|
||||
eq obj1.one, 1
|
||||
ok Object::hasOwnProperty.call(obj1,'two')
|
||||
eq obj1.two, 2
|
||||
|
||||
test "comments in YAML-style objects", ->
|
||||
obj2 =
|
||||
# comment
|
||||
# comment
|
||||
# comment
|
||||
three: 3
|
||||
# comment
|
||||
four: 4
|
||||
# comment
|
||||
|
||||
ok Object::hasOwnProperty.call(obj2,'three')
|
||||
eq obj2.three, 3
|
||||
ok Object::hasOwnProperty.call(obj2,'four')
|
||||
eq obj2.four, 4
|
||||
|
||||
test "comments following operators that continue lines", ->
|
||||
sum =
|
||||
1 +
|
||||
1 + # comment
|
||||
1
|
||||
eq 3, sum
|
||||
|
||||
test "comments in functions", ->
|
||||
fn = ->
|
||||
# comment
|
||||
false
|
||||
false # comment
|
||||
false
|
||||
# comment
|
||||
|
||||
# comment
|
||||
true
|
||||
|
||||
ok fn()
|
||||
|
||||
fn2 = -> #comment
|
||||
fn()
|
||||
# comment
|
||||
|
||||
ok fn2()
|
||||
|
||||
test "trailing comment before an outdent", ->
|
||||
nonce = {}
|
||||
fn3 = ->
|
||||
if true
|
||||
undefined # comment
|
||||
nonce
|
||||
|
||||
eq nonce, fn3()
|
||||
|
||||
test "comments in a switch", ->
|
||||
nonce = {}
|
||||
result = switch nonce #comment
|
||||
# comment
|
||||
when false then undefined
|
||||
# comment
|
||||
when null #comment
|
||||
undefined
|
||||
else nonce # comment
|
||||
|
||||
eq nonce, result
|
||||
|
||||
test "comment with conditional statements", ->
|
||||
nonce = {}
|
||||
result = if false # comment
|
||||
undefined
|
||||
#comment
|
||||
else # comment
|
||||
nonce
|
||||
# comment
|
||||
eq nonce, result
|
||||
|
||||
test "spaced comments with conditional statements", ->
|
||||
nonce = {}
|
||||
result = if false
|
||||
undefined
|
||||
|
||||
# comment
|
||||
else if false
|
||||
undefined
|
||||
|
||||
# comment
|
||||
else
|
||||
nonce
|
||||
|
||||
eq nonce, result
|
||||
|
||||
|
||||
#### Block Comments
|
||||
|
||||
###
|
||||
This is a here-comment.
|
||||
Kind of like a heredoc.
|
||||
###
|
||||
|
||||
test "block comments in objects", ->
|
||||
a = {}
|
||||
b = {}
|
||||
obj = {
|
||||
a: a
|
||||
###
|
||||
comment
|
||||
###
|
||||
b: b
|
||||
}
|
||||
|
||||
eq a, obj.a
|
||||
eq b, obj.b
|
||||
|
||||
test "block comments in YAML-style", ->
|
||||
a = {}
|
||||
b = {}
|
||||
obj =
|
||||
a: a
|
||||
###
|
||||
comment
|
||||
###
|
||||
b: b
|
||||
|
||||
eq a, obj.a
|
||||
eq b, obj.b
|
||||
|
||||
|
||||
test "block comments in functions", ->
|
||||
nonce = {}
|
||||
|
||||
fn1 = ->
|
||||
true
|
||||
###
|
||||
false
|
||||
###
|
||||
|
||||
ok fn1()
|
||||
|
||||
fn2 = ->
|
||||
###
|
||||
block comment
|
||||
###
|
||||
nonce
|
||||
|
||||
eq nonce, fn2()
|
||||
|
||||
fn3 = ->
|
||||
nonce
|
||||
###
|
||||
block comment
|
||||
###
|
||||
|
||||
eq nonce, fn3()
|
||||
|
||||
fn4 = ->
|
||||
one = ->
|
||||
###
|
||||
block comment
|
||||
###
|
||||
two = ->
|
||||
three = ->
|
||||
nonce
|
||||
|
||||
eq nonce, fn4()()()()
|
||||
|
||||
test "block comments inside class bodies", ->
|
||||
class A
|
||||
a: ->
|
||||
|
||||
###
|
||||
Comment
|
||||
###
|
||||
b: ->
|
||||
|
||||
ok A.prototype.b instanceof Function
|
||||
|
||||
class B
|
||||
###
|
||||
Comment
|
||||
###
|
||||
a: ->
|
||||
b: ->
|
||||
|
||||
ok B.prototype.a instanceof Function
|
||||
181
test/conditionals.coffee
Normal file
@@ -0,0 +1,181 @@
|
||||
# Conditionals
|
||||
# ------------
|
||||
|
||||
# shared identity function
|
||||
id = (_) -> if arguments.length is 1 then _ else Array::slice.call(arguments)
|
||||
|
||||
#### Basic Conditionals
|
||||
|
||||
test "basic conditionals", ->
|
||||
if false
|
||||
ok false
|
||||
else if false
|
||||
ok false
|
||||
else
|
||||
ok true
|
||||
|
||||
if true
|
||||
ok true
|
||||
else if true
|
||||
ok false
|
||||
else
|
||||
ok true
|
||||
|
||||
unless true
|
||||
ok false
|
||||
else unless true
|
||||
ok false
|
||||
else
|
||||
ok true
|
||||
|
||||
unless false
|
||||
ok true
|
||||
else unless false
|
||||
ok false
|
||||
else
|
||||
ok true
|
||||
|
||||
test "single-line conditional", ->
|
||||
if false then ok false else ok true
|
||||
unless false then ok true else ok false
|
||||
|
||||
test "nested conditionals", ->
|
||||
nonce = {}
|
||||
eq nonce, (if true
|
||||
unless false
|
||||
if false then false else
|
||||
if true
|
||||
nonce)
|
||||
|
||||
test "nested single-line conditionals", ->
|
||||
nonce = {}
|
||||
|
||||
a = if false then undefined else b = if 0 then undefined else nonce
|
||||
eq nonce, a
|
||||
eq nonce, b
|
||||
|
||||
c = if false then undefined else (if 0 then undefined else nonce)
|
||||
eq nonce, c
|
||||
|
||||
d = if true then id(if false then undefined else nonce)
|
||||
eq nonce, d
|
||||
|
||||
test "empty conditional bodies", ->
|
||||
eq undefined, (if false
|
||||
else if false
|
||||
else)
|
||||
|
||||
test "conditional bodies containing only comments", ->
|
||||
eq undefined, (if true
|
||||
###
|
||||
block comment
|
||||
###
|
||||
else
|
||||
# comment
|
||||
)
|
||||
|
||||
eq undefined, (if false
|
||||
# comment
|
||||
else if true
|
||||
###
|
||||
block comment
|
||||
###
|
||||
else)
|
||||
|
||||
test "return value of if-else is from the proper body", ->
|
||||
nonce = {}
|
||||
eq nonce, if false then undefined else nonce
|
||||
|
||||
test "return value of unless-else is from the proper body", ->
|
||||
nonce = {}
|
||||
eq nonce, unless true then undefined else nonce
|
||||
|
||||
|
||||
#### Interactions With Functions
|
||||
|
||||
test "single-line function definition with single-line conditional", ->
|
||||
fn = -> if 1 < 0.5 then 1 else -1
|
||||
ok fn() is -1
|
||||
|
||||
test "function resturns conditional value with no `else`", ->
|
||||
fn = ->
|
||||
return if false then true
|
||||
eq undefined, fn()
|
||||
|
||||
test "function returns a conditional value", ->
|
||||
a = {}
|
||||
fnA = ->
|
||||
return if false then undefined else a
|
||||
eq a, fnA()
|
||||
|
||||
b = {}
|
||||
fnB = ->
|
||||
return unless false then b else undefined
|
||||
eq b, fnB()
|
||||
|
||||
test "passing a conditional value to a function", ->
|
||||
nonce = {}
|
||||
eq nonce, id if false then undefined else nonce
|
||||
|
||||
test "unmatched `then` should catch implicit calls", ->
|
||||
a = 0
|
||||
trueFn = -> true
|
||||
if trueFn undefined then a += 1
|
||||
eq 1, a
|
||||
|
||||
|
||||
#### if-to-ternary
|
||||
|
||||
test "if-to-ternary with instanceof requires parentheses", ->
|
||||
nonce = {}
|
||||
eq nonce, (if {} instanceof Object
|
||||
nonce
|
||||
else
|
||||
undefined)
|
||||
|
||||
test "if-to-ternary as part of a larger operation requires parentheses", ->
|
||||
ok 2, 1 + if false then 0 else 1
|
||||
|
||||
|
||||
#### Odd Formatting
|
||||
|
||||
test "if-else indented within an assignment", ->
|
||||
nonce = {}
|
||||
result =
|
||||
if false
|
||||
undefined
|
||||
else
|
||||
nonce
|
||||
eq nonce, result
|
||||
|
||||
test "suppressed indentation via assignment", ->
|
||||
nonce = {}
|
||||
result =
|
||||
if false then undefined
|
||||
else if no then undefined
|
||||
else if 0 then undefined
|
||||
else if 1 < 0 then undefined
|
||||
else id(
|
||||
if false then undefined
|
||||
else nonce
|
||||
)
|
||||
eq nonce, result
|
||||
|
||||
test "tight formatting with leading `then`", ->
|
||||
nonce = {}
|
||||
eq nonce,
|
||||
if true
|
||||
then nonce
|
||||
else undefined
|
||||
|
||||
test "#738", ->
|
||||
nonce = {}
|
||||
fn = if true then -> nonce
|
||||
eq nonce, fn()
|
||||
|
||||
test "#748: trailing reserved identifiers", ->
|
||||
nonce = {}
|
||||
obj = delete: true
|
||||
result = if obj.delete
|
||||
nonce
|
||||
eq nonce, result
|
||||
90
test/exception_handling.coffee
Normal file
@@ -0,0 +1,90 @@
|
||||
# Exceptions
|
||||
# ----------
|
||||
|
||||
# shared nonce
|
||||
nonce = {}
|
||||
|
||||
|
||||
#### Throw
|
||||
|
||||
test "basic exception throwing", ->
|
||||
throws (-> throw 'error'), 'error'
|
||||
|
||||
|
||||
#### Empty Try/Catch/Finally
|
||||
|
||||
test "try can exist alone", ->
|
||||
try
|
||||
|
||||
test "try/catch with empty try, empty catch", ->
|
||||
try
|
||||
# nothing
|
||||
catch err
|
||||
# nothing
|
||||
|
||||
test "single-line try/catch with empty try, empty catch", ->
|
||||
try catch err
|
||||
|
||||
test "try/finally with empty try, empty finally", ->
|
||||
try
|
||||
# nothing
|
||||
finally
|
||||
# nothing
|
||||
|
||||
test "single-line try/finally with empty try, empty finally", ->
|
||||
try finally
|
||||
|
||||
test "try/catch/finally with empty try, empty catch, empty finally", ->
|
||||
try
|
||||
catch err
|
||||
finally
|
||||
|
||||
test "single-line try/catch/finally with empty try, empty catch, empty finally", ->
|
||||
try catch err then finally
|
||||
|
||||
|
||||
#### Try/Catch/Finally as an Expression
|
||||
|
||||
test "return the result of try when no exception is thrown", ->
|
||||
result = try
|
||||
nonce
|
||||
catch err
|
||||
undefined
|
||||
finally
|
||||
undefined
|
||||
eq nonce, result
|
||||
|
||||
test "single-line result of try when no exception is thrown", ->
|
||||
result = try nonce catch err then undefined
|
||||
eq nonce, result
|
||||
|
||||
test "return the result of catch when an exception is thrown", ->
|
||||
fn = ->
|
||||
try
|
||||
throw ->
|
||||
catch err
|
||||
nonce
|
||||
doesNotThrow fn
|
||||
eq nonce, fn()
|
||||
|
||||
test "single-line result of catch when an exception is thrown", ->
|
||||
fn = ->
|
||||
try throw (->) catch err then nonce
|
||||
doesNotThrow fn
|
||||
eq nonce, fn()
|
||||
|
||||
test "optional catch", ->
|
||||
fn = ->
|
||||
try throw ->
|
||||
nonce
|
||||
doesNotThrow fn
|
||||
eq nonce, fn()
|
||||
|
||||
|
||||
#### Try/Catch/Finally Interaction With Other Constructs
|
||||
|
||||
test "try/catch with empty catch as last statement in a function body", ->
|
||||
fn = ->
|
||||
try nonce
|
||||
catch err
|
||||
eq nonce, fn()
|
||||
96
test/helpers.coffee
Normal file
@@ -0,0 +1,96 @@
|
||||
# Helpers
|
||||
# -------
|
||||
|
||||
# pull the helpers from `CoffeeScript.helpers` into local variables
|
||||
{starts, ends, compact, count, merge, extend, flatten, del, last} = CoffeeScript.helpers
|
||||
|
||||
|
||||
#### `starts`
|
||||
|
||||
test "the `starts` helper tests if a string starts with another string", ->
|
||||
ok starts('01234', '012')
|
||||
ok not starts('01234', '123')
|
||||
|
||||
test "the `starts` helper can take an optional offset", ->
|
||||
ok starts('01234', '34', 3)
|
||||
ok not starts('01234', '01', 1)
|
||||
|
||||
|
||||
#### `ends`
|
||||
|
||||
test "the `ends` helper tests if a string ends with another string", ->
|
||||
ok ends('01234', '234')
|
||||
ok not ends('01234', '012')
|
||||
|
||||
test "the `ends` helper can take an optional offset", ->
|
||||
ok ends('01234', '012', 2)
|
||||
ok not ends('01234', '234', 6)
|
||||
|
||||
|
||||
#### `compact`
|
||||
|
||||
test "the `compact` helper removes falsey values from an array, preserves truthy ones", ->
|
||||
allValues = [1, 0, false, obj={}, [], '', ' ', -1, null, undefined, true]
|
||||
truthyValues = [1, obj, [], ' ', -1, true]
|
||||
arrayEq truthyValues, compact(allValues)
|
||||
|
||||
|
||||
#### `count`
|
||||
|
||||
test "the `count` helper counts the number of occurances of a string in another string", ->
|
||||
eq 1/0, count('abc', '')
|
||||
eq 0, count('abc', 'z')
|
||||
eq 1, count('abc', 'a')
|
||||
eq 1, count('abc', 'b')
|
||||
eq 2, count('abcdc', 'c')
|
||||
eq 2, count('abcdabcd','abc')
|
||||
|
||||
|
||||
#### `merge`
|
||||
|
||||
test "the `merge` helper makes a new object with all properties of the objects given as its arguments", ->
|
||||
ary = [0, 1, 2, 3, 4]
|
||||
obj = {}
|
||||
merged = merge obj, ary
|
||||
ok merged isnt obj
|
||||
ok merged isnt ary
|
||||
for own key, val of ary
|
||||
eq val, merged[key]
|
||||
|
||||
|
||||
#### `extend`
|
||||
|
||||
test "the `extend` helper performs a shallow copy", ->
|
||||
ary = [0, 1, 2, 3]
|
||||
obj = {}
|
||||
# should return the object being extended
|
||||
eq obj, extend(obj, ary)
|
||||
# should copy the other object's properties as well (obviously)
|
||||
eq 2, obj[2]
|
||||
|
||||
|
||||
#### `flatten`
|
||||
|
||||
test "the `flatten` helper flattens an array", ->
|
||||
success = yes
|
||||
(success and= typeof n is 'number') for n in flatten [0, [[[1]], 2], 3, [4]]
|
||||
ok success
|
||||
|
||||
|
||||
#### `del`
|
||||
|
||||
test "the `del` helper deletes a property from an object and returns the deleted value", ->
|
||||
obj = [0, 1, 2]
|
||||
eq 1, del(obj, 1)
|
||||
ok 1 not of obj
|
||||
|
||||
|
||||
#### `last`
|
||||
|
||||
test "the `last` helper returns the last item of an array-like object", ->
|
||||
ary = [0, 1, 2, 3, 4]
|
||||
eq 4, last(ary)
|
||||
|
||||
test "the `last` helper allows one to specify an optional offset", ->
|
||||
ary = [0, 1, 2, 3, 4]
|
||||
eq 2, last(ary, 2)
|
||||
18
test/importing.coffee
Normal file
@@ -0,0 +1,18 @@
|
||||
# Importing
|
||||
# ---------
|
||||
|
||||
unless window? or testingBrowser?
|
||||
test "coffeescript modules can be imported and executed", ->
|
||||
|
||||
magicKey = __filename
|
||||
magicValue = 0xFFFF
|
||||
|
||||
if global[magicKey]?
|
||||
if exports?
|
||||
local = magicValue
|
||||
exports.method = -> local
|
||||
else
|
||||
global[magicKey] = {}
|
||||
if require?.extensions? or require?.registerExtension?
|
||||
ok require(__filename).method() is magicValue
|
||||
delete global[magicKey]
|
||||
225
test/operators.coffee
Normal file
@@ -0,0 +1,225 @@
|
||||
# Operators
|
||||
# ---------
|
||||
|
||||
test "binary (2-ary) math operators do not require spaces", ->
|
||||
a = 1
|
||||
b = -1
|
||||
eq +1, a*-b
|
||||
eq -1, a*+b
|
||||
eq +1, a/-b
|
||||
eq -1, a/+b
|
||||
|
||||
test "operators should respect new lines as spaced", ->
|
||||
a = 123 +
|
||||
456
|
||||
eq 579, a
|
||||
|
||||
b = "1#{2}3" +
|
||||
"456"
|
||||
eq '123456', b
|
||||
|
||||
test "multiple operators should space themselves", ->
|
||||
eq (+ +1), (- -1)
|
||||
|
||||
test "bitwise operators", ->
|
||||
eq 2, (10 & 3)
|
||||
eq 11, (10 | 3)
|
||||
eq 9, (10 ^ 3)
|
||||
eq 80, (10 << 3)
|
||||
eq 1, (10 >> 3)
|
||||
eq 1, (10 >>> 3)
|
||||
num = 10; eq 2, (num &= 3)
|
||||
num = 10; eq 11, (num |= 3)
|
||||
num = 10; eq 9, (num ^= 3)
|
||||
num = 10; eq 80, (num <<= 3)
|
||||
num = 10; eq 1, (num >>= 3)
|
||||
num = 10; eq 1, (num >>>= 3)
|
||||
|
||||
test "`instanceof`", ->
|
||||
ok new String instanceof String
|
||||
ok new Boolean instanceof Boolean
|
||||
# `instanceof` supports negation by prefixing the operator with `not`
|
||||
ok new Number not instanceof String
|
||||
ok new Array not instanceof Boolean
|
||||
|
||||
|
||||
#### Compound Assignment Operators
|
||||
|
||||
test "boolean operators", ->
|
||||
nonce = {}
|
||||
|
||||
a = 0
|
||||
a or= nonce
|
||||
eq nonce, a
|
||||
|
||||
b = 1
|
||||
b or= nonce
|
||||
eq 1, b
|
||||
|
||||
c = 0
|
||||
c and= nonce
|
||||
eq 0, c
|
||||
|
||||
d = 1
|
||||
d and= nonce
|
||||
eq nonce, d
|
||||
|
||||
# ensure that RHS is treated as a group
|
||||
e = f = false
|
||||
e and= f or true
|
||||
eq false, e
|
||||
|
||||
test "compound assignment as a sub expression", ->
|
||||
[a, b, c] = [1, 2, 3]
|
||||
eq 6, (a + b += c)
|
||||
eq 1, a
|
||||
eq 5, b
|
||||
eq 3, c
|
||||
|
||||
# *note: this test could still use refactoring*
|
||||
test "compound assignment should be careful about caching variables", ->
|
||||
count = 0
|
||||
list = []
|
||||
|
||||
list[++count] or= 1
|
||||
eq 1, list[1]
|
||||
eq 1, count
|
||||
|
||||
list[++count] ?= 2
|
||||
eq 2, list[2]
|
||||
eq 2, count
|
||||
|
||||
list[count++] and= 6
|
||||
eq 6, list[2]
|
||||
eq 3, count
|
||||
|
||||
base = ->
|
||||
++count
|
||||
base
|
||||
|
||||
base().four or= 4
|
||||
eq 4, base.four
|
||||
eq 4, count
|
||||
|
||||
base().five ?= 5
|
||||
eq 5, base.five
|
||||
eq 5, count
|
||||
|
||||
test "compound assignment with implicit objects", ->
|
||||
obj = undefined
|
||||
obj ?=
|
||||
one: 1
|
||||
|
||||
eq 1, obj.one
|
||||
|
||||
obj and=
|
||||
two: 2
|
||||
|
||||
eq undefined, obj.one
|
||||
eq 2, obj.two
|
||||
|
||||
|
||||
#### `is`,`isnt`,`==`,`!=`
|
||||
|
||||
test "`==` and `is` should be interchangeable", ->
|
||||
a = b = 1
|
||||
ok a is 1 and b == 1
|
||||
ok a == b
|
||||
ok a is b
|
||||
|
||||
test "`!=` and `isnt` should be interchangeable", ->
|
||||
a = 0
|
||||
b = 1
|
||||
ok a isnt 1 and b != 0
|
||||
ok a != b
|
||||
ok a isnt b
|
||||
|
||||
|
||||
#### `in`, `of`
|
||||
|
||||
# - `in` should check if an array contains a value using `indexOf`
|
||||
# - `of` should check if a property is defined on an object using `in`
|
||||
test "in, of", ->
|
||||
arr = [1]
|
||||
ok 0 of arr
|
||||
ok 1 in arr
|
||||
# prefixing `not` to `in and `of` should negate them
|
||||
ok 1 not of arr
|
||||
ok 0 not in arr
|
||||
|
||||
test "`in` should be able to operate on an array literal", ->
|
||||
ok 2 in [0, 1, 2, 3]
|
||||
ok 4 not in [0, 1, 2, 3]
|
||||
arr = [0, 1, 2, 3]
|
||||
ok 2 in arr
|
||||
ok 4 not in arr
|
||||
# should cache the value used to test the array
|
||||
arr = [0]
|
||||
val = 0
|
||||
ok val++ in arr
|
||||
ok val++ not in arr
|
||||
val = 0
|
||||
ok val++ of arr
|
||||
ok val++ not of arr
|
||||
|
||||
test "`of` and `in` should be able to operate on instance variables", ->
|
||||
obj = {
|
||||
list: [2,3]
|
||||
in_list: (value) -> value in @list
|
||||
not_in_list: (value) -> value not in @list
|
||||
of_list: (value) -> value of @list
|
||||
not_of_list: (value) -> value not of @list
|
||||
}
|
||||
ok obj.in_list 3
|
||||
ok obj.not_in_list 1
|
||||
ok obj.of_list 0
|
||||
ok obj.not_of_list 2
|
||||
|
||||
test "#???: `in` with cache and `__indexOf` should work in argument lists", ->
|
||||
eq 1, [Object() in Array()].length
|
||||
|
||||
test "#737: `in` should have higher precedence than logical operators", ->
|
||||
eq 1, 1 in [1] and 1
|
||||
|
||||
test "#768: `in` should preserve evaluation order", ->
|
||||
share = 0
|
||||
a = -> share++ if share is 0
|
||||
b = -> share++ if share is 1
|
||||
c = -> share++ if share is 2
|
||||
ok a() not in [b(),c()]
|
||||
eq 3, share
|
||||
|
||||
|
||||
#### Chainable Operators
|
||||
|
||||
test "chainable operators", ->
|
||||
ok 100 > 10 > 1 > 0 > -1
|
||||
ok -1 < 0 < 1 < 10 < 100
|
||||
|
||||
test "`is` and `isnt` may be chained", ->
|
||||
ok true is not false is true is not false
|
||||
ok 0 is 0 isnt 1 is 1
|
||||
|
||||
test "different comparison operators (`>`,`<`,`is`,etc.) may be combined", ->
|
||||
ok 1 < 2 > 1
|
||||
ok 10 < 20 > 2+3 is 5
|
||||
|
||||
test "some chainable operators can be negated by `unless`", ->
|
||||
ok (true unless 0==10!=100)
|
||||
|
||||
test "operator precedence: `|` lower than `<`", ->
|
||||
eq 1, 1 | 2 < 3 < 4
|
||||
|
||||
test "preserve references", ->
|
||||
a = b = c = 1
|
||||
# `a == b <= c` should become `a === b && b <= c`
|
||||
# (this test does not seem to test for this)
|
||||
ok a == b <= c
|
||||
|
||||
test "chained operations should evaluate each value only once", ->
|
||||
a = 0
|
||||
ok 1 > a++ < 1
|
||||
|
||||
test "#891: incorrect inversion of chained comparisons", ->
|
||||
ok (true unless 0 > 1 > 2)
|
||||
ok (true unless (NaN = 0/0) < 0/0 < NaN)
|
||||
186
test/ranges_slices_and_splices.coffee
Normal file
@@ -0,0 +1,186 @@
|
||||
# Ranges, Slices, and Splices
|
||||
# ---------------------------
|
||||
|
||||
# shared array
|
||||
shared = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
|
||||
|
||||
|
||||
#### Ranges
|
||||
|
||||
test "basic inclusive ranges", ->
|
||||
arrayEq [1, 2, 3] , [1..3]
|
||||
arrayEq [0, 1, 2] , [0..2]
|
||||
arrayEq [0, 1] , [0..1]
|
||||
arrayEq [0] , [0..0]
|
||||
arrayEq [-1] , [-1..-1]
|
||||
arrayEq [-1, 0] , [-1..0]
|
||||
arrayEq [-1, 0, 1], [-1..1]
|
||||
|
||||
test "basic exclusive ranges", ->
|
||||
arrayEq [1, 2, 3] , [1...4]
|
||||
arrayEq [0, 1, 2] , [0...3]
|
||||
arrayEq [0, 1] , [0...2]
|
||||
arrayEq [0] , [0...1]
|
||||
arrayEq [-1] , [-1...0]
|
||||
arrayEq [-1, 0] , [-1...1]
|
||||
arrayEq [-1, 0, 1], [-1...2]
|
||||
|
||||
arrayEq [], [1...1]
|
||||
arrayEq [], [0...0]
|
||||
arrayEq [], [-1...-1]
|
||||
|
||||
test "downward ranges", ->
|
||||
arrayEq shared, [9..0].reverse()
|
||||
arrayEq [5, 4, 3, 2] , [5..2]
|
||||
arrayEq [2, 1, 0, -1], [2..-1]
|
||||
|
||||
arrayEq [3, 2, 1] , [3..1]
|
||||
arrayEq [2, 1, 0] , [2..0]
|
||||
arrayEq [1, 0] , [1..0]
|
||||
arrayEq [0] , [0..0]
|
||||
arrayEq [-1] , [-1..-1]
|
||||
arrayEq [0, -1] , [0..-1]
|
||||
arrayEq [1, 0, -1] , [1..-1]
|
||||
arrayEq [0, -1, -2], [0..-2]
|
||||
|
||||
arrayEq [4, 3, 2], [4...1]
|
||||
arrayEq [3, 2, 1], [3...0]
|
||||
arrayEq [2, 1] , [2...0]
|
||||
arrayEq [1] , [1...0]
|
||||
arrayEq [] , [0...0]
|
||||
arrayEq [] , [-1...-1]
|
||||
arrayEq [0] , [0...-1]
|
||||
arrayEq [0, -1] , [0...-2]
|
||||
arrayEq [1, 0] , [1...-1]
|
||||
arrayEq [2, 1, 0], [2...-1]
|
||||
|
||||
test "ranges with variables as enpoints", ->
|
||||
[a, b] = [1, 3]
|
||||
arrayEq [1, 2, 3], [a..b]
|
||||
arrayEq [1, 2] , [a...b]
|
||||
b = -2
|
||||
arrayEq [1, 0, -1, -2], [a..b]
|
||||
arrayEq [1, 0, -1] , [a...b]
|
||||
|
||||
test "ranges with expressions as endpoints", ->
|
||||
[a, b] = [1, 3]
|
||||
arrayEq [2, 3, 4, 5, 6], [(a+1)..2*b]
|
||||
arrayEq [2, 3, 4, 5] , [(a+1)...2*b]
|
||||
|
||||
test "large ranges are generated with looping constructs", ->
|
||||
down = [99..0]
|
||||
eq 100, (len = down.length)
|
||||
eq 0, down[len - 1]
|
||||
|
||||
up = [0...100]
|
||||
eq 100, (len = up.length)
|
||||
eq 99, up[len - 1]
|
||||
|
||||
|
||||
#### Slices
|
||||
|
||||
test "basic slicing", ->
|
||||
arrayEq [7, 8, 9] , shared[7..9]
|
||||
arrayEq [2, 3] , shared[2...4]
|
||||
arrayEq [2, 3, 4, 5], shared[2...6]
|
||||
|
||||
test "slicing with variables as endpoints", ->
|
||||
[a, b] = [1, 4]
|
||||
arrayEq [1, 2, 3, 4], shared[a..b]
|
||||
arrayEq [1, 2, 3] , shared[a...b]
|
||||
|
||||
test "slicing with expressions as endpoints", ->
|
||||
[a, b] = [1, 3]
|
||||
arrayEq [2, 3, 4, 5, 6], shared[(a+1)..2*b]
|
||||
arrayEq [2, 3, 4, 5] , shared[a+1...(2*b)]
|
||||
|
||||
test "unbounded slicing", ->
|
||||
arrayEq [7, 8, 9] , shared[7..]
|
||||
arrayEq [8, 9] , shared[-2..]
|
||||
arrayEq [9] , shared[-1...]
|
||||
arrayEq [0, 1, 2] , shared[...3]
|
||||
arrayEq [0, 1, 2, 3], shared[..-7]
|
||||
|
||||
arrayEq shared , shared[..-1]
|
||||
arrayEq shared[0..8], shared[...-1]
|
||||
|
||||
for a in [-shared.length..shared.length]
|
||||
arrayEq shared[a..] , shared[a...]
|
||||
for a in [-shared.length+1...shared.length]
|
||||
arrayEq shared[..a][...-1] , shared[...a]
|
||||
|
||||
test "#930, #835, #831, #746 #624: inclusive slices to -1 should slice to end", ->
|
||||
arrayEq shared, shared[0..-1]
|
||||
arrayEq shared, shared[..-1]
|
||||
arrayEq shared.slice(1,shared.length), shared[1..-1]
|
||||
|
||||
test "string slicing", ->
|
||||
str = "abcdefghijklmnopqrstuvwxyz"
|
||||
ok str[1...1] is ""
|
||||
ok str[1..1] is "b"
|
||||
ok str[1...5] is "bcde"
|
||||
ok str[0..4] is "abcde"
|
||||
ok str[-5..] is "vwxyz"
|
||||
|
||||
|
||||
#### Splices
|
||||
|
||||
test "basic splicing", ->
|
||||
ary = [0..9]
|
||||
ary[5..9] = [0, 0, 0]
|
||||
arrayEq [0, 1, 2, 3, 4, 0, 0, 0], ary
|
||||
|
||||
ary = [0..9]
|
||||
ary[2...8] = []
|
||||
arrayEq [0, 1, 8, 9], ary
|
||||
|
||||
test "unbounded splicing", ->
|
||||
ary = [0..9]
|
||||
ary[3..] = [9, 8, 7]
|
||||
arrayEq [0, 1, 2, 9, 8, 7]. ary
|
||||
|
||||
ary[...3] = [7, 8, 9]
|
||||
arrayEq [7, 8, 9, 9, 8, 7], ary
|
||||
|
||||
test "splicing with variables as endpoints", ->
|
||||
[a, b] = [1, 8]
|
||||
|
||||
ary = [0..9]
|
||||
ary[a..b] = [2, 3]
|
||||
arrayEq [0, 2, 3, 9], ary
|
||||
|
||||
ary = [0..9]
|
||||
ary[a...b] = [5]
|
||||
arrayEq [0, 5, 8, 9], ary
|
||||
|
||||
test "splicing with expressions as endpoints", ->
|
||||
[a, b] = [1, 3]
|
||||
|
||||
ary = [0..9]
|
||||
ary[ a+1 .. 2*b+1 ] = [4]
|
||||
arrayEq [0, 1, 4, 8, 9], ary
|
||||
|
||||
ary = [0..9]
|
||||
ary[a+1...2*b+1] = [4]
|
||||
arrayEq [0, 1, 4, 7, 8, 9], ary
|
||||
|
||||
test "splicing to the end, against a one-time function", ->
|
||||
ary = null
|
||||
fn = ->
|
||||
if ary
|
||||
throw 'err'
|
||||
else
|
||||
ary = [1, 2, 3]
|
||||
|
||||
fn()[0..] = 1
|
||||
|
||||
arrayEq ary, [1]
|
||||
|
||||
test "the return value of a splice literal should be the RHS", ->
|
||||
ary = [0, 0, 0]
|
||||
eq (ary[0..1] = 2), 2
|
||||
|
||||
ary = [0, 0, 0]
|
||||
eq (ary[0..] = 3), 3
|
||||
|
||||
arrayEq [ary[0..0] = 0], [0]
|
||||
56
test/regular_expressions.coffee
Normal file
@@ -0,0 +1,56 @@
|
||||
# Regular Expressions
|
||||
# -------------------
|
||||
#TODO: add some rigorous regex interpolation tests
|
||||
|
||||
test "basic regular expression literals", ->
|
||||
ok 'a'.match(/a/)
|
||||
ok 'a'.match /a/
|
||||
ok 'a'.match(/a/g)
|
||||
ok 'a'.match /a/g
|
||||
|
||||
test "division is not confused for a regular expression", ->
|
||||
eq 2, 4 / 2 / 1
|
||||
|
||||
a = 4
|
||||
b = 2
|
||||
g = 1
|
||||
eq 2, a / b/g
|
||||
|
||||
obj = method: -> 2
|
||||
two = 2
|
||||
eq 2, (obj.method()/two + obj.method()/two)
|
||||
|
||||
i = 1
|
||||
eq 2, (4)/2/i
|
||||
eq 1, i/i/i
|
||||
|
||||
test "backslash escapes", ->
|
||||
eq "\\/\\\\", /\/\\/.source
|
||||
|
||||
test "#764: regular expressions should be indexable", ->
|
||||
eq /0/['source'], ///#{0}///['source']
|
||||
|
||||
test "#584: slashes are allowed unescaped in character classes", ->
|
||||
ok /^a\/[/]b$/.test 'a//b'
|
||||
|
||||
|
||||
#### Heregexe(n|s)
|
||||
|
||||
test "a heregex will ignore whitespace and comments", ->
|
||||
eq /^I'm\x20+[a]\s+Heregex?\/\/\//gim + '', ///
|
||||
^ I'm \x20+ [a] \s+
|
||||
Heregex? / // # or not
|
||||
///gim + ''
|
||||
|
||||
test "heregex interpolation", ->
|
||||
eq /\\#{}\\\"/ + '', ///
|
||||
#{
|
||||
"#{ '\\' }" # normal comment
|
||||
}
|
||||
# regex comment
|
||||
\#{}
|
||||
\\ \"
|
||||
/// + ''
|
||||
|
||||
test "an empty heregex will compile to an empty, non-capturing group", ->
|
||||
eq /(?:)/ + '', /// /// + ''
|
||||
@@ -34,15 +34,44 @@
|
||||
stdout.appendChild div
|
||||
msg
|
||||
|
||||
this.ok = (good, msg) ->
|
||||
@test = (desc, fn) ->
|
||||
fn()
|
||||
|
||||
@ok = (good, msg) ->
|
||||
++total
|
||||
if good then ++success else throw Error say msg
|
||||
|
||||
this.eq = (x, y, msg) -> ok x is y, msg ? x + ' !== ' + y
|
||||
@eq = (x, y, msg) -> ok x is y, msg ? x + ' !== ' + y
|
||||
|
||||
arrayEqual = (a, b) ->
|
||||
if a is b
|
||||
# 0 isnt -0
|
||||
a isnt 0 or 1/a is 1/b
|
||||
else if a instanceof Array and b instanceof Array
|
||||
return no unless a.length is b.length
|
||||
return no for el, idx in a when not arrayEq el, b[idx]
|
||||
yes
|
||||
else
|
||||
# NaN is NaN
|
||||
a isnt a and b isnt b
|
||||
|
||||
@doesNotThrow = (fn) ->
|
||||
fn()
|
||||
ok true
|
||||
|
||||
@arrayEq = (a, b, msg) -> ok arrayEqual(a,b), msg
|
||||
|
||||
@throws = (fun, err, msg) ->
|
||||
try
|
||||
fun()
|
||||
catch e
|
||||
if err
|
||||
eq e, err
|
||||
else
|
||||
ok yes
|
||||
return
|
||||
ok no
|
||||
|
||||
this.throws = (fun, err, msg) ->
|
||||
try fun(); throw new String 'No Error'
|
||||
catch e then eq e, err
|
||||
|
||||
CoffeeScript.run = (code, cb) ->
|
||||
try Function(CoffeeScript.compile code, wrap: no)()
|
||||
@@ -50,7 +79,7 @@
|
||||
cb yes
|
||||
|
||||
run = (name) ->
|
||||
CoffeeScript.load "test_#{name}.coffee", (yay) ->
|
||||
CoffeeScript.load "#{name}.coffee", (yay) ->
|
||||
say "#{ if yay then '\u2714' else '\u3000' } #{name}", yay
|
||||
++failed unless yay
|
||||
fin() if ++done is names.length
|
||||
@@ -66,28 +95,29 @@
|
||||
'arguments'
|
||||
'assignment'
|
||||
'break'
|
||||
'chaining'
|
||||
'classes'
|
||||
'comments'
|
||||
'compilation'
|
||||
'comprehensions'
|
||||
'existence'
|
||||
'functions'
|
||||
'exception_handling'
|
||||
'helpers'
|
||||
'heredocs'
|
||||
'if'
|
||||
'literals'
|
||||
'operations'
|
||||
'pattern_matching'
|
||||
'regexps'
|
||||
'returns'
|
||||
'splats'
|
||||
'strings'
|
||||
'switch'
|
||||
'try_catch'
|
||||
'while'
|
||||
'operators'
|
||||
'regular_expressions'
|
||||
'test_chaining'
|
||||
'test_classes'
|
||||
'test_compilation'
|
||||
'test_comprehensions'
|
||||
'test_existence'
|
||||
'test_functions'
|
||||
'test_heredocs'
|
||||
'conditionals'
|
||||
'test_literals'
|
||||
'test_pattern_matching'
|
||||
'ranges_slices_and_splices'
|
||||
'test_returns'
|
||||
'test_splats'
|
||||
'test_strings'
|
||||
'test_switch'
|
||||
'test_while'
|
||||
]
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
||||
@@ -1,63 +0,0 @@
|
||||
area = (x, y, x1, y1) ->
|
||||
(x - x1) * (x - y1)
|
||||
|
||||
x = y = 10
|
||||
x1 = y1 = 20
|
||||
|
||||
ok area(x, y, x1, y1) is 100
|
||||
|
||||
# ok(area(x, y,
|
||||
# x1, y1) is 100)
|
||||
|
||||
ok(area(
|
||||
x
|
||||
y
|
||||
x1
|
||||
y1
|
||||
) is 100)
|
||||
|
||||
|
||||
sumOfArgs = ->
|
||||
sum = 0
|
||||
sum += val for val in arguments
|
||||
sum
|
||||
|
||||
ok sumOfArgs(1, 2, 3, 4, 5) is 15
|
||||
|
||||
|
||||
((@arg) ->).call context = {}, 1
|
||||
ok context.arg is 1
|
||||
|
||||
((splat..., @arg) ->).call context, 1, 2, 3
|
||||
eq context.arg, 3
|
||||
|
||||
((@arg...) ->).call context, 1, 2, 3
|
||||
eq context.arg.join(' '), '1 2 3'
|
||||
|
||||
class Klass
|
||||
constructor: (@one, @two) ->
|
||||
|
||||
obj = new Klass 1, 2
|
||||
|
||||
eq obj.one, 1
|
||||
eq obj.two, 2
|
||||
|
||||
|
||||
# Destructuring.
|
||||
(([{a: [b], c}]...) ->
|
||||
eq b, 123
|
||||
eq c, 456
|
||||
) {a: [123], c: 456}
|
||||
|
||||
|
||||
# Default values.
|
||||
obj = f: (q = 123, @p = 456) -> q
|
||||
eq obj.f(), 123
|
||||
eq obj.p , 456
|
||||
|
||||
withSplats = (a = 2, b..., c = 3, d = 5) -> a * (b.length + 1) * c * d
|
||||
eq 30, withSplats()
|
||||
eq 15, withSplats 1
|
||||
eq 5, withSplats 1, 1
|
||||
eq 1, withSplats 1, 1, 1
|
||||
eq 2, withSplats 1, 1, 1, 1
|
||||
@@ -1,72 +0,0 @@
|
||||
# Can assign the result of a try/catch block.
|
||||
result = try
|
||||
nonexistent * missing
|
||||
catch error
|
||||
true
|
||||
|
||||
result2 = try nonexistent * missing catch error then true
|
||||
|
||||
ok result is true and result2 is true
|
||||
|
||||
|
||||
# Can assign a conditional statement.
|
||||
getX = -> 10
|
||||
|
||||
if x = getX() then 100
|
||||
|
||||
ok x is 10
|
||||
|
||||
x = if getX() then 100
|
||||
|
||||
ok x is 100
|
||||
|
||||
|
||||
# This-assignment.
|
||||
tester = ->
|
||||
@example = -> 'example function'
|
||||
this
|
||||
|
||||
ok tester().example() is 'example function'
|
||||
|
||||
|
||||
try throw CoffeeScript.tokens 'in = 1'
|
||||
catch e then eq e.message, 'Reserved word "in" on line 1 can\'t be assigned'
|
||||
|
||||
|
||||
num = 10
|
||||
num -= 5
|
||||
eq num, 5
|
||||
|
||||
num *= 10
|
||||
eq num, 50
|
||||
|
||||
num /= 10
|
||||
eq num, 5
|
||||
|
||||
num %= 3
|
||||
eq num, 2
|
||||
|
||||
val = false
|
||||
val ||= 'value'
|
||||
val ||= 'eulav'
|
||||
eq val, 'value'
|
||||
|
||||
val &&= 'rehto'
|
||||
val &&= 'other'
|
||||
eq val, 'other'
|
||||
|
||||
val = null
|
||||
val ?= 'value'
|
||||
val ?= 'eulav'
|
||||
eq val, 'value'
|
||||
|
||||
|
||||
for nonref in ['""', '0', 'f()']
|
||||
try
|
||||
ok not CoffeeScript.compile "{k: #{nonref}} = v"
|
||||
catch e
|
||||
eq e.message, "\"#{nonref}\" cannot be assigned."
|
||||
|
||||
|
||||
# Compound assignments should not declare.
|
||||
eq Math, (-> Math or= 0)()
|
||||
@@ -1,28 +0,0 @@
|
||||
# Test with break at the top level.
|
||||
array = [1,2,3]
|
||||
callWithLambda = (l) -> null
|
||||
for i in array
|
||||
result = callWithLambda(->)
|
||||
if i == 2
|
||||
console.log "i = 2"
|
||||
else
|
||||
break
|
||||
|
||||
ok result is null
|
||||
|
||||
|
||||
# Test with break *not* at the top level.
|
||||
someFunc = (input) ->
|
||||
takesLambda = (l) -> null
|
||||
for i in [1,2]
|
||||
result = takesLambda(->)
|
||||
if input == 1
|
||||
return 1
|
||||
else
|
||||
break
|
||||
|
||||
return 2
|
||||
|
||||
ok someFunc(1) is 1
|
||||
ok someFunc(2) is 2
|
||||
|
||||
@@ -1,3 +1,11 @@
|
||||
# Chaining
|
||||
# --------
|
||||
|
||||
# shared identity function
|
||||
id = (_) -> if arguments.length is 1 then _ else Array::slice.call(arguments)
|
||||
|
||||
|
||||
|
||||
# Basic chained function calls.
|
||||
identityWrap = (x) ->
|
||||
-> x
|
||||
@@ -57,8 +65,6 @@ func(
|
||||
[[]]]],
|
||||
[]])
|
||||
|
||||
id = (x) -> x
|
||||
|
||||
greeting = id(
|
||||
"""
|
||||
Hello
|
||||
|
||||
@@ -39,17 +39,19 @@ ok result is '9two/three/four'
|
||||
ok (new ThirdChild).array.join(' ') is '1 2 3'
|
||||
|
||||
|
||||
identity = (f) -> f
|
||||
|
||||
class TopClass
|
||||
constructor: (arg) ->
|
||||
@prop = 'top-' + arg
|
||||
|
||||
class SuperClass extends TopClass
|
||||
constructor: (arg) ->
|
||||
super 'super-' + arg
|
||||
identity super 'super-' + arg
|
||||
|
||||
class SubClass extends SuperClass
|
||||
constructor: ->
|
||||
super 'sub'
|
||||
identity super 'sub'
|
||||
|
||||
ok (new SubClass).prop is 'top-super-sub'
|
||||
|
||||
@@ -346,3 +348,25 @@ class A
|
||||
a = new A
|
||||
eq a.captured().x, 10
|
||||
eq a.captured().y, 2
|
||||
|
||||
|
||||
# Issue #924: Static methods in nested classes.
|
||||
class A
|
||||
@B: class
|
||||
@c = -> 5
|
||||
|
||||
eq A.B.c(), 5
|
||||
|
||||
|
||||
# `class extends this` ...
|
||||
class A
|
||||
func: -> 'A'
|
||||
|
||||
B = null
|
||||
makeClass = ->
|
||||
B = class extends this
|
||||
func: -> super + ' B'
|
||||
|
||||
makeClass.call A
|
||||
|
||||
eq (new B()).func(), 'A B'
|
||||
|
||||
@@ -1,158 +0,0 @@
|
||||
# comment before a ...
|
||||
|
||||
###
|
||||
... block comment.
|
||||
###
|
||||
|
||||
|
||||
# comment
|
||||
func = ->
|
||||
# comment
|
||||
false
|
||||
false # comment
|
||||
false
|
||||
|
||||
# comment
|
||||
true
|
||||
|
||||
switch 'string'
|
||||
# comment
|
||||
when false then something()
|
||||
# comment
|
||||
when null
|
||||
somethingElse()
|
||||
|
||||
->
|
||||
code()
|
||||
# comment
|
||||
|
||||
ok func()
|
||||
|
||||
func
|
||||
func
|
||||
# Line3
|
||||
|
||||
obj = {
|
||||
# comment
|
||||
# comment
|
||||
# comment
|
||||
one: 1
|
||||
# comment
|
||||
two: 2
|
||||
# comment
|
||||
}
|
||||
|
||||
result = if true # comment
|
||||
false
|
||||
|
||||
ok not result
|
||||
|
||||
result = if false
|
||||
false
|
||||
else # comment
|
||||
45
|
||||
|
||||
ok result is 45
|
||||
|
||||
|
||||
test =
|
||||
'test ' +
|
||||
'test ' + # comment
|
||||
'test'
|
||||
|
||||
ok test is 'test test test'
|
||||
|
||||
###
|
||||
This is a here-comment.
|
||||
Kind of like a heredoc.
|
||||
###
|
||||
|
||||
func = ->
|
||||
###
|
||||
Another block comment.
|
||||
###
|
||||
code
|
||||
|
||||
func = ->
|
||||
one = ->
|
||||
two = ->
|
||||
three = ->
|
||||
###
|
||||
block.
|
||||
###
|
||||
four = ->
|
||||
|
||||
fn1 = ->
|
||||
oneLevel = null
|
||||
###
|
||||
This isn't fine.
|
||||
###
|
||||
|
||||
ok ok
|
||||
|
||||
obj = {
|
||||
a: 'b'
|
||||
###
|
||||
comment
|
||||
###
|
||||
c: 'd'
|
||||
}
|
||||
|
||||
# Spaced comments in if / elses.
|
||||
result = if false
|
||||
1
|
||||
|
||||
# comment
|
||||
else if false
|
||||
2
|
||||
|
||||
# comment
|
||||
else
|
||||
3
|
||||
|
||||
ok result is 3
|
||||
|
||||
|
||||
result = switch 'z'
|
||||
when 'z' then 7
|
||||
# comment
|
||||
ok result is 7
|
||||
|
||||
|
||||
# Trailing-line comment before an outdent.
|
||||
func = ->
|
||||
if true
|
||||
true # comment
|
||||
7
|
||||
|
||||
ok func() is 7
|
||||
|
||||
|
||||
# Trailing herecomment in a function.
|
||||
fn = ->
|
||||
code
|
||||
###
|
||||
debug code commented
|
||||
###
|
||||
|
||||
fn2 = ->
|
||||
|
||||
|
||||
class A
|
||||
b: ->
|
||||
|
||||
###
|
||||
Comment
|
||||
###
|
||||
c: ->
|
||||
|
||||
ok A.prototype.c instanceof Function
|
||||
|
||||
class A
|
||||
###
|
||||
Comment
|
||||
###
|
||||
b: ->
|
||||
c: ->
|
||||
|
||||
ok A.prototype.b instanceof Function
|
||||
@@ -13,3 +13,14 @@ catch e then eq e.message, 'unclosed CALL_START on line 1'
|
||||
eq CoffeeScript.compile('for k of o then', bare: on, globals: on),
|
||||
'for (k in o) {}'
|
||||
|
||||
# Compilations that should fail.
|
||||
cantCompile = (code) ->
|
||||
throws -> CoffeeScript.compile code
|
||||
|
||||
cantCompile 'a = (break)'
|
||||
|
||||
cantCompile 'a = (return 5 for item in list)'
|
||||
|
||||
cantCompile 'a = (return 5 while condition)'
|
||||
|
||||
cantCompile 'a = for x in y\n return 5'
|
||||
@@ -76,7 +76,7 @@ all = 1
|
||||
# Ensure that the closure wrapper preserves local variables.
|
||||
obj = {}
|
||||
|
||||
for method in ['one', 'two', 'three']
|
||||
for method in ['one', 'two', 'three'] then do (method) ->
|
||||
obj[method] = ->
|
||||
"I'm " + method
|
||||
|
||||
@@ -84,6 +84,8 @@ ok obj.one() is "I'm one"
|
||||
ok obj.two() is "I'm two"
|
||||
ok obj.three() is "I'm three"
|
||||
|
||||
|
||||
# Index values at the end of a loop.
|
||||
i = 0
|
||||
for i in [1..3]
|
||||
-> 'func'
|
||||
@@ -93,9 +95,10 @@ ok i is 4
|
||||
|
||||
# Ensure that local variables are closed over for range comprehensions.
|
||||
funcs = for i in [1..3]
|
||||
-> -i
|
||||
do (i) ->
|
||||
-> -i
|
||||
|
||||
ok (func() for func in funcs).join(' ') is '-1 -2 -3'
|
||||
eq (func() for func in funcs).join(' '), '-1 -2 -3'
|
||||
ok i is 4
|
||||
|
||||
|
||||
@@ -103,7 +106,8 @@ ok i is 4
|
||||
list = ['one', 'two', 'three']
|
||||
|
||||
methods = for num, i in list when num isnt 'two' and i isnt 1
|
||||
-> num + ' ' + i
|
||||
do (num, i) ->
|
||||
-> num + ' ' + i
|
||||
|
||||
ok methods.length is 2
|
||||
ok methods[0]() is 'one 0'
|
||||
@@ -114,18 +118,20 @@ ok methods[1]() is 'three 2'
|
||||
funcs = []
|
||||
|
||||
for i in [1..3]
|
||||
x = i * 2
|
||||
((z)->
|
||||
funcs.push -> z + ' ' + i
|
||||
)(x)
|
||||
do (i) ->
|
||||
x = i * 2
|
||||
((z)->
|
||||
funcs.push -> z + ' ' + i
|
||||
)(x)
|
||||
|
||||
ok (func() for func in funcs).join(', ') is '2 1, 4 2, 6 3'
|
||||
|
||||
funcs = []
|
||||
|
||||
results = for i in [1..3]
|
||||
z = (x * 3 for x in [1..i])
|
||||
((a, b, c) -> [a, b, c].join(' ')).apply this, z
|
||||
do (i) ->
|
||||
z = (x * 3 for x in [1..i])
|
||||
((a, b, c) -> [a, b, c].join(' ')).apply this, z
|
||||
|
||||
ok results.join(', ') is '3 , 3 6 , 3 6 9'
|
||||
|
||||
@@ -135,6 +141,29 @@ array = [0..10]
|
||||
ok(num % 2 is 0 for num in array by 2)
|
||||
|
||||
|
||||
# Nested shared scopes.
|
||||
foo = ->
|
||||
for i in [0..7]
|
||||
do (i) ->
|
||||
for j in [0..7]
|
||||
do (j) ->
|
||||
-> i + j
|
||||
|
||||
eq foo()[3][4](), 7
|
||||
|
||||
|
||||
# Scoped loop pattern matching.
|
||||
a = [[0], [1]]
|
||||
funcs = []
|
||||
|
||||
for [v] in a
|
||||
do (v) ->
|
||||
funcs.push -> v
|
||||
|
||||
eq funcs[0](), 0
|
||||
eq funcs[1](), 1
|
||||
|
||||
|
||||
# Nested comprehensions.
|
||||
multiLiner =
|
||||
for x in [3..5]
|
||||
@@ -221,23 +250,69 @@ odds = while i--
|
||||
ok odds.join(', ') is '5, 3, 1'
|
||||
|
||||
|
||||
# Nested shared scopes.
|
||||
foo = ->
|
||||
for i in [0..7]
|
||||
for j in [0..7]
|
||||
-> i + j
|
||||
|
||||
eq foo()[3][4](), 7
|
||||
|
||||
|
||||
# Issue #897: Ensure that plucked function variables aren't leaked.
|
||||
facets = {}
|
||||
list = ['one', 'two']
|
||||
|
||||
(->
|
||||
for entity in list
|
||||
facets[entity] = -> entity
|
||||
facets[entity] = -> entity
|
||||
)()
|
||||
|
||||
eq typeof entity, 'undefined'
|
||||
eq facets['two'](), 'two'
|
||||
|
||||
|
||||
# Issue #905. Soaks as the for loop subject.
|
||||
a = {b: {c: [1, 2, 3]}}
|
||||
for d in a.b?.c
|
||||
e = d
|
||||
|
||||
eq e, 3
|
||||
|
||||
|
||||
# Issue #948. Capturing loop variables.
|
||||
funcs = []
|
||||
list = ->
|
||||
[1, 2, 3]
|
||||
|
||||
for y in list()
|
||||
do (y) ->
|
||||
z = y
|
||||
funcs.push -> "y is #{y} and z is #{z}"
|
||||
|
||||
eq funcs[1](), "y is 2 and z is 2"
|
||||
|
||||
|
||||
# Cancel the comprehension if there's a jump inside the loop.
|
||||
result = try
|
||||
for i in [0...10]
|
||||
continue if i < 5
|
||||
i
|
||||
|
||||
eq result, 10
|
||||
|
||||
|
||||
# Comprehensions over break.
|
||||
arrayEq (break for [1..10]), []
|
||||
|
||||
# Comprehensions over continue.
|
||||
arrayEq (break for [1..10]), []
|
||||
|
||||
|
||||
# Comprehensions over function literals.
|
||||
a = 0
|
||||
for f in [-> a = 1]
|
||||
do (f) ->
|
||||
do f
|
||||
|
||||
eq a, 1
|
||||
|
||||
|
||||
# Comprehensions that mention arguments.
|
||||
list = [arguments: 10]
|
||||
args = for f in list
|
||||
do (f) ->
|
||||
f.arguments
|
||||
|
||||
eq args[0], 10
|
||||
|
||||
@@ -22,18 +22,18 @@ obj = {
|
||||
name: 'Fred'
|
||||
|
||||
bound: ->
|
||||
(=> eq this, obj)()
|
||||
do (=> eq this, obj)
|
||||
|
||||
unbound: ->
|
||||
(-> ok this isnt obj)()
|
||||
do (-> ok this isnt obj)
|
||||
|
||||
nested: ->
|
||||
(=>
|
||||
(=>
|
||||
do (=>
|
||||
(=>
|
||||
eq this, obj
|
||||
)()
|
||||
)()
|
||||
)
|
||||
)()
|
||||
}
|
||||
|
||||
@@ -366,4 +366,14 @@ class Foo
|
||||
|
||||
new Foo().bar([101]...)
|
||||
|
||||
eq x, 101
|
||||
eq x, 101
|
||||
|
||||
|
||||
test "#904: Destructuring function arguments with same-named variables in scope", ->
|
||||
a = b = nonce = {}
|
||||
fn = ([a,b]) -> {a:a,b:b}
|
||||
result = fn([c={},d={}])
|
||||
eq c, result.a
|
||||
eq d, result.b
|
||||
eq nonce, a
|
||||
eq nonce, b
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
{starts, ends, compact, count, merge, extend, flatten, del, last} = CoffeeScript.helpers
|
||||
|
||||
array = [0, 1, 2, 3, 4]
|
||||
string = array.join ''
|
||||
object = {}
|
||||
|
||||
# Test `starts`
|
||||
ok starts string, '012'
|
||||
ok starts string, '34', 3
|
||||
ok not starts string, '42'
|
||||
ok not starts string, '42', 6
|
||||
|
||||
# Test `ends`
|
||||
ok ends string, '234'
|
||||
ok ends string, '01', 3
|
||||
ok not ends string, '42'
|
||||
ok not ends string, '42', 6
|
||||
|
||||
# Test `merge`
|
||||
merged = merge object, array
|
||||
ok merged isnt object
|
||||
eq merged[3], 3
|
||||
|
||||
# Test `extend`
|
||||
ok object is extend object, array
|
||||
eq object[3], 3
|
||||
|
||||
# Test `flatten`
|
||||
ay = yes
|
||||
(ay and= typeof n is 'number') for n in flatten [0, [[1], 2], 3, [4]]
|
||||
ok ay
|
||||
|
||||
# Test `del`
|
||||
eq 1, del object, 1
|
||||
ok 1 not of object
|
||||
|
||||
# Test `last`
|
||||
eq 4, last array
|
||||
eq 2, last array, 2
|
||||
@@ -1,149 +0,0 @@
|
||||
a = b = d = true
|
||||
c = false
|
||||
|
||||
result = if a
|
||||
if b
|
||||
if c then false else
|
||||
if d
|
||||
true
|
||||
|
||||
ok result
|
||||
|
||||
|
||||
first = if false then false else second = if false then false else true
|
||||
|
||||
ok first
|
||||
ok second
|
||||
|
||||
|
||||
result = if false
|
||||
false
|
||||
else if NaN
|
||||
false
|
||||
else
|
||||
true
|
||||
|
||||
ok result
|
||||
|
||||
|
||||
# Testing unless.
|
||||
result = unless true
|
||||
10
|
||||
else
|
||||
11
|
||||
|
||||
ok result is 11
|
||||
|
||||
|
||||
# Nested inline if statements.
|
||||
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
|
||||
ok func() is -1
|
||||
|
||||
|
||||
# Testing empty or commented if statements ... should compile:
|
||||
result = if false
|
||||
else if false
|
||||
else
|
||||
|
||||
ok result is undefined
|
||||
|
||||
result = if false
|
||||
# comment
|
||||
else if true
|
||||
# comment
|
||||
else
|
||||
|
||||
ok result is undefined
|
||||
|
||||
|
||||
# Return an if with no else.
|
||||
func = ->
|
||||
return if false then callback()
|
||||
|
||||
ok func() is undefined
|
||||
|
||||
func = ->
|
||||
return unless false then 100 else -100
|
||||
|
||||
ok func() is 100
|
||||
|
||||
ident = (x) -> x
|
||||
result = ident if false then 300 else 100
|
||||
|
||||
ok result is 100
|
||||
|
||||
|
||||
# If-to-ternary with instanceof requires parentheses (no comment).
|
||||
if {} instanceof Object
|
||||
ok yes
|
||||
else
|
||||
ok no
|
||||
|
||||
try
|
||||
{} + {}
|
||||
ok yes
|
||||
catch e
|
||||
ok no
|
||||
|
||||
|
||||
# If-to-ternary as part of a larger operation requires parens.
|
||||
x = 1
|
||||
result = x + if false then 10 else 1
|
||||
ok result is 2
|
||||
|
||||
|
||||
# If/else indented within an assignment.
|
||||
func = ->
|
||||
a =
|
||||
if false
|
||||
3
|
||||
else
|
||||
5
|
||||
101
|
||||
a
|
||||
|
||||
ok func() is 5
|
||||
|
||||
|
||||
# Unmatched 'then' should catch implicit calls.
|
||||
i = 1
|
||||
isTrue = (x) -> x is true
|
||||
|
||||
if isTrue yes then i += 1
|
||||
|
||||
ok i is 2
|
||||
|
||||
# If/else with a suppressed indentation via assignment.
|
||||
result =
|
||||
if false then 10
|
||||
else if no then 20
|
||||
else if 0 then 30
|
||||
else if NaN then 40
|
||||
else 50 +
|
||||
if false then 10
|
||||
else 20
|
||||
|
||||
ok result is 70
|
||||
|
||||
if 'tight formatting with leading `then` is allowed'
|
||||
then ok 'yay'
|
||||
else throw 'boo'
|
||||
|
||||
# Issue #738
|
||||
func = if true then -> 1
|
||||
eq func(), 1
|
||||
|
||||
|
||||
# Issue #748. Trailing reserved identifiers.
|
||||
obj = delete: true
|
||||
|
||||
result = if obj.delete
|
||||
101
|
||||
|
||||
ok result is 101
|
||||
@@ -1,3 +0,0 @@
|
||||
# Check if we can import and execute a CoffeeScript-only module successfully.
|
||||
if require?.extensions? or require?.registerExtension?
|
||||
ok require('./test_module').func() is "from over there"
|
||||
@@ -140,6 +140,7 @@ ok obj.fn() is null
|
||||
|
||||
# Implicit arguments to function calls:
|
||||
func = (obj) -> obj.a
|
||||
func2 = -> arguments
|
||||
|
||||
result = func
|
||||
a: 10
|
||||
@@ -159,6 +160,27 @@ obj =
|
||||
ok obj.one is 'one'
|
||||
ok obj.two is 'three'
|
||||
|
||||
a = b = undefined
|
||||
|
||||
result = func
|
||||
b:1
|
||||
a
|
||||
|
||||
ok result is undefined
|
||||
|
||||
result = func
|
||||
a:
|
||||
b:2
|
||||
b:1
|
||||
ok result.b is 2
|
||||
|
||||
result = func2
|
||||
a:1
|
||||
b
|
||||
c:1
|
||||
|
||||
ok result.length is 3
|
||||
ok result[2].c is 1
|
||||
|
||||
# Implicit objects with wacky indentation:
|
||||
obj =
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
# This file is imported by `testImporting.coffee`
|
||||
if exports?
|
||||
local = "from over there"
|
||||
exports.func = -> local
|
||||
@@ -1,184 +0,0 @@
|
||||
# CoffeeScript's operations should be chainable, like Python's.
|
||||
ok 500 > 50 > 5 > -5
|
||||
|
||||
# Some chainable operators can be negated by `unless`
|
||||
ok (true unless 0==10!=100)
|
||||
|
||||
ok true is not false is true is not false
|
||||
|
||||
ok 0 is 0 isnt 50 is 50
|
||||
|
||||
ok 10 < 20 > 10
|
||||
|
||||
ok 50 > 10 > 5 is parseInt('5', 10)
|
||||
|
||||
eq 1, 1 | 2 < 3 < 4
|
||||
|
||||
ok 1 == 1 <= 1, '`x == y <= z` should become `x === y && y <= z`'
|
||||
|
||||
i = 0
|
||||
ok 1 > i++ < 1, 'chained operations should evaluate each value only once'
|
||||
|
||||
|
||||
# `==` and `is` should be interchangeable.
|
||||
a = b = 1
|
||||
|
||||
ok a is 1 and b is 1
|
||||
ok a == b
|
||||
ok a is b
|
||||
|
||||
|
||||
# Allow "if x not in y"
|
||||
obj = {a: true}
|
||||
ok 'a' of obj
|
||||
ok 'b' not of obj
|
||||
|
||||
# And for "a in b" with array presence.
|
||||
ok 200 in [100, 200, 300]
|
||||
array = [100, 200, 300]
|
||||
ok 200 in array
|
||||
ok 1 not in array
|
||||
ok array[0]++ in [99, 100], 'should cache testee'
|
||||
|
||||
# And with array presence on an instance variable.
|
||||
obj = {
|
||||
list: [1, 2, 3, 4, 5]
|
||||
in_list: (value) -> value in @list
|
||||
}
|
||||
ok obj.in_list 4
|
||||
ok not obj.in_list 0
|
||||
|
||||
# Non-spaced values still work.
|
||||
x = 10
|
||||
y = -5
|
||||
|
||||
ok x*-y is 50
|
||||
ok x*+y is -50
|
||||
|
||||
|
||||
# Compound operators.
|
||||
one = 1
|
||||
two = 0
|
||||
one or= 2
|
||||
two or= 2
|
||||
|
||||
eq one, 1
|
||||
eq two, 2
|
||||
|
||||
zero = 0
|
||||
|
||||
zero and= 'one'
|
||||
one and= 'one'
|
||||
|
||||
eq zero, 0
|
||||
eq one , 'one'
|
||||
|
||||
|
||||
# Compound assignment should be careful about caching variables.
|
||||
count = 0
|
||||
list = []
|
||||
|
||||
list[++count] or= 1
|
||||
eq list[1], 1
|
||||
eq count, 1
|
||||
|
||||
list[++count] ?= 2
|
||||
eq list[2], 2
|
||||
eq count, 2
|
||||
|
||||
list[count++] and= 'two'
|
||||
eq list[2], 'two'
|
||||
eq count, 3
|
||||
|
||||
base = -> ++count; base
|
||||
|
||||
base().four or= 4
|
||||
eq base.four, 4
|
||||
eq count, 4
|
||||
|
||||
base().five ?= 5
|
||||
eq base.five, 5
|
||||
eq count, 5
|
||||
|
||||
|
||||
# Ensure that RHS is treated as a group.
|
||||
a = b = false
|
||||
a and= b or true
|
||||
ok a is false
|
||||
|
||||
|
||||
# Bitwise operators:
|
||||
ok (10 & 3) is 2
|
||||
ok (10 | 3) is 11
|
||||
ok (10 ^ 3) is 9
|
||||
ok (10 << 3) is 80
|
||||
ok (10 >> 3) is 1
|
||||
ok (10 >>> 3) is 1
|
||||
|
||||
num = 10; ok (num <<= 3) is 80
|
||||
num = 10; ok (num >>= 3) is 1
|
||||
num = 10; ok (num >>>= 3) is 1
|
||||
num = 10; ok (num &= 3) is 2
|
||||
num = 10; ok (num ^= 3) is 9
|
||||
num = 10; ok (num |= 3) is 11
|
||||
|
||||
|
||||
# Compound assignment with implicit objects.
|
||||
obj = undefined
|
||||
obj ?=
|
||||
one: 1
|
||||
|
||||
ok obj.one is 1
|
||||
|
||||
obj and=
|
||||
two: 2
|
||||
|
||||
ok not obj.one
|
||||
ok obj.two is 2
|
||||
|
||||
|
||||
# Compound assignment as a sub expression.
|
||||
[a, b, c] = [1, 2, 3]
|
||||
ok (a + b += c) is 6
|
||||
ok a is 1
|
||||
ok b is 5
|
||||
ok c is 3
|
||||
|
||||
|
||||
# Instanceof.
|
||||
ok new String instanceof String
|
||||
ok new Number not instanceof String
|
||||
|
||||
|
||||
#737: `in` should have higher precedence than logical operators.
|
||||
eq 1, 1 in [1] and 1
|
||||
|
||||
#768: `in` should preserve evaluation order.
|
||||
share = 0
|
||||
a = -> share++ if share is 0
|
||||
b = -> share++ if share is 1
|
||||
c = -> share++ if share is 2
|
||||
ok a() not in [b(),c()] and share is 3
|
||||
|
||||
# `in` with cache and `__indexOf` should work in commaed lists.
|
||||
eq [Object() in Array()].length, 1
|
||||
|
||||
|
||||
# Operators should respect new lines as spaced.
|
||||
a = (123) +
|
||||
456
|
||||
ok a is 579
|
||||
|
||||
a = "1#{2}3" +
|
||||
"456"
|
||||
ok a is '123456'
|
||||
|
||||
|
||||
# Multiple operators should space themselves.
|
||||
ok + +1 is - -1
|
||||
|
||||
#891: incorrect inversion of chained comparisons
|
||||
(->
|
||||
ok (true unless 0 > 1 > 2)
|
||||
ok (true unless (NaN = 0/0) < 0/0 < NaN)
|
||||
)()
|
||||
@@ -1,74 +0,0 @@
|
||||
# # Slice.
|
||||
array = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
|
||||
|
||||
a = array[7..9]
|
||||
b = array[2...4]
|
||||
|
||||
result = a.concat(b).join(' ')
|
||||
|
||||
ok result is "7 8 9 2 3"
|
||||
|
||||
a = [0, 1, 2, 3, 4, 5, 6, 7]
|
||||
eq a[2...6].join(' '), '2 3 4 5'
|
||||
|
||||
|
||||
# Ranges.
|
||||
countdown = [10..1].join(' ')
|
||||
ok countdown is "10 9 8 7 6 5 4 3 2 1"
|
||||
|
||||
a = 1
|
||||
b = 5
|
||||
nums = [a...b]
|
||||
ok nums.join(' ') is '1 2 3 4'
|
||||
|
||||
b = -5
|
||||
nums = [a..b]
|
||||
ok nums.join(' ') is '1 0 -1 -2 -3 -4 -5'
|
||||
|
||||
|
||||
# Expression-based range.
|
||||
array = [(1+5)..1+9]
|
||||
ok array.join(' ') is "6 7 8 9 10"
|
||||
|
||||
array = [5..1]
|
||||
ok array.join(' ') is '5 4 3 2 1'
|
||||
|
||||
array = [30...0]
|
||||
ok (len = array.length) is 30
|
||||
ok array[len - 1] is 1
|
||||
|
||||
|
||||
|
||||
# String slicing (at least on Node).
|
||||
hello = "Hello World"
|
||||
|
||||
ok hello[1...1] is ""
|
||||
ok hello[1..1] is "e"
|
||||
ok hello[1...5] is "ello"
|
||||
ok hello[0..4] is "Hello"
|
||||
|
||||
|
||||
# Splice literals.
|
||||
array = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
|
||||
|
||||
array[5..10] = [0, 0, 0]
|
||||
|
||||
ok array.join(' ') is '0 1 2 3 4 0 0 0'
|
||||
|
||||
|
||||
# Slices and splices that omit their beginning or end.
|
||||
array = [0..10]
|
||||
|
||||
ok array[7..].join(' ') is '7 8 9 10'
|
||||
ok array[-2..].join(' ') is '9 10'
|
||||
|
||||
ok array[...3].join(' ') is '0 1 2'
|
||||
ok array[..-5].join(' ') is '0 1 2 3 4 5 6'
|
||||
|
||||
array[3..] = [9, 8, 7]
|
||||
|
||||
ok array.join(' ') is '0 1 2 9 8 7'
|
||||
|
||||
array[...3] = [7, 8, 9]
|
||||
|
||||
ok array.join(' ') is '7 8 9 9 8 7'
|
||||