Compare commits
201 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 | ||
|
|
fa53a4c057 | ||
|
|
edd0c5af5a | ||
|
|
2fb269a938 | ||
|
|
3eac6aeb99 | ||
|
|
ec64646fee | ||
|
|
5371268f8f | ||
|
|
2decb30d4e | ||
|
|
c0bbc609be | ||
|
|
f6be426aa0 | ||
|
|
17b5c8ac6f | ||
|
|
b18d0d75fd | ||
|
|
77e13e459b | ||
|
|
06647bdd0a | ||
|
|
24183d9a39 | ||
|
|
1e080cc258 | ||
|
|
dc5854689b | ||
|
|
ed70b9d4d0 | ||
|
|
c7a9801db7 | ||
|
|
85521f88b2 | ||
|
|
75ca0f23ac | ||
|
|
eba73f6844 | ||
|
|
cf45da33f6 | ||
|
|
fb7498a8ec | ||
|
|
574f9afa3d | ||
|
|
3751ac1784 | ||
|
|
af759dcf42 | ||
|
|
47426c28e1 | ||
|
|
49f7775d2d | ||
|
|
67c20c0715 | ||
|
|
c50cb65019 | ||
|
|
23b4d2fd1d | ||
|
|
dd18703b50 | ||
|
|
b1ba298ffc | ||
|
|
992324b425 | ||
|
|
56e10f9bce | ||
|
|
69664a1bb3 | ||
|
|
1f5727fe9d | ||
|
|
b52a1ed60a | ||
|
|
c3f1820ebc | ||
|
|
4afa6a2887 | ||
|
|
1254efaddb | ||
|
|
adeace8f62 | ||
|
|
4447180d5a | ||
|
|
41beccbe3c | ||
|
|
a4958e76c1 | ||
|
|
a9e264dd84 | ||
|
|
51988dba09 | ||
|
|
39c4c23200 | ||
|
|
63cbb64341 | ||
|
|
c0cb0c35e2 | ||
|
|
9db6d6f4ef | ||
|
|
57bd6bc2cd |
11
.npmignore
Normal file
@@ -0,0 +1,11 @@
|
||||
*.coffee
|
||||
*.html
|
||||
.DS_Store
|
||||
.git*
|
||||
Cakefile
|
||||
documentation/
|
||||
examples/
|
||||
extras/
|
||||
raw/
|
||||
src/
|
||||
test/
|
||||
69
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,32 +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
|
||||
for all name, func of require 'assert'
|
||||
startTime = Date.now()
|
||||
currentFile = null
|
||||
passedTests = 0
|
||||
failures = []
|
||||
|
||||
# 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', ->
|
||||
@@ -178,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
|
||||
|
||||
57
Rakefile
@@ -1,6 +1,8 @@
|
||||
require 'rubygems'
|
||||
require 'erb'
|
||||
require 'fileutils'
|
||||
require 'rake/testtask'
|
||||
require 'json'
|
||||
|
||||
desc "Build the documentation page"
|
||||
task :doc do
|
||||
@@ -19,3 +21,58 @@ task :doc do
|
||||
end
|
||||
end
|
||||
|
||||
desc "Build coffee-script-source gem"
|
||||
task :gem do
|
||||
require 'rubygems'
|
||||
require 'rubygems/package'
|
||||
|
||||
gemspec = Gem::Specification.new do |s|
|
||||
s.name = 'coffee-script-source'
|
||||
s.version = JSON.parse(File.read('package.json'))["version"]
|
||||
s.date = Time.now.strftime("%Y-%m-%d")
|
||||
|
||||
s.homepage = "http://jashkenas.github.com/coffee-script/"
|
||||
s.summary = "The CoffeeScript Compiler"
|
||||
s.description = <<-EOS
|
||||
CoffeeScript is a little language that compiles into JavaScript.
|
||||
Underneath all of those embarrassing braces and semicolons,
|
||||
JavaScript has always had a gorgeous object model at its heart.
|
||||
CoffeeScript is an attempt to expose the good parts of JavaScript
|
||||
in a simple way.
|
||||
EOS
|
||||
|
||||
s.files = [
|
||||
'lib/coffee_script/coffee-script.js',
|
||||
'lib/coffee_script/source.rb'
|
||||
]
|
||||
|
||||
s.authors = ['Jeremy Ashkenas']
|
||||
s.email = 'jashkenas@gmail.com'
|
||||
s.rubyforge_project = 'coffee-script-source'
|
||||
end
|
||||
|
||||
file = File.open("coffee-script-source.gem", "w")
|
||||
Gem::Package.open(file, 'w') do |pkg|
|
||||
pkg.metadata = gemspec.to_yaml
|
||||
|
||||
path = "lib/coffee_script/source.rb"
|
||||
contents = <<-ERUBY
|
||||
module CoffeeScript
|
||||
module Source
|
||||
def self.bundled_path
|
||||
File.expand_path("../coffee-script.js", __FILE__)
|
||||
end
|
||||
end
|
||||
end
|
||||
ERUBY
|
||||
pkg.add_file_simple(path, 0644, contents.size) do |tar_io|
|
||||
tar_io.write(contents)
|
||||
end
|
||||
|
||||
contents = File.read("extras/coffee-script.js")
|
||||
path = "lib/coffee_script/coffee-script.js"
|
||||
pkg.add_file_simple(path, 0644, contents.size) do |tar_io|
|
||||
tar_io.write(contents)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,7 +1,2 @@
|
||||
# Eat lunch.
|
||||
lunch = eat food for food in ['toast', 'cheese', 'wine']
|
||||
|
||||
# Naive collision detection.
|
||||
for roid, pos in asteroids
|
||||
for roid2 in asteroids when roid isnt roid2
|
||||
roid.explode() if roid.overlaps roid2
|
||||
eat food for food in ['toast', 'cheese', 'wine']
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
###
|
||||
CoffeeScript Compiler v0.9.5
|
||||
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, "-"
|
||||
|
||||
|
||||
7
documentation/coffee/slices.coffee
Normal file
@@ -0,0 +1,7 @@
|
||||
numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
|
||||
|
||||
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
|
||||
|
||||
|
||||
|
||||
5
documentation/coffee/splices.coffee
Normal file
@@ -0,0 +1,5 @@
|
||||
numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
|
||||
|
||||
numbers[3..6] = [-3, -4, -5, -6]
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -76,26 +79,35 @@ code, pre, tt, textarea {
|
||||
margin-left: 0;
|
||||
padding-left: 0;
|
||||
}
|
||||
.timestamp {
|
||||
font-size: 12px;
|
||||
font-weight: normal;
|
||||
color: black;
|
||||
}
|
||||
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;
|
||||
@@ -116,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;
|
||||
}
|
||||
@@ -153,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 {
|
||||
@@ -247,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;
|
||||
}
|
||||
@@ -31,7 +31,7 @@ If no tasks are passed, print the help screen.</p> </td>
|
||||
<span class="nv">options = </span><span class="nx">oparse</span><span class="p">.</span><span class="nx">parse</span><span class="p">(</span><span class="nx">args</span><span class="p">)</span>
|
||||
<span class="nx">invoke</span> <span class="nx">arg</span> <span class="k">for</span> <span class="nx">arg</span> <span class="k">in</span> <span class="nx">options</span><span class="p">.</span><span class="nx">arguments</span></pre></div> </td> </tr> <tr id="section-9"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-9">¶</a> </div> <p>Display the list of Cake tasks in a format similar to <code>rake -T</code></p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">printTasks = </span><span class="o">-></span>
|
||||
<span class="nx">console</span><span class="p">.</span><span class="nx">log</span> <span class="s1">''</span>
|
||||
<span class="k">for</span> <span class="nx">all</span> <span class="nx">name</span><span class="p">,</span> <span class="nx">task</span> <span class="k">of</span> <span class="nx">tasks</span>
|
||||
<span class="k">for</span> <span class="nx">name</span><span class="p">,</span> <span class="nx">task</span> <span class="k">of</span> <span class="nx">tasks</span>
|
||||
<span class="nv">spaces = </span><span class="mi">20</span> <span class="o">-</span> <span class="nx">name</span><span class="p">.</span><span class="nx">length</span>
|
||||
<span class="nv">spaces = </span><span class="k">if</span> <span class="nx">spaces</span> <span class="o">></span> <span class="mi">0</span> <span class="k">then</span> <span class="nb">Array</span><span class="p">(</span><span class="nx">spaces</span> <span class="o">+</span> <span class="mi">1</span><span class="p">).</span><span class="nx">join</span><span class="p">(</span><span class="s1">' '</span><span class="p">)</span> <span class="k">else</span> <span class="s1">''</span>
|
||||
<span class="nv">desc = </span><span class="k">if</span> <span class="nx">task</span><span class="p">.</span><span class="nx">description</span> <span class="k">then</span> <span class="s2">"# #{task.description}"</span> <span class="k">else</span> <span class="s1">''</span>
|
||||
|
||||
@@ -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.5'</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>
|
||||
|
||||
@@ -4,16 +4,21 @@ into various forms: saved into <code>.js</code> files or printed to stdout, pipe
|
||||
saved, printed as a token stream or as the syntax tree, or launch an
|
||||
interactive REPL.</p> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-2"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-2">¶</a> </div> <p>External dependencies.</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="nv">util = </span><span class="nx">require</span> <span class="s1">'util'</span>
|
||||
<span class="nv">helpers = </span><span class="nx">require</span> <span class="s1">'./helpers'</span>
|
||||
<span class="nv">optparse = </span><span class="nx">require</span> <span class="s1">'./optparse'</span>
|
||||
<span class="nv">CoffeeScript = </span><span class="nx">require</span> <span class="s1">'./coffee-script'</span>
|
||||
<span class="p">{</span><span class="nx">spawn</span><span class="p">,</span> <span class="nx">exec</span><span class="p">}</span> <span class="o">=</span> <span class="nx">require</span> <span class="s1">'child_process'</span>
|
||||
<span class="p">{</span><span class="nx">EventEmitter</span><span class="p">}</span> <span class="o">=</span> <span class="nx">require</span> <span class="s1">'events'</span></pre></div> </td> </tr> <tr id="section-3"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-3">¶</a> </div> <p>Allow CoffeeScript to emit Node.js events.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nx">helpers</span><span class="p">.</span><span class="nx">extend</span> <span class="nx">CoffeeScript</span><span class="p">,</span> <span class="k">new</span> <span class="nx">EventEmitter</span></pre></div> </td> </tr> <tr id="section-4"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-4">¶</a> </div> <p>The help banner that is printed when <code>coffee</code> is called without arguments.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">BANNER = </span><span class="s1">'''</span>
|
||||
<span class="p">{</span><span class="nx">EventEmitter</span><span class="p">}</span> <span class="o">=</span> <span class="nx">require</span> <span class="s1">'events'</span></pre></div> </td> </tr> <tr id="section-3"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-3">¶</a> </div> <p>Allow CoffeeScript to emit Node.js events.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nx">helpers</span><span class="p">.</span><span class="nx">extend</span> <span class="nx">CoffeeScript</span><span class="p">,</span> <span class="k">new</span> <span class="nx">EventEmitter</span>
|
||||
|
||||
<span class="nv">printLine = </span><span class="p">(</span><span class="nx">line</span><span class="p">)</span> <span class="o">-></span> <span class="nx">process</span><span class="p">.</span><span class="nx">stdout</span><span class="p">.</span><span class="nx">write</span> <span class="nx">line</span> <span class="o">+</span> <span class="s1">'\n'</span>
|
||||
<span class="nv">printWarn = </span><span class="p">(</span><span class="nx">line</span><span class="p">)</span> <span class="o">-></span> <span class="nx">process</span><span class="p">.</span><span class="nx">binding</span><span class="p">(</span><span class="s1">'stdio'</span><span class="p">).</span><span class="nx">writeError</span> <span class="nx">line</span> <span class="o">+</span> <span class="s1">'\n'</span></pre></div> </td> </tr> <tr id="section-4"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-4">¶</a> </div> <p>The help banner that is printed when <code>coffee</code> is called without arguments.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">BANNER = </span><span class="s1">'''</span>
|
||||
<span class="s1"> Usage: coffee [options] path/to/script.coffee</span>
|
||||
<span class="s1"> '''</span></pre></div> </td> </tr> <tr id="section-5"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-5">¶</a> </div> <p>The list of all the valid option flags that <code>coffee</code> knows how to handle.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">SWITCHES = </span><span class="p">[</span>
|
||||
<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>
|
||||
@@ -23,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>
|
||||
@@ -63,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>
|
||||
@@ -76,27 +80,30 @@ requested options. If evaluating the script directly sets <code>__filename</code
|
||||
<span class="nv">t = task = </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">options</span><span class="p">}</span>
|
||||
<span class="nx">CoffeeScript</span><span class="p">.</span><span class="nx">emit</span> <span class="s1">'compile'</span><span class="p">,</span> <span class="nx">task</span>
|
||||
<span class="k">if</span> <span class="nx">o</span><span class="p">.</span><span class="nx">tokens</span> <span class="k">then</span> <span class="nx">printTokens</span> <span class="nx">CoffeeScript</span><span class="p">.</span><span class="nx">tokens</span> <span class="nx">t</span><span class="p">.</span><span class="nx">input</span>
|
||||
<span class="k">else</span> <span class="k">if</span> <span class="nx">o</span><span class="p">.</span><span class="nx">nodes</span> <span class="k">then</span> <span class="nx">console</span><span class="p">.</span><span class="nx">log</span> <span class="nx">CoffeeScript</span><span class="p">.</span><span class="nx">nodes</span><span class="p">(</span><span class="nx">t</span><span class="p">.</span><span class="nx">input</span><span class="p">).</span><span class="nx">toString</span><span class="p">().</span><span class="nx">trim</span><span class="p">()</span>
|
||||
<span class="k">else</span> <span class="k">if</span> <span class="nx">o</span><span class="p">.</span><span class="nx">nodes</span> <span class="k">then</span> <span class="nx">printLine</span> <span class="nx">CoffeeScript</span><span class="p">.</span><span class="nx">nodes</span><span class="p">(</span><span class="nx">t</span><span class="p">.</span><span class="nx">input</span><span class="p">).</span><span class="nx">toString</span><span class="p">().</span><span class="nx">trim</span><span class="p">()</span>
|
||||
<span class="k">else</span> <span class="k">if</span> <span class="nx">o</span><span class="p">.</span><span class="nx">run</span> <span class="k">then</span> <span class="nx">CoffeeScript</span><span class="p">.</span><span class="nx">run</span> <span class="nx">t</span><span class="p">.</span><span class="nx">input</span><span class="p">,</span> <span class="nx">t</span><span class="p">.</span><span class="nx">options</span>
|
||||
<span class="k">else</span>
|
||||
<span class="nv">t.output = </span><span class="nx">CoffeeScript</span><span class="p">.</span><span class="nx">compile</span> <span class="nx">t</span><span class="p">.</span><span class="nx">input</span><span class="p">,</span> <span class="nx">t</span><span class="p">.</span><span class="nx">options</span>
|
||||
<span class="nx">CoffeeScript</span><span class="p">.</span><span class="nx">emit</span> <span class="s1">'success'</span><span class="p">,</span> <span class="nx">task</span>
|
||||
<span class="k">if</span> <span class="nx">o</span><span class="p">.</span><span class="nx">print</span> <span class="k">then</span> <span class="nx">console</span><span class="p">.</span><span class="nx">log</span> <span class="nx">t</span><span class="p">.</span><span class="nx">output</span><span class="p">.</span><span class="nx">trim</span><span class="p">()</span>
|
||||
<span class="k">if</span> <span class="nx">o</span><span class="p">.</span><span class="nx">print</span> <span class="k">then</span> <span class="nx">printLine</span> <span class="nx">t</span><span class="p">.</span><span class="nx">output</span><span class="p">.</span><span class="nx">trim</span><span class="p">()</span>
|
||||
<span class="k">else</span> <span class="k">if</span> <span class="nx">o</span><span class="p">.</span><span class="nx">compile</span> <span class="k">then</span> <span class="nx">writeJs</span> <span class="nx">t</span><span class="p">.</span><span class="nx">file</span><span class="p">,</span> <span class="nx">t</span><span class="p">.</span><span class="nx">output</span><span class="p">,</span> <span class="nx">base</span>
|
||||
<span class="k">else</span> <span class="k">if</span> <span class="nx">o</span><span class="p">.</span><span class="nx">lint</span> <span class="k">then</span> <span class="nx">lint</span> <span class="nx">t</span><span class="p">.</span><span class="nx">file</span><span class="p">,</span> <span class="nx">t</span><span class="p">.</span><span class="nx">output</span>
|
||||
<span class="k">catch</span> <span class="nx">err</span>
|
||||
<span class="nx">CoffeeScript</span><span class="p">.</span><span class="nx">emit</span> <span class="s1">'failure'</span><span class="p">,</span> <span class="nx">err</span><span class="p">,</span> <span class="nx">task</span>
|
||||
<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">console</span><span class="p">.</span><span class="nx">log</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">console</span><span class="p">.</span><span class="nx">error</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="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-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>
|
||||
@@ -108,18 +115,18 @@ 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>
|
||||
<span class="nv">js = </span><span class="s1">' '</span> <span class="k">if</span> <span class="nx">js</span><span class="p">.</span><span class="nx">length</span> <span class="o"><=</span> <span class="mi">0</span>
|
||||
<span class="nx">fs</span><span class="p">.</span><span class="nx">writeFile</span> <span class="nx">jsPath</span><span class="p">,</span> <span class="nx">js</span><span class="p">,</span> <span class="p">(</span><span class="nx">err</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="k">if</span> <span class="nx">err</span> <span class="k">then</span> <span class="nx">console</span><span class="p">.</span><span class="nx">log</span> <span class="nx">err</span><span class="p">.</span><span class="nx">message</span>
|
||||
<span class="k">else</span> <span class="k">if</span> <span class="nx">opts</span><span class="p">.</span><span class="nx">compile</span> <span class="o">and</span> <span class="nx">opts</span><span class="p">.</span><span class="nx">watch</span> <span class="k">then</span> <span class="nx">console</span><span class="p">.</span><span class="nx">log</span> <span class="s2">"Compiled #{source}"</span>
|
||||
<span class="k">if</span> <span class="nx">err</span> <span class="k">then</span> <span class="nx">printLine</span> <span class="nx">err</span><span class="p">.</span><span class="nx">message</span>
|
||||
<span class="k">else</span> <span class="k">if</span> <span class="nx">opts</span><span class="p">.</span><span class="nx">compile</span> <span class="o">and</span> <span class="nx">opts</span><span class="p">.</span><span class="nx">watch</span> <span class="k">then</span> <span class="nx">util</span><span class="p">.</span><span class="nx">log</span> <span class="s2">"compiled #{source}"</span>
|
||||
<span class="nx">path</span><span class="p">.</span><span class="nx">exists</span> <span class="nx">dir</span><span class="p">,</span> <span class="p">(</span><span class="nx">exists</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="k">if</span> <span class="nx">exists</span> <span class="k">then</span> <span class="nx">compile</span><span class="p">()</span> <span class="k">else</span> <span class="nx">exec</span> <span class="s2">"mkdir -p #{dir}"</span><span class="p">,</span> <span class="nx">compile</span></pre></div> </td> </tr> <tr id="section-14"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-14">¶</a> </div> <p>Pipe compiled JS through JSLint (requires a working <code>jsl</code> command), printing
|
||||
any errors or warnings that arise.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">lint = </span><span class="p">(</span><span class="nx">file</span><span class="p">,</span> <span class="nx">js</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nv">printIt = </span><span class="p">(</span><span class="nx">buffer</span><span class="p">)</span> <span class="o">-></span> <span class="nx">console</span><span class="p">.</span><span class="nx">log</span> <span class="nx">file</span> <span class="o">+</span> <span class="s1">':\t'</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="nx">trim</span><span class="p">()</span>
|
||||
<span class="nv">printIt = </span><span class="p">(</span><span class="nx">buffer</span><span class="p">)</span> <span class="o">-></span> <span class="nx">printLine</span> <span class="nx">file</span> <span class="o">+</span> <span class="s1">':\t'</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="nx">trim</span><span class="p">()</span>
|
||||
<span class="nv">conf = </span><span class="nx">__dirname</span> <span class="o">+</span> <span class="s1">'/../extras/jsl.conf'</span>
|
||||
<span class="nv">jsl = </span><span class="nx">spawn</span> <span class="s1">'jsl'</span><span class="p">,</span> <span class="p">[</span><span class="s1">'-nologo'</span><span class="p">,</span> <span class="s1">'-stdin'</span><span class="p">,</span> <span class="s1">'-conf'</span><span class="p">,</span> <span class="nx">conf</span><span class="p">]</span>
|
||||
<span class="nx">jsl</span><span class="p">.</span><span class="nx">stdout</span><span class="p">.</span><span class="kc">on</span> <span class="s1">'data'</span><span class="p">,</span> <span class="nx">printIt</span>
|
||||
@@ -129,20 +136,26 @@ any errors or warnings that arise.</p> </td> <td class="
|
||||
<span class="nv">strings = </span><span class="k">for</span> <span class="nx">token</span> <span class="k">in</span> <span class="nx">tokens</span>
|
||||
<span class="p">[</span><span class="nx">tag</span><span class="p">,</span> <span class="nx">value</span><span class="p">]</span> <span class="o">=</span> <span class="p">[</span><span class="nx">token</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="nx">token</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="nx">toString</span><span class="p">().</span><span class="nx">replace</span><span class="p">(</span><span class="sr">/\n/</span><span class="p">,</span> <span class="s1">'\\n'</span><span class="p">)]</span>
|
||||
<span class="s2">"[#{tag} #{value}]"</span>
|
||||
<span class="nx">console</span><span class="p">.</span><span class="nx">log</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
|
||||
<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">console</span><span class="p">.</span><span class="nx">warn</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">console</span><span class="p">.</span><span class="nx">log</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">console</span><span class="p">.</span><span class="nx">log</span> <span class="s2">"CoffeeScript version #{CoffeeScript.VERSION}"</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-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>
|
||||
|
||||
</pre></div> </td> </tr> </tbody> </table> </div> </body> </html>
|
||||
@@ -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
|
||||
@@ -99,7 +99,6 @@ the ordinary <strong>Assign</strong> is that these allow numbers and strings as
|
||||
<span class="nx">ObjAssignable</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s1">'Identifier'</span>
|
||||
<span class="nx">o</span> <span class="s1">'AlphaNumeric'</span>
|
||||
<span class="nx">o</span> <span class="s1">'Parenthetical'</span>
|
||||
<span class="nx">o</span> <span class="s1">'ThisProperty'</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>A return statement from a function body.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">Return</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s1">'RETURN Expression'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Return</span> <span class="nx">$2</span>
|
||||
@@ -186,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>
|
||||
@@ -263,19 +260,19 @@ 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.raw = </span><span class="nx">$1</span><span class="p">.</span><span class="nx">raw</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>
|
||||
<span class="nx">o</span> <span class="s1">'FOR ForVariables'</span><span class="p">,</span> <span class="o">-></span> <span class="nx">$2</span>
|
||||
<span class="nx">o</span> <span class="s1">'FOR ALL ForVariables'</span><span class="p">,</span> <span class="o">-></span> <span class="nv">$3.raw = </span><span class="kc">yes</span><span class="p">;</span> <span class="nx">$3</span>
|
||||
<span class="nx">o</span> <span class="s1">'FOR OWN ForVariables'</span><span class="p">,</span> <span class="o">-></span> <span class="nv">$3.own = </span><span class="kc">yes</span><span class="p">;</span> <span class="nx">$3</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-54"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-54">¶</a> </div> <p>An array of all accepted values for a variable inside the loop.
|
||||
This enables support for pattern matching.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">ForValue</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s1">'Identifier'</span>
|
||||
@@ -314,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
|
||||
@@ -382,13 +376,13 @@ 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)
|
||||
as "tokens".</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">tokens = </span><span class="p">[]</span>
|
||||
<span class="k">for</span> <span class="nx">all</span> <span class="nx">name</span><span class="p">,</span> <span class="nx">alternatives</span> <span class="k">of</span> <span class="nx">grammar</span>
|
||||
<span class="k">for</span> <span class="nx">name</span><span class="p">,</span> <span class="nx">alternatives</span> <span class="k">of</span> <span class="nx">grammar</span>
|
||||
<span class="nx">grammar</span><span class="p">[</span><span class="nx">name</span><span class="p">]</span> <span class="o">=</span> <span class="k">for</span> <span class="nx">alt</span> <span class="k">in</span> <span class="nx">alternatives</span>
|
||||
<span class="k">for</span> <span class="nx">token</span> <span class="k">in</span> <span class="nx">alt</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="nx">split</span> <span class="s1">' '</span>
|
||||
<span class="nx">tokens</span><span class="p">.</span><span class="nx">push</span> <span class="nx">token</span> <span class="nx">unless</span> <span class="nx">grammar</span><span class="p">[</span><span class="nx">token</span><span class="p">]</span>
|
||||
|
||||
@@ -4,14 +4,15 @@ 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>
|
||||
<span class="nx">extend</span> <span class="p">(</span><span class="nx">extend</span> <span class="p">{},</span> <span class="nx">options</span><span class="p">),</span> <span class="nx">overrides</span></pre></div> </td> </tr> <tr id="section-7"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-7">¶</a> </div> <p>Extend a source object with the properties of another object (shallow copy).</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">extend = exports.extend = </span><span class="p">(</span><span class="nx">object</span><span class="p">,</span> <span class="nx">properties</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="k">for</span> <span class="nx">all</span> <span class="nx">key</span><span class="p">,</span> <span class="nx">val</span> <span class="k">of</span> <span class="nx">properties</span>
|
||||
<span class="k">for</span> <span class="nx">key</span><span class="p">,</span> <span class="nx">val</span> <span class="k">of</span> <span class="nx">properties</span>
|
||||
<span class="nx">object</span><span class="p">[</span><span class="nx">key</span><span class="p">]</span> <span class="o">=</span> <span class="nx">val</span>
|
||||
<span class="nx">object</span></pre></div> </td> </tr> <tr id="section-8"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-8">¶</a> </div> <p>Return a flattened version of an array.
|
||||
Handy for getting a list of <code>children</code> from the nodes.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.flatten = flatten = </span><span class="p">(</span><span class="nx">array</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>
|
||||
|
||||
@@ -5,15 +5,16 @@ Using it looks like this:</p>
|
||||
<pre><code>coffee> console.log "#{num} bottles of beer" for num in [99..1]
|
||||
</code></pre> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-2"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-2">¶</a> </div> <p>Require the <strong>coffee-script</strong> module to get access to the compiler.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">CoffeeScript = </span><span class="nx">require</span> <span class="s1">'./coffee-script'</span>
|
||||
<span class="nv">helpers = </span><span class="nx">require</span> <span class="s1">'./helpers'</span>
|
||||
<span class="nv">readline = </span><span class="nx">require</span> <span class="s1">'readline'</span></pre></div> </td> </tr> <tr id="section-3"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-3">¶</a> </div> <p>Start by opening up <strong>stdio</strong>.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">stdio = </span><span class="nx">process</span><span class="p">.</span><span class="nx">openStdin</span><span class="p">()</span></pre></div> </td> </tr> <tr id="section-4"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-4">¶</a> </div> <p>Quick alias for quitting the REPL.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nx">helpers</span><span class="p">.</span><span class="nx">extend</span> <span class="nx">global</span><span class="p">,</span> <span class="nx">quit</span><span class="o">:</span> <span class="o">-></span> <span class="nx">process</span><span class="p">.</span><span class="nx">exit</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span></pre></div> </td> </tr> <tr id="section-5"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-5">¶</a> </div> <p>The main REPL function. <strong>run</strong> is called every time a line of code is entered.
|
||||
<span class="nv">readline = </span><span class="nx">require</span> <span class="s1">'readline'</span></pre></div> </td> </tr> <tr id="section-3"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-3">¶</a> </div> <p>Start by opening up <strong>stdio</strong>.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">stdio = </span><span class="nx">process</span><span class="p">.</span><span class="nx">openStdin</span><span class="p">()</span></pre></div> </td> </tr> <tr id="section-4"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-4">¶</a> </div> <p>Log an error.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">error = </span><span class="p">(</span><span class="nx">err</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nx">stdio</span><span class="p">.</span><span class="nx">write</span> <span class="p">(</span><span class="nx">err</span><span class="p">.</span><span class="nx">stack</span> <span class="o">or</span> <span class="nx">err</span><span class="p">.</span><span class="nx">toString</span><span class="p">())</span> <span class="o">+</span> <span class="s1">'\n\n'</span></pre></div> </td> </tr> <tr id="section-5"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-5">¶</a> </div> <p>Quick alias for quitting the REPL.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nx">helpers</span><span class="p">.</span><span class="nx">extend</span> <span class="nx">global</span><span class="p">,</span> <span class="nx">quit</span><span class="o">:</span> <span class="o">-></span> <span class="nx">process</span><span class="p">.</span><span class="nx">exit</span><span class="p">(</span><span class="mi">0</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>The main REPL function. <strong>run</strong> is called every time a line of code is entered.
|
||||
Attempt to evaluate the command. If there's an exception, print it out instead
|
||||
of exiting.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">run = </span><span class="p">(</span><span class="nx">buffer</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="k">try</span>
|
||||
<span class="nv">val = </span><span class="nx">CoffeeScript</span><span class="p">.</span><span class="nb">eval</span> <span class="nx">buffer</span><span class="p">.</span><span class="nx">toString</span><span class="p">(),</span> <span class="nx">bare</span><span class="o">:</span> <span class="kc">on</span><span class="p">,</span> <span class="nx">globals</span><span class="o">:</span> <span class="kc">on</span><span class="p">,</span> <span class="nx">fileName</span><span class="o">:</span> <span class="s1">'repl'</span>
|
||||
<span class="nx">console</span><span class="p">.</span><span class="nx">log</span> <span class="nx">val</span> <span class="k">if</span> <span class="nx">val</span> <span class="o">isnt</span> <span class="kc">undefined</span>
|
||||
<span class="k">catch</span> <span class="nx">err</span>
|
||||
<span class="nx">console</span><span class="p">.</span><span class="nx">error</span> <span class="nx">err</span><span class="p">.</span><span class="nx">stack</span> <span class="o">or</span> <span class="nx">err</span><span class="p">.</span><span class="nx">toString</span><span class="p">()</span>
|
||||
<span class="nx">repl</span><span class="p">.</span><span class="nx">prompt</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>Create the REPL by listening to <strong>stdin</strong>.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">repl = </span><span class="nx">readline</span><span class="p">.</span><span class="nx">createInterface</span> <span class="nx">stdio</span>
|
||||
<span class="nx">error</span> <span class="nx">err</span>
|
||||
<span class="nx">repl</span><span class="p">.</span><span class="nx">prompt</span><span class="p">()</span></pre></div> </td> </tr> <tr id="section-7"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-7">¶</a> </div> <p>Make sure that uncaught exceptions don't kill the REPL.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nx">process</span><span class="p">.</span><span class="kc">on</span> <span class="s1">'uncaughtException'</span><span class="p">,</span> <span class="nx">error</span></pre></div> </td> </tr> <tr id="section-8"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-8">¶</a> </div> <p>Create the REPL by listening to <strong>stdin</strong>.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">repl = </span><span class="nx">readline</span><span class="p">.</span><span class="nx">createInterface</span> <span class="nx">stdio</span>
|
||||
<span class="nx">repl</span><span class="p">.</span><span class="nx">setPrompt</span> <span class="s1">'coffee> '</span>
|
||||
<span class="nx">stdio</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">repl</span><span class="p">.</span><span class="nx">write</span> <span class="nx">buffer</span>
|
||||
<span class="nx">repl</span><span class="p">.</span><span class="kc">on</span> <span class="s1">'close'</span><span class="p">,</span> <span class="o">-></span> <span class="nx">stdio</span><span class="p">.</span><span class="nx">destroy</span><span class="p">()</span>
|
||||
|
||||
@@ -71,13 +71,13 @@ Insert the missing braces here, so that the parser doesn't have to.</p>
|
||||
<span class="nv">start = </span><span class="kc">null</span>
|
||||
<span class="nv">startIndent = </span><span class="mi">0</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="p">{(</span><span class="nx">i</span><span class="o">+</span><span class="mi">1</span><span class="p">)</span><span class="o">:</span> <span class="nx">one</span><span class="p">,</span> <span class="p">(</span><span class="nx">i</span><span class="o">+</span><span class="mi">2</span><span class="p">)</span><span class="o">:</span> <span class="nx">two</span><span class="p">,</span> <span class="p">(</span><span class="nx">i</span><span class="o">+</span><span class="mi">3</span><span class="p">)</span><span class="o">:</span> <span class="nx">three</span><span class="p">}</span> <span class="o">=</span> <span class="nx">@tokens</span>
|
||||
<span class="p">[</span><span class="nx">one</span><span class="p">,</span> <span class="nx">two</span><span class="p">,</span> <span class="nx">three</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">3</span><span class="p">]</span>
|
||||
<span class="k">return</span> <span class="kc">false</span> <span class="k">if</span> <span class="s1">'HERECOMMENT'</span> <span class="o">is</span> <span class="nx">one</span><span class="o">?</span><span class="p">[</span><span class="mi">0</span><span class="p">]</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="p">(</span><span class="nx">tag</span> <span class="k">in</span> <span class="p">[</span><span class="s1">'TERMINATOR'</span><span class="p">,</span> <span class="s1">'OUTDENT'</span><span class="p">]</span> <span class="o">and</span>
|
||||
<span class="o">not</span> <span class="p">(</span><span class="nx">two</span><span class="o">?</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">or</span> <span class="nx">one</span><span class="o">?</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">three</span><span class="o">?</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="p">))</span> <span class="o">or</span>
|
||||
<span class="p">(</span><span class="nx">tag</span> <span class="o">is</span> <span class="s1">','</span> <span class="o">and</span> <span class="nx">one</span> <span class="o">and</span>
|
||||
<span class="nx">one</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">not</span> <span class="k">in</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">'@'</span><span class="p">,</span> <span class="s1">'TERMINATOR'</span><span class="p">,</span> <span class="s1">'OUTDENT'</span><span class="p">,</span> <span class="s1">'('</span><span class="p">])</span>
|
||||
<span class="nx">one</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">not</span> <span class="k">in</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">'@'</span><span class="p">,</span> <span class="s1">'TERMINATOR'</span><span class="p">,</span> <span class="s1">'OUTDENT'</span><span class="p">])</span>
|
||||
<span class="nv">action = </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">@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">'}'</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="k">if</span> <span class="p">(</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="k">in</span> <span class="nx">EXPRESSION_START</span>
|
||||
@@ -87,17 +87,10 @@ Insert the missing braces here, so that the parser doesn't have to.</p>
|
||||
<span class="nv">start = </span><span class="nx">stack</span><span class="p">.</span><span class="nx">pop</span><span class="p">()</span>
|
||||
<span class="k">return</span> <span class="mi">1</span>
|
||||
<span class="k">return</span> <span class="mi">1</span> <span class="nx">unless</span> <span class="nx">tag</span> <span class="o">is</span> <span class="s1">':'</span> <span class="o">and</span>
|
||||
<span class="p">((</span><span class="nv">ago2 = </span><span class="nx">@tag</span> <span class="nx">i</span> <span class="o">-</span> <span class="mi">2</span><span class="p">)</span> <span class="o">is</span> <span class="s1">':'</span> <span class="o">or</span>
|
||||
<span class="p">(</span><span class="nv">ago1 = </span><span class="nx">@tag</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">')'</span> <span class="o">and</span> <span class="nx">@tag</span><span class="p">(</span><span class="nx">start</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span> <span class="o">is</span> <span class="s1">':'</span> <span class="o">or</span>
|
||||
<span class="nx">stack</span><span class="p">[</span><span class="nx">stack</span><span class="p">.</span><span class="nx">length</span> <span class="o">-</span> <span class="mi">1</span><span class="p">]</span><span class="o">?</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">isnt</span> <span class="s1">'{'</span><span class="p">)</span>
|
||||
<span class="p">((</span><span class="nv">ago = </span><span class="nx">@tag</span> <span class="nx">i</span> <span class="o">-</span> <span class="mi">2</span><span class="p">)</span> <span class="o">is</span> <span class="s1">':'</span> <span class="o">or</span> <span class="nx">stack</span><span class="p">[</span><span class="nx">stack</span><span class="p">.</span><span class="nx">length</span> <span class="o">-</span> <span class="mi">1</span><span class="p">]</span><span class="o">?</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">isnt</span> <span class="s1">'{'</span><span class="p">)</span>
|
||||
<span class="nx">stack</span><span class="p">.</span><span class="nx">push</span> <span class="p">[</span><span class="s1">'{'</span><span class="p">]</span>
|
||||
<span class="nv">idx = </span><span class="k">if</span> <span class="nx">ago1</span> <span class="o">is</span> <span class="s1">')'</span>
|
||||
<span class="nx">start</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
|
||||
<span class="k">else</span> <span class="k">if</span> <span class="nx">ago2</span> <span class="o">is</span> <span class="s1">'@'</span>
|
||||
<span class="nx">i</span> <span class="o">-</span> <span class="mi">2</span>
|
||||
<span class="k">else</span>
|
||||
<span class="nx">i</span> <span class="o">-</span> <span class="mi">1</span>
|
||||
<span class="nx">idx</span> <span class="o">-=</span> <span class="mi">2</span> <span class="k">if</span> <span class="nx">@tag</span><span class="p">(</span><span class="nx">idx</span> <span class="o">-</span> <span class="mi">2</span><span class="p">)</span> <span class="o">is</span> <span class="s1">'HERECOMMENT'</span>
|
||||
<span class="nv">idx = </span> <span class="k">if</span> <span class="nx">ago</span> <span class="o">is</span> <span class="s1">'@'</span> <span class="k">then</span> <span class="nx">i</span> <span class="o">-</span> <span class="mi">2</span> <span class="k">else</span> <span class="nx">i</span> <span class="o">-</span> <span class="mi">1</span>
|
||||
<span class="nx">idx</span> <span class="o">-=</span> <span class="mi">2</span> <span class="k">while</span> <span class="nx">@tag</span><span class="p">(</span><span class="nx">idx</span> <span class="o">-</span> <span class="mi">2</span><span class="p">)</span> <span class="o">is</span> <span class="s1">'HERECOMMENT'</span>
|
||||
<span class="nv">value = </span><span class="k">new</span> <span class="nb">String</span><span class="p">(</span><span class="s1">'{'</span><span class="p">)</span>
|
||||
<span class="nv">value.generated = </span><span class="kc">yes</span>
|
||||
<span class="nv">tok = </span><span class="p">[</span><span class="s1">'{'</span><span class="p">,</span> <span class="nx">value</span><span class="p">,</span> <span class="nx">token</span><span class="p">[</span><span class="mi">2</span><span class="p">]]</span>
|
||||
@@ -113,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="p">{(</span><span class="nx">i</span><span class="o">-</span><span class="mi">1</span><span class="p">)</span><span class="o">:</span> <span class="nx">prev</span><span class="p">,</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">:</span> <span class="nx">next</span><span class="p">}</span> <span class="o">=</span> <span class="nx">tokens</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>
|
||||
@@ -170,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>
|
||||
@@ -186,7 +179,7 @@ the course of the token stream.</p> </td> <td class="cod
|
||||
<span class="nx">openLine</span><span class="p">[</span><span class="nx">open</span><span class="p">]</span> <span class="o">=</span> <span class="nx">token</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="k">if</span> <span class="nx">levels</span><span class="p">[</span><span class="nx">open</span><span class="p">]</span><span class="o">++</span> <span class="o">is</span> <span class="mi">0</span>
|
||||
<span class="k">else</span> <span class="k">if</span> <span class="nx">tag</span> <span class="o">is</span> <span class="nx">close</span> <span class="o">and</span> <span class="o">--</span><span class="nx">levels</span><span class="p">[</span><span class="nx">open</span><span class="p">]</span> <span class="o"><</span> <span class="mi">0</span>
|
||||
<span class="k">throw</span> <span class="nb">Error</span> <span class="s2">"too many #{token[1]} on line #{token[2] + 1}"</span>
|
||||
<span class="k">for</span> <span class="nx">all</span> <span class="nx">open</span><span class="p">,</span> <span class="nx">level</span> <span class="k">of</span> <span class="nx">levels</span> <span class="k">when</span> <span class="nx">level</span> <span class="o">></span> <span class="mi">0</span>
|
||||
<span class="k">for</span> <span class="nx">open</span><span class="p">,</span> <span class="nx">level</span> <span class="k">of</span> <span class="nx">levels</span> <span class="k">when</span> <span class="nx">level</span> <span class="o">></span> <span class="mi">0</span>
|
||||
<span class="k">throw</span> <span class="nb">Error</span> <span class="s2">"unclosed #{ open } on line #{openLine[open] + 1}"</span>
|
||||
<span class="k">this</span></pre></div> </td> </tr> <tr id="section-15"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-15">¶</a> </div> <p>We'd like to support syntax like this:</p>
|
||||
|
||||
@@ -209,7 +202,7 @@ rewriting.</li>
|
||||
</ol> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">rewriteClosingParens</span><span class="o">:</span> <span class="o">-></span>
|
||||
<span class="nv">stack = </span><span class="p">[]</span>
|
||||
<span class="nv">debt = </span><span class="p">{}</span>
|
||||
<span class="nx">debt</span><span class="p">[</span><span class="nx">key</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span> <span class="k">for</span> <span class="nx">all</span> <span class="nx">key</span> <span class="k">of</span> <span class="nx">INVERSES</span>
|
||||
<span class="nx">debt</span><span class="p">[</span><span class="nx">key</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span> <span class="k">for</span> <span class="nx">key</span> <span class="k">of</span> <span class="nx">INVERSES</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="k">if</span> <span class="p">(</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="k">in</span> <span class="nx">EXPRESSION_START</span>
|
||||
<span class="nx">stack</span><span class="p">.</span><span class="nx">push</span> <span class="nx">token</span>
|
||||
@@ -247,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,58 +11,44 @@ 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="k">if</span> <span class="nx">@parent</span>
|
||||
<span class="vi">@garbage = </span><span class="nx">@parent</span><span class="p">.</span><span class="nx">garbage</span>
|
||||
<span class="k">else</span>
|
||||
<span class="vi">@garbage = </span><span class="p">[]</span>
|
||||
<span class="nv">Scope.root = </span><span class="k">this</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>
|
||||
<span class="nx">@positions</span><span class="p">[</span><span class="nx">name</span><span class="p">]</span> <span class="o">=</span> <span class="nx">@variables</span><span class="p">.</span><span class="nx">push</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="mi">1</span></pre></div> </td> </tr> <tr id="section-6"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-6">¶</a> </div> <p>Create a new garbage level</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">startLevel</span><span class="o">:</span> <span class="o">-></span>
|
||||
<span class="nx">@garbage</span><span class="p">.</span><span class="nx">push</span> <span class="p">[]</span>
|
||||
<span class="k">this</span></pre></div> </td> </tr> <tr id="section-7"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-7">¶</a> </div> <p>Return to the previous garbage level and erase referenced temporary
|
||||
variables in current level from scope.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">endLevel</span><span class="o">:</span> <span class="o">-></span>
|
||||
<span class="nx">@add</span> <span class="nx">name</span><span class="p">,</span> <span class="s1">'reuse'</span> <span class="k">for</span> <span class="nx">name</span> <span class="k">in</span> <span class="nx">@garbage</span><span class="p">.</span><span class="nx">pop</span><span class="p">()</span> <span class="k">when</span> <span class="nx">@type</span><span class="p">(</span><span class="nx">name</span><span class="p">)</span> <span class="o">is</span> <span class="s1">'var'</span>
|
||||
<span class="k">this</span></pre></div> </td> </tr> <tr id="section-8"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-8">¶</a> </div> <p>Look up a variable name in lexical scope, and declare it if it does not
|
||||
<span class="nx">@positions</span><span class="p">[</span><span class="nx">name</span><span class="p">]</span> <span class="o">=</span> <span class="nx">@variables</span><span class="p">.</span><span class="nx">push</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="mi">1</span></pre></div> </td> </tr> <tr id="section-6"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-6">¶</a> </div> <p>Look up a variable name in lexical scope, and declare it if it does not
|
||||
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">true</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="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="kc">false</span></pre></div> </td> </tr> <tr id="section-9"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-9">¶</a> </div> <p>Test variables and return <code>true</code> the first time <code>fn(v)</code> returns <code>true</code></p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">any</span><span class="o">:</span> <span class="p">(</span><span class="nx">fn</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="k">return</span> <span class="kc">yes</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">fn</span> <span class="nx">v</span>
|
||||
<span class="kc">no</span></pre></div> </td> </tr> <tr id="section-10"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-10">¶</a> </div> <p>Reserve a variable name as originating from a function parameter for this
|
||||
<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="nx">@add</span> <span class="nx">name</span><span class="p">,</span> <span class="s1">'param'</span></pre></div> </td> </tr> <tr id="section-11"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-11">¶</a> </div> <p>Just check to see if a variable has already been declared, without reserving,
|
||||
<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>
|
||||
<span class="k">return</span> <span class="nx">found</span> <span class="k">if</span> <span class="nx">found</span> <span class="o">or</span> <span class="nx">immediate</span>
|
||||
<span class="o">!!</span><span class="nx">@parent</span><span class="o">?</span><span class="p">.</span><span class="nx">check</span> <span class="nx">name</span></pre></div> </td> </tr> <tr id="section-12"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-12">¶</a> </div> <p>Generate a temporary variable name at the given index.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">temporary</span><span class="o">:</span> <span class="p">(</span><span class="nx">name</span><span class="p">,</span> <span class="nx">index</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="o">!!</span><span class="nx">@parent</span><span class="o">?</span><span class="p">.</span><span class="nx">check</span> <span class="nx">name</span></pre></div> </td> </tr> <tr id="section-9"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-9">¶</a> </div> <p>Generate a temporary variable name at the given index.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">temporary</span><span class="o">:</span> <span class="p">(</span><span class="nx">name</span><span class="p">,</span> <span class="nx">index</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="k">if</span> <span class="nx">name</span><span class="p">.</span><span class="nx">length</span> <span class="o">></span> <span class="mi">1</span>
|
||||
<span class="s1">'_'</span> <span class="o">+</span> <span class="nx">name</span> <span class="o">+</span> <span class="k">if</span> <span class="nx">index</span> <span class="o">></span> <span class="mi">1</span> <span class="k">then</span> <span class="nx">index</span> <span class="k">else</span> <span class="s1">''</span>
|
||||
<span class="k">else</span>
|
||||
<span class="s1">'_'</span> <span class="o">+</span> <span class="p">(</span><span class="nx">index</span> <span class="o">+</span> <span class="nb">parseInt</span> <span class="nx">name</span><span class="p">,</span> <span class="mi">36</span><span class="p">).</span><span class="nx">toString</span><span class="p">(</span><span class="mi">36</span><span class="p">).</span><span class="nx">replace</span> <span class="sr">/\d/g</span><span class="p">,</span> <span class="s1">'a'</span></pre></div> </td> </tr> <tr id="section-13"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-13">¶</a> </div> <p>Gets the type of a variable.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">type</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">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">name</span> <span class="o">is</span> <span class="nx">name</span> <span class="k">then</span> <span class="k">return</span> <span class="nx">v</span><span class="p">.</span><span class="nx">type</span>
|
||||
<span class="kc">null</span></pre></div> </td> </tr> <tr id="section-14"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-14">¶</a> </div> <p>If we need to store an intermediate result, find an available name for a
|
||||
<span class="s1">'_'</span> <span class="o">+</span> <span class="p">(</span><span class="nx">index</span> <span class="o">+</span> <span class="nb">parseInt</span> <span class="nx">name</span><span class="p">,</span> <span class="mi">36</span><span class="p">).</span><span class="nx">toString</span><span class="p">(</span><span class="mi">36</span><span class="p">).</span><span class="nx">replace</span> <span class="sr">/\d/g</span><span class="p">,</span> <span class="s1">'a'</span></pre></div> </td> </tr> <tr id="section-10"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-10">¶</a> </div> <p>Gets the type of a variable.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">type</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="nx">v</span><span class="p">.</span><span class="nx">type</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">name</span> <span class="o">is</span> <span class="nx">name</span>
|
||||
<span class="kc">null</span></pre></div> </td> </tr> <tr id="section-11"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-11">¶</a> </div> <p>If we need to store an intermediate result, find an available name for a
|
||||
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="o">and</span> <span class="nx">@type</span><span class="p">(</span><span class="nx">temp</span><span class="p">)</span> <span class="o">isnt</span> <span class="s1">'reuse'</span>
|
||||
<span class="nx">@add</span> <span class="nx">temp</span><span class="p">,</span> <span class="s1">'var'</span>
|
||||
<span class="nx">last</span><span class="p">(</span><span class="nx">@garbage</span><span class="p">)</span><span class="o">?</span><span class="p">.</span><span class="nx">push</span> <span class="nx">temp</span>
|
||||
<span class="nx">temp</span></pre></div> </td> </tr> <tr id="section-15"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-15">¶</a> </div> <p>Ensure that an assignment is made at the top of this scope
|
||||
<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="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></pre></div> </td> </tr> <tr id="section-16"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-16">¶</a> </div> <p>Does this scope reference any variables that need to be declared in the
|
||||
given function body?</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">hasDeclarations</span><span class="o">:</span> <span class="p">(</span><span class="nx">body</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nx">body</span> <span class="o">is</span> <span class="nx">@expressions</span> <span class="o">and</span> <span class="nx">@any</span> <span class="p">(</span><span class="nx">v</span><span class="p">)</span> <span class="o">-></span> <span class="nx">v</span><span class="p">.</span><span class="nx">type</span> <span class="k">in</span> <span class="p">[</span><span class="s1">'var'</span><span class="p">,</span> <span class="s1">'reuse'</span><span class="p">]</span></pre></div> </td> </tr> <tr id="section-17"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-17">¶</a> </div> <p>Does this scope reference any assignments that need to be declared at the
|
||||
top of the given function body?</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">hasAssignments</span><span class="o">:</span> <span class="p">(</span><span class="nx">body</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nx">body</span> <span class="o">is</span> <span class="nx">@expressions</span> <span class="o">and</span> <span class="nx">@any</span> <span class="p">(</span><span class="nx">v</span><span class="p">)</span> <span class="o">-></span> <span class="nx">v</span><span class="p">.</span><span class="nx">type</span><span class="p">.</span><span class="nx">assigned</span></pre></div> </td> </tr> <tr id="section-18"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-18">¶</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">usr = </span><span class="p">[]</span>
|
||||
<span class="nv">tmp = </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="k">in</span> <span class="p">[</span><span class="s1">'var'</span><span class="p">,</span> <span class="s1">'reuse'</span><span class="p">]</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">tmp</span> <span class="k">else</span> <span class="nx">usr</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">usr</span><span class="p">.</span><span class="nx">sort</span><span class="p">().</span><span class="nx">concat</span> <span class="nx">tmp</span><span class="p">.</span><span class="nx">sort</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>Return the list of assignments that are supposed to be made at the top
|
||||
<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>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-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="p">(</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><span class="p">)</span></pre></div> </td> </tr> <tr id="section-20"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-20">¶</a> </div> <p>Compile the JavaScript for all of the variable declarations in this scope.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">compiledDeclarations</span><span class="o">:</span> <span class="o">-></span>
|
||||
<span class="nx">@declaredVariables</span><span class="p">().</span><span class="nx">join</span> <span class="s1">', '</span></pre></div> </td> </tr> <tr id="section-21"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-21">¶</a> </div> <p>Compile the JavaScript for all of the variable assignments in this scope.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">compiledAssignments</span><span class="o">:</span> <span class="o">-></span>
|
||||
<span class="nx">@assignedVariables</span><span class="p">().</span><span class="nx">join</span> <span class="s1">', '</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>
|
||||
|
||||
</pre></div> </td> </tr> </tbody> </table> </div> </body> </html>
|
||||
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,17 +1,6 @@
|
||||
var food, lunch, pos, roid, roid2, _i, _j, _len, _len2, _len3, _ref;
|
||||
var food, _i, _len, _ref;
|
||||
_ref = ['toast', 'cheese', 'wine'];
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
food = _ref[_i];
|
||||
lunch = eat(food);
|
||||
}
|
||||
for (pos = 0, _len2 = asteroids.length; pos < _len2; pos++) {
|
||||
roid = asteroids[pos];
|
||||
for (_j = 0, _len3 = asteroids.length; _j < _len3; _j++) {
|
||||
roid2 = asteroids[_j];
|
||||
if (roid !== roid2) {
|
||||
if (roid.overlaps(roid2)) {
|
||||
roid.explode();
|
||||
}
|
||||
}
|
||||
}
|
||||
eat(food);
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
/*
|
||||
CoffeeScript Compiler v0.9.5
|
||||
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();
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
var cholesterol, healthy;
|
||||
cholesterol = 127;
|
||||
healthy = 200 > cholesterol && cholesterol > 60;
|
||||
healthy = (200 > cholesterol && cholesterol > 60);
|
||||
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,10 +1,9 @@
|
||||
var globals, name, _results;
|
||||
var __hasProp = Object.prototype.hasOwnProperty;
|
||||
globals = (function() {
|
||||
var globals, name;
|
||||
globals = ((function() {
|
||||
var _results;
|
||||
_results = [];
|
||||
for (name in window) {
|
||||
if (!__hasProp.call(window, name)) continue;
|
||||
_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,16 +1,15 @@
|
||||
var age, ages, child, yearsOld, _results;
|
||||
var __hasProp = Object.prototype.hasOwnProperty;
|
||||
var age, ages, child, yearsOld;
|
||||
yearsOld = {
|
||||
max: 10,
|
||||
ida: 9,
|
||||
tim: 11
|
||||
};
|
||||
ages = function() {
|
||||
ages = (function() {
|
||||
var _results;
|
||||
_results = [];
|
||||
for (child in yearsOld) {
|
||||
if (!__hasProp.call(yearsOld, child)) continue;
|
||||
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;
|
||||
}());
|
||||
})();
|
||||
4
documentation/js/slices.js
Normal file
@@ -0,0 +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, 7);
|
||||
@@ -9,7 +9,7 @@ awardMedals = function() {
|
||||
return rest = others;
|
||||
};
|
||||
contenders = ["Michael Phelps", "Liu Xiang", "Yao Ming", "Allyson Felix", "Shawn Johnson", "Roman Sebrle", "Guo Jingjing", "Tyson Gay", "Asafa Powell", "Usain Bolt"];
|
||||
awardMedals.apply(awardMedals, contenders);
|
||||
awardMedals.apply(null, contenders);
|
||||
alert("Gold: " + gold);
|
||||
alert("Silver: " + silver);
|
||||
alert("The Field: " + rest);
|
||||
3
documentation/js/splices.js
Normal file
@@ -0,0 +1,3 @@
|
||||
var numbers, _ref;
|
||||
numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
|
||||
[].splice.apply(numbers, [3, 4].concat(_ref = [-3, -4, -5, -6])), _ref;
|
||||
@@ -1,17 +1,18 @@
|
||||
var lyrics, num, _results;
|
||||
var lyrics, num;
|
||||
if (this.studyingEconomics) {
|
||||
while (supply > demand) {
|
||||
buy();
|
||||
}
|
||||
while (supply <= demand) {
|
||||
while (!(supply > demand)) {
|
||||
sell();
|
||||
}
|
||||
}
|
||||
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
@@ -85,7 +85,7 @@ _.each = (obj, iterator, context) ->
|
||||
else if _.isNumber obj.length
|
||||
iterator.call context, obj[i], i, obj for i in [0...obj.length]
|
||||
else
|
||||
iterator.call context, val, key, obj for key, val of obj
|
||||
iterator.call context, val, key, obj for own key, val of obj
|
||||
catch e
|
||||
throw e if e isnt breaker
|
||||
obj
|
||||
@@ -176,8 +176,7 @@ _.some = (obj, iterator, context) ->
|
||||
# based on `===`.
|
||||
_.include = (obj, target) ->
|
||||
return _.indexOf(obj, target) isnt -1 if nativeIndexOf and obj.indexOf is nativeIndexOf
|
||||
for key, val of obj
|
||||
return true if val is target
|
||||
return true for own key, val of obj when val is target
|
||||
false
|
||||
|
||||
|
||||
@@ -486,14 +485,14 @@ _.isEqual = (a, b) ->
|
||||
# Different object sizes?
|
||||
return false if aKeys.length isnt bKeys.length
|
||||
# Recursive comparison of contents.
|
||||
return false for all key, val of a when !(key of b) or !_.isEqual(val, b[key])
|
||||
return false for key, val of a when !(key of b) or !_.isEqual(val, b[key])
|
||||
true
|
||||
|
||||
|
||||
# Is a given array or object empty?
|
||||
_.isEmpty = (obj) ->
|
||||
return obj.length is 0 if _.isArray(obj) or _.isString(obj)
|
||||
return false for key of obj when hasOwnProperty.call(obj, key)
|
||||
return false for own key of obj
|
||||
true
|
||||
|
||||
|
||||
@@ -654,7 +653,7 @@ addToWrapper = (name, func) ->
|
||||
result func.apply(_, args), this._chain
|
||||
|
||||
|
||||
# Add all of the Underscore functions to the wrapper object.
|
||||
# Add all ofthe Underscore functions to the wrapper object.
|
||||
_.mixin _
|
||||
|
||||
|
||||
|
||||
1352
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.5';
|
||||
exports.VERSION = '1.0.0';
|
||||
exports.RESERVED = RESERVED;
|
||||
exports.helpers = require('./helpers');
|
||||
exports.compile = compile = function(code, options) {
|
||||
if (options == null) {
|
||||
|
||||
107
lib/command.js
@@ -1,23 +1,31 @@
|
||||
(function() {
|
||||
var ALL_SWITCHES, BANNER, CoffeeScript, DEPRECATED_SWITCHES, EventEmitter, SWITCHES, compileOptions, compileScript, compileScripts, compileStdio, exec, fs, helpers, lint, optionParser, optparse, opts, parseOptions, path, printTokens, sources, spawn, usage, 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');
|
||||
helpers = require('./helpers');
|
||||
optparse = require('./optparse');
|
||||
CoffeeScript = require('./coffee-script');
|
||||
_ref = require('child_process'), spawn = _ref.spawn, exec = _ref.exec;
|
||||
EventEmitter = require('events').EventEmitter;
|
||||
helpers.extend(CoffeeScript, new EventEmitter);
|
||||
printLine = function(line) {
|
||||
return process.stdout.write(line + '\n');
|
||||
};
|
||||
printWarn = function(line) {
|
||||
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();
|
||||
}
|
||||
@@ -36,22 +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 _fn, _i, _len, _results;
|
||||
_fn = function(source) {
|
||||
var base, compile;
|
||||
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) {
|
||||
@@ -71,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;
|
||||
};
|
||||
@@ -110,14 +115,14 @@
|
||||
if (o.tokens) {
|
||||
return printTokens(CoffeeScript.tokens(t.input));
|
||||
} else if (o.nodes) {
|
||||
return console.log(CoffeeScript.nodes(t.input).toString().trim());
|
||||
return printLine(CoffeeScript.nodes(t.input).toString().trim());
|
||||
} else if (o.run) {
|
||||
return CoffeeScript.run(t.input, t.options);
|
||||
} else {
|
||||
t.output = CoffeeScript.compile(t.input, t.options);
|
||||
CoffeeScript.emit('success', task);
|
||||
if (o.print) {
|
||||
return console.log(t.output.trim());
|
||||
return printLine(t.output.trim());
|
||||
} else if (o.compile) {
|
||||
return writeJs(t.file, t.output, base);
|
||||
} else if (o.lint) {
|
||||
@@ -130,9 +135,9 @@
|
||||
return;
|
||||
}
|
||||
if (o.watch) {
|
||||
return console.log(err.message);
|
||||
return printLine(err.message);
|
||||
}
|
||||
console.error(err.stack);
|
||||
printWarn(err.stack);
|
||||
return process.exit(1);
|
||||
}
|
||||
};
|
||||
@@ -149,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,
|
||||
@@ -169,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() {
|
||||
@@ -178,9 +188,9 @@
|
||||
}
|
||||
return fs.writeFile(jsPath, js, function(err) {
|
||||
if (err) {
|
||||
return console.log(err.message);
|
||||
return printLine(err.message);
|
||||
} else if (opts.compile && opts.watch) {
|
||||
return console.log("Compiled " + source);
|
||||
return util.log("compiled " + source);
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -195,7 +205,7 @@
|
||||
lint = function(file, js) {
|
||||
var conf, jsl, printIt;
|
||||
printIt = function(buffer) {
|
||||
return console.log(file + ':\t' + buffer.toString().trim());
|
||||
return printLine(file + ':\t' + buffer.toString().trim());
|
||||
};
|
||||
conf = __dirname + '/../extras/jsl.conf';
|
||||
jsl = spawn('jsl', ['-nologo', '-stdin', '-conf', conf]);
|
||||
@@ -205,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];
|
||||
@@ -214,33 +225,41 @@
|
||||
_results.push("[" + tag + " " + value + "]");
|
||||
}
|
||||
return _results;
|
||||
}();
|
||||
return console.log(strings.join(' '));
|
||||
})();
|
||||
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 console.warn('--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() {
|
||||
console.log((new optparse.OptionParser(SWITCHES, BANNER)).help());
|
||||
printLine((new optparse.OptionParser(SWITCHES, BANNER)).help());
|
||||
return process.exit(0);
|
||||
};
|
||||
version = function() {
|
||||
console.log("CoffeeScript version " + CoffeeScript.VERSION);
|
||||
printLine("CoffeeScript version " + CoffeeScript.VERSION);
|
||||
return process.exit(0);
|
||||
};
|
||||
}).call(this);
|
||||
|
||||
@@ -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: [
|
||||
@@ -78,7 +78,7 @@
|
||||
return new Assign(new Value($1), $4, 'object');
|
||||
}), o('Comment')
|
||||
],
|
||||
ObjAssignable: [o('Identifier'), o('AlphaNumeric'), o('Parenthetical'), o('ThisProperty')],
|
||||
ObjAssignable: [o('Identifier'), o('AlphaNumeric'), o('ThisProperty')],
|
||||
Return: [
|
||||
o('RETURN Expression', function() {
|
||||
return new Return($2);
|
||||
@@ -368,30 +368,30 @@
|
||||
],
|
||||
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.raw = $1.raw;
|
||||
$2.vars = $1;
|
||||
$2.own = $1.own;
|
||||
$2.name = $1[0];
|
||||
$2.index = $1[1];
|
||||
return $2;
|
||||
})
|
||||
],
|
||||
ForStart: [
|
||||
o('FOR ForVariables', function() {
|
||||
return $2;
|
||||
}), o('FOR ALL ForVariables', function() {
|
||||
$3.raw = true;
|
||||
}), o('FOR OWN ForVariables', function() {
|
||||
$3.own = true;
|
||||
return $3;
|
||||
})
|
||||
],
|
||||
@@ -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;
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
(function() {
|
||||
var key, val, _ref;
|
||||
var __hasProp = Object.prototype.hasOwnProperty;
|
||||
_ref = require('./coffee-script');
|
||||
for (key in _ref) {
|
||||
if (!__hasProp.call(_ref, key)) continue;
|
||||
val = _ref[key];
|
||||
exports[key] = val;
|
||||
}
|
||||
|
||||
70
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;
|
||||
@@ -39,8 +39,8 @@
|
||||
return 0;
|
||||
}
|
||||
input = match[0], id = match[1], colon = match[2];
|
||||
if (id === 'all' && this.tag() === 'FOR') {
|
||||
this.token('ALL', id);
|
||||
if (id === 'own' && this.tag() === 'FOR') {
|
||||
this.token('OWN', id);
|
||||
return id.length;
|
||||
}
|
||||
forcedIdentifier = colon || (prev = last(this.tokens)) && !prev.spaced && ((_ref = prev[0]) === '.' || _ref === '?.' || _ref === '@' || _ref === '::');
|
||||
@@ -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)) {
|
||||
@@ -208,7 +210,7 @@
|
||||
return regex.length;
|
||||
};
|
||||
Lexer.prototype.heregexToken = function(match) {
|
||||
var body, flags, heregex, re, tag, tokens, value, _i, _len, _ref, _ref2, _ref3, _this;
|
||||
var body, flags, heregex, re, tag, tokens, value, _i, _len, _ref, _ref2, _ref3, _ref4;
|
||||
heregex = match[0], body = match[1], flags = match[2];
|
||||
if (0 > body.indexOf('#{')) {
|
||||
re = body.replace(HEREGEX_OMIT, '').replace(/\//g, '\\/');
|
||||
@@ -238,7 +240,7 @@
|
||||
if (((_ref3 = tokens[0]) != null ? _ref3[0] : void 0) !== 'STRING') {
|
||||
this.tokens.push(['STRING', '""'], ['+', '+']);
|
||||
}
|
||||
(_this = this.tokens).push.apply(_this, tokens);
|
||||
(_ref4 = this.tokens).push.apply(_ref4, tokens);
|
||||
if (flags) {
|
||||
this.tokens.push([',', ','], ['STRING', '"' + flags + '"']);
|
||||
}
|
||||
@@ -447,38 +449,35 @@
|
||||
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, _this;
|
||||
var expr, heredoc, i, inner, interpolated, letter, nested, pi, regex, tag, tokens, value, _len, _ref, _ref2, _ref3;
|
||||
if (options == null) {
|
||||
options = {};
|
||||
}
|
||||
@@ -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) {
|
||||
@@ -516,7 +515,7 @@
|
||||
i += expr.length;
|
||||
pi = i + 1;
|
||||
}
|
||||
if (i > pi && pi < str.length) {
|
||||
if ((i > pi && pi < str.length)) {
|
||||
tokens.push(['NEOSTRING', str.slice(pi)]);
|
||||
}
|
||||
if (regex) {
|
||||
@@ -537,7 +536,7 @@
|
||||
this.token('+', '+');
|
||||
}
|
||||
if (tag === 'TOKENS') {
|
||||
(_this = this.tokens).push.apply(_this, value);
|
||||
(_ref3 = this.tokens).push.apply(_ref3, value);
|
||||
} else {
|
||||
this.token('STRING', this.makeString(value, '"', heredoc));
|
||||
}
|
||||
@@ -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 = ['==', '!=', '<', '>', '<=', '>='];
|
||||
|
||||
761
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,})/;
|
||||
@@ -65,7 +70,7 @@
|
||||
if (tuple.length < 3) {
|
||||
tuple.unshift(null);
|
||||
}
|
||||
_results.push(buildRule.apply(buildRule, tuple));
|
||||
_results.push(buildRule.apply(null, tuple));
|
||||
}
|
||||
return _results;
|
||||
};
|
||||
|
||||
506
lib/parser.js
@@ -1,9 +1,12 @@
|
||||
(function() {
|
||||
var CoffeeScript, helpers, readline, repl, run, stdio;
|
||||
var CoffeeScript, error, helpers, readline, repl, run, stdio;
|
||||
CoffeeScript = require('./coffee-script');
|
||||
helpers = require('./helpers');
|
||||
readline = require('readline');
|
||||
stdio = process.openStdin();
|
||||
error = function(err) {
|
||||
return stdio.write((err.stack || err.toString()) + '\n\n');
|
||||
};
|
||||
helpers.extend(global, {
|
||||
quit: function() {
|
||||
return process.exit(0);
|
||||
@@ -21,10 +24,11 @@
|
||||
console.log(val);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err.stack || err.toString());
|
||||
error(err);
|
||||
}
|
||||
return repl.prompt();
|
||||
};
|
||||
process.on('uncaughtException', error);
|
||||
repl = readline.createInterface(stdio);
|
||||
repl.setPrompt('coffee> ');
|
||||
stdio.on('data', function(buffer) {
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
(function() {
|
||||
var BALANCED_PAIRS, EXPRESSION_CLOSE, EXPRESSION_END, EXPRESSION_START, IMPLICIT_BLOCK, IMPLICIT_CALL, IMPLICIT_END, IMPLICIT_FUNC, IMPLICIT_UNSPACED_CALL, INVERSES, LINEBREAKS, Rewriter, SINGLE_CLOSERS, SINGLE_LINERS, left, rite, _i, _len, _ref;
|
||||
var BALANCED_PAIRS, EXPRESSION_CLOSE, EXPRESSION_END, EXPRESSION_START, IMPLICIT_BLOCK, IMPLICIT_CALL, IMPLICIT_END, IMPLICIT_FUNC, IMPLICIT_UNSPACED_CALL, INVERSES, LINEBREAKS, SINGLE_CLOSERS, SINGLE_LINERS, left, rite, _i, _len, _ref;
|
||||
var __indexOf = Array.prototype.indexOf || function(item) {
|
||||
for (var i = 0, l = this.length; i < l; i++) {
|
||||
if (this[i] === item) return i;
|
||||
}
|
||||
return -1;
|
||||
}, __slice = Array.prototype.slice;
|
||||
exports.Rewriter = Rewriter = function() {
|
||||
exports.Rewriter = (function() {
|
||||
function Rewriter() {}
|
||||
Rewriter.prototype.rewrite = function(tokens) {
|
||||
this.tokens = tokens;
|
||||
@@ -113,18 +113,18 @@
|
||||
startIndent = 0;
|
||||
condition = function(token, i) {
|
||||
var one, tag, three, two, _ref, _ref2;
|
||||
_ref = this.tokens, one = _ref[i + 1], two = _ref[i + 2], three = _ref[i + 3];
|
||||
_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;
|
||||
}
|
||||
tag = token[0];
|
||||
return ((tag === 'TERMINATOR' || tag === 'OUTDENT') && !((two != null ? two[0] : void 0) === ':' || (one != null ? one[0] : void 0) === '@' && (three != null ? three[0] : void 0) === ':')) || (tag === ',' && one && ((_ref2 = one[0]) !== 'IDENTIFIER' && _ref2 !== 'NUMBER' && _ref2 !== 'STRING' && _ref2 !== '@' && _ref2 !== 'TERMINATOR' && _ref2 !== 'OUTDENT' && _ref2 !== '('));
|
||||
return ((tag === 'TERMINATOR' || tag === 'OUTDENT') && !((two != null ? two[0] : void 0) === ':' || (one != null ? one[0] : void 0) === '@' && (three != null ? three[0] : void 0) === ':')) || (tag === ',' && one && ((_ref2 = one[0]) !== 'IDENTIFIER' && _ref2 !== 'NUMBER' && _ref2 !== 'STRING' && _ref2 !== '@' && _ref2 !== 'TERMINATOR' && _ref2 !== 'OUTDENT'));
|
||||
};
|
||||
action = function(token, i) {
|
||||
return this.tokens.splice(i, 0, ['}', '}', token[2]]);
|
||||
};
|
||||
return this.scanTokens(function(token, i, tokens) {
|
||||
var ago1, ago2, idx, tag, tok, value, _ref, _ref2;
|
||||
var ago, idx, tag, tok, value, _ref, _ref2;
|
||||
if (_ref = (tag = token[0]), __indexOf.call(EXPRESSION_START, _ref) >= 0) {
|
||||
stack.push([(tag === 'INDENT' && this.tag(i - 1) === '{' ? '{' : tag), i]);
|
||||
return 1;
|
||||
@@ -133,12 +133,12 @@
|
||||
start = stack.pop();
|
||||
return 1;
|
||||
}
|
||||
if (!(tag === ':' && ((ago2 = this.tag(i - 2)) === ':' || (ago1 = this.tag(i - 1)) === ')' && this.tag(start[1] - 1) === ':' || ((_ref2 = stack[stack.length - 1]) != null ? _ref2[0] : void 0) !== '{'))) {
|
||||
if (!(tag === ':' && ((ago = this.tag(i - 2)) === ':' || ((_ref2 = stack[stack.length - 1]) != null ? _ref2[0] : void 0) !== '{'))) {
|
||||
return 1;
|
||||
}
|
||||
stack.push(['{']);
|
||||
idx = ago1 === ')' ? start[1] : ago2 === '@' ? i - 2 : i - 1;
|
||||
if (this.tag(idx - 2) === 'HERECOMMENT') {
|
||||
idx = ago === '@' ? i - 2 : i - 1;
|
||||
while (this.tag(idx - 2) === 'HERECOMMENT') {
|
||||
idx -= 2;
|
||||
}
|
||||
value = new String('{');
|
||||
@@ -159,13 +159,13 @@
|
||||
return this.tokens.splice(idx, 0, ['CALL_END', ')', token[2]]);
|
||||
};
|
||||
return this.scanTokens(function(token, i, tokens) {
|
||||
var callObject, next, prev, seenSingle, tag, _ref, _ref2;
|
||||
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;
|
||||
}
|
||||
prev = tokens[i - 1], next = tokens[i + 1];
|
||||
callObject = !noCall && tag === 'INDENT' && next && next.generated && next[0] === '{' && prev && (_ref = prev[0], __indexOf.call(IMPLICIT_FUNC, _ref) >= 0);
|
||||
_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) {
|
||||
noCall = false;
|
||||
@@ -173,17 +173,17 @@
|
||||
if (prev && !prev.spaced && tag === '?') {
|
||||
token.call = true;
|
||||
}
|
||||
if (!(callObject || (prev != null ? prev.spaced : void 0) && (prev.call || (_ref2 = prev[0], __indexOf.call(IMPLICIT_FUNC, _ref2) >= 0)) && (__indexOf.call(IMPLICIT_CALL, tag) >= 0 || !(token.spaced || token.newLine) && __indexOf.call(IMPLICIT_UNSPACED_CALL, tag) >= 0))) {
|
||||
if (!(callObject || (prev != null ? prev.spaced : void 0) && (prev.call || (_ref3 = prev[0], __indexOf.call(IMPLICIT_FUNC, _ref3) >= 0)) && (__indexOf.call(IMPLICIT_CALL, tag) >= 0 || !(token.spaced || token.newLine) && __indexOf.call(IMPLICIT_UNSPACED_CALL, tag) >= 0))) {
|
||||
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'];
|
||||
|
||||
87
lib/scope.js
@@ -1,7 +1,8 @@
|
||||
(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;
|
||||
this.expressions = expressions;
|
||||
@@ -13,16 +14,15 @@
|
||||
}
|
||||
];
|
||||
this.positions = {};
|
||||
if (this.parent) {
|
||||
this.garbage = this.parent.garbage;
|
||||
} else {
|
||||
this.garbage = [];
|
||||
if (!this.parent) {
|
||||
Scope.root = this;
|
||||
}
|
||||
}
|
||||
Scope.root = null;
|
||||
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 {
|
||||
@@ -32,21 +32,6 @@
|
||||
}) - 1;
|
||||
}
|
||||
};
|
||||
Scope.prototype.startLevel = function() {
|
||||
this.garbage.push([]);
|
||||
return this;
|
||||
};
|
||||
Scope.prototype.endLevel = function() {
|
||||
var name, _i, _len, _ref;
|
||||
_ref = this.garbage.pop();
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
name = _ref[_i];
|
||||
if (this.type(name) === 'var') {
|
||||
this.add(name, 'reuse');
|
||||
}
|
||||
}
|
||||
return this;
|
||||
};
|
||||
Scope.prototype.find = function(name, options) {
|
||||
if (this.check(name, options)) {
|
||||
return true;
|
||||
@@ -54,18 +39,10 @@
|
||||
this.add(name, 'var');
|
||||
return false;
|
||||
};
|
||||
Scope.prototype.any = function(fn) {
|
||||
var v, _i, _len, _ref;
|
||||
_ref = this.variables;
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
v = _ref[_i];
|
||||
if (fn(v)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
Scope.prototype.parameter = function(name) {
|
||||
if (this.shared && this.parent.check(name, true)) {
|
||||
return;
|
||||
}
|
||||
return this.add(name, 'param');
|
||||
};
|
||||
Scope.prototype.check = function(name, immediate) {
|
||||
@@ -95,46 +72,36 @@
|
||||
return null;
|
||||
};
|
||||
Scope.prototype.freeVariable = function(type) {
|
||||
var index, temp, _ref;
|
||||
var index, temp;
|
||||
index = 0;
|
||||
while (this.check((temp = this.temporary(type, index)), true) && this.type(temp) !== 'reuse') {
|
||||
while (this.check((temp = this.temporary(type, index)), true)) {
|
||||
index++;
|
||||
}
|
||||
this.add(temp, 'var');
|
||||
if ((_ref = last(this.garbage)) != null) {
|
||||
_ref.push(temp);
|
||||
}
|
||||
this.add(temp, 'var', true);
|
||||
return temp;
|
||||
};
|
||||
Scope.prototype.assign = function(name, value) {
|
||||
return this.add(name, {
|
||||
this.add(name, {
|
||||
value: value,
|
||||
assigned: true
|
||||
});
|
||||
return this.hasAssignments = true;
|
||||
};
|
||||
Scope.prototype.hasDeclarations = function(body) {
|
||||
return body === this.expressions && this.any(function(v) {
|
||||
var _ref;
|
||||
return (_ref = v.type) === 'var' || _ref === 'reuse';
|
||||
});
|
||||
};
|
||||
Scope.prototype.hasAssignments = function(body) {
|
||||
return body === this.expressions && this.any(function(v) {
|
||||
return v.type.assigned;
|
||||
});
|
||||
Scope.prototype.hasDeclarations = function() {
|
||||
return !!this.declaredVariables().length;
|
||||
};
|
||||
Scope.prototype.declaredVariables = function() {
|
||||
var tmp, usr, v, _i, _len, _ref, _ref2;
|
||||
usr = [];
|
||||
tmp = [];
|
||||
var realVars, tempVars, v, _i, _len, _ref;
|
||||
realVars = [];
|
||||
tempVars = [];
|
||||
_ref = this.variables;
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
v = _ref[_i];
|
||||
if ((_ref2 = v.type) === 'var' || _ref2 === 'reuse') {
|
||||
(v.name.charAt(0) === '_' ? tmp : usr).push(v.name);
|
||||
if (v.type === 'var') {
|
||||
(v.name.charAt(0) === '_' ? tempVars : realVars).push(v.name);
|
||||
}
|
||||
}
|
||||
return usr.sort().concat(tmp.sort());
|
||||
return realVars.sort().concat(tempVars.sort());
|
||||
};
|
||||
Scope.prototype.assignedVariables = function() {
|
||||
var v, _i, _len, _ref, _results;
|
||||
@@ -148,12 +115,6 @@
|
||||
}
|
||||
return _results;
|
||||
};
|
||||
Scope.prototype.compiledDeclarations = function() {
|
||||
return this.declaredVariables().join(', ');
|
||||
};
|
||||
Scope.prototype.compiledAssignments = function() {
|
||||
return this.assignedVariables().join(', ');
|
||||
};
|
||||
return Scope;
|
||||
}();
|
||||
})();
|
||||
}).call(this);
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
"description": "Unfancy JavaScript",
|
||||
"keywords": ["javascript", "language", "coffeescript", "compiler"],
|
||||
"author": "Jeremy Ashkenas",
|
||||
"version": "0.9.5",
|
||||
"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"
|
||||
|
||||
@@ -56,7 +56,7 @@ exports.run = ->
|
||||
# Display the list of Cake tasks in a format similar to `rake -T`
|
||||
printTasks = ->
|
||||
console.log ''
|
||||
for all name, task of tasks
|
||||
for name, task of tasks
|
||||
spaces = 20 - name.length
|
||||
spaces = if spaces > 0 then Array(spaces + 1).join(' ') else ''
|
||||
desc = if task.description then "# #{task.description}" else ''
|
||||
|
||||
@@ -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.5'
|
||||
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'
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
# External dependencies.
|
||||
fs = require 'fs'
|
||||
path = require 'path'
|
||||
util = require 'util'
|
||||
helpers = require './helpers'
|
||||
optparse = require './optparse'
|
||||
CoffeeScript = require './coffee-script'
|
||||
@@ -16,6 +17,9 @@ CoffeeScript = require './coffee-script'
|
||||
# Allow CoffeeScript to emit Node.js events.
|
||||
helpers.extend CoffeeScript, new EventEmitter
|
||||
|
||||
printLine = (line) -> process.stdout.write line + '\n'
|
||||
printWarn = (line) -> process.binding('stdio').writeError line + '\n'
|
||||
|
||||
# The help banner that is printed when `coffee` is called without arguments.
|
||||
BANNER = '''
|
||||
Usage: coffee [options] path/to/script.coffee
|
||||
@@ -26,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']
|
||||
@@ -35,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.
|
||||
@@ -56,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
|
||||
@@ -87,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
|
||||
@@ -103,19 +104,19 @@ compileScript = (file, input, base) ->
|
||||
t = task = {file, input, options}
|
||||
CoffeeScript.emit 'compile', task
|
||||
if o.tokens then printTokens CoffeeScript.tokens t.input
|
||||
else if o.nodes then console.log CoffeeScript.nodes(t.input).toString().trim()
|
||||
else if o.nodes then printLine CoffeeScript.nodes(t.input).toString().trim()
|
||||
else if o.run then CoffeeScript.run t.input, t.options
|
||||
else
|
||||
t.output = CoffeeScript.compile t.input, t.options
|
||||
CoffeeScript.emit 'success', task
|
||||
if o.print then console.log t.output.trim()
|
||||
if o.print then printLine t.output.trim()
|
||||
else if o.compile then writeJs t.file, t.output, base
|
||||
else if o.lint then lint t.file, t.output
|
||||
catch err
|
||||
CoffeeScript.emit 'failure', err, task
|
||||
return if CoffeeScript.listeners('failure').length
|
||||
return console.log err.message if o.watch
|
||||
console.error err.stack
|
||||
return printLine err.message if o.watch
|
||||
printWarn err.stack
|
||||
process.exit 1
|
||||
|
||||
# Attach the appropriate listeners to compile scripts incoming over **stdin**,
|
||||
@@ -128,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`.
|
||||
@@ -144,21 +151,21 @@ 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 = ->
|
||||
js = ' ' if js.length <= 0
|
||||
fs.writeFile jsPath, js, (err) ->
|
||||
if err then console.log err.message
|
||||
else if opts.compile and opts.watch then console.log "Compiled #{source}"
|
||||
if err then printLine err.message
|
||||
else if opts.compile and opts.watch then util.log "compiled #{source}"
|
||||
path.exists dir, (exists) ->
|
||||
if exists then compile() else exec "mkdir -p #{dir}", compile
|
||||
|
||||
# Pipe compiled JS through JSLint (requires a working `jsl` command), printing
|
||||
# any errors or warnings that arise.
|
||||
lint = (file, js) ->
|
||||
printIt = (buffer) -> console.log file + ':\t' + buffer.toString().trim()
|
||||
printIt = (buffer) -> printLine file + ':\t' + buffer.toString().trim()
|
||||
conf = __dirname + '/../extras/jsl.conf'
|
||||
jsl = spawn 'jsl', ['-nologo', '-stdin', '-conf', conf]
|
||||
jsl.stdout.on 'data', printIt
|
||||
@@ -171,30 +178,39 @@ printTokens = (tokens) ->
|
||||
strings = for token in tokens
|
||||
[tag, value] = [token[0], token[1].toString().replace(/\n/, '\\n')]
|
||||
"[#{tag} #{value}]"
|
||||
console.log strings.join(' ')
|
||||
printLine strings.join(' ')
|
||||
|
||||
# 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']
|
||||
console.warn '--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.
|
||||
usage = ->
|
||||
console.log (new optparse.OptionParser SWITCHES, BANNER).help()
|
||||
printLine (new optparse.OptionParser SWITCHES, BANNER).help()
|
||||
process.exit 0
|
||||
|
||||
# Print the `--version` message and exit.
|
||||
version = ->
|
||||
console.log "CoffeeScript version #{CoffeeScript.VERSION}"
|
||||
printLine "CoffeeScript version #{CoffeeScript.VERSION}"
|
||||
process.exit 0
|
||||
|
||||
@@ -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.
|
||||
@@ -149,7 +149,6 @@ grammar =
|
||||
ObjAssignable: [
|
||||
o 'Identifier'
|
||||
o 'AlphaNumeric'
|
||||
o 'Parenthetical'
|
||||
o 'ThisProperty'
|
||||
]
|
||||
|
||||
@@ -287,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.
|
||||
@@ -418,19 +415,19 @@ 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.raw = $1.raw; $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: [
|
||||
o 'FOR ForVariables', -> $2
|
||||
o 'FOR ALL ForVariables', -> $3.raw = yes; $3
|
||||
o 'FOR OWN ForVariables', -> $3.own = yes; $3
|
||||
]
|
||||
|
||||
# An array of all accepted values for a variable inside the loop.
|
||||
@@ -484,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
|
||||
]
|
||||
|
||||
@@ -494,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.
|
||||
@@ -566,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
|
||||
@@ -578,7 +572,7 @@ operators = [
|
||||
# terminals (every symbol which does not appear as the name of a rule above)
|
||||
# as "tokens".
|
||||
tokens = []
|
||||
for all name, alternatives of grammar
|
||||
for name, alternatives of grammar
|
||||
grammar[name] = for alt in alternatives
|
||||
for token in alt[0].split ' '
|
||||
tokens.push token unless grammar[token]
|
||||
|
||||
@@ -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.
|
||||
@@ -29,7 +30,7 @@ exports.merge = (options, overrides) ->
|
||||
|
||||
# Extend a source object with the properties of another object (shallow copy).
|
||||
extend = exports.extend = (object, properties) ->
|
||||
for all key, val of properties
|
||||
for key, val of properties
|
||||
object[key] = val
|
||||
object
|
||||
|
||||
|
||||
@@ -75,8 +75,8 @@ exports.Lexer = class Lexer
|
||||
return 0 unless match = IDENTIFIER.exec @chunk
|
||||
[input, id, colon] = match
|
||||
|
||||
if id is 'all' and @tag() is 'FOR'
|
||||
@token 'ALL', id
|
||||
if id is 'own' and @tag() is 'FOR'
|
||||
@token 'OWN', id
|
||||
return id.length
|
||||
forcedIdentifier = colon or
|
||||
(prev = last @tokens) and not prev.spaced and prev[0] in ['.', '?.', '@', '::']
|
||||
@@ -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,13 +500,13 @@ 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'
|
||||
]
|
||||
|
||||
# CoffeeScript-only keywords.
|
||||
COFFEE_KEYWORDS = ['undefined', 'then', 'unless', 'until', 'loop', 'of', 'by', 'when']
|
||||
COFFEE_KEYWORDS.push op for all op of COFFEE_ALIASES =
|
||||
COFFEE_KEYWORDS.push op for op of COFFEE_ALIASES =
|
||||
and : '&&'
|
||||
or : '||'
|
||||
is : '=='
|
||||
@@ -514,15 +521,17 @@ COFFEE_KEYWORDS.push op for all 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 = ['&&', '||', '&', '|', '^']
|
||||
|
||||
369
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,17 +242,18 @@ 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
|
||||
@expressions = rest
|
||||
post = @compileNode o
|
||||
{scope} = o
|
||||
if not o.globals and o.scope.hasDeclarations this
|
||||
code += "#{@tab}var #{ scope.compiledDeclarations() };\n"
|
||||
if scope.hasAssignments this
|
||||
code += "#{@tab}var #{ multident scope.compiledAssignments(), @tab };\n"
|
||||
if scope.expressions is this
|
||||
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"
|
||||
code + post
|
||||
|
||||
# Wrap up the given nodes as an **Expressions**, unless it already happens
|
||||
@@ -265,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 + '"'
|
||||
@@ -296,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
|
||||
|
||||
@@ -341,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
|
||||
@@ -410,7 +419,6 @@ exports.Value = class Value extends Base
|
||||
exports.Comment = class Comment extends Base
|
||||
constructor: (@comment) ->
|
||||
|
||||
isPureStatement: YES
|
||||
isStatement: YES
|
||||
makeReturn: THIS
|
||||
|
||||
@@ -433,7 +441,11 @@ exports.Call = class Call extends Base
|
||||
|
||||
# Tag this invocation as creating a new instance.
|
||||
newInstance: ->
|
||||
@isNew = true
|
||||
base = @variable.base or @variable
|
||||
if base instanceof Call
|
||||
base.newInstance()
|
||||
else
|
||||
@isNew = true
|
||||
this
|
||||
|
||||
# Grab the reference to the superclass's implementation of the current
|
||||
@@ -487,7 +499,7 @@ exports.Call = class Call extends Base
|
||||
return @compileSplat o, code
|
||||
args = (arg.compile o, LEVEL_LIST for arg in @args).join ', '
|
||||
if @isSuper
|
||||
@compileSuper args, o
|
||||
@superReference(o) + ".call(this#{ args and ', ' + args })"
|
||||
else
|
||||
(if @isNew then 'new ' else '') + @variable.compile(o, LEVEL_ACCESS) + "(#{args})"
|
||||
|
||||
@@ -502,23 +514,27 @@ exports.Call = class Call extends Base
|
||||
# inner constructor in order to be able to pass the varargs.
|
||||
compileSplat: (o, splatArgs) ->
|
||||
return "#{ @superReference o }.apply(this, #{splatArgs})" if @isSuper
|
||||
unless @isNew
|
||||
base = new Value @variable
|
||||
if (name = base.properties.pop()) and base.isComplex()
|
||||
ref = o.scope.freeVariable 'this'
|
||||
fun = "(#{ref} = #{ base.compile o, LEVEL_LIST })#{ name.compile o }"
|
||||
if @isNew
|
||||
idt = @tab + TAB
|
||||
return """
|
||||
(function(func, args, ctor) {
|
||||
#{idt}ctor.prototype = func.prototype;
|
||||
#{idt}var child = new ctor, result = func.apply(child, args);
|
||||
#{idt}return typeof result === "object" ? result : child;
|
||||
#{@tab}})(#{ @variable.compile o, LEVEL_LIST }, #{splatArgs}, function() {})
|
||||
"""
|
||||
base = new Value @variable
|
||||
if (name = base.properties.pop()) and base.isComplex()
|
||||
ref = o.scope.freeVariable 'ref'
|
||||
fun = "(#{ref} = #{ base.compile o, LEVEL_LIST })#{ name.compile o }"
|
||||
else
|
||||
fun = base.compile o, LEVEL_ACCESS
|
||||
if name
|
||||
ref = fun
|
||||
fun += name.compile o
|
||||
else
|
||||
fun = ref = base.compile o, LEVEL_ACCESS
|
||||
fun += name.compile o if name
|
||||
return "#{fun}.apply(#{ref}, #{splatArgs})"
|
||||
idt = @tab + TAB
|
||||
"""
|
||||
(function(func, args, ctor) {
|
||||
#{idt}ctor.prototype = func.prototype;
|
||||
#{idt}var child = new ctor, result = func.apply(child, args);
|
||||
#{idt}return typeof result === "object" ? result : child;
|
||||
#{@tab}})(#{ @variable.compile o, LEVEL_LIST }, #{splatArgs}, function() {})
|
||||
"""
|
||||
ref = 'null'
|
||||
"#{fun}.apply(#{ref}, #{splatArgs})"
|
||||
|
||||
#### Extends
|
||||
|
||||
@@ -541,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'
|
||||
|
||||
@@ -648,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
|
||||
|
||||
@@ -667,13 +693,8 @@ exports.Obj = class Obj extends Base
|
||||
compileNode: (o) ->
|
||||
props = @properties
|
||||
return (if @front then '({})' else '{}') unless props.length
|
||||
for prop, i in props
|
||||
if prop instanceof Splat or (prop.variable or prop).base instanceof Parens
|
||||
rest = props.splice i, 1/0
|
||||
break
|
||||
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
|
||||
''
|
||||
@@ -684,36 +705,15 @@ 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 }}"
|
||||
return @compileDynamic o, obj, rest if rest
|
||||
if @front then "(#{obj})" else obj
|
||||
|
||||
compileDynamic: (o, code, props) ->
|
||||
code = "#{ oref = o.scope.freeVariable 'obj' } = #{code}, "
|
||||
for prop, i in props
|
||||
if prop instanceof Comment
|
||||
code += prop.compile(o, LEVEL_LIST) + ' '
|
||||
continue
|
||||
if prop instanceof Assign
|
||||
acc = prop.variable.base
|
||||
key = acc.compile o, LEVEL_PAREN
|
||||
val = prop.value.compile o, LEVEL_LIST
|
||||
else
|
||||
acc = prop.base
|
||||
[key, val] = acc.cache o, LEVEL_LIST, ref
|
||||
ref = val if key isnt val
|
||||
key = if acc instanceof Literal and IDENTIFIER.test key
|
||||
'.' + key
|
||||
else
|
||||
'[' + key + ']'
|
||||
code += "#{oref}#{key} = #{val}, "
|
||||
code += oref
|
||||
if o.level <= LEVEL_PAREN then code else "(#{code})"
|
||||
|
||||
assigns: (name) ->
|
||||
for prop in @properties when prop.assigns name then return yes
|
||||
no
|
||||
@@ -749,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']
|
||||
|
||||
@@ -765,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
|
||||
@@ -794,10 +796,9 @@ exports.Class = class Class extends Base
|
||||
if func.bound
|
||||
throw new Error 'cannot define a constructor as a bound function'
|
||||
if func instanceof Code
|
||||
@ctor = func
|
||||
assign = @ctor = func
|
||||
else
|
||||
@ctor = new Assign(new Value(new Literal name), func)
|
||||
assign = null
|
||||
assign = @ctor = new Assign(new Value(new Literal name), func)
|
||||
else
|
||||
unless assign.variable.this
|
||||
assign.variable = new Value(new Literal(name), [new Access(base, 'proto')])
|
||||
@@ -809,11 +810,12 @@ exports.Class = class Class extends Base
|
||||
# Walk the body of the class, looking for prototype properties to be converted.
|
||||
walkBody: (name) ->
|
||||
@traverseChildren false, (child) =>
|
||||
return false if child instanceof Class
|
||||
if child instanceof Expressions
|
||||
for node, i in exps = child.expressions
|
||||
if node instanceof Value and node.isObject(true)
|
||||
exps[i] = compact @addProperties node, name
|
||||
child.expressions = exps = compact flatten exps
|
||||
exps[i] = @addProperties node, name
|
||||
child.expressions = exps = flatten exps
|
||||
|
||||
# Make sure that a constructor is defined for the class, and properly
|
||||
# configured.
|
||||
@@ -821,6 +823,7 @@ exports.Class = class Class extends Base
|
||||
if not @ctor
|
||||
@ctor = new Code
|
||||
@ctor.body.push new Call 'super', [new Splat new Literal 'arguments'] if @parent
|
||||
@body.expressions.unshift @ctor
|
||||
@ctor.ctor = @ctor.name = name
|
||||
@ctor.klass = null
|
||||
@ctor.noReturn = yes
|
||||
@@ -835,14 +838,12 @@ exports.Class = class Class extends Base
|
||||
|
||||
@setContext name
|
||||
@walkBody name
|
||||
@ensureConstructor name
|
||||
@body.expressions.unshift new Extends lname, @parent if @parent
|
||||
@body.expressions.unshift @ctor
|
||||
@ensureConstructor name
|
||||
@body.expressions.push lname
|
||||
@addBoundFunctions o
|
||||
|
||||
klass = new Parens new Call(new Code [], @body), true
|
||||
klass = new Assign new Value(lname), klass if decl and @variable?.isComplex()
|
||||
klass = new Parens Closure.wrap(@body), true
|
||||
klass = new Assign @variable, klass if @variable
|
||||
klass.compile o
|
||||
|
||||
@@ -851,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]*)$/
|
||||
@@ -881,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})"
|
||||
|
||||
@@ -951,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})"
|
||||
@@ -966,14 +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 = if range.to then range.to.compile(o) + ' - ' + from + plus else "#{name}.length"
|
||||
ref = o.scope.freeVariable 'ref'
|
||||
val = @value.compile(o)
|
||||
"([].splice.apply(#{name}, [#{from}, #{to}].concat(#{ref} = #{val})), #{ref})"
|
||||
{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 = 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
|
||||
|
||||
@@ -991,15 +1003,17 @@ 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 = scope = sharedScope or new Scope o.scope, @body, this
|
||||
o.indent += TAB
|
||||
o.scope = new Scope o.scope, @body, this
|
||||
o.scope.shared = del o, 'sharedScope'
|
||||
o.indent += TAB
|
||||
delete o.bare
|
||||
delete o.globals
|
||||
vars = []
|
||||
@@ -1012,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
|
||||
@@ -1020,11 +1034,10 @@ exports.Code = class Code extends Base
|
||||
val = new Assign new Value(param.name), param.value, '='
|
||||
exprs.push new If lit, val
|
||||
vars.push ref unless splats
|
||||
scope.startLevel()
|
||||
wasEmpty = @body.isEmpty()
|
||||
exprs.unshift splats if splats
|
||||
@body.expressions.unshift exprs... if exprs.length
|
||||
scope.parameter vars[i] = v.compile o for v, i in vars unless splats
|
||||
o.scope.parameter vars[i] = v.compile o for v, i in vars unless splats
|
||||
@body.makeReturn() unless wasEmpty or @noReturn
|
||||
idt = o.indent
|
||||
code = 'function'
|
||||
@@ -1034,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`.
|
||||
@@ -1129,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
|
||||
@@ -1155,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
|
||||
@@ -1166,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
|
||||
@@ -1185,13 +1197,11 @@ exports.Op = class Op extends Base
|
||||
INVERSIONS =
|
||||
'!==': '==='
|
||||
'===': '!=='
|
||||
'>': '<='
|
||||
'<=': '>'
|
||||
'<': '>='
|
||||
'>=': '<'
|
||||
|
||||
children: ['first', 'second']
|
||||
|
||||
isSimpleNumber: NO
|
||||
|
||||
isUnary: ->
|
||||
not @second
|
||||
|
||||
@@ -1201,8 +1211,23 @@ exports.Op = class Op extends Base
|
||||
@operator in ['<', '>', '>=', '<=', '===', '!==']
|
||||
|
||||
invert: ->
|
||||
if op = INVERSIONS[@operator]
|
||||
if @isChainable() and @first.isChainable()
|
||||
allInvertable = yes
|
||||
curr = this
|
||||
while curr and curr.operator
|
||||
allInvertable and= (curr.operator of INVERSIONS)
|
||||
curr = curr.first
|
||||
return new Parens(this).invert() unless allInvertable
|
||||
curr = this
|
||||
while curr and curr.operator
|
||||
curr.invert = !curr.invert
|
||||
curr.operator = INVERSIONS[curr.operator]
|
||||
curr = curr.first
|
||||
this
|
||||
else if op = INVERSIONS[@operator]
|
||||
@operator = op
|
||||
if @first.unwrap() instanceof Op
|
||||
@first.invert()
|
||||
this
|
||||
else if @second
|
||||
new Parens(this).invert()
|
||||
@@ -1231,10 +1256,9 @@ exports.Op = class Op extends Base
|
||||
# true
|
||||
compileChain: (o) ->
|
||||
[@first.second, shared] = @first.second.cache o
|
||||
fst = @first .compile o, LEVEL_OP
|
||||
fst = fst.slice 1, -1 if fst.charAt(0) is '('
|
||||
code = "#{fst} && #{ shared.compile o } #{@operator} #{ @second.compile o, LEVEL_OP }"
|
||||
if o.level < LEVEL_OP then code else "(#{code})"
|
||||
fst = @first.compile o, LEVEL_OP
|
||||
code = "#{fst} #{if @invert then '&&' else '||'} #{ shared.compile o } #{@operator} #{ @second.compile o, LEVEL_OP }"
|
||||
"(#{code})"
|
||||
|
||||
compileExistence: (o) ->
|
||||
if @first.isComplex()
|
||||
@@ -1300,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
|
||||
@@ -1329,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
|
||||
@@ -1381,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
|
||||
@@ -1395,45 +1423,46 @@ 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]
|
||||
@raw = !!source.raw
|
||||
@own = !!source.own
|
||||
@object = !!source.object
|
||||
[@name, @index] = [@index, @name] if @object
|
||||
throw SyntaxError 'index cannot be a pattern matching expression' if @index instanceof Value
|
||||
@range = @source instanceof Value and @source.base instanceof Range and not @source.properties.length
|
||||
@pattern = @name instanceof Value
|
||||
throw SyntaxError 'cannot pattern match a range loop' if @range and @pattern
|
||||
throw SyntaxError 'indexes do not apply to range loops' if @range and @index
|
||||
throw SyntaxError 'cannot pattern match over range loops' if @range and @pattern
|
||||
@returns = false
|
||||
|
||||
children: ['body', 'source', 'guard', 'step']
|
||||
|
||||
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
|
||||
unless hasCode
|
||||
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
|
||||
scope.find(name, immediate: yes) if name and not @pattern
|
||||
scope.find(index, immediate: yes) if index
|
||||
rvar = scope.freeVariable 'results' if @returns
|
||||
ivar = (if @range then name else index) or scope.freeVariable 'i'
|
||||
name = ivar if @pattern
|
||||
varPart = ''
|
||||
guardPart = ''
|
||||
defPart = ''
|
||||
@@ -1441,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
|
||||
if (name or not @raw) and not IDENTIFIER.test svar
|
||||
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;" unless @raw
|
||||
defPart += @pluckDirectCall o, body, name, index unless @pattern
|
||||
guardPart = "\n#{idt1}if (!#{utility('hasProp')}.call(#{svar}, #{ivar})) continue;" if @own
|
||||
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()
|
||||
@@ -1486,14 +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
|
||||
body.expressions[idx] = new Call base, expr.args
|
||||
defs += @tab + new Assign(ref, fn).compile(o, LEVEL_TOP) + ';\n'
|
||||
defs
|
||||
|
||||
@@ -1507,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()
|
||||
@@ -1522,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
|
||||
@@ -1537,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
|
||||
@@ -1562,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
|
||||
|
||||
@@ -1613,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
|
||||
@@ -1625,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
|
||||
@@ -1634,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
|
||||
|
||||
@@ -12,6 +12,10 @@ readline = require 'readline'
|
||||
# Start by opening up **stdio**.
|
||||
stdio = process.openStdin()
|
||||
|
||||
# Log an error.
|
||||
error = (err) ->
|
||||
stdio.write (err.stack or err.toString()) + '\n\n'
|
||||
|
||||
# Quick alias for quitting the REPL.
|
||||
helpers.extend global, quit: -> process.exit(0)
|
||||
|
||||
@@ -23,9 +27,12 @@ run = (buffer) ->
|
||||
val = CoffeeScript.eval buffer.toString(), bare: on, globals: on, fileName: 'repl'
|
||||
console.log val if val isnt undefined
|
||||
catch err
|
||||
console.error err.stack or err.toString()
|
||||
error err
|
||||
repl.prompt()
|
||||
|
||||
# Make sure that uncaught exceptions don't kill the REPL.
|
||||
process.on 'uncaughtException', error
|
||||
|
||||
# Create the REPL by listening to **stdin**.
|
||||
repl = readline.createInterface stdio
|
||||
repl.setPrompt 'coffee> '
|
||||
|
||||
@@ -97,13 +97,13 @@ class exports.Rewriter
|
||||
start = null
|
||||
startIndent = 0
|
||||
condition = (token, i) ->
|
||||
{(i+1): one, (i+2): two, (i+3): three} = @tokens
|
||||
[one, two, three] = @tokens[i + 1 .. i + 3]
|
||||
return false if 'HERECOMMENT' is one?[0]
|
||||
[tag] = token
|
||||
(tag in ['TERMINATOR', 'OUTDENT'] and
|
||||
not (two?[0] is ':' or one?[0] is '@' and three?[0] is ':')) or
|
||||
(tag is ',' and one and
|
||||
one[0] not in ['IDENTIFIER', 'NUMBER', 'STRING', '@', 'TERMINATOR', 'OUTDENT', '('])
|
||||
one[0] not in ['IDENTIFIER', 'NUMBER', 'STRING', '@', 'TERMINATOR', 'OUTDENT'])
|
||||
action = (token, i) -> @tokens.splice i, 0, ['}', '}', token[2]]
|
||||
@scanTokens (token, i, tokens) ->
|
||||
if (tag = token[0]) in EXPRESSION_START
|
||||
@@ -113,17 +113,10 @@ class exports.Rewriter
|
||||
start = stack.pop()
|
||||
return 1
|
||||
return 1 unless tag is ':' and
|
||||
((ago2 = @tag i - 2) is ':' or
|
||||
(ago1 = @tag i - 1) is ')' and @tag(start[1] - 1) is ':' or
|
||||
stack[stack.length - 1]?[0] isnt '{')
|
||||
((ago = @tag i - 2) is ':' or stack[stack.length - 1]?[0] isnt '{')
|
||||
stack.push ['{']
|
||||
idx = if ago1 is ')'
|
||||
start[1]
|
||||
else if ago2 is '@'
|
||||
i - 2
|
||||
else
|
||||
i - 1
|
||||
idx -= 2 if @tag(idx - 2) is 'HERECOMMENT'
|
||||
idx = if ago is '@' then i - 2 else i - 1
|
||||
idx -= 2 while @tag(idx - 2) is 'HERECOMMENT'
|
||||
value = new String('{')
|
||||
value.generated = yes
|
||||
tok = ['{', value, token[2]]
|
||||
@@ -142,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']
|
||||
{(i-1): prev, (i+1): next} = tokens
|
||||
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
|
||||
@@ -205,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'
|
||||
@@ -224,7 +217,7 @@ class exports.Rewriter
|
||||
openLine[open] = token[2] if levels[open]++ is 0
|
||||
else if tag is close and --levels[open] < 0
|
||||
throw Error "too many #{token[1]} on line #{token[2] + 1}"
|
||||
for all open, level of levels when level > 0
|
||||
for open, level of levels when level > 0
|
||||
throw Error "unclosed #{ open } on line #{openLine[open] + 1}"
|
||||
this
|
||||
|
||||
@@ -247,7 +240,7 @@ class exports.Rewriter
|
||||
rewriteClosingParens: ->
|
||||
stack = []
|
||||
debt = {}
|
||||
debt[key] = 0 for all key of INVERSES
|
||||
debt[key] = 0 for key of INVERSES
|
||||
@scanTokens (token, i, tokens) ->
|
||||
if (tag = token[0]) in EXPRESSION_START
|
||||
stack.push token
|
||||
@@ -312,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'
|
||||
'@', '->', '=>', '[', '(', '{', '--', '++'
|
||||
]
|
||||
|
||||
@@ -322,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.
|
||||
|
||||
@@ -20,45 +20,27 @@ exports.Scope = class Scope
|
||||
constructor:(@parent, @expressions, @method) ->
|
||||
@variables = [{name: 'arguments', type: 'arguments'}]
|
||||
@positions = {}
|
||||
if @parent
|
||||
@garbage = @parent.garbage
|
||||
else
|
||||
@garbage = []
|
||||
Scope.root = this
|
||||
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
|
||||
@positions[name] = @variables.push({name, type}) - 1
|
||||
|
||||
# Create a new garbage level
|
||||
startLevel: ->
|
||||
@garbage.push []
|
||||
this
|
||||
|
||||
# Return to the previous garbage level and erase referenced temporary
|
||||
# variables in current level from scope.
|
||||
endLevel: ->
|
||||
@add name, 'reuse' for name in @garbage.pop() when @type(name) is 'var'
|
||||
this
|
||||
|
||||
# Look up a variable name in lexical scope, and declare it if it does not
|
||||
# already exist.
|
||||
find: (name, options) ->
|
||||
return true if @check name, options
|
||||
return yes if @check name, options
|
||||
@add name, 'var'
|
||||
false
|
||||
|
||||
# Test variables and return `true` the first time `fn(v)` returns `true`
|
||||
any: (fn) ->
|
||||
return yes for v in @variables when fn v
|
||||
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 @parent.check name, yes
|
||||
@add name, 'param'
|
||||
|
||||
# Just check to see if a variable has already been declared, without reserving,
|
||||
@@ -77,50 +59,36 @@ exports.Scope = class Scope
|
||||
|
||||
# Gets the type of a variable.
|
||||
type: (name) ->
|
||||
for v in @variables when v.name is name then return v.type
|
||||
return v.type for v in @variables when v.name is name
|
||||
null
|
||||
|
||||
# If we need to store an intermediate result, find an available name for a
|
||||
# compiler-generated variable. `_var`, `_var2`, and so on...
|
||||
freeVariable: (type) ->
|
||||
index = 0
|
||||
index++ while @check((temp = @temporary type, index), true) and @type(temp) isnt 'reuse'
|
||||
@add temp, 'var'
|
||||
last(@garbage)?.push temp
|
||||
index++ while @check((temp = @temporary type, index), true)
|
||||
@add temp, 'var', yes
|
||||
temp
|
||||
|
||||
# Ensure that an assignment is made at the top of this scope
|
||||
# (or at the top-level scope, if requested).
|
||||
assign: (name, value) ->
|
||||
@add name, value: value, assigned: true
|
||||
@hasAssignments = yes
|
||||
|
||||
# Does this scope reference any variables that need to be declared in the
|
||||
# given function body?
|
||||
hasDeclarations: (body) ->
|
||||
body is @expressions and @any (v) -> v.type in ['var', 'reuse']
|
||||
|
||||
# Does this scope reference any assignments that need to be declared at the
|
||||
# top of the given function body?
|
||||
hasAssignments: (body) ->
|
||||
body is @expressions and @any (v) -> v.type.assigned
|
||||
# Does this scope have any declared variables?
|
||||
hasDeclarations: ->
|
||||
!!@declaredVariables().length
|
||||
|
||||
# Return the list of variables first declared in this scope.
|
||||
declaredVariables: ->
|
||||
usr = []
|
||||
tmp = []
|
||||
for v in @variables when v.type in ['var', 'reuse']
|
||||
(if v.name.charAt(0) is '_' then tmp else usr).push v.name
|
||||
usr.sort().concat tmp.sort()
|
||||
realVars = []
|
||||
tempVars = []
|
||||
for v in @variables when v.type is 'var'
|
||||
(if v.name.charAt(0) is '_' then tempVars else realVars).push v.name
|
||||
realVars.sort().concat tempVars.sort()
|
||||
|
||||
# Return the list of assignments that are supposed to be made at the top
|
||||
# of this scope.
|
||||
assignedVariables: ->
|
||||
("#{v.name} = #{v.type.value}" for v in @variables when v.type.assigned)
|
||||
|
||||
# Compile the JavaScript for all of the variable declarations in this scope.
|
||||
compiledDeclarations: ->
|
||||
@declaredVariables().join ', '
|
||||
|
||||
# Compile the JavaScript for all of the variable assignments in this scope.
|
||||
compiledAssignments: ->
|
||||
@assignedVariables().join ', '
|
||||
"#{v.name} = #{v.type.value}" for v in @variables when v.type.assigned
|
||||
|
||||
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
|
||||
|
||||