mirror of
https://github.com/jashkenas/coffeescript.git
synced 2026-01-13 16:57:54 -05:00
Compare commits
306 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3e41659095 | ||
|
|
d592d2c9cb | ||
|
|
78491b3a58 | ||
|
|
426f51db21 | ||
|
|
5ae4e06770 | ||
|
|
683b3afbc1 | ||
|
|
1c86aee7a4 | ||
|
|
11f048c368 | ||
|
|
f0043468a0 | ||
|
|
a6081caf50 | ||
|
|
c77f7737a5 | ||
|
|
91cb433b66 | ||
|
|
2cb42b502c | ||
|
|
64bd4b3f74 | ||
|
|
41f2d2f789 | ||
|
|
913171f708 | ||
|
|
3f4daaf2ad | ||
|
|
cf32ba0149 | ||
|
|
6bec372684 | ||
|
|
620d8ce9ed | ||
|
|
bf8062ce7f | ||
|
|
350e50600d | ||
|
|
938abae4b5 | ||
|
|
264f881a81 | ||
|
|
d359764fba | ||
|
|
4a937ec3b8 | ||
|
|
0ded5b3ff3 | ||
|
|
c20a8ff53d | ||
|
|
2f38ed5e69 | ||
|
|
054fe34434 | ||
|
|
e686e3f6e9 | ||
|
|
cf996d2c4a | ||
|
|
9fef66ffcf | ||
|
|
1627922060 | ||
|
|
981db17b8f | ||
|
|
52dd348289 | ||
|
|
f4c1b20ec2 | ||
|
|
08762a101c | ||
|
|
3b5c889040 | ||
|
|
0171204e50 | ||
|
|
dd82b15b78 | ||
|
|
3d91b10927 | ||
|
|
65b3bf0d4c | ||
|
|
4c0b2372c7 | ||
|
|
54110c98d9 | ||
|
|
a2c593bc2c | ||
|
|
de0122dc17 | ||
|
|
2c43a9d209 | ||
|
|
6da70168a6 | ||
|
|
0199515cef | ||
|
|
37705e712b | ||
|
|
d2b0404188 | ||
|
|
80f9a20bfd | ||
|
|
94a9551ffa | ||
|
|
4419f7ca0f | ||
|
|
19f77cfff5 | ||
|
|
3cdee749c6 | ||
|
|
d03d288a98 | ||
|
|
c5dbb1c933 | ||
|
|
85342f1e31 | ||
|
|
c1f9ae8208 | ||
|
|
bd1672621c | ||
|
|
2d6cda7f32 | ||
|
|
2c8690ee39 | ||
|
|
6c98480a1e | ||
|
|
98cc7eb149 | ||
|
|
6278930aef | ||
|
|
0b57b3136c | ||
|
|
46b7a2d17c | ||
|
|
588af1f6af | ||
|
|
34f99c4a79 | ||
|
|
a0d4242da4 | ||
|
|
447c3639e7 | ||
|
|
f0e276c63a | ||
|
|
7d4e693d20 | ||
|
|
03372c9b29 | ||
|
|
6d0ba4b3bd | ||
|
|
6622f015ab | ||
|
|
d6ec5e40cc | ||
|
|
c44b80b6b6 | ||
|
|
9db814f70d | ||
|
|
d7f9054108 | ||
|
|
2df9204104 | ||
|
|
ed4f7046d3 | ||
|
|
ad1bc1e0b8 | ||
|
|
2ea51b02cc | ||
|
|
036fc561a2 | ||
|
|
a8185407fa | ||
|
|
1cc85aad64 | ||
|
|
067cd4b4fe | ||
|
|
6d68b1f5ad | ||
|
|
e8b3e2f248 | ||
|
|
d5aad39b3f | ||
|
|
cce9ac28c9 | ||
|
|
49e3a91d67 | ||
|
|
76b6a1771b | ||
|
|
c88cb5c8b5 | ||
|
|
efd503f84a | ||
|
|
7ba52ae729 | ||
|
|
8ebda7ac02 | ||
|
|
43a8b46203 | ||
|
|
d1af5163eb | ||
|
|
ee6eccbfe1 | ||
|
|
d37cfc69d9 | ||
|
|
3a6c8c92b3 | ||
|
|
e17b67e6f2 | ||
|
|
c0e0ede09f | ||
|
|
a4425471fd | ||
|
|
b4e2240ede | ||
|
|
539b872e02 | ||
|
|
2ff6c4c3fc | ||
|
|
8686e31271 | ||
|
|
0bf0f6d721 | ||
|
|
3ef0c1c88a | ||
|
|
5b115ddb74 | ||
|
|
604e39b413 | ||
|
|
f3253f4f5c | ||
|
|
2fb2ddb9b4 | ||
|
|
7e4d6198d4 | ||
|
|
8c31f2ee44 | ||
|
|
9a026e51bd | ||
|
|
50982b668b | ||
|
|
c6c988ae28 | ||
|
|
306d84828d | ||
|
|
4710e744dc | ||
|
|
0b3029dd3f | ||
|
|
41b8b3256d | ||
|
|
42f2bd926b | ||
|
|
197d07cc85 | ||
|
|
c9fd0659c2 | ||
|
|
fa2fbf0c60 | ||
|
|
c3fe29455b | ||
|
|
df5aca9348 | ||
|
|
ab0b36a53f | ||
|
|
29a44b84d5 | ||
|
|
e5b77b180a | ||
|
|
fc1cdfc913 | ||
|
|
8c5027abb9 | ||
|
|
333daf33a3 | ||
|
|
064f2b5787 | ||
|
|
13ac72239a | ||
|
|
818216374c | ||
|
|
5a9cf5722f | ||
|
|
a5ba0c27ae | ||
|
|
f6d3953bc6 | ||
|
|
c9a5135e23 | ||
|
|
ab326aea4c | ||
|
|
7cf5988099 | ||
|
|
35a30fbd6d | ||
|
|
6608a7aa98 | ||
|
|
803a7d06e3 | ||
|
|
be4685589a | ||
|
|
bf7d62affb | ||
|
|
718b73a0ba | ||
|
|
c2a43f70f2 | ||
|
|
c222da9dd6 | ||
|
|
55e366f29c | ||
|
|
4e71aad124 | ||
|
|
a03f2fe937 | ||
|
|
5710992156 | ||
|
|
0ed9be4665 | ||
|
|
d665c3a75f | ||
|
|
48f3c70013 | ||
|
|
8a4ec8f562 | ||
|
|
1a652a9736 | ||
|
|
15fed8d17f | ||
|
|
396f9b3a12 | ||
|
|
1f69200d06 | ||
|
|
0e0d625adb | ||
|
|
638dbbecbc | ||
|
|
9f89a83c27 | ||
|
|
178af9de56 | ||
|
|
e7854bec09 | ||
|
|
9b9612e09c | ||
|
|
d2d02bf91d | ||
|
|
860c5030d2 | ||
|
|
2d54fea90c | ||
|
|
5ee0254ce5 | ||
|
|
37019dab1c | ||
|
|
2b31f28f8f | ||
|
|
8931e31991 | ||
|
|
813efbe1d3 | ||
|
|
7790df0df6 | ||
|
|
c2b32df22b | ||
|
|
479a2e0383 | ||
|
|
471cf1d51a | ||
|
|
ecdaad2fd6 | ||
|
|
3e20622bd5 | ||
|
|
8a4a28bd33 | ||
|
|
8fe59ed888 | ||
|
|
1927213174 | ||
|
|
cb8e147212 | ||
|
|
07baed89ed | ||
|
|
af1cf3400e | ||
|
|
eb53670676 | ||
|
|
709dc73c27 | ||
|
|
14e09d2ca8 | ||
|
|
0353b0ddd3 | ||
|
|
f2ba08f77f | ||
|
|
1d7d8cb4d2 | ||
|
|
6e9cfd8a33 | ||
|
|
2a9fd34a03 | ||
|
|
b1111c96ca | ||
|
|
55383155e5 | ||
|
|
bb1502a9d7 | ||
|
|
40ee30ecde | ||
|
|
4ff00359b6 | ||
|
|
f433fa4187 | ||
|
|
594ead00e8 | ||
|
|
5adf3b8865 | ||
|
|
4fc52cd08e | ||
|
|
4af47f0c26 | ||
|
|
9d3510a1e4 | ||
|
|
18f6ad9583 | ||
|
|
4c70ea5e09 | ||
|
|
d32c060e05 | ||
|
|
caa3d1ab5d | ||
|
|
d3e809da38 | ||
|
|
5ab892d009 | ||
|
|
54dbc0fdf8 | ||
|
|
003f91d43d | ||
|
|
83806a4d77 | ||
|
|
c4324f1db2 | ||
|
|
b9c3e0e640 | ||
|
|
60e51a238d | ||
|
|
fff4c9c672 | ||
|
|
ab17f41652 | ||
|
|
18ab569b2d | ||
|
|
2951d34dc0 | ||
|
|
0cc5379caa | ||
|
|
f6fcfa831c | ||
|
|
c93fc3ec76 | ||
|
|
7b5f012f79 | ||
|
|
22cee5d2d6 | ||
|
|
0f18dff464 | ||
|
|
e38aeefb5c | ||
|
|
baa983ac33 | ||
|
|
cd65c66cf9 | ||
|
|
dc272a680b | ||
|
|
6f64fc266d | ||
|
|
73af3b17b1 | ||
|
|
8b2884e40f | ||
|
|
f0c22f390d | ||
|
|
11f2cd4515 | ||
|
|
5ce7984a2b | ||
|
|
9699059226 | ||
|
|
9941c3f045 | ||
|
|
25e7eeac8f | ||
|
|
277e82bd03 | ||
|
|
a1f1afe3ed | ||
|
|
0f523de212 | ||
|
|
47f12c453a | ||
|
|
dfcff3f0fc | ||
|
|
522f2ee3b3 | ||
|
|
8ce1fdb5bb | ||
|
|
a0efdac8ce | ||
|
|
22bc54f974 | ||
|
|
e240621a72 | ||
|
|
35c2a72ad2 | ||
|
|
10ec1a659f | ||
|
|
1fb34e42a6 | ||
|
|
7082000e66 | ||
|
|
79fff367c2 | ||
|
|
9cbf2a82ec | ||
|
|
6a40807330 | ||
|
|
8d6e33c2cf | ||
|
|
085874d5f3 | ||
|
|
94fb7e32ea | ||
|
|
042f7ec791 | ||
|
|
e4f47a05f6 | ||
|
|
bbf37e5229 | ||
|
|
454aa8433b | ||
|
|
bbf1c6a8df | ||
|
|
8e5eff5e1e | ||
|
|
e64fa71185 | ||
|
|
c8845643e5 | ||
|
|
371ff5e726 | ||
|
|
19520d8d35 | ||
|
|
abb11a7c0e | ||
|
|
2ac74356bd | ||
|
|
004f13f0fc | ||
|
|
395a97ef07 | ||
|
|
01b0cfc8ab | ||
|
|
f3758e4af0 | ||
|
|
2563324ed8 | ||
|
|
d91ccd4003 | ||
|
|
15ddb8e2ea | ||
|
|
c056c93e19 | ||
|
|
9e32a5bfa1 | ||
|
|
cd5c41f351 | ||
|
|
b780d707ab | ||
|
|
84ae563368 | ||
|
|
dddc7c6edb | ||
|
|
bd8d82809b | ||
|
|
51b7142805 | ||
|
|
6c9ef76b95 | ||
|
|
a024ec5b27 | ||
|
|
2212e959ac | ||
|
|
dc499089e9 | ||
|
|
1809c0e675 | ||
|
|
d11d69958f | ||
|
|
6d2733405d | ||
|
|
2dc2d162bc | ||
|
|
b9d3bc5b44 | ||
|
|
fa2ed81485 | ||
|
|
ea4a723379 |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -5,4 +5,5 @@ parser.output
|
||||
test/fixtures/underscore
|
||||
test/*.js
|
||||
examples/beautiful_code/parse.coffee
|
||||
*.gem
|
||||
*.gem
|
||||
/node_modules
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
Cakefile
|
||||
documentation/
|
||||
examples/
|
||||
extras/
|
||||
extras/coffee-script.js
|
||||
raw/
|
||||
src/
|
||||
test/
|
||||
|
||||
117
Cakefile
117
Cakefile
@@ -1,14 +1,20 @@
|
||||
fs = require 'fs'
|
||||
path = require 'path'
|
||||
{extend} = require './lib/helpers'
|
||||
{extend} = require './lib/coffee-script/helpers'
|
||||
CoffeeScript = require './lib/coffee-script'
|
||||
{spawn, exec} = require 'child_process'
|
||||
|
||||
# ANSI Terminal Colors.
|
||||
bold = '\033[0;1m'
|
||||
red = '\033[0;31m'
|
||||
green = '\033[0;32m'
|
||||
reset = '\033[0m'
|
||||
enableColors = no
|
||||
unless process.platform is 'win32'
|
||||
enableColors = not process.env.NODE_DISABLE_COLORS
|
||||
|
||||
bold = red = green = reset = ''
|
||||
if enableColors
|
||||
bold = '\033[0;1m'
|
||||
red = '\033[0;31m'
|
||||
green = '\033[0;32m'
|
||||
reset = '\033[0m'
|
||||
|
||||
# Built file header.
|
||||
header = """
|
||||
@@ -22,16 +28,17 @@ header = """
|
||||
"""
|
||||
|
||||
sources = [
|
||||
'src/coffee-script.coffee', 'src/grammar.coffee'
|
||||
'src/helpers.coffee', 'src/lexer.coffee', 'src/nodes.coffee'
|
||||
'src/rewriter.coffee', 'src/scope.coffee'
|
||||
]
|
||||
'coffee-script', 'grammar', 'helpers'
|
||||
'lexer', 'nodes', 'rewriter', 'scope'
|
||||
].map (filename) -> "src/#{filename}.coffee"
|
||||
|
||||
# Run a CoffeeScript through our node/coffee interpreter.
|
||||
run = (args) ->
|
||||
run = (args, cb) ->
|
||||
proc = spawn 'bin/coffee', args
|
||||
proc.stderr.on 'data', (buffer) -> console.log buffer.toString()
|
||||
proc.on 'exit', (status) -> process.exit(1) if status != 0
|
||||
proc.on 'exit', (status) ->
|
||||
process.exit(1) if status != 0
|
||||
cb() if typeof cb is 'function'
|
||||
|
||||
# Log a message with a color.
|
||||
log = (message, color, explanation) ->
|
||||
@@ -53,30 +60,32 @@ task 'install', 'install CoffeeScript into /usr/local (or --prefix)', (options)
|
||||
"ln -sfn #{lib}/bin/coffee #{bin}/coffee"
|
||||
"ln -sfn #{lib}/bin/cake #{bin}/cake"
|
||||
"mkdir -p ~/.node_libraries"
|
||||
"ln -sfn #{lib}/lib #{node}"
|
||||
"ln -sfn #{lib}/lib/coffee-script #{node}"
|
||||
].join(' && '), (err, stdout, stderr) ->
|
||||
if err then console.log stderr.trim() else log 'done', green
|
||||
)
|
||||
|
||||
|
||||
task 'build', 'build the CoffeeScript language from source', ->
|
||||
task 'build', 'build the CoffeeScript language from source', build = (cb) ->
|
||||
files = fs.readdirSync 'src'
|
||||
files = ('src/' + file for file in files when file.match(/\.coffee$/))
|
||||
run ['-c', '-o', 'lib'].concat(files)
|
||||
run ['-c', '-o', 'lib/coffee-script'].concat(files), cb
|
||||
|
||||
|
||||
task 'build:full', 'rebuild the source twice, and run the tests', ->
|
||||
exec 'bin/cake build && bin/cake build && bin/cake test', (err, stdout, stderr) ->
|
||||
console.log stdout.trim() if stdout
|
||||
console.log stderr.trim() if stderr
|
||||
throw err if err
|
||||
build ->
|
||||
build ->
|
||||
csPath = './lib/coffee-script'
|
||||
delete require.cache[require.resolve csPath]
|
||||
unless runTests require csPath
|
||||
process.exit 1
|
||||
|
||||
|
||||
task 'build:parser', 'rebuild the Jison parser (run build first)', ->
|
||||
extend global, require('util')
|
||||
require 'jison'
|
||||
parser = require('./lib/grammar').parser
|
||||
fs.writeFile 'lib/parser.js', parser.generate()
|
||||
parser = require('./lib/coffee-script/grammar').parser
|
||||
fs.writeFile 'lib/coffee-script/parser.js', parser.generate()
|
||||
|
||||
|
||||
task 'build:ultraviolet', 'build and install the Ultraviolet syntax highlighter', ->
|
||||
@@ -91,7 +100,7 @@ task 'build:browser', 'rebuild the merged script for inclusion in the browser',
|
||||
code += """
|
||||
require['./#{name}'] = new function() {
|
||||
var exports = this;
|
||||
#{fs.readFileSync "lib/#{name}.js"}
|
||||
#{fs.readFileSync "lib/coffee-script/#{name}.js"}
|
||||
};
|
||||
"""
|
||||
code = """
|
||||
@@ -124,7 +133,7 @@ task 'doc:underscore', 'rebuild the Underscore.coffee documentation page', ->
|
||||
throw err if err
|
||||
|
||||
task 'bench', 'quick benchmark of compilation time', ->
|
||||
{Rewriter} = require './lib/rewriter'
|
||||
{Rewriter} = require './lib/coffee-script/rewriter'
|
||||
co = sources.map((name) -> fs.readFileSync name).join '\n'
|
||||
fmt = (ms) -> " #{bold}#{ " #{ms}".slice -4 }#{reset} ms"
|
||||
total = 0
|
||||
@@ -152,19 +161,9 @@ runTests = (CoffeeScript) ->
|
||||
passedTests = 0
|
||||
failures = []
|
||||
|
||||
# make "global" reference available to tests
|
||||
global.global = global
|
||||
|
||||
# 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'
|
||||
global[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.
|
||||
@@ -172,26 +171,29 @@ runTests = (CoffeeScript) ->
|
||||
try
|
||||
fn.test = {description, currentFile}
|
||||
fn.call(fn)
|
||||
++passedTests
|
||||
catch e
|
||||
e.description = description if description?
|
||||
e.source = fn.toString() if fn.toString?
|
||||
failures.push file: currentFile, error: e
|
||||
failures.push filename: 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) ->
|
||||
egal = (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
|
||||
# A recursive functional equivalence helper; uses egal for testing equivalence.
|
||||
arrayEgal = (a, b) ->
|
||||
if egal a, b then yes
|
||||
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 arrayEgal el, b[idx]
|
||||
yes
|
||||
|
||||
global.eq = (a, b, msg) -> ok egal(a, b), msg
|
||||
global.arrayEq = (a, b, msg) -> ok arrayEgal(a,b), msg
|
||||
|
||||
# When all the tests have run, collect and print errors.
|
||||
# If a stacktrace is available, output the compiled function source.
|
||||
@@ -201,27 +203,28 @@ runTests = (CoffeeScript) ->
|
||||
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')
|
||||
{error, filename} = fail
|
||||
jsFilename = filename.replace(/\.coffee$/,'.js')
|
||||
match = error.stack?.match(new RegExp(fail.file+":(\\d+):(\\d+)"))
|
||||
match = error.stack?.match(/on line (\d+):/) unless match
|
||||
[match, line, col] = match if match
|
||||
log "\n #{error.toString()}", red
|
||||
console.log ''
|
||||
log " #{error.description}", red if error.description
|
||||
log " #{jsFile}: line #{line or 'unknown'}, column #{col or 'unknown'}", red
|
||||
log " #{error.stack}", red
|
||||
log " #{jsFilename}: line #{line ? 'unknown'}, column #{col ? 'unknown'}", red
|
||||
console.log " #{error.source}" if error.source
|
||||
return
|
||||
|
||||
# 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 e
|
||||
failures.push file: currentFile, error: e
|
||||
files = fs.readdirSync 'test'
|
||||
for file in files when file.match /\.coffee$/i
|
||||
currentFile = filename = path.join 'test', file
|
||||
code = fs.readFileSync filename
|
||||
try
|
||||
CoffeeScript.run code.toString(), {filename}
|
||||
catch error
|
||||
failures.push {filename, error}
|
||||
return !failures.length
|
||||
|
||||
|
||||
task 'test', 'run the CoffeeScript language test suite', ->
|
||||
|
||||
7
README
7
README
@@ -1,4 +1,4 @@
|
||||
=
|
||||
|
||||
{
|
||||
} } {
|
||||
{ { } }
|
||||
@@ -29,9 +29,12 @@
|
||||
npm install -g coffee-script
|
||||
(Leave off the -g if you don't wish to install globally.)
|
||||
|
||||
Compile a script:
|
||||
Execute a script:
|
||||
coffee /path/to/script.coffee
|
||||
|
||||
Compile a script:
|
||||
coffee -c /path/to/script.coffee
|
||||
|
||||
For documentation, usage, and examples, see:
|
||||
http://coffeescript.org/
|
||||
|
||||
|
||||
2
bin/cake
2
bin/cake
@@ -4,4 +4,4 @@ var path = require('path');
|
||||
var fs = require('fs');
|
||||
var lib = path.join(path.dirname(fs.realpathSync(__filename)), '../lib');
|
||||
|
||||
require(lib + '/cake').run();
|
||||
require(lib + '/coffee-script/cake').run();
|
||||
|
||||
@@ -4,4 +4,4 @@ var path = require('path');
|
||||
var fs = require('fs');
|
||||
var lib = path.join(path.dirname(fs.realpathSync(__filename)), '../lib');
|
||||
|
||||
require(lib + '/command').run();
|
||||
require(lib + '/coffee-script/command').run();
|
||||
|
||||
@@ -8,4 +8,4 @@ if car.speed < limit then accelerate()
|
||||
|
||||
winner = yes if pick in [47, 92, 13]
|
||||
|
||||
print inspect "My name is " + @name
|
||||
print inspect "My name is #{@name}"
|
||||
|
||||
@@ -1,2 +1,10 @@
|
||||
# Eat lunch.
|
||||
eat food for food in ['toast', 'cheese', 'wine']
|
||||
|
||||
# Fine dining
|
||||
courses = ['salad', 'entree', 'dessert']
|
||||
menu course + 1, dish for dish, course in courses
|
||||
|
||||
# Health conscious meal
|
||||
foods = ['broccoli', 'spinach', 'chocolate']
|
||||
eat food for food in foods when food isnt 'chocolate'
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
###
|
||||
CoffeeScript Compiler v1.1.1
|
||||
CoffeeScript Compiler v1.1.3
|
||||
Released under the MIT License
|
||||
###
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ class Animal
|
||||
constructor: (@name) ->
|
||||
|
||||
move: (meters) ->
|
||||
alert @name + " moved " + meters + "m."
|
||||
alert @name + " moved #{meters}m."
|
||||
|
||||
class Snake extends Animal
|
||||
move: ->
|
||||
|
||||
@@ -2,6 +2,6 @@ alert(
|
||||
try
|
||||
nonexistent / undefined
|
||||
catch error
|
||||
"And the error is ... " + error
|
||||
"And the error is ... #{error}"
|
||||
)
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
yearsOld = max: 10, ida: 9, tim: 11
|
||||
|
||||
ages = for child, age of yearsOld
|
||||
child + " is " + age
|
||||
"#{child} is #{age}"
|
||||
|
||||
@@ -6,5 +6,5 @@ if this.studyingEconomics
|
||||
# Nursery Rhyme
|
||||
num = 6
|
||||
lyrics = while num -= 1
|
||||
num + " little monkeys, jumping on the bed.
|
||||
"#{num} little monkeys, jumping on the bed.
|
||||
One fell out and bumped his head."
|
||||
|
||||
@@ -85,6 +85,10 @@ code, pre, tt, textarea {
|
||||
font-weight: normal;
|
||||
color: black;
|
||||
}
|
||||
.timestamp small {
|
||||
font-size: 11px;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
div.code {
|
||||
position: relative;
|
||||
background: #fff;
|
||||
@@ -260,6 +264,10 @@ div.code {
|
||||
width: 40px;
|
||||
text-transform: none;
|
||||
}
|
||||
.navigation .code a.minibutton.permalink {
|
||||
top: 38px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.bookmark {
|
||||
display: block;
|
||||
|
||||
@@ -9,10 +9,10 @@
|
||||
<span class="nv">xhr.onreadystatechange = </span><span class="o">-></span>
|
||||
<span class="k">if</span> <span class="nx">xhr</span><span class="p">.</span><span class="nx">readyState</span> <span class="o">is</span> <span class="mi">4</span>
|
||||
<span class="k">if</span> <span class="nx">xhr</span><span class="p">.</span><span class="nx">status</span> <span class="k">in</span> <span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">200</span><span class="p">]</span>
|
||||
<span class="nx">CoffeeScript</span><span class="p">.</span><span class="nx">run</span> <span class="nx">xhr</span><span class="p">.</span><span class="nx">responseText</span>
|
||||
<span class="nx">CoffeeScript</span><span class="p">.</span><span class="nx">run</span> <span class="nx">xhr</span><span class="p">.</span><span class="nx">responseText</span>
|
||||
<span class="k">else</span>
|
||||
<span class="k">throw</span> <span class="k">new</span> <span class="nb">Error</span> <span class="s2">"Could not load #{url}"</span>
|
||||
<span class="nx">callback</span><span class="p">()</span> <span class="k">if</span> <span class="nx">callback</span>
|
||||
<span class="nx">callback</span><span class="p">()</span> <span class="k">if</span> <span class="nx">callback</span>
|
||||
<span class="nx">xhr</span><span class="p">.</span><span class="nx">send</span> <span class="kc">null</span></pre></div> </td> </tr> <tr id="section-6"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-6">¶</a> </div> <p>Activate CoffeeScript in the browser by having it compile and evaluate
|
||||
all script tags with a content-type of <code>text/coffeescript</code>.
|
||||
This happens on page load.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">runScripts = </span><span class="o">-></span>
|
||||
|
||||
@@ -21,23 +21,29 @@ as the first argument to the action.</p> </td> <td class
|
||||
<span class="nx">missingTask</span> <span class="nx">name</span> <span class="nx">unless</span> <span class="nx">tasks</span><span class="p">[</span><span class="nx">name</span><span class="p">]</span>
|
||||
<span class="nx">tasks</span><span class="p">[</span><span class="nx">name</span><span class="p">].</span><span class="nx">action</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>Run <code>cake</code>. Executes all of the tasks you pass, in order. Note that Node's
|
||||
asynchrony may cause tasks to execute in a different order than you'd expect.
|
||||
If no tasks are passed, print the help screen.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.run = </span><span class="o">-></span>
|
||||
<span class="nx">path</span><span class="p">.</span><span class="nx">exists</span> <span class="s1">'Cakefile'</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">throw</span> <span class="k">new</span> <span class="nb">Error</span><span class="p">(</span><span class="s2">"Cakefile not found in #{process.cwd()}"</span><span class="p">)</span> <span class="nx">unless</span> <span class="nx">exists</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="nx">slice</span> <span class="mi">2</span>
|
||||
<span class="nx">CoffeeScript</span><span class="p">.</span><span class="nx">run</span> <span class="nx">fs</span><span class="p">.</span><span class="nx">readFileSync</span><span class="p">(</span><span class="s1">'Cakefile'</span><span class="p">).</span><span class="nx">toString</span><span class="p">(),</span> <span class="nx">filename</span><span class="o">:</span> <span class="s1">'Cakefile'</span>
|
||||
<span class="nv">oparse = </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="k">return</span> <span class="nx">printTasks</span><span class="p">()</span> <span class="nx">unless</span> <span class="nx">args</span><span class="p">.</span><span class="nx">length</span>
|
||||
<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>
|
||||
If no tasks are passed, print the help screen. Keep a reference to the
|
||||
original directory name, when running Cake tasks from subdirectories. </p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.run = </span><span class="o">-></span>
|
||||
<span class="nv">global.__originalDirname = </span><span class="nx">fs</span><span class="p">.</span><span class="nx">realpathSync</span> <span class="s1">'.'</span>
|
||||
<span class="nx">process</span><span class="p">.</span><span class="nx">chdir</span> <span class="nx">cakefileDirectory</span> <span class="nx">__originalDirname</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="nx">slice</span> <span class="mi">2</span>
|
||||
<span class="nx">CoffeeScript</span><span class="p">.</span><span class="nx">run</span> <span class="nx">fs</span><span class="p">.</span><span class="nx">readFileSync</span><span class="p">(</span><span class="s1">'Cakefile'</span><span class="p">).</span><span class="nx">toString</span><span class="p">(),</span> <span class="nx">filename</span><span class="o">:</span> <span class="s1">'Cakefile'</span>
|
||||
<span class="nv">oparse = </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="k">return</span> <span class="nx">printTasks</span><span class="p">()</span> <span class="nx">unless</span> <span class="nx">args</span><span class="p">.</span><span class="nx">length</span>
|
||||
<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">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>
|
||||
<span class="nx">console</span><span class="p">.</span><span class="nx">log</span> <span class="s2">"cake #{name}#{spaces} #{desc}"</span>
|
||||
<span class="nx">console</span><span class="p">.</span><span class="nx">log</span> <span class="nx">oparse</span><span class="p">.</span><span class="nx">help</span><span class="p">()</span> <span class="k">if</span> <span class="nx">switches</span><span class="p">.</span><span class="nx">length</span></pre></div> </td> </tr> <tr id="section-10"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-10">¶</a> </div> <p>Print an error and exit when attempting to all an undefined task.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">missingTask = </span><span class="p">(</span><span class="nx">task</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">oparse</span><span class="p">.</span><span class="nx">help</span><span class="p">()</span> <span class="k">if</span> <span class="nx">switches</span><span class="p">.</span><span class="nx">length</span></pre></div> </td> </tr> <tr id="section-10"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-10">¶</a> </div> <p>Print an error and exit when attempting to call an undefined task.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">missingTask = </span><span class="p">(</span><span class="nx">task</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="s2">"No such task: \"#{task}\""</span>
|
||||
<span class="nx">process</span><span class="p">.</span><span class="nx">exit</span> <span class="mi">1</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>When <code>cake</code> is invoked, search in the current and all parent directories
|
||||
to find the relevant Cakefile.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">cakefileDirectory = </span><span class="p">(</span><span class="nx">dir</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="k">return</span> <span class="nx">dir</span> <span class="k">if</span> <span class="nx">path</span><span class="p">.</span><span class="nx">existsSync</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="s1">'Cakefile'</span>
|
||||
<span class="nv">parent = </span><span class="nx">path</span><span class="p">.</span><span class="nx">normalize</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="s1">'..'</span>
|
||||
<span class="k">return</span> <span class="nx">cakefileDirectory</span> <span class="nx">parent</span> <span class="nx">unless</span> <span class="nx">parent</span> <span class="o">is</span> <span class="nx">dir</span>
|
||||
<span class="k">throw</span> <span class="k">new</span> <span class="nb">Error</span> <span class="s2">"Cakefile not found in #{process.cwd()}"</span>
|
||||
|
||||
</pre></div> </td> </tr> </tbody> </table> </div> </body> </html>
|
||||
@@ -6,14 +6,14 @@ 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="nv">vm = </span><span class="nx">require</span> <span class="s1">'vm'</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="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>
|
||||
<span class="nv">vm = </span><span class="nx">require</span> <span class="s1">'vm'</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="p">(</span><span class="nx">filename</span><span class="p">,</span> <span class="s1">'utf8'</span><span class="p">),</span> <span class="p">{</span><span class="nx">filename</span><span class="p">}</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">'1.1.1'</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
|
||||
<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.1.3'</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>
|
||||
@@ -27,28 +27,41 @@ or traverse it by using <code>.traverse()</code> with a callback.</p>
|
||||
<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-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-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">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="o">=</span>
|
||||
<span class="k">if</span> <span class="nx">options</span><span class="p">.</span><span class="nx">filename</span> <span class="k">then</span> <span class="nx">fs</span><span class="p">.</span><span class="nx">realpathSync</span><span class="p">(</span><span class="nx">options</span><span class="p">.</span><span class="nx">filename</span><span class="p">)</span> <span class="k">else</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>Assign paths for node_modules loading</p> </td> <td class="code"> <div class="highlight"><pre> <span class="k">if</span> <span class="nx">process</span><span class="p">.</span><span class="nx">binding</span><span class="p">(</span><span class="s1">'natives'</span><span class="p">).</span><span class="nx">module</span>
|
||||
<span class="p">{</span><span class="nx">Module</span><span class="p">}</span> <span class="o">=</span> <span class="nx">require</span> <span class="s1">'module'</span>
|
||||
<span class="nv">root.paths = </span><span class="nx">Module</span><span class="p">.</span><span class="nx">_nodeModulePaths</span> <span class="nx">path</span><span class="p">.</span><span class="nx">dirname</span> <span class="nx">options</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.</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>
|
||||
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>
|
||||
<span class="nv">mainModule = </span><span class="nx">require</span><span class="p">.</span><span class="nx">main</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">mainModule.filename = </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="o">=</span>
|
||||
<span class="k">if</span> <span class="nx">options</span><span class="p">.</span><span class="nx">filename</span> <span class="k">then</span> <span class="nx">fs</span><span class="p">.</span><span class="nx">realpathSync</span><span class="p">(</span><span class="nx">options</span><span class="p">.</span><span class="nx">filename</span><span class="p">)</span> <span class="k">else</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="nx">mainModule</span><span class="p">.</span><span class="nx">moduleCache</span> <span class="o">and=</span> <span class="p">{}</span></pre></div> </td> </tr> <tr id="section-12"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-12">¶</a> </div> <p>Assign paths for node_modules loading</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">mainModule.paths = </span><span class="nx">require</span><span class="p">(</span><span class="s1">'module'</span><span class="p">).</span><span class="nx">_nodeModulePaths</span> <span class="nx">path</span><span class="p">.</span><span class="nx">dirname</span> <span class="nx">options</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.</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">mainModule</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">mainModule</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">mainModule</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-15"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-15">¶</a> </div> <p>Compile and evaluate a string of CoffeeScript (in a Node.js-like environment).
|
||||
<span class="nx">mainModule</span><span class="p">.</span><span class="nx">_compile</span> <span class="nx">code</span><span class="p">,</span> <span class="nx">mainModule</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="nv">options = </span><span class="p">{})</span> <span class="o">-></span>
|
||||
<span class="nv">sandbox = </span><span class="nx">options</span><span class="p">.</span><span class="nx">sandbox</span>
|
||||
<span class="nx">unless</span> <span class="nx">sandbox</span>
|
||||
<span class="nv">sandbox =</span>
|
||||
<span class="nx">require</span><span class="o">:</span> <span class="nx">require</span>
|
||||
<span class="nx">module</span> <span class="o">:</span> <span class="p">{</span> <span class="nx">exports</span><span class="o">:</span> <span class="p">{}</span> <span class="p">}</span>
|
||||
<span class="nx">sandbox</span><span class="p">[</span><span class="nx">g</span><span class="p">]</span> <span class="o">=</span> <span class="nx">global</span><span class="p">[</span><span class="nx">g</span><span class="p">]</span> <span class="k">for</span> <span class="nx">g</span> <span class="k">of</span> <span class="nx">global</span>
|
||||
<span class="nv">sandbox.global = </span><span class="nx">sandbox</span>
|
||||
<span class="nv">sandbox.global.global = sandbox.global.root = sandbox.global.GLOBAL = </span><span class="nx">sandbox</span>
|
||||
<span class="nv">sandbox.__filename = </span><span class="nx">options</span><span class="p">.</span><span class="nx">filename</span> <span class="o">||</span> <span class="s1">'eval'</span>
|
||||
<span class="nv">sandbox.__dirname = </span><span class="nx">path</span><span class="p">.</span><span class="nx">dirname</span> <span class="nx">sandbox</span><span class="p">.</span><span class="nx">__filename</span>
|
||||
<span class="nv">js = </span><span class="nx">compile</span> <span class="s2">"_=(#{code.trim()})"</span><span class="p">,</span> <span class="nx">options</span>
|
||||
<span class="nx">vm</span><span class="p">.</span><span class="nx">runInNewContext</span> <span class="nx">js</span><span class="p">,</span> <span class="nx">sandbox</span><span class="p">,</span> <span class="nx">sandbox</span><span class="p">.</span><span class="nx">__filename</span></pre></div> </td> </tr> <tr id="section-16"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-16">¶</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-17"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-17">¶</a> </div> <p>The real Lexer produces a generic stream of tokens. This object provides a
|
||||
<span class="k">return</span> <span class="nx">unless</span> <span class="nv">code = </span><span class="nx">code</span><span class="p">.</span><span class="nx">trim</span><span class="p">()</span>
|
||||
<span class="nv">Script = </span><span class="nx">vm</span><span class="p">.</span><span class="nx">Script</span>
|
||||
<span class="k">if</span> <span class="nx">Script</span>
|
||||
<span class="k">if</span> <span class="nx">options</span><span class="p">.</span><span class="nx">sandbox</span><span class="o">?</span>
|
||||
<span class="k">if</span> <span class="nx">options</span><span class="p">.</span><span class="nx">sandbox</span> <span class="k">instanceof</span> <span class="nx">Script</span><span class="p">.</span><span class="nx">createContext</span><span class="p">().</span><span class="nx">constructor</span>
|
||||
<span class="nv">sandbox = </span><span class="nx">options</span><span class="p">.</span><span class="nx">sandbox</span>
|
||||
<span class="k">else</span>
|
||||
<span class="nv">sandbox = </span><span class="nx">Script</span><span class="p">.</span><span class="nx">createContext</span><span class="p">()</span>
|
||||
<span class="nx">sandbox</span><span class="p">[</span><span class="nx">k</span><span class="p">]</span> <span class="o">=</span> <span class="nx">v</span> <span class="k">for</span> <span class="nx">own</span> <span class="nx">k</span><span class="p">,</span> <span class="nx">v</span> <span class="k">of</span> <span class="nx">options</span><span class="p">.</span><span class="nx">sandbox</span>
|
||||
<span class="nv">sandbox.global = sandbox.root = sandbox.GLOBAL = </span><span class="nx">sandbox</span>
|
||||
<span class="k">else</span>
|
||||
<span class="nv">sandbox = </span><span class="nx">global</span>
|
||||
<span class="nv">sandbox.__filename = </span><span class="nx">options</span><span class="p">.</span><span class="nx">filename</span> <span class="o">||</span> <span class="s1">'eval'</span>
|
||||
<span class="nv">sandbox.__dirname = </span><span class="nx">path</span><span class="p">.</span><span class="nx">dirname</span> <span class="nx">sandbox</span><span class="p">.</span><span class="nx">__filename</span></pre></div> </td> </tr> <tr id="section-15"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-15">¶</a> </div> <p>define module/require only if they chose not to specify their own</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">unless</span> <span class="nx">sandbox</span> <span class="o">isnt</span> <span class="nx">global</span> <span class="o">or</span> <span class="nx">sandbox</span><span class="p">.</span><span class="nx">module</span> <span class="o">or</span> <span class="nx">sandbox</span><span class="p">.</span><span class="nx">require</span>
|
||||
<span class="nv">Module = </span><span class="nx">require</span> <span class="s1">'module'</span>
|
||||
<span class="nv">sandbox.module = _module = </span><span class="k">new</span> <span class="nx">Module</span><span class="p">(</span><span class="nx">options</span><span class="p">.</span><span class="nx">modulename</span> <span class="o">||</span> <span class="s1">'eval'</span><span class="p">)</span>
|
||||
<span class="nv">sandbox.require = _require = </span><span class="p">(</span><span class="nx">path</span><span class="p">)</span> <span class="o">-></span> <span class="nx">Module</span><span class="p">.</span><span class="nx">_load</span> <span class="nx">path</span><span class="p">,</span> <span class="nx">_module</span><span class="p">,</span> <span class="kc">true</span>
|
||||
<span class="nv">_module.filename = </span><span class="nx">sandbox</span><span class="p">.</span><span class="nx">__filename</span>
|
||||
<span class="nx">_require</span><span class="p">[</span><span class="nx">r</span><span class="p">]</span> <span class="o">=</span> <span class="nx">require</span><span class="p">[</span><span class="nx">r</span><span class="p">]</span> <span class="k">for</span> <span class="nx">r</span> <span class="k">in</span> <span class="nb">Object</span><span class="p">.</span><span class="nx">getOwnPropertyNames</span> <span class="nx">require</span> <span class="k">when</span> <span class="nx">r</span> <span class="o">isnt</span> <span class="s1">'paths'</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 same hack node currently uses for their own REPL</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">_require.paths = _module.paths = </span><span class="nx">Module</span><span class="p">.</span><span class="nx">_nodeModulePaths</span> <span class="nx">process</span><span class="p">.</span><span class="nx">cwd</span><span class="p">()</span>
|
||||
<span class="nv">_require.resolve = </span><span class="p">(</span><span class="nx">request</span><span class="p">)</span> <span class="o">-></span> <span class="nx">Module</span><span class="p">.</span><span class="nx">_resolveFilename</span> <span class="nx">request</span><span class="p">,</span> <span class="nx">_module</span>
|
||||
<span class="nv">o = </span><span class="p">{}</span>
|
||||
<span class="nx">o</span><span class="p">[</span><span class="nx">k</span><span class="p">]</span> <span class="o">=</span> <span class="nx">v</span> <span class="k">for</span> <span class="nx">own</span> <span class="nx">k</span><span class="p">,</span> <span class="nx">v</span> <span class="k">of</span> <span class="nx">options</span>
|
||||
<span class="nv">o.bare = </span><span class="kc">on</span> <span class="c1"># ensure return value</span>
|
||||
<span class="nv">js = </span><span class="nx">compile</span> <span class="nx">code</span><span class="p">,</span> <span class="nx">o</span>
|
||||
<span class="k">if</span> <span class="nx">sandbox</span> <span class="o">is</span> <span class="nx">global</span>
|
||||
<span class="nx">vm</span><span class="p">.</span><span class="nx">runInThisContext</span> <span class="nx">js</span>
|
||||
<span class="k">else</span>
|
||||
<span class="nx">vm</span><span class="p">.</span><span class="nx">runInContext</span> <span class="nx">js</span><span class="p">,</span> <span class="nx">sandbox</span></pre></div> </td> </tr> <tr id="section-17"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-17">¶</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-18"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-18">¶</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>
|
||||
|
||||
@@ -11,25 +11,27 @@ interactive REPL.</p> </td> <td class="code">
|
||||
<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="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">stderr</span><span class="p">.</span><span class="nx">write</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"> If called without options, `coffee` will run your script.</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">'-b'</span><span class="p">,</span> <span class="s1">'--bare'</span><span class="p">,</span> <span class="s1">'compile without a top-level function wrapper'</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 [FILE]'</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 JavaScript Lint'</span><span class="p">]</span>
|
||||
<span class="p">[</span><span class="s1">'-s'</span><span class="p">,</span> <span class="s1">'--stdio'</span><span class="p">,</span> <span class="s1">'listen for and compile scripts over stdio'</span><span class="p">]</span>
|
||||
<span class="p">[</span><span class="s1">'-e'</span><span class="p">,</span> <span class="s1">'--eval'</span><span class="p">,</span> <span class="s1">'compile a string from the command line'</span><span class="p">]</span>
|
||||
<span class="p">[</span><span class="s1">'-r'</span><span class="p">,</span> <span class="s1">'--require [FILE*]'</span><span class="p">,</span> <span class="s1">'require a library before executing your script'</span><span class="p">]</span>
|
||||
<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">'-e'</span><span class="p">,</span> <span class="s1">'--eval'</span><span class="p">,</span> <span class="s1">'pass a string from the command line as input'</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><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">'-j'</span><span class="p">,</span> <span class="s1">'--join [FILE]'</span><span class="p">,</span> <span class="s1">'concatenate the source CoffeeScript before compiling'</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 JavaScript Lint'</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 out the parse tree that the parser 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 directly to the "node" binary'</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 output directory for compiled JavaScript'</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 out the compiled JavaScript'</span><span class="p">]</span>
|
||||
<span class="p">[</span><span class="s1">'-r'</span><span class="p">,</span> <span class="s1">'--require [FILE*]'</span><span class="p">,</span> <span class="s1">'require a library before executing your script'</span><span class="p">]</span>
|
||||
<span class="p">[</span><span class="s1">'-s'</span><span class="p">,</span> <span class="s1">'--stdio'</span><span class="p">,</span> <span class="s1">'listen for and compile scripts over stdio'</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 out the tokens that the lexer/rewriter produce'</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 the version number'</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 rerun commands'</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">contents = </span><span class="p">[]</span>
|
||||
@@ -47,32 +49,55 @@ Many flags cause us to divert before compiling anything. Flags passed after
|
||||
<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">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="nv">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">process</span><span class="p">.</span><span class="nx">argv</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="s1">'coffee'</span>
|
||||
<span class="nv">process.execPath = </span><span class="nx">require</span><span class="p">.</span><span class="nx">main</span><span class="p">.</span><span class="nx">filename</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="nv">unprocessed = </span><span class="p">[]</span>
|
||||
<span class="nv">remaining_files = </span><span class="o">-></span>
|
||||
<span class="nv">total = </span><span class="mi">0</span>
|
||||
<span class="nx">total</span> <span class="o">+=</span> <span class="nx">x</span> <span class="k">for</span> <span class="nx">x</span> <span class="k">in</span> <span class="nx">unprocessed</span>
|
||||
<span class="nx">total</span>
|
||||
<span class="nv">trackUnprocessedFiles = </span><span class="p">(</span><span class="nx">sourceIndex</span><span class="p">,</span> <span class="nx">fileCount</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nx">unprocessed</span><span class="p">[</span><span class="nx">sourceIndex</span><span class="p">]</span> <span class="o">?=</span> <span class="mi">0</span>
|
||||
<span class="nx">unprocessed</span><span class="p">[</span><span class="nx">sourceIndex</span><span class="p">]</span> <span class="o">+=</span> <span class="nx">fileCount</span>
|
||||
<span class="nv">trackCompleteFiles = </span><span class="p">(</span><span class="nx">sourceIndex</span><span class="p">,</span> <span class="nx">fileCount</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nx">unprocessed</span><span class="p">[</span><span class="nx">sourceIndex</span><span class="p">]</span> <span class="o">-=</span> <span class="nx">fileCount</span>
|
||||
<span class="k">if</span> <span class="nx">opts</span><span class="p">.</span><span class="nx">join</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">></span> <span class="mi">0</span> <span class="o">and</span> <span class="nx">remaining_files</span><span class="p">()</span> <span class="o">==</span> <span class="mi">0</span>
|
||||
<span class="nx">compileJoin</span><span class="p">()</span>
|
||||
<span class="k">for</span> <span class="nx">source</span> <span class="k">in</span> <span class="nx">sources</span>
|
||||
<span class="nx">trackUnprocessedFiles</span> <span class="nx">sources</span><span class="p">.</span><span class="nx">indexOf</span><span class="p">(</span><span class="nx">source</span><span class="p">),</span> <span class="mi">1</span>
|
||||
<span class="k">for</span> <span class="nx">source</span> <span class="k">in</span> <span class="nx">sources</span>
|
||||
<span class="nv">base = </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="nv">compile = </span><span class="p">(</span><span class="nx">source</span><span class="p">,</span> <span class="nx">topLevel</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nv">compile = </span><span class="p">(</span><span class="nx">source</span><span class="p">,</span> <span class="nx">sourceIndex</span><span class="p">,</span> <span class="nx">topLevel</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nx">path</span><span class="p">.</span><span class="nx">exists</span> <span class="nx">source</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">topLevel</span> <span class="o">and</span> <span class="o">not</span> <span class="nx">exists</span> <span class="o">and</span> <span class="nx">source</span><span class="p">[</span><span class="o">-</span><span class="mi">7</span><span class="p">..]</span> <span class="o">isnt</span> <span class="s1">'.coffee'</span>
|
||||
<span class="k">return</span> <span class="nx">compile</span> <span class="s2">"#{source}.coffee"</span><span class="p">,</span> <span class="nx">sourceIndex</span><span class="p">,</span> <span class="nx">topLevel</span>
|
||||
<span class="k">throw</span> <span class="k">new</span> <span class="nb">Error</span> <span class="s2">"File not found: #{source}"</span> <span class="k">if</span> <span class="nx">topLevel</span> <span class="o">and</span> <span class="o">not</span> <span class="nx">exists</span>
|
||||
<span class="nx">fs</span><span class="p">.</span><span class="nx">stat</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">stats</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="k">throw</span> <span class="nx">err</span> <span class="k">if</span> <span class="nx">err</span>
|
||||
<span class="k">if</span> <span class="nx">stats</span><span class="p">.</span><span class="nx">isDirectory</span><span class="p">()</span>
|
||||
<span class="nx">fs</span><span class="p">.</span><span class="nx">readdir</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">files</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="k">throw</span> <span class="nx">err</span> <span class="k">if</span> <span class="nx">err</span>
|
||||
<span class="nx">trackUnprocessedFiles</span> <span class="nx">sourceIndex</span><span class="p">,</span> <span class="nx">files</span><span class="p">.</span><span class="nx">length</span>
|
||||
<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="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="nx">sourceIndex</span>
|
||||
<span class="nx">trackCompleteFiles</span> <span class="nx">sourceIndex</span><span class="p">,</span> <span class="mi">1</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="k">throw</span> <span class="nx">err</span> <span class="k">if</span> <span class="nx">err</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">></span> <span class="mi">0</span>
|
||||
<span class="nx">contents</span><span class="p">[</span><span class="nx">sourceIndex</span><span class="p">]</span> <span class="o">=</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">sourceIndex</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">join</span><span class="p">(</span><span class="s1">'\n'</span><span class="p">)</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">trackCompleteFiles</span> <span class="nx">sourceIndex</span><span class="p">,</span> <span class="mi">1</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
|
||||
<span class="k">else</span>
|
||||
<span class="nx">trackCompleteFiles</span> <span class="nx">sourceIndex</span><span class="p">,</span> <span class="mi">1</span>
|
||||
<span class="nx">compile</span> <span class="nx">source</span><span class="p">,</span> <span class="nx">sources</span><span class="p">.</span><span class="nx">indexOf</span><span class="p">(</span><span class="nx">source</span><span class="p">),</span> <span class="kc">true</span></pre></div> </td> </tr> <tr id="section-9"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-9">¶</a> </div> <p>Compile a single source script, containing the given code, according to the
|
||||
requested options. If evaluating the script directly sets <code>__filename</code>,
|
||||
<code>__dirname</code> and <code>module.filename</code> to be correct relative to the script's path.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">compileScript = </span><span class="p">(</span><span class="nx">file</span><span class="p">,</span> <span class="nx">input</span><span class="p">,</span> <span class="nx">base</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nv">o = </span><span class="nx">opts</span>
|
||||
@@ -93,7 +118,7 @@ requested options. If evaluating the script directly sets <code>__filename</code
|
||||
<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">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">printWarn</span> <span class="nx">err</span> <span class="k">instanceof</span> <span class="nb">Error</span> <span class="o">and</span> <span class="nx">err</span><span class="p">.</span><span class="nx">stack</span> <span class="o">or</span> <span class="s2">"ERROR: #{err}"</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>
|
||||
@@ -108,14 +133,21 @@ them together.</p> </td> <td class="code">
|
||||
<span class="nv">realFilename = </span><span class="nx">module</span><span class="p">.</span><span class="nx">filename</span>
|
||||
<span class="nv">module.filename = </span><span class="s1">'.'</span>
|
||||
<span class="nx">require</span> <span class="nx">req</span> <span class="k">for</span> <span class="nx">req</span> <span class="k">in</span> <span class="nx">opts</span><span class="p">.</span><span class="nx">require</span>
|
||||
<span class="nv">module.filename = </span><span class="nx">realFilename</span></pre></div> </td> </tr> <tr id="section-13"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-13">¶</a> </div> <p>Watch a source CoffeeScript file using <code>fs.watchFile</code>, recompiling it every
|
||||
<span class="nv">module.filename = </span><span class="nx">realFilename</span></pre></div> </td> </tr> <tr id="section-13"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-13">¶</a> </div> <p>Watch a source CoffeeScript file using <code>fs.watch</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>
|
||||
<span class="k">return</span> <span class="k">if</span> <span class="nx">curr</span><span class="p">.</span><span class="nx">size</span> <span class="o">is</span> <span class="nx">prev</span><span class="p">.</span><span class="nx">size</span> <span class="o">and</span> <span class="nx">curr</span><span class="p">.</span><span class="nx">mtime</span><span class="p">.</span><span class="nx">getTime</span><span class="p">()</span> <span class="o">is</span> <span class="nx">prev</span><span class="p">.</span><span class="nx">mtime</span><span class="p">.</span><span class="nx">getTime</span><span class="p">()</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="k">throw</span> <span class="nx">err</span> <span class="k">if</span> <span class="nx">err</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></pre></div> </td> </tr> <tr id="section-14"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-14">¶</a> </div> <p>Write out a JavaScript source file with the compiled code. By default, files
|
||||
<span class="nx">fs</span><span class="p">.</span><span class="nx">stat</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">prevStats</span><span class="p">)</span><span class="o">-></span>
|
||||
<span class="k">throw</span> <span class="nx">err</span> <span class="k">if</span> <span class="nx">err</span>
|
||||
<span class="nx">fs</span><span class="p">.</span><span class="nx">watch</span> <span class="nx">source</span><span class="p">,</span> <span class="p">(</span><span class="nx">event</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="k">if</span> <span class="nx">event</span> <span class="o">is</span> <span class="s1">'change'</span>
|
||||
<span class="nx">fs</span><span class="p">.</span><span class="nx">stat</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">stats</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="k">throw</span> <span class="nx">err</span> <span class="k">if</span> <span class="nx">err</span>
|
||||
<span class="k">return</span> <span class="k">if</span> <span class="nx">stats</span><span class="p">.</span><span class="nx">size</span> <span class="o">is</span> <span class="nx">prevStats</span><span class="p">.</span><span class="nx">size</span> <span class="o">and</span>
|
||||
<span class="nx">stats</span><span class="p">.</span><span class="nx">mtime</span><span class="p">.</span><span class="nx">getTime</span><span class="p">()</span> <span class="o">is</span> <span class="nx">prevStats</span><span class="p">.</span><span class="nx">mtime</span><span class="p">.</span><span class="nx">getTime</span><span class="p">()</span>
|
||||
<span class="nv">prevStats = </span><span class="nx">stats</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="k">throw</span> <span class="nx">err</span> <span class="k">if</span> <span class="nx">err</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></pre></div> </td> </tr> <tr id="section-14"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-14">¶</a> </div> <p>Write out a JavaScript source file with the compiled code. By default, files
|
||||
are written out in <code>cwd</code> as <code>.js</code> files with the same name, but the output
|
||||
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>
|
||||
@@ -134,7 +166,7 @@ directory can be customized with <code>--output</code>.</p> </td>
|
||||
<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-15"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-15">¶</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">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">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>
|
||||
<span class="nx">jsl</span><span class="p">.</span><span class="nx">stderr</span><span class="p">.</span><span class="kc">on</span> <span class="s1">'data'</span><span class="p">,</span> <span class="nx">printIt</span>
|
||||
|
||||
@@ -53,7 +53,7 @@ all parsing must end here.</p> </td> <td class="code">
|
||||
<span class="nx">o</span> <span class="s1">'STATEMENT'</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-12"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-12">¶</a> </div> <p>All the different types of expressions in our language. The basic unit of
|
||||
CoffeeScript is the <strong>Expression</strong> -- everything that can be an expression
|
||||
is one. Block serve as the building blocks of many other rules, making
|
||||
is one. Blocks serve as the building blocks of many other rules, making
|
||||
them somewhat circular.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">Expression</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s1">'Value'</span>
|
||||
<span class="nx">o</span> <span class="s1">'Invocation'</span>
|
||||
@@ -77,7 +77,7 @@ token stream.</p> </td> <td class="code">
|
||||
they can also serve as keys in object literals.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">AlphaNumeric</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s1">'NUMBER'</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="nx">o</span> <span class="s1">'STRING'</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-16"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-16">¶</a> </div> <p>All of our immediate values. These can (in general), be passed straight
|
||||
<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>All of our immediate values. Generally these can be passed straight
|
||||
through and printed to JavaScript.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">Literal</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s1">'AlphaNumeric'</span>
|
||||
<span class="nx">o</span> <span class="s1">'JS'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Literal</span> <span class="nx">$1</span>
|
||||
@@ -128,95 +128,92 @@ that hoovers up the remaining arguments.</p> </td> <td c
|
||||
<span class="nx">o</span> <span class="s1">'ParamVar'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Param</span> <span class="nx">$1</span>
|
||||
<span class="nx">o</span> <span class="s1">'ParamVar ...'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Param</span> <span class="nx">$1</span><span class="p">,</span> <span class="kc">null</span><span class="p">,</span> <span class="kc">on</span>
|
||||
<span class="nx">o</span> <span class="s1">'ParamVar = Expression'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Param</span> <span class="nx">$1</span><span class="p">,</span> <span class="nx">$3</span>
|
||||
<span class="p">]</span>
|
||||
|
||||
<span class="nx">ParamVar</span><span class="o">:</span> <span class="p">[</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>Function Parameters</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">ParamVar</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">'ThisProperty'</span>
|
||||
<span class="nx">o</span> <span class="s1">'Array'</span>
|
||||
<span class="nx">o</span> <span class="s1">'Object'</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>A splat that occurs outside of a parameter list.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">Splat</span><span class="o">:</span> <span class="p">[</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>A splat that occurs outside of a parameter list.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">Splat</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s1">'Expression ...'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Splat</span> <span class="nx">$1</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>Variables and properties that can be assigned to.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">SimpleAssignable</span><span class="o">:</span> <span class="p">[</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>Variables and properties that can be assigned to.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">SimpleAssignable</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">Value</span> <span class="nx">$1</span>
|
||||
<span class="nx">o</span> <span class="s1">'Value Accessor'</span><span class="p">,</span> <span class="o">-></span> <span class="nx">$1</span><span class="p">.</span><span class="nx">push</span> <span class="nx">$2</span>
|
||||
<span class="nx">o</span> <span class="s1">'Value Accessor'</span><span class="p">,</span> <span class="o">-></span> <span class="nx">$1</span><span class="p">.</span><span class="nx">add</span> <span class="nx">$2</span>
|
||||
<span class="nx">o</span> <span class="s1">'Invocation Accessor'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Value</span> <span class="nx">$1</span><span class="p">,</span> <span class="p">[</span><span class="nx">$2</span><span class="p">]</span>
|
||||
<span class="nx">o</span> <span class="s1">'ThisProperty'</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>Everything that can be assigned to.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">Assignable</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-29"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-29">¶</a> </div> <p>Everything that can be assigned to.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">Assignable</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s1">'SimpleAssignable'</span>
|
||||
<span class="nx">o</span> <span class="s1">'Array'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Value</span> <span class="nx">$1</span>
|
||||
<span class="nx">o</span> <span class="s1">'Object'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Value</span> <span class="nx">$1</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-29"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-29">¶</a> </div> <p>The types of things that can be treated as values -- assigned to, invoked
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-30"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-30">¶</a> </div> <p>The types of things that can be treated as values -- assigned to, invoked
|
||||
as functions, indexed into, named as a class, etc.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">Value</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s1">'Assignable'</span>
|
||||
<span class="nx">o</span> <span class="s1">'Literal'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Value</span> <span class="nx">$1</span>
|
||||
<span class="nx">o</span> <span class="s1">'Parenthetical'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Value</span> <span class="nx">$1</span>
|
||||
<span class="nx">o</span> <span class="s1">'Range'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Value</span> <span class="nx">$1</span>
|
||||
<span class="nx">o</span> <span class="s1">'This'</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-30"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-30">¶</a> </div> <p>The general group of accessors into an object, by property, by prototype
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-31"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-31">¶</a> </div> <p>The general group of accessors into an object, by property, by prototype
|
||||
or by array index or slice.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">Accessor</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">Access</span> <span class="nx">$2</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">Access</span> <span class="nx">$2</span><span class="p">,</span> <span class="s1">'soak'</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">Access</span> <span class="nx">$2</span><span class="p">,</span> <span class="s1">'proto'</span>
|
||||
<span class="nx">o</span> <span class="s1">':: Identifier'</span><span class="p">,</span> <span class="o">-></span> <span class="p">[(</span><span class="k">new</span> <span class="nx">Access</span> <span class="k">new</span> <span class="nx">Literal</span> <span class="s1">'prototype'</span><span class="p">),</span> <span class="k">new</span> <span class="nx">Access</span> <span class="nx">$2</span><span class="p">]</span>
|
||||
<span class="nx">o</span> <span class="s1">'::'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Access</span> <span class="k">new</span> <span class="nx">Literal</span> <span class="s1">'prototype'</span>
|
||||
<span class="nx">o</span> <span class="s1">'Index'</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-31"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-31">¶</a> </div> <p>Indexing into an object or array using bracket notation.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">Index</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-32"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-32">¶</a> </div> <p>Indexing into an object or array using bracket notation.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">Index</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s1">'INDEX_START IndexValue INDEX_END'</span><span class="p">,</span> <span class="o">-></span> <span class="nx">$2</span>
|
||||
<span class="nx">o</span> <span class="s1">'INDEX_SOAK Index'</span><span class="p">,</span> <span class="o">-></span> <span class="nx">extend</span> <span class="nx">$2</span><span class="p">,</span> <span class="nx">soak</span> <span class="o">:</span> <span class="kc">yes</span>
|
||||
<span class="nx">o</span> <span class="s1">'INDEX_PROTO Index'</span><span class="p">,</span> <span class="o">-></span> <span class="nx">extend</span> <span class="nx">$2</span><span class="p">,</span> <span class="nx">proto</span><span class="o">:</span> <span class="kc">yes</span>
|
||||
<span class="p">]</span>
|
||||
|
||||
|
||||
<span class="nx">IndexValue</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s1">'Expression'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Index</span> <span class="nx">$1</span>
|
||||
<span class="nx">o</span> <span class="s1">'Slice'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Slice</span> <span class="nx">$1</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-32"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-32">¶</a> </div> <p>In CoffeeScript, an object literal is simply a list of assignments.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nb">Object</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-33"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-33">¶</a> </div> <p>In CoffeeScript, an object literal is simply a list of assignments.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nb">Object</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s1">'{ AssignList OptComma }'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Obj</span> <span class="nx">$2</span><span class="p">,</span> <span class="nx">$1</span><span class="p">.</span><span class="nx">generated</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-33"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-33">¶</a> </div> <p>Assignment of properties within an object literal can be separated by
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-34"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-34">¶</a> </div> <p>Assignment of properties within an object literal can be separated by
|
||||
comma, as in JavaScript, or simply by newline.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">AssignList</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="p">[]</span>
|
||||
<span class="nx">o</span> <span class="s1">'AssignObj'</span><span class="p">,</span> <span class="o">-></span> <span class="p">[</span><span class="nx">$1</span><span class="p">]</span>
|
||||
<span class="nx">o</span> <span class="s1">'AssignList , AssignObj'</span><span class="p">,</span> <span class="o">-></span> <span class="nx">$1</span><span class="p">.</span><span class="nx">concat</span> <span class="nx">$3</span>
|
||||
<span class="nx">o</span> <span class="s1">'AssignList OptComma TERMINATOR AssignObj'</span><span class="p">,</span> <span class="o">-></span> <span class="nx">$1</span><span class="p">.</span><span class="nx">concat</span> <span class="nx">$4</span>
|
||||
<span class="nx">o</span> <span class="s1">'AssignList OptComma INDENT AssignList OptComma OUTDENT'</span><span class="p">,</span> <span class="o">-></span> <span class="nx">$1</span><span class="p">.</span><span class="nx">concat</span> <span class="nx">$4</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-34"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-34">¶</a> </div> <p>Class definitions have optional bodies of prototype property assignments,
|
||||
<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>Class definitions have optional bodies of prototype property assignments,
|
||||
and optional references to the superclass.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">Class</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s1">'CLASS'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Class</span>
|
||||
<span class="nx">o</span> <span class="s1">'CLASS Block'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Class</span> <span class="kc">null</span><span class="p">,</span> <span class="kc">null</span><span class="p">,</span> <span class="nx">$2</span>
|
||||
<span class="nx">o</span> <span class="s1">'CLASS EXTENDS Value'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Class</span> <span class="kc">null</span><span class="p">,</span> <span class="nx">$3</span>
|
||||
<span class="nx">o</span> <span class="s1">'CLASS EXTENDS Value Block'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Class</span> <span class="kc">null</span><span class="p">,</span> <span class="nx">$3</span><span class="p">,</span> <span class="nx">$4</span>
|
||||
<span class="nx">o</span> <span class="s1">'CLASS SimpleAssignable'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Class</span> <span class="nx">$2</span>
|
||||
<span class="nx">o</span> <span class="s1">'CLASS SimpleAssignable Block'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Class</span> <span class="nx">$2</span><span class="p">,</span> <span class="kc">null</span><span class="p">,</span> <span class="nx">$3</span>
|
||||
<span class="nx">o</span> <span class="s1">'CLASS SimpleAssignable EXTENDS Value'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Class</span> <span class="nx">$2</span><span class="p">,</span> <span class="nx">$4</span>
|
||||
<span class="nx">o</span> <span class="s1">'CLASS SimpleAssignable EXTENDS Value Block'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Class</span> <span class="nx">$2</span><span class="p">,</span> <span class="nx">$4</span><span class="p">,</span> <span class="nx">$5</span>
|
||||
<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">'CLASS'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Class</span>
|
||||
<span class="nx">o</span> <span class="s1">'CLASS Block'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Class</span> <span class="kc">null</span><span class="p">,</span> <span class="kc">null</span><span class="p">,</span> <span class="nx">$2</span>
|
||||
<span class="nx">o</span> <span class="s1">'CLASS EXTENDS Expression'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Class</span> <span class="kc">null</span><span class="p">,</span> <span class="nx">$3</span>
|
||||
<span class="nx">o</span> <span class="s1">'CLASS EXTENDS Expression Block'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Class</span> <span class="kc">null</span><span class="p">,</span> <span class="nx">$3</span><span class="p">,</span> <span class="nx">$4</span>
|
||||
<span class="nx">o</span> <span class="s1">'CLASS SimpleAssignable'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Class</span> <span class="nx">$2</span>
|
||||
<span class="nx">o</span> <span class="s1">'CLASS SimpleAssignable Block'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Class</span> <span class="nx">$2</span><span class="p">,</span> <span class="kc">null</span><span class="p">,</span> <span class="nx">$3</span>
|
||||
<span class="nx">o</span> <span class="s1">'CLASS SimpleAssignable EXTENDS Expression'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Class</span> <span class="nx">$2</span><span class="p">,</span> <span class="nx">$4</span>
|
||||
<span class="nx">o</span> <span class="s1">'CLASS SimpleAssignable EXTENDS Expression Block'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Class</span> <span class="nx">$2</span><span class="p">,</span> <span class="nx">$4</span><span class="p">,</span> <span class="nx">$5</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>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="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="p">]</span></pre></div> </td> </tr> <tr id="section-37"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-37">¶</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>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-37"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-37">¶</a> </div> <p>The list of arguments to a function call.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">Arguments</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-38"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-38">¶</a> </div> <p>The list of arguments to a function call.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">Arguments</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s1">'CALL_START CALL_END'</span><span class="p">,</span> <span class="o">-></span> <span class="p">[]</span>
|
||||
<span class="nx">o</span> <span class="s1">'CALL_START ArgList OptComma CALL_END'</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-38"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-38">¶</a> </div> <p>A reference to the <em>this</em> current object.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">This</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-39"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-39">¶</a> </div> <p>A reference to the <em>this</em> current object.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">This</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s1">'THIS'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Value</span> <span class="k">new</span> <span class="nx">Literal</span> <span class="s1">'this'</span>
|
||||
<span class="nx">o</span> <span class="s1">'@'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Value</span> <span class="k">new</span> <span class="nx">Literal</span> <span class="s1">'this'</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-39"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-39">¶</a> </div> <p>A reference to a property on <em>this</em>.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">ThisProperty</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-40"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-40">¶</a> </div> <p>A reference to a property on <em>this</em>.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">ThisProperty</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">Value</span> <span class="k">new</span> <span class="nx">Literal</span><span class="p">(</span><span class="s1">'this'</span><span class="p">),</span> <span class="p">[</span><span class="k">new</span> <span class="nx">Access</span><span class="p">(</span><span class="nx">$2</span><span class="p">)],</span> <span class="s1">'this'</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-40"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-40">¶</a> </div> <p>The array literal.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nb">Array</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-41"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-41">¶</a> </div> <p>The array literal.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nb">Array</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="k">new</span> <span class="nx">Arr</span> <span class="p">[]</span>
|
||||
<span class="nx">o</span> <span class="s1">'[ ArgList OptComma ]'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Arr</span> <span class="nx">$2</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-41"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-41">¶</a> </div> <p>Inclusive and exclusive range dots.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">RangeDots</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-42"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-42">¶</a> </div> <p>Inclusive and exclusive range dots.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">RangeDots</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="s1">'inclusive'</span>
|
||||
<span class="nx">o</span> <span class="s1">'...'</span><span class="p">,</span> <span class="o">-></span> <span class="s1">'exclusive'</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-42"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-42">¶</a> </div> <p>The CoffeeScript range literal.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">Range</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-43"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-43">¶</a> </div> <p>The CoffeeScript range literal.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">Range</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s1">'[ Expression RangeDots Expression ]'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Range</span> <span class="nx">$2</span><span class="p">,</span> <span class="nx">$4</span><span class="p">,</span> <span class="nx">$3</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-43"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-43">¶</a> </div> <p>Array slice literals.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">Slice</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-44"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-44">¶</a> </div> <p>Array slice literals.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">Slice</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s1">'Expression RangeDots Expression'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Range</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">'Expression RangeDots'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Range</span> <span class="nx">$1</span><span class="p">,</span> <span class="kc">null</span><span class="p">,</span> <span class="nx">$2</span>
|
||||
<span class="nx">o</span> <span class="s1">'RangeDots Expression'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Range</span> <span class="kc">null</span><span class="p">,</span> <span class="nx">$2</span><span class="p">,</span> <span class="nx">$1</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-44"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-44">¶</a> </div> <p>The <strong>ArgList</strong> is both the list of objects passed into a function call,
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-45"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-45">¶</a> </div> <p>The <strong>ArgList</strong> is both the list of objects passed into a function call,
|
||||
as well as the contents of an array literal
|
||||
(i.e. comma-separated expressions). Newlines work as well.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">ArgList</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s1">'Arg'</span><span class="p">,</span> <span class="o">-></span> <span class="p">[</span><span class="nx">$1</span><span class="p">]</span>
|
||||
@@ -224,35 +221,35 @@ as well as the contents of an array literal
|
||||
<span class="nx">o</span> <span class="s1">'ArgList OptComma TERMINATOR Arg'</span><span class="p">,</span> <span class="o">-></span> <span class="nx">$1</span><span class="p">.</span><span class="nx">concat</span> <span class="nx">$4</span>
|
||||
<span class="nx">o</span> <span class="s1">'INDENT ArgList OptComma OUTDENT'</span><span class="p">,</span> <span class="o">-></span> <span class="nx">$2</span>
|
||||
<span class="nx">o</span> <span class="s1">'ArgList OptComma INDENT ArgList OptComma OUTDENT'</span><span class="p">,</span> <span class="o">-></span> <span class="nx">$1</span><span class="p">.</span><span class="nx">concat</span> <span class="nx">$4</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-45"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-45">¶</a> </div> <p>Valid arguments are Block or Splats.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">Arg</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-46"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-46">¶</a> </div> <p>Valid arguments are Blocks or Splats.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">Arg</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s1">'Expression'</span>
|
||||
<span class="nx">o</span> <span class="s1">'Splat'</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-46"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-46">¶</a> </div> <p>Just simple, comma-separated, required arguments (no fancy syntax). We need
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-47"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-47">¶</a> </div> <p>Just simple, comma-separated, required arguments (no fancy syntax). We need
|
||||
this to be separate from the <strong>ArgList</strong> for use in <strong>Switch</strong> blocks, where
|
||||
having the newlines wouldn't make sense.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">SimpleArgs</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s1">'Expression'</span>
|
||||
<span class="nx">o</span> <span class="s1">'SimpleArgs , Expression'</span><span class="p">,</span> <span class="o">-></span> <span class="p">[].</span><span class="nx">concat</span> <span class="nx">$1</span><span class="p">,</span> <span class="nx">$3</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-47"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-47">¶</a> </div> <p>The variants of <em>try/catch/finally</em> exception handling blocks.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">Try</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-48"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-48">¶</a> </div> <p>The variants of <em>try/catch/finally</em> exception handling blocks.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">Try</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s1">'TRY Block'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Try</span> <span class="nx">$2</span>
|
||||
<span class="nx">o</span> <span class="s1">'TRY Block Catch'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Try</span> <span class="nx">$2</span><span class="p">,</span> <span class="nx">$3</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="nx">$3</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
|
||||
<span class="nx">o</span> <span class="s1">'TRY Block FINALLY Block'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Try</span> <span class="nx">$2</span><span class="p">,</span> <span class="kc">null</span><span class="p">,</span> <span class="kc">null</span><span class="p">,</span> <span class="nx">$4</span>
|
||||
<span class="nx">o</span> <span class="s1">'TRY Block Catch FINALLY Block'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Try</span> <span class="nx">$2</span><span class="p">,</span> <span class="nx">$3</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="nx">$3</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">$5</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-48"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-48">¶</a> </div> <p>A catch clause names its error and runs a block of code.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">Catch</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-49"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-49">¶</a> </div> <p>A catch clause names its error and runs a block of code.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">Catch</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s1">'CATCH Identifier Block'</span><span class="p">,</span> <span class="o">-></span> <span class="p">[</span><span class="nx">$2</span><span class="p">,</span> <span class="nx">$3</span><span class="p">]</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-49"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-49">¶</a> </div> <p>Throw an exception object.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">Throw</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-50"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-50">¶</a> </div> <p>Throw an exception object.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">Throw</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s1">'THROW Expression'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Throw</span> <span class="nx">$2</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-50"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-50">¶</a> </div> <p>Parenthetical expressions. Note that the <strong>Parenthetical</strong> is a <strong>Value</strong>,
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-51"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-51">¶</a> </div> <p>Parenthetical expressions. Note that the <strong>Parenthetical</strong> is a <strong>Value</strong>,
|
||||
not an <strong>Expression</strong>, so if you need to use an expression in a place
|
||||
where only values are accepted, wrapping it in parentheses will always do
|
||||
the trick.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">Parenthetical</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s1">'( Body )'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Parens</span> <span class="nx">$2</span>
|
||||
<span class="nx">o</span> <span class="s1">'( INDENT Body OUTDENT )'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Parens</span> <span class="nx">$3</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-51"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-51">¶</a> </div> <p>The condition portion of a while loop.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">WhileSource</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-52"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-52">¶</a> </div> <p>The condition portion of a while loop.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">WhileSource</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s1">'WHILE Expression'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">While</span> <span class="nx">$2</span>
|
||||
<span class="nx">o</span> <span class="s1">'WHILE Expression WHEN Expression'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">While</span> <span class="nx">$2</span><span class="p">,</span> <span class="nx">guard</span><span class="o">:</span> <span class="nx">$4</span>
|
||||
<span class="nx">o</span> <span class="s1">'UNTIL Expression'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">While</span> <span class="nx">$2</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">'UNTIL Expression WHEN Expression'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">While</span> <span class="nx">$2</span><span class="p">,</span> <span class="nx">invert</span><span class="o">:</span> <span class="kc">true</span><span class="p">,</span> <span class="nx">guard</span><span class="o">:</span> <span class="nx">$4</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-52"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-52">¶</a> </div> <p>The while loop can either be normal, with a block of expressions to execute,
|
||||
<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>The while loop can either be normal, with a block of expressions to execute,
|
||||
or postfix, with a single expression. There is no do..while.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">While</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s1">'WhileSource Block'</span><span class="p">,</span> <span class="o">-></span> <span class="nx">$1</span><span class="p">.</span><span class="nx">addBody</span> <span class="nx">$2</span>
|
||||
<span class="nx">o</span> <span class="s1">'Statement WhileSource'</span><span class="p">,</span> <span class="o">-></span> <span class="nx">$2</span><span class="p">.</span><span class="nx">addBody</span> <span class="nx">Block</span><span class="p">.</span><span class="nx">wrap</span> <span class="p">[</span><span class="nx">$1</span><span class="p">]</span>
|
||||
@@ -263,7 +260,7 @@ or postfix, with a single expression. There is no do..while.</p> </t
|
||||
<span class="nx">Loop</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s1">'LOOP Block'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">While</span><span class="p">(</span><span class="k">new</span> <span class="nx">Literal</span> <span class="s1">'true'</span><span class="p">).</span><span class="nx">addBody</span> <span class="nx">$2</span>
|
||||
<span class="nx">o</span> <span class="s1">'LOOP Expression'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">While</span><span class="p">(</span><span class="k">new</span> <span class="nx">Literal</span> <span class="s1">'true'</span><span class="p">).</span><span class="nx">addBody</span> <span class="nx">Block</span><span class="p">.</span><span class="nx">wrap</span> <span class="p">[</span><span class="nx">$2</span><span class="p">]</span>
|
||||
<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.
|
||||
<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>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>
|
||||
@@ -279,17 +276,17 @@ or postfix, with a single expression.</p> </td> <td clas
|
||||
<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 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.
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-55"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-55">¶</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>
|
||||
<span class="nx">o</span> <span class="s1">'Array'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Value</span> <span class="nx">$1</span>
|
||||
<span class="nx">o</span> <span class="s1">'Object'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Value</span> <span class="nx">$1</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-55"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-55">¶</a> </div> <p>An array or range comprehension has variables for the current element
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-56"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-56">¶</a> </div> <p>An array or range comprehension has variables for the current element
|
||||
and (optional) reference to the current index. Or, <em>key, value</em>, in the case
|
||||
of object comprehensions.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">ForVariables</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s1">'ForValue'</span><span class="p">,</span> <span class="o">-></span> <span class="p">[</span><span class="nx">$1</span><span class="p">]</span>
|
||||
<span class="nx">o</span> <span class="s1">'ForValue , ForValue'</span><span class="p">,</span> <span class="o">-></span> <span class="p">[</span><span class="nx">$1</span><span class="p">,</span> <span class="nx">$3</span><span class="p">]</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-56"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-56">¶</a> </div> <p>The source of a comprehension is an array or object with an optional guard
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-57"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-57">¶</a> </div> <p>The source of a comprehension is an array or object with an optional guard
|
||||
clause. If it's an array comprehension, you can also choose to step through
|
||||
in fixed-size increments.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">ForSource</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s1">'FORIN Expression'</span><span class="p">,</span> <span class="o">-></span> <span class="nx">source</span><span class="o">:</span> <span class="nx">$2</span>
|
||||
@@ -311,21 +308,21 @@ in fixed-size increments.</p> </td> <td class="code">
|
||||
<span class="nx">Whens</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s1">'When'</span>
|
||||
<span class="nx">o</span> <span class="s1">'Whens When'</span><span class="p">,</span> <span class="o">-></span> <span class="nx">$1</span><span class="p">.</span><span class="nx">concat</span> <span class="nx">$2</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-57"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-57">¶</a> </div> <p>An individual <strong>When</strong> clause, with action.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">When</span><span class="o">:</span> <span class="p">[</span>
|
||||
<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>An individual <strong>When</strong> clause, with action.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">When</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s1">'LEADING_WHEN SimpleArgs Block'</span><span class="p">,</span> <span class="o">-></span> <span class="p">[[</span><span class="nx">$2</span><span class="p">,</span> <span class="nx">$3</span><span class="p">]]</span>
|
||||
<span class="nx">o</span> <span class="s1">'LEADING_WHEN SimpleArgs Block TERMINATOR'</span><span class="p">,</span> <span class="o">-></span> <span class="p">[[</span><span class="nx">$2</span><span class="p">,</span> <span class="nx">$3</span><span class="p">]]</span>
|
||||
<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
|
||||
<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 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="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="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
|
||||
<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>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">'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="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">Block</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">Block</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.
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-61"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-61">¶</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
|
||||
combine most of these rules into a single generic <em>Operand OpSymbol Operand</em>
|
||||
@@ -338,7 +335,7 @@ rules are necessary.</p> </td> <td class="code">
|
||||
<span class="nx">o</span> <span class="s1">'-- SimpleAssignable'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Op</span> <span class="s1">'--'</span><span class="p">,</span> <span class="nx">$2</span>
|
||||
<span class="nx">o</span> <span class="s1">'++ SimpleAssignable'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Op</span> <span class="s1">'++'</span><span class="p">,</span> <span class="nx">$2</span>
|
||||
<span class="nx">o</span> <span class="s1">'SimpleAssignable --'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Op</span> <span class="s1">'--'</span><span class="p">,</span> <span class="nx">$1</span><span class="p">,</span> <span class="kc">null</span><span class="p">,</span> <span class="kc">true</span>
|
||||
<span class="nx">o</span> <span class="s1">'SimpleAssignable ++'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Op</span> <span class="s1">'++'</span><span class="p">,</span> <span class="nx">$1</span><span class="p">,</span> <span class="kc">null</span><span class="p">,</span> <span class="kc">true</span></pre></div> </td> </tr> <tr id="section-61"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-61">¶</a> </div> <p><a href="http://jashkenas.github.com/coffee-script/#existence">The existential operator</a>.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">o</span> <span class="s1">'Expression ?'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Existence</span> <span class="nx">$1</span>
|
||||
<span class="nx">o</span> <span class="s1">'SimpleAssignable ++'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Op</span> <span class="s1">'++'</span><span class="p">,</span> <span class="nx">$1</span><span class="p">,</span> <span class="kc">null</span><span class="p">,</span> <span class="kc">true</span></pre></div> </td> </tr> <tr id="section-62"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-62">¶</a> </div> <p><a href="http://jashkenas.github.com/coffee-script/#existence">The existential operator</a>.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">o</span> <span class="s1">'Expression ?'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Existence</span> <span class="nx">$1</span>
|
||||
|
||||
<span class="nx">o</span> <span class="s1">'Expression + Expression'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Op</span> <span class="s1">'+'</span> <span class="p">,</span> <span class="nx">$1</span><span class="p">,</span> <span class="nx">$3</span>
|
||||
<span class="nx">o</span> <span class="s1">'Expression - Expression'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Op</span> <span class="s1">'-'</span> <span class="p">,</span> <span class="nx">$1</span><span class="p">,</span> <span class="nx">$3</span>
|
||||
@@ -358,7 +355,7 @@ rules are necessary.</p> </td> <td class="code">
|
||||
<span class="nx">o</span> <span class="s1">'SimpleAssignable COMPOUND_ASSIGN</span>
|
||||
<span class="s1"> INDENT Expression OUTDENT'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Assign</span> <span class="nx">$1</span><span class="p">,</span> <span class="nx">$4</span><span class="p">,</span> <span class="nx">$2</span>
|
||||
<span class="nx">o</span> <span class="s1">'SimpleAssignable EXTENDS Expression'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Extends</span> <span class="nx">$1</span><span class="p">,</span> <span class="nx">$3</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-62"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-62">¶</a> </div> <h2>Precedence</h2> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-63"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-63">¶</a> </div> <p>Operators at the top of this list have higher precedence than the ones lower
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-63"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-63">¶</a> </div> <h2>Precedence</h2> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-64"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-64">¶</a> </div> <p>Operators at the top of this list have higher precedence than the ones lower
|
||||
down. Following these rules is what makes <code>2 + 3 * 4</code> parse as:</p>
|
||||
|
||||
<pre><code>2 + (3 * 4)
|
||||
@@ -384,7 +381,7 @@ down. Following these rules is what makes <code>2 + 3 * 4</code> parse as:</p>
|
||||
<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">'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
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-65"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-65">¶</a> </div> <h2>Wrapping Up</h2> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-66"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-66">¶</a> </div> <p>Finally, now that 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>
|
||||
@@ -393,7 +390,7 @@ as "tokens".</p> </td> <td class="code"> <
|
||||
<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>
|
||||
<span class="nx">alt</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="s2">"return #{alt[1]}"</span> <span class="k">if</span> <span class="nx">name</span> <span class="o">is</span> <span class="s1">'Root'</span>
|
||||
<span class="nx">alt</span></pre></div> </td> </tr> <tr id="section-66"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-66">¶</a> </div> <p>Initialize the <strong>Parser</strong> with our list of terminal <strong>tokens</strong>, our <strong>grammar</strong>
|
||||
<span class="nx">alt</span></pre></div> </td> </tr> <tr id="section-67"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-67">¶</a> </div> <p>Initialize the <strong>Parser</strong> with our list of terminal <strong>tokens</strong>, our <strong>grammar</strong>
|
||||
rules, and the name of the root. Reverse the operators because Jison orders
|
||||
precedence from low to high, and we have it high to low
|
||||
(as in <a href="http://dinosaur.compilertools.net/yacc/index.html">Yacc</a>).</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.parser = </span><span class="k">new</span> <span class="nx">Parser</span>
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
@@ -13,17 +13,20 @@ 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
|
||||
specified options, and return it. <code>options.arguments</code> will be an array
|
||||
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="nv">originalArgs = </span><span class="nx">args</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="nv">pos = </span><span class="nx">originalArgs</span><span class="p">.</span><span class="nx">indexOf</span> <span class="s1">'--'</span>
|
||||
<span class="nv">options.arguments = </span><span class="p">[</span><span class="nx">originalArgs</span><span class="p">[</span><span class="mi">1</span> <span class="o">+</span> <span class="nx">pos</span><span class="p">]]</span>
|
||||
<span class="nv">options.literals = </span><span class="nx">originalArgs</span><span class="p">[(</span><span class="mi">2</span> <span class="o">+</span> <span class="nx">pos</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>
|
||||
@@ -35,7 +38,7 @@ for interpreting the options object.</p> </td> <td class
|
||||
<span class="k">break</span>
|
||||
<span class="k">throw</span> <span class="k">new</span> <span class="nb">Error</span> <span class="s2">"unrecognized option: #{arg}"</span> <span class="k">if</span> <span class="nx">isOption</span> <span class="o">and</span> <span class="o">not</span> <span class="nx">matchedRule</span>
|
||||
<span class="k">if</span> <span class="o">not</span> <span class="nx">isOption</span>
|
||||
<span class="nv">options.arguments = </span><span class="nx">args</span><span class="p">.</span><span class="nx">slice</span> <span class="nx">i</span>
|
||||
<span class="nv">options.arguments = </span><span class="nx">originalArgs</span><span class="p">[(</span><span class="nx">originalArgs</span><span class="p">.</span><span class="nx">indexOf</span> <span class="nx">arg</span><span class="p">)..]</span>
|
||||
<span class="k">break</span>
|
||||
<span class="nx">options</span></pre></div> </td> </tr> <tr id="section-4"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-4">¶</a> </div> <p>Return the help text for this <strong>OptionParser</strong>, listing and describing all
|
||||
of the valid options, for <code>--help</code> and such.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">help</span><span class="o">:</span> <span class="o">-></span>
|
||||
|
||||
@@ -6,35 +6,39 @@ Using it looks like this:</p>
|
||||
</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">readline = </span><span class="nx">require</span> <span class="s1">'readline'</span>
|
||||
<span class="p">{</span><span class="nx">inspect</span><span class="p">}</span> <span class="o">=</span> <span class="nx">require</span> <span class="s1">'util'</span>
|
||||
<span class="p">{</span><span class="nx">Script</span><span class="p">}</span> <span class="o">=</span> <span class="nx">require</span> <span class="s1">'vm'</span></pre></div> </td> </tr> <tr id="section-3"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-3">¶</a> </div> <p>REPL Setup</p> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-4"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-4">¶</a> </div> <p>Config</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">enableColours = </span><span class="kc">no</span>
|
||||
<span class="p">{</span><span class="nx">Script</span><span class="p">}</span> <span class="o">=</span> <span class="nx">require</span> <span class="s1">'vm'</span>
|
||||
<span class="nv">Module = </span><span class="nx">require</span> <span class="s1">'module'</span></pre></div> </td> </tr> <tr id="section-3"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-3">¶</a> </div> <p>REPL Setup</p> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-4"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-4">¶</a> </div> <p>Config</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">REPL_PROMPT = </span><span class="s1">'coffee> '</span>
|
||||
<span class="nv">REPL_PROMPT_CONTINUATION = </span><span class="s1">'......> '</span>
|
||||
<span class="nv">enableColours = </span><span class="kc">no</span>
|
||||
<span class="nx">unless</span> <span class="nx">process</span><span class="p">.</span><span class="nx">platform</span> <span class="o">is</span> <span class="s1">'win32'</span>
|
||||
<span class="nv">enableColours = </span><span class="o">not</span> <span class="nx">process</span><span class="p">.</span><span class="nx">env</span><span class="p">.</span><span class="nx">NODE_DISABLE_COLORS</span></pre></div> </td> </tr> <tr id="section-5"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-5">¶</a> </div> <p>Start by opening up <code>stdin</code> and <code>stdout</code>.</p> </td> <td class="code"> <div class="highlight"><pre><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="nv">stdout = </span><span class="nx">process</span><span class="p">.</span><span class="nx">stdout</span></pre></div> </td> </tr> <tr id="section-6"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-6">¶</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">stdout</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-7"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-7">¶</a> </div> <p>The current backlog of multi-line code.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">backlog = </span><span class="s1">''</span></pre></div> </td> </tr> <tr id="section-8"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-8">¶</a> </div> <p>The main REPL function. <strong>run</strong> is called every time a line of code is entered.
|
||||
<span class="nx">stdout</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'</span></pre></div> </td> </tr> <tr id="section-7"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-7">¶</a> </div> <p>The current backlog of multi-line code.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">backlog = </span><span class="s1">''</span></pre></div> </td> </tr> <tr id="section-8"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-8">¶</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="nx">do</span> <span class="o">-></span>
|
||||
<span class="nv">sandbox =</span>
|
||||
<span class="nx">require</span><span class="o">:</span> <span class="nx">require</span>
|
||||
<span class="nx">module</span> <span class="o">:</span> <span class="p">{</span> <span class="nx">exports</span><span class="o">:</span> <span class="p">{}</span> <span class="p">}</span>
|
||||
<span class="nx">sandbox</span><span class="p">[</span><span class="nx">g</span><span class="p">]</span> <span class="o">=</span> <span class="nx">global</span><span class="p">[</span><span class="nx">g</span><span class="p">]</span> <span class="k">for</span> <span class="nx">g</span> <span class="k">of</span> <span class="nx">global</span>
|
||||
<span class="nv">sandbox.global = </span><span class="nx">sandbox</span>
|
||||
<span class="nv">sandbox.global.global = sandbox.global.root = sandbox.global.GLOBAL = </span><span class="nx">sandbox</span>
|
||||
<span class="p">(</span><span class="nx">buffer</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nv">code = </span><span class="nx">backlog</span> <span class="o">+=</span> <span class="s1">'\n'</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">code</span><span class="p">[</span><span class="nx">code</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">is</span> <span class="s1">'\\'</span>
|
||||
<span class="k">return</span> <span class="nv">backlog = </span><span class="nx">backlog</span><span class="p">[</span><span class="mi">0</span><span class="p">...</span><span class="nx">backlog</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="nv">backlog = </span><span class="s1">''</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">code</span><span class="p">,</span> <span class="p">{</span>
|
||||
<span class="nx">sandbox</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">filename</span><span class="o">:</span> <span class="s1">'repl'</span>
|
||||
<span class="p">}</span>
|
||||
<span class="nx">unless</span> <span class="nx">val</span> <span class="o">is</span> <span class="kc">undefined</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">inspect</span><span class="p">(</span><span class="nx">val</span><span class="p">,</span> <span class="kc">no</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="nx">enableColours</span><span class="p">)</span> <span class="o">+</span> <span class="s1">'\n'</span>
|
||||
<span class="k">catch</span> <span class="nx">err</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-9"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-9">¶</a> </div> <h1>Autocompletion</h1> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-10"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-10">¶</a> </div> <p>Regexes to match complete-able bits of text.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">ACCESSOR = </span><span class="sr">/\s*([\w\.]+)(?:\.(\w*))$/</span>
|
||||
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">if</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="o">and</span> <span class="o">!</span><span class="nx">backlog</span>
|
||||
<span class="nx">repl</span><span class="p">.</span><span class="nx">prompt</span><span class="p">()</span>
|
||||
<span class="k">return</span>
|
||||
<span class="nv">code = </span><span class="nx">backlog</span> <span class="o">+=</span> <span class="nx">buffer</span>
|
||||
<span class="k">if</span> <span class="nx">code</span><span class="p">[</span><span class="nx">code</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">is</span> <span class="s1">'\\'</span>
|
||||
<span class="nv">backlog = </span><span class="s2">"#{backlog[...-1]}\n"</span>
|
||||
<span class="nx">repl</span><span class="p">.</span><span class="nx">setPrompt</span> <span class="nx">REPL_PROMPT_CONTINUATION</span>
|
||||
<span class="nx">repl</span><span class="p">.</span><span class="nx">prompt</span><span class="p">()</span>
|
||||
<span class="k">return</span>
|
||||
<span class="nx">repl</span><span class="p">.</span><span class="nx">setPrompt</span> <span class="nx">REPL_PROMPT</span>
|
||||
<span class="nv">backlog = </span><span class="s1">''</span>
|
||||
<span class="k">try</span>
|
||||
<span class="nv">_ = </span><span class="nx">global</span><span class="p">.</span><span class="nx">_</span>
|
||||
<span class="nv">returnValue = </span><span class="nx">CoffeeScript</span><span class="p">.</span><span class="nb">eval</span> <span class="s2">"_=(#{code}\n)"</span><span class="p">,</span> <span class="p">{</span>
|
||||
<span class="nx">filename</span><span class="o">:</span> <span class="s1">'repl'</span>
|
||||
<span class="nx">modulename</span><span class="o">:</span> <span class="s1">'repl'</span>
|
||||
<span class="p">}</span>
|
||||
<span class="k">if</span> <span class="nx">returnValue</span> <span class="o">is</span> <span class="kc">undefined</span>
|
||||
<span class="nv">global._ = </span><span class="nx">_</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">inspect</span><span class="p">(</span><span class="nx">returnValue</span><span class="p">,</span> <span class="kc">no</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="nx">enableColours</span><span class="p">)</span> <span class="o">+</span> <span class="s1">'\n'</span>
|
||||
<span class="k">catch</span> <span class="nx">err</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-9"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-9">¶</a> </div> <h1>Autocompletion</h1> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-10"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-10">¶</a> </div> <p>Regexes to match complete-able bits of text.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">ACCESSOR = </span><span class="sr">/\s*([\w\.]+)(?:\.(\w*))$/</span>
|
||||
<span class="nv">SIMPLEVAR = </span><span class="sr">/\s*(\w*)$/i</span></pre></div> </td> </tr> <tr id="section-11"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-11">¶</a> </div> <p>Returns a list of completions, and the completed text.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">autocomplete = </span><span class="p">(</span><span class="nx">text</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nx">completeAttribute</span><span class="p">(</span><span class="nx">text</span><span class="p">)</span> <span class="o">or</span> <span class="nx">completeVariable</span><span class="p">(</span><span class="nx">text</span><span class="p">)</span> <span class="o">or</span> <span class="p">[[],</span> <span class="nx">text</span><span class="p">]</span></pre></div> </td> </tr> <tr id="section-12"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-12">¶</a> </div> <p>Attempt to autocomplete a chained dotted attribute: <code>one.two.three</code>.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">completeAttribute = </span><span class="p">(</span><span class="nx">text</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="k">if</span> <span class="nv">match = </span><span class="nx">text</span><span class="p">.</span><span class="nx">match</span> <span class="nx">ACCESSOR</span>
|
||||
@@ -42,23 +46,38 @@ of exiting.</p> </td> <td class="code"> <d
|
||||
<span class="k">try</span>
|
||||
<span class="nv">val = </span><span class="nx">Script</span><span class="p">.</span><span class="nx">runInThisContext</span> <span class="nx">obj</span>
|
||||
<span class="k">catch</span> <span class="nx">error</span>
|
||||
<span class="k">return</span> <span class="p">[[],</span> <span class="nx">text</span><span class="p">]</span>
|
||||
<span class="nv">completions = </span><span class="nx">getCompletions</span> <span class="nx">prefix</span><span class="p">,</span> <span class="nx">getPropertyNames</span> <span class="nx">val</span>
|
||||
<span class="k">return</span>
|
||||
<span class="nv">completions = </span><span class="nx">getCompletions</span> <span class="nx">prefix</span><span class="p">,</span> <span class="nb">Object</span><span class="p">.</span><span class="nx">getOwnPropertyNames</span> <span class="nx">val</span>
|
||||
<span class="p">[</span><span class="nx">completions</span><span class="p">,</span> <span class="nx">prefix</span><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>Attempt to autocomplete an in-scope free variable: <code>one</code>.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">completeVariable = </span><span class="p">(</span><span class="nx">text</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="k">if</span> <span class="nv">free = </span><span class="nx">text</span><span class="p">.</span><span class="nx">match</span><span class="p">(</span><span class="nx">SIMPLEVAR</span><span class="p">)</span><span class="o">?</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
|
||||
<span class="nv">scope = </span><span class="nx">Script</span><span class="p">.</span><span class="nx">runInThisContext</span> <span class="s1">'this'</span>
|
||||
<span class="nv">completions = </span><span class="nx">getCompletions</span> <span class="nx">free</span><span class="p">,</span> <span class="nx">CoffeeScript</span><span class="p">.</span><span class="nx">RESERVED</span><span class="p">.</span><span class="nx">concat</span><span class="p">(</span><span class="nx">getPropertyNames</span> <span class="nx">scope</span><span class="p">)</span>
|
||||
<span class="nv">free = </span><span class="p">(</span><span class="nx">text</span><span class="p">.</span><span class="nx">match</span> <span class="nx">SIMPLEVAR</span><span class="p">)</span><span class="o">?</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
|
||||
<span class="k">if</span> <span class="nx">free</span><span class="o">?</span>
|
||||
<span class="nv">vars = </span><span class="nx">Script</span><span class="p">.</span><span class="nx">runInThisContext</span> <span class="s1">'Object.getOwnPropertyNames(this)'</span>
|
||||
<span class="nv">keywords = </span><span class="p">(</span><span class="nx">r</span> <span class="k">for</span> <span class="nx">r</span> <span class="k">in</span> <span class="nx">CoffeeScript</span><span class="p">.</span><span class="nx">RESERVED</span> <span class="k">when</span> <span class="nx">r</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="o">isnt</span> <span class="s1">'__'</span><span class="p">)</span>
|
||||
<span class="nv">possibilities = </span><span class="nx">vars</span><span class="p">.</span><span class="nx">concat</span> <span class="nx">keywords</span>
|
||||
<span class="nv">completions = </span><span class="nx">getCompletions</span> <span class="nx">free</span><span class="p">,</span> <span class="nx">possibilities</span>
|
||||
<span class="p">[</span><span class="nx">completions</span><span class="p">,</span> <span class="nx">free</span><span class="p">]</span></pre></div> </td> </tr> <tr id="section-14"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-14">¶</a> </div> <p>Return elements of candidates for which <code>prefix</code> is a prefix.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">getCompletions = </span><span class="p">(</span><span class="nx">prefix</span><span class="p">,</span> <span class="nx">candidates</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="p">(</span><span class="nx">el</span> <span class="k">for</span> <span class="nx">el</span> <span class="k">in</span> <span class="nx">candidates</span> <span class="k">when</span> <span class="nx">el</span><span class="p">.</span><span class="nx">indexOf</span><span class="p">(</span><span class="nx">prefix</span><span class="p">)</span> <span class="o">is</span> <span class="mi">0</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 all "own" properties of an object.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">getPropertyNames = </span><span class="p">(</span><span class="nx">obj</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="p">(</span><span class="nx">name</span> <span class="k">for</span> <span class="nx">own</span> <span class="nx">name</span> <span class="k">of</span> <span class="nx">obj</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>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-17"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-17">¶</a> </div> <p>Create the REPL by listening to <strong>stdin</strong>.</p> </td> <td class="code"> <div class="highlight"><pre><span class="k">if</span> <span class="nx">readline</span><span class="p">.</span><span class="nx">createInterface</span><span class="p">.</span><span class="nx">length</span> <span class="o"><</span> <span class="mi">3</span>
|
||||
<span class="p">(</span><span class="nx">el</span> <span class="k">for</span> <span class="nx">el</span> <span class="k">in</span> <span class="nx">candidates</span> <span class="k">when</span> <span class="nx">el</span><span class="p">.</span><span class="nx">indexOf</span><span class="p">(</span><span class="nx">prefix</span><span class="p">)</span> <span class="o">is</span> <span class="mi">0</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>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-16"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-16">¶</a> </div> <p>Create the REPL by listening to <strong>stdin</strong>.</p> </td> <td class="code"> <div class="highlight"><pre><span class="k">if</span> <span class="nx">readline</span><span class="p">.</span><span class="nx">createInterface</span><span class="p">.</span><span class="nx">length</span> <span class="o"><</span> <span class="mi">3</span>
|
||||
<span class="nv">repl = </span><span class="nx">readline</span><span class="p">.</span><span class="nx">createInterface</span> <span class="nx">stdin</span><span class="p">,</span> <span class="nx">autocomplete</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">repl</span><span class="p">.</span><span class="nx">write</span> <span class="nx">buffer</span>
|
||||
<span class="k">else</span>
|
||||
<span class="nv">repl = </span><span class="nx">readline</span><span class="p">.</span><span class="nx">createInterface</span> <span class="nx">stdin</span><span class="p">,</span> <span class="nx">stdout</span><span class="p">,</span> <span class="nx">autocomplete</span>
|
||||
|
||||
<span class="nx">repl</span><span class="p">.</span><span class="nx">setPrompt</span> <span class="s1">'coffee> '</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">stdin</span><span class="p">.</span><span class="nx">destroy</span><span class="p">()</span>
|
||||
<span class="nx">repl</span><span class="p">.</span><span class="kc">on</span> <span class="s1">'line'</span><span class="p">,</span> <span class="nx">run</span>
|
||||
<span class="nx">repl</span><span class="p">.</span><span class="kc">on</span> <span class="s1">'attemptClose'</span><span class="p">,</span> <span class="o">-></span>
|
||||
<span class="k">if</span> <span class="nx">backlog</span>
|
||||
<span class="nv">backlog = </span><span class="s1">''</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="s1">'\n'</span>
|
||||
<span class="nx">repl</span><span class="p">.</span><span class="nx">setPrompt</span> <span class="nx">REPL_PROMPT</span>
|
||||
<span class="nx">repl</span><span class="p">.</span><span class="nx">prompt</span><span class="p">()</span>
|
||||
<span class="k">else</span>
|
||||
<span class="nx">repl</span><span class="p">.</span><span class="nx">close</span><span class="p">()</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">process</span><span class="p">.</span><span class="nx">stdout</span><span class="p">.</span><span class="nx">write</span> <span class="s1">'\n'</span>
|
||||
<span class="nx">stdin</span><span class="p">.</span><span class="nx">destroy</span><span class="p">()</span>
|
||||
|
||||
<span class="nx">repl</span><span class="p">.</span><span class="kc">on</span> <span class="s1">'line'</span><span class="p">,</span> <span class="nx">run</span>
|
||||
|
||||
<span class="nx">repl</span><span class="p">.</span><span class="nx">setPrompt</span> <span class="nx">REPL_PROMPT</span>
|
||||
<span class="nx">repl</span><span class="p">.</span><span class="nx">prompt</span><span class="p">()</span>
|
||||
|
||||
</pre></div> </td> </tr> </tbody> </table> </div> </body> </html>
|
||||
@@ -3,7 +3,7 @@ and shorthand syntax. This can greatly complicate a grammar and bloat
|
||||
the resulting parse table. Instead of making the parser handle it all, we take
|
||||
a series of passes over the token stream, using this <strong>Rewriter</strong> to convert
|
||||
shorthand into the unambiguous long form, add implicit indentation and
|
||||
parentheses, balance incorrect nestings, and generally clean things up.</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>The <strong>Rewriter</strong> class is used by the <a href="lexer.html">Lexer</a>, directly against
|
||||
parentheses, and generally clean things up.</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>The <strong>Rewriter</strong> class is used by the <a href="lexer.html">Lexer</a>, directly against
|
||||
its internal array of tokens.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nx">class</span> <span class="nx">exports</span><span class="p">.</span><span class="nx">Rewriter</span></pre></div> </td> </tr> <tr id="section-3"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-3">¶</a> </div> <p>Helpful snippet for debugging:
|
||||
console.log (t[0] + '/' + t[1] for t in @tokens).join ' '</p> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-4"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-4">¶</a> </div> <p>Rewrite the token stream in multiple passes, one logical filter at
|
||||
a time. This could certainly be changed into a single pass through the
|
||||
@@ -18,8 +18,6 @@ corrected before implicit parentheses can be wrapped around blocks of code.</p>
|
||||
<span class="nx">@tagPostfixConditionals</span><span class="p">()</span>
|
||||
<span class="nx">@addImplicitBraces</span><span class="p">()</span>
|
||||
<span class="nx">@addImplicitParentheses</span><span class="p">()</span>
|
||||
<span class="nx">@ensureBalance</span> <span class="nx">BALANCED_PAIRS</span>
|
||||
<span class="nx">@rewriteClosingParens</span><span class="p">()</span>
|
||||
<span class="nx">@tokens</span></pre></div> </td> </tr> <tr id="section-5"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-5">¶</a> </div> <p>Rewrite the token stream, looking one token ahead and behind.
|
||||
Allow the return value of the block to tell us how many tokens to move
|
||||
forwards (or backwards) in the stream, to make sure we don't miss anything
|
||||
@@ -104,19 +102,18 @@ Insert the missing braces here, so that the parser doesn't have to.</p>
|
||||
Insert the implicit parentheses here, so that the parser doesn't have to
|
||||
deal with them.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">addImplicitParentheses</span><span class="o">:</span> <span class="o">-></span>
|
||||
<span class="nv">noCall = </span><span class="kc">no</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="nv">idx = </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">is</span> <span class="s1">'OUTDENT'</span> <span class="k">then</span> <span class="nx">i</span> <span class="o">+</span> <span class="mi">1</span> <span class="k">else</span> <span class="nx">i</span>
|
||||
<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="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">'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="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">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="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">seenControl = </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">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="k">if</span> <span class="nx">token</span><span class="p">.</span><span class="nx">fromThen</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>
|
||||
@@ -125,9 +122,11 @@ deal with them.</p> </td> <td class="code">
|
||||
<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="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="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">'CATCH'</span><span class="p">,</span> <span class="s1">'->'</span><span class="p">,</span> <span class="s1">'=>'</span><span class="p">]</span>
|
||||
<span class="nv">seenControl = </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">'SWITCH'</span><span class="p">,</span> <span class="s1">'TRY'</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="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="p">(</span><span class="nx">tag</span> <span class="k">in</span> <span class="nx">IMPLICIT_END</span> <span class="o">or</span>
|
||||
<span class="p">(</span><span class="nx">tag</span> <span class="o">is</span> <span class="s1">'INDENT'</span> <span class="o">and</span> <span class="o">not</span> <span class="nx">seenControl</span><span class="p">))</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>
|
||||
<span class="p">(</span><span class="nx">@tag</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">isnt</span> <span class="s1">'CLASS'</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">not</span> <span class="k">in</span> <span class="nx">IMPLICIT_BLOCK</span> <span class="o">and</span>
|
||||
<span class="o">not</span> <span class="p">((</span><span class="nv">post = </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="o">and</span> <span class="nx">post</span><span class="p">.</span><span class="nx">generated</span> <span class="o">and</span> <span class="nx">post</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>
|
||||
@@ -171,64 +170,8 @@ different precedence.</p> </td> <td class="code">
|
||||
<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>
|
||||
<span class="mi">1</span></pre></div> </td> </tr> <tr id="section-14"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-14">¶</a> </div> <p>Ensure that all listed pairs of tokens are correctly balanced throughout
|
||||
the course of the token stream.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">ensureBalance</span><span class="o">:</span> <span class="p">(</span><span class="nx">pairs</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nv">levels = </span><span class="p">{}</span>
|
||||
<span class="nv">openLine = </span><span class="p">{}</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="o">=</span> <span class="nx">token</span>
|
||||
<span class="k">for</span> <span class="p">[</span><span class="nx">open</span><span class="p">,</span> <span class="nx">close</span><span class="p">]</span> <span class="k">in</span> <span class="nx">pairs</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">if</span> <span class="nx">tag</span> <span class="o">is</span> <span class="nx">open</span>
|
||||
<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">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>
|
||||
|
||||
<pre><code>el.click((event) ->
|
||||
el.hide())
|
||||
</code></pre>
|
||||
|
||||
<p>In order to accomplish this, move outdents that follow closing parens
|
||||
inwards, safely. The steps to accomplish this are:</p>
|
||||
|
||||
<ol>
|
||||
<li>Check that all paired tokens are balanced and in order.</li>
|
||||
<li>Rewrite the stream with a stack: if you see an <code>EXPRESSION_START</code>, add it
|
||||
to the stack. If you see an <code>EXPRESSION_END</code>, pop the stack and replace
|
||||
it with the inverse of what we've just popped.</li>
|
||||
<li>Keep track of "debt" for tokens that we manufacture, to make sure we end
|
||||
up balanced in the end.</li>
|
||||
<li>Be careful not to alter array or parentheses delimiters with overzealous
|
||||
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">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>
|
||||
<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="k">in</span> <span class="nx">EXPRESSION_END</span>
|
||||
<span class="k">if</span> <span class="nx">debt</span><span class="p">[</span><span class="nv">inv = </span><span class="nx">INVERSES</span><span class="p">[</span><span class="nx">tag</span><span class="p">]]</span> <span class="o">></span> <span class="mi">0</span>
|
||||
<span class="nx">debt</span><span class="p">[</span><span class="nx">inv</span><span class="p">]</span> <span class="o">-=</span> <span class="mi">1</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">1</span>
|
||||
<span class="k">return</span> <span class="mi">0</span>
|
||||
<span class="nv">match = </span><span class="nx">stack</span><span class="p">.</span><span class="nx">pop</span><span class="p">()</span>
|
||||
<span class="nv">mtag = </span><span class="nx">match</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
|
||||
<span class="nv">oppos = </span><span class="nx">INVERSES</span><span class="p">[</span><span class="nx">mtag</span><span class="p">]</span>
|
||||
<span class="k">return</span> <span class="mi">1</span> <span class="k">if</span> <span class="nx">tag</span> <span class="o">is</span> <span class="nx">oppos</span>
|
||||
<span class="nx">debt</span><span class="p">[</span><span class="nx">mtag</span><span class="p">]</span> <span class="o">+=</span> <span class="mi">1</span>
|
||||
<span class="nv">val = </span><span class="p">[</span><span class="nx">oppos</span><span class="p">,</span> <span class="k">if</span> <span class="nx">mtag</span> <span class="o">is</span> <span class="s1">'INDENT'</span> <span class="k">then</span> <span class="nx">match</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="k">else</span> <span class="nx">oppos</span><span class="p">]</span>
|
||||
<span class="k">if</span> <span class="nx">@tag</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">is</span> <span class="nx">mtag</span>
|
||||
<span class="nx">tokens</span><span class="p">.</span><span class="nx">splice</span> <span class="nx">i</span> <span class="o">+</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="nx">val</span>
|
||||
<span class="nx">stack</span><span class="p">.</span><span class="nx">push</span> <span class="nx">match</span>
|
||||
<span class="k">else</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="nx">val</span>
|
||||
<span class="mi">1</span></pre></div> </td> </tr> <tr id="section-16"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-16">¶</a> </div> <p>Generate the indentation tokens, based on another token on the same line.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">indentation</span><span class="o">:</span> <span class="p">(</span><span class="nx">token</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="p">[[</span><span class="s1">'INDENT'</span><span class="p">,</span> <span class="mi">2</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="p">[</span><span class="s1">'OUTDENT'</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="nx">token</span><span class="p">[</span><span class="mi">2</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>Look up a tag by token index.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">tag</span><span class="o">:</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">i</span><span class="p">]</span><span class="o">?</span><span class="p">[</span><span class="mi">0</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> <h2>Constants</h2> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-19"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-19">¶</a> </div> <p>List of the token pairs that must be balanced.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">BALANCED_PAIRS = </span><span class="p">[</span>
|
||||
<span class="mi">1</span></pre></div> </td> </tr> <tr id="section-14"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-14">¶</a> </div> <p>Generate the indentation tokens, based on another token on the same line.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">indentation</span><span class="o">:</span> <span class="p">(</span><span class="nx">token</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="p">[[</span><span class="s1">'INDENT'</span><span class="p">,</span> <span class="mi">2</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="p">[</span><span class="s1">'OUTDENT'</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="nx">token</span><span class="p">[</span><span class="mi">2</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>Look up a tag by token index.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">tag</span><span class="o">:</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">i</span><span class="p">]</span><span class="o">?</span><span class="p">[</span><span class="mi">0</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> <h2>Constants</h2> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-17"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-17">¶</a> </div> <p>List of the token pairs that must be balanced.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">BALANCED_PAIRS = </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="p">[</span><span class="s1">'['</span><span class="p">,</span> <span class="s1">']'</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>
|
||||
@@ -236,20 +179,20 @@ rewriting.</li>
|
||||
<span class="p">[</span><span class="s1">'CALL_START'</span><span class="p">,</span> <span class="s1">'CALL_END'</span><span class="p">]</span>
|
||||
<span class="p">[</span><span class="s1">'PARAM_START'</span><span class="p">,</span> <span class="s1">'PARAM_END'</span><span class="p">]</span>
|
||||
<span class="p">[</span><span class="s1">'INDEX_START'</span><span class="p">,</span> <span class="s1">'INDEX_END'</span><span class="p">]</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>The inverse mappings of <code>BALANCED_PAIRS</code> we're trying to fix up, so we can
|
||||
look things up from either end.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">INVERSES = </span><span class="p">{}</span></pre></div> </td> </tr> <tr id="section-21"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-21">¶</a> </div> <p>The tokens that signal the start/end of a balanced pair.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">EXPRESSION_START = </span><span class="p">[]</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>The inverse mappings of <code>BALANCED_PAIRS</code> we're trying to fix up, so we can
|
||||
look things up from either end.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.INVERSES = INVERSES = </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>The tokens that signal the start/end of a balanced pair.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">EXPRESSION_START = </span><span class="p">[]</span>
|
||||
<span class="nv">EXPRESSION_END = </span><span class="p">[]</span>
|
||||
|
||||
<span class="k">for</span> <span class="p">[</span><span class="nx">left</span><span class="p">,</span> <span class="nx">rite</span><span class="p">]</span> <span class="k">in</span> <span class="nx">BALANCED_PAIRS</span>
|
||||
<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="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-20"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-20">¶</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-21"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-21">¶</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-22"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-22">¶</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">'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">'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-23"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-23">¶</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-24"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-24">¶</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></pre></div> </td> </tr> <tr id="section-25"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-25">¶</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>
|
||||
<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-26"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-26">¶</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>
|
||||
|
||||
</pre></div> </td> </tr> </tbody> </table> </div> </body> </html>
|
||||
@@ -6,7 +6,7 @@ variables are new and need to be declared with <code>var</code>, and which are s
|
||||
with the outside.</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>Import the helpers we plan to use.</p> </td> <td class="code"> <div class="highlight"><pre><span class="p">{</span><span class="nx">extend</span><span class="p">,</span> <span class="nx">last</span><span class="p">}</span> <span class="o">=</span> <span class="nx">require</span> <span class="s1">'./helpers'</span>
|
||||
|
||||
<span class="nv">exports.Scope = </span><span class="nx">class</span> <span class="nx">Scope</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 top-level <strong>Scope</strong> object.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">@root</span><span class="o">:</span> <span class="kc">null</span></pre></div> </td> </tr> <tr id="section-4"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-4">¶</a> </div> <p>Initialize a scope with its parent, for lookups up the chain,
|
||||
as well as a reference to the <strong>Block</strong> node is belongs to, which is
|
||||
as well as a reference to the <strong>Block</strong> node it belongs to, which is
|
||||
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>
|
||||
|
||||
@@ -64,7 +64,7 @@
|
||||
<a href="#regexes">Extended Regular Expressions</a>
|
||||
<a href="#cake">Cake, and Cakefiles</a>
|
||||
<a href="#scripts">"text/coffeescript" Script Tags</a>
|
||||
<a href="#resources">Examples and Resources</a>
|
||||
<a href="#resources">Books, Screencasts, Examples and Resources</a>
|
||||
<a href="#change_log">Change Log</a>
|
||||
</div>
|
||||
</div>
|
||||
@@ -84,6 +84,7 @@
|
||||
</div>
|
||||
<div id="repl_results_wrap"><pre id="repl_results"></pre></div>
|
||||
<div class="minibutton dark run" title="Ctrl-Enter">Run</div>
|
||||
<a class="minibutton permalink" id="repl_permalink">Link</a>
|
||||
<br class="clear" />
|
||||
</div>
|
||||
</div>
|
||||
@@ -114,7 +115,7 @@
|
||||
|
||||
<p>
|
||||
<b>CoffeeScript is a little language that compiles into JavaScript.</b> Underneath
|
||||
all of those embarrassing braces and semicolons, JavaScript has always had
|
||||
all those awkward 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.
|
||||
</p>
|
||||
@@ -123,15 +124,16 @@
|
||||
The golden rule of CoffeeScript is: <i>"It's just JavaScript"</i>. The code
|
||||
compiles one-to-one into the equivalent JS, and there is
|
||||
no interpretation at runtime. You can use any existing JavaScript library
|
||||
seamlessly (and vice-versa). The compiled output is readable and pretty-printed,
|
||||
passes through <a href="http://www.javascriptlint.com/">JavaScript Lint</a>
|
||||
seamlessly from CoffeeScript (and vice-versa). The compiled output is
|
||||
readable and pretty-printed, passes through
|
||||
<a href="http://www.javascriptlint.com/">JavaScript Lint</a>
|
||||
without warnings, will work in every JavaScript implementation, and tends
|
||||
to run as fast or faster than the equivalent handwritten JavaScript.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<b>Latest Version:</b>
|
||||
<a href="http://github.com/jashkenas/coffee-script/tarball/1.1.1">1.1.1</a>
|
||||
<a href="http://github.com/jashkenas/coffee-script/tarball/1.1.3">1.1.3</a>
|
||||
</p>
|
||||
|
||||
<h2>
|
||||
@@ -171,7 +173,7 @@ npm install -g coffee-script</pre>
|
||||
<p>
|
||||
(Leave off the <tt>-g</tt> if you don't wish to install globally.)
|
||||
</p>
|
||||
|
||||
|
||||
<p>
|
||||
If you'd prefer to install the latest master version of CoffeeScript, you
|
||||
can clone the CoffeeScript
|
||||
@@ -189,7 +191,9 @@ sudo bin/cake install</pre>
|
||||
If installing on Ubuntu or Debian,
|
||||
<a href="http://opinionated-programmer.com/2010/12/installing-coffeescript-on-debian-or-ubuntu/">be
|
||||
careful not to use the existing out-of-date package</a>. If installing on
|
||||
Windows, your best bet is probably to run Node.js under Cygwin.
|
||||
Windows, your best bet is probably to run Node.js under Cygwin. If you'd
|
||||
just like to experiment, you can try the
|
||||
<a href="https://github.com/alisey/CoffeeScript-Compiler-for-Windows">CoffeeScript Compiler For Windows</a>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
@@ -211,8 +215,7 @@ sudo bin/cake install</pre>
|
||||
<td width="25%"><code>-i, --interactive</code></td>
|
||||
<td>
|
||||
Launch an interactive CoffeeScript session to try short snippets.
|
||||
More pleasant if wrapped with
|
||||
<a href="http://utopia.knoware.nl/~hlub/uck/rlwrap/rlwrap.html">rlwrap</a>.
|
||||
Identical to calling <tt>coffee</tt> with no arguments.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
@@ -226,15 +229,15 @@ sudo bin/cake install</pre>
|
||||
<td><code>-j, --join [FILE]</code></td>
|
||||
<td>
|
||||
Before compiling, concatenate all scripts together in the order they
|
||||
were passed, and write them into the specified file.
|
||||
were passed, and write them into the specified file.
|
||||
Useful for building large projects.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>-w, --watch</code></td>
|
||||
<td>
|
||||
Watch the modification times of the coffee-scripts, recompiling as
|
||||
soon as a change occurs.
|
||||
Watch files for changes, rerunning the specified command when any
|
||||
file is updated.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
@@ -266,7 +269,7 @@ sudo bin/cake install</pre>
|
||||
<td><code>-e, --eval</code></td>
|
||||
<td>
|
||||
Compile and print a little snippet of CoffeeScript directly from the
|
||||
command line. For example:<br /><tt>coffee -e "puts num for num in [10..1]"</tt>
|
||||
command line. For example:<br /><tt>coffee -e "console.log num for num in [10..1]"</tt>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
@@ -279,8 +282,8 @@ sudo bin/cake install</pre>
|
||||
<tr>
|
||||
<td><code>-b, --bare</code></td>
|
||||
<td>
|
||||
Compile the JavaScript without the top-level function safety wrapper.
|
||||
(Used for CoffeeScript as a Node.js module.)
|
||||
Compile the JavaScript without the
|
||||
<a href="#lexical_scope">top-level function safety wrapper</a>.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
@@ -309,7 +312,7 @@ Expressions
|
||||
<td><code>--nodejs</code></td>
|
||||
<td>
|
||||
The <tt>node</tt> executable has some useful options you can set,
|
||||
such as<br /> <tt>--debug</tt> and <tt>--max-stack-size</tt>. Use this
|
||||
such as<br /> <tt>--debug</tt>, <tt>--debug-brk</tt> and <tt>--max-stack-size</tt>. Use this
|
||||
flag to forward options directly to Node.js.
|
||||
</td>
|
||||
</tr>
|
||||
@@ -321,9 +324,9 @@ Expressions
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
Compile a directory tree of <tt>.coffee</tt> files into a parallel
|
||||
tree of <tt>.js</tt>, in <tt>lib</tt>:<br />
|
||||
<tt>coffee -o lib/ -c src/</tt>
|
||||
Compile a directory tree of <tt>.coffee</tt> files in <tt>src</tt> into a parallel
|
||||
tree of <tt>.js</tt> files in <tt>lib</tt>:<br />
|
||||
<tt>coffee --compile --output lib/ src/</tt>
|
||||
</li>
|
||||
<li>
|
||||
Watch a file for changes, and recompile it every time the file is saved:<br />
|
||||
@@ -337,6 +340,10 @@ Expressions
|
||||
Print out the compiled JS from a one-liner:<br />
|
||||
<tt>coffee -bpe "alert i for i in [0..10]"</tt>
|
||||
</li>
|
||||
<li>
|
||||
All together now, watch and recompile an entire project as you work on it:<br />
|
||||
<tt>coffee -o lib/ -cw src/</tt>
|
||||
</li>
|
||||
<li>
|
||||
Start the CoffeeScript REPL:<br />
|
||||
<tt>coffee</tt>
|
||||
@@ -367,8 +374,8 @@ Expressions
|
||||
<p>
|
||||
First, the basics: CoffeeScript uses significant whitespace to delimit blocks of code.
|
||||
You don't need to use semicolons <tt>;</tt> to terminate expressions,
|
||||
ending the line will do just as well, (although semicolons can still
|
||||
be used to fit multiple expressions onto a single line.)
|
||||
ending the line will do just as well (although semicolons can still
|
||||
be used to fit multiple expressions onto a single line).
|
||||
Instead of using curly braces
|
||||
<tt>{ }</tt> to surround blocks of code in <a href="#functions">functions</a>,
|
||||
<a href="#conditionals">if-statements</a>,
|
||||
@@ -447,7 +454,7 @@ Expressions
|
||||
If you'd like to create top-level variables for other scripts to use,
|
||||
attach them as properties on <b>window</b>, or on the <b>exports</b>
|
||||
object in CommonJS. The <b>existential operator</b> (covered below), gives you a
|
||||
reliable way to figure out where to add them, if you're targeting both
|
||||
reliable way to figure out where to add them; if you're targeting both
|
||||
CommonJS and the browser: <tt>exports ? this</tt>
|
||||
</p>
|
||||
|
||||
@@ -502,7 +509,7 @@ Expressions
|
||||
each iteration into an array. Sometimes functions end with loops that are
|
||||
intended to run only for their side-effects. Be careful that you're not
|
||||
accidentally returning the results of the comprehension in these cases,
|
||||
by adding a meaningful return value, like <tt>true</tt>, or <tt>null</tt>,
|
||||
by adding a meaningful return value — like <tt>true</tt> — or <tt>null</tt>,
|
||||
to the bottom of your function.
|
||||
</p>
|
||||
<p>
|
||||
@@ -565,7 +572,7 @@ Expressions
|
||||
to CoffeeScript functions, they nonetheless return their final value.
|
||||
The CoffeeScript compiler tries to make sure that all statements in the
|
||||
language can be used as expressions. Watch how the <tt>return</tt> gets
|
||||
pushed down into each possible branch of execution, in the function
|
||||
pushed down into each possible branch of execution in the function
|
||||
below.
|
||||
</p>
|
||||
<%= code_for('expressions', 'eldest') %>
|
||||
@@ -625,7 +632,7 @@ Expressions
|
||||
are the same as boolean <tt>true</tt>, while <tt>off</tt> and <tt>no</tt> are boolean <tt>false</tt>.
|
||||
</p>
|
||||
<p>
|
||||
For single-line statements, <tt>unless</tt> can be used as the inverse of <tt>if</tt>.
|
||||
<tt>unless</tt> can be used as the inverse of <tt>if</tt>.
|
||||
</p>
|
||||
<p>
|
||||
As a shortcut for <tt>this.property</tt>, you can use <tt>@property</tt>.
|
||||
@@ -719,7 +726,7 @@ Expressions
|
||||
</p>
|
||||
<%= code_for('prototypes', '"one_two".dasherize()') %>
|
||||
<p>
|
||||
Finally class definitions are blocks of executable code, which make for interesting
|
||||
Finally, class definitions are blocks of executable code, which make for interesting
|
||||
metaprogramming possibilities. Because in the context of a class definition,
|
||||
<tt>this</tt> is the class object itself (the constructor function), you
|
||||
can assign static properties by using <br /><tt>@property: value</tt>, and call
|
||||
@@ -758,7 +765,7 @@ Expressions
|
||||
<b class="header">Function binding</b>
|
||||
In JavaScript, the <tt>this</tt> keyword is dynamically scoped to mean the
|
||||
object that the current function is attached to. If you pass a function as
|
||||
as callback, or attach it to a different object, the original value of <tt>this</tt>
|
||||
a callback or attach it to a different object, the original value of <tt>this</tt>
|
||||
will be lost. If you're not familiar with this behavior,
|
||||
<a href="http://www.digital-web.com/articles/scope_in_javascript/">this Digital Web article</a>
|
||||
gives a good overview of the quirks.
|
||||
@@ -840,7 +847,7 @@ Expressions
|
||||
indentation level that begins the heredoc is maintained throughout, so
|
||||
you can keep it all aligned with the body of your code.
|
||||
</p>
|
||||
<%= code_for('heredocs') %>
|
||||
<%= code_for('heredocs', 'html') %>
|
||||
<p>
|
||||
Double-quoted heredocs, like double-quoted strings, allow interpolation.
|
||||
</p>
|
||||
@@ -870,13 +877,13 @@ Expressions
|
||||
</h2>
|
||||
|
||||
<p>
|
||||
CoffeeScript includes a simple build system similar to
|
||||
CoffeeScript includes a (very) simple build system similar to
|
||||
<a href="http://www.gnu.org/software/make/">Make</a> and
|
||||
<a href="http://rake.rubyforge.org/">Rake</a>. Naturally,
|
||||
it's called Cake, and is used for the build and test tasks for the CoffeeScript
|
||||
it's called Cake, and is used for the tasks that build and test the CoffeeScript
|
||||
language itself. Tasks are defined in a file named <tt>Cakefile</tt>, and
|
||||
can be invoked by running <tt>cake taskname</tt> from within the directory.
|
||||
To print a list of all the tasks and options, just run <tt>cake</tt>.
|
||||
can be invoked by running <tt>cake [task]</tt> from within the directory.
|
||||
To print a list of all the tasks and options, just type <tt>cake</tt>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
@@ -891,7 +898,11 @@ Expressions
|
||||
<p>
|
||||
If you need to invoke one task before another — for example, running
|
||||
<tt>build</tt> before <tt>test</tt>, you can use the <tt>invoke</tt> function:
|
||||
<tt>invoke 'build'</tt>
|
||||
<tt>invoke 'build'</tt>. Cake tasks are a minimal way to expose your
|
||||
CoffeeScript functions to the command line, so
|
||||
<a href="documentation/docs/cake.html">don't expect any fanciness built-in</a>.
|
||||
If you need dependencies, or async callbacks, it's best to put them in your
|
||||
code itself — not the cake task.
|
||||
</p>
|
||||
|
||||
<h2>
|
||||
@@ -910,7 +921,7 @@ Expressions
|
||||
|
||||
<p>
|
||||
In fact, the little bit of glue script that runs "Try CoffeeScript" above,
|
||||
as well as jQuery for the menu, is implemented in just this way.
|
||||
as well as the jQuery for the menu, is implemented in just this way.
|
||||
View source and look at the bottom of the page to see the example.
|
||||
Including the script also gives you access to <tt>CoffeeScript.compile()</tt>
|
||||
so you can pop open Firebug and try compiling some strings.
|
||||
@@ -924,10 +935,65 @@ Expressions
|
||||
|
||||
<h2>
|
||||
<span id="resources" class="bookmark"></span>
|
||||
Examples
|
||||
Books and Screencasts
|
||||
</h2>
|
||||
|
||||
<p>
|
||||
There are a number of excellent books and screencasts to help you get
|
||||
started with CoffeeScript, some of which are freely available online.
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<a href="http://arcturo.github.com/library/coffeescript/">The Little Book on CoffeeScript</a>
|
||||
is a brief 5-chapter introduction to CoffeeScript, written with great
|
||||
clarity and precision by
|
||||
<a href="http://alexmaccaw.co.uk/">Alex MacCaw</a>.
|
||||
</li>
|
||||
<li>
|
||||
<a href="http://autotelicum.github.com/Smooth-CoffeeScript/">Smooth CoffeeScript</a>
|
||||
is a reimagination of the excellent book
|
||||
<a href="http://eloquentjavascript.net/">Eloquent JavaScript</a>, as if
|
||||
it had been written in CoffeeScript instead. Covers language features
|
||||
as well a the functional and object oriented programming styles. By
|
||||
<a href="https://github.com/autotelicum">E. Hoigaard</a>.
|
||||
</li>
|
||||
<li>
|
||||
<a href="http://pragprog.com/book/tbcoffee/coffeescript">CoffeeScript: Accelerated JavaScript Development</a>
|
||||
is <a href="http://trevorburnham.com/">Trevor Burnham</a>'s thorough
|
||||
introduction to the language. By the end of the book, you'll have built
|
||||
a fast-paced multiplayer word game, writing both the client-side and Node.js
|
||||
portions in CoffeeScript.
|
||||
</li>
|
||||
<li>
|
||||
<a href="http://peepcode.com/products/coffeescript">Meet CoffeeScript</a>
|
||||
is a 75-minute long screencast by <a href="http://peepcode.com/">PeepCode</a>.
|
||||
Highly memorable for its animations which demonstrate transforming CoffeeScript
|
||||
into the equivalent JS.
|
||||
</li>
|
||||
<li>
|
||||
If you're looking for less of a time commitment, RailsCasts'
|
||||
<a href="http://railscasts.com/episodes/267-coffeescript-basics">CoffeeScript Basics</a>
|
||||
should have you covered, hitting all of the important notes about CoffeeScript
|
||||
in 11 minutes.
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h2>
|
||||
Examples
|
||||
</h2>
|
||||
|
||||
<p>
|
||||
The <a href="https://github.com/languages/coffeescript">best list of
|
||||
open-source CoffeeScript examples</a> can be found on GitHub. But just
|
||||
to throw out few more:
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<b>github</b>'s <a href="http://hubot.github.com/">Hubot</a>,
|
||||
a friendly IRC robot that can perform any number of useful and useless tasks.
|
||||
</li>
|
||||
<li>
|
||||
<b>sstephenson</b>'s <a href="http://pow.cx/">Pow</a>,
|
||||
a zero-configuration Rack server, with comprehensive annotated source.
|
||||
@@ -943,7 +1009,7 @@ Expressions
|
||||
</li>
|
||||
<li>
|
||||
<b>assaf</b>'s <a href="http://zombie.labnotes.org/">Zombie.js</a>,
|
||||
A headless, full-stack, faux-browser testing library for Node.js.
|
||||
a headless, full-stack, faux-browser testing library for Node.js.
|
||||
</li>
|
||||
<li>
|
||||
<b>jashkenas</b>' <a href="documentation/docs/underscore.html">Underscore.coffee</a>, a port
|
||||
@@ -989,7 +1055,7 @@ Expressions
|
||||
<li>
|
||||
<a href="http://github.com/jashkenas/coffee-script/wiki">The CoffeeScript Wiki</a><br />
|
||||
If you've ever learned a neat CoffeeScript tip or trick, or ran into a gotcha — share it on the wiki.
|
||||
The wiki also serves as a directory of handy
|
||||
The wiki also serves as a directory of handy
|
||||
<a href="http://github.com/jashkenas/coffee-script/wiki/Text-editor-plugins">text editor extensions</a>,
|
||||
<a href="http://github.com/jashkenas/coffee-script/wiki/Web-framework-plugins">web framework plugins</a>,
|
||||
and general <a href="http://github.com/jashkenas/coffee-script/wiki/Build-tools">CoffeeScript build tools</a>.
|
||||
@@ -1020,19 +1086,76 @@ Expressions
|
||||
Change Log
|
||||
</h2>
|
||||
|
||||
<p>
|
||||
<b class="header" style="margin-top: 20px;">
|
||||
<a href="https://github.com/jashkenas/coffee-script/compare/1.1.2...1.1.3">1.1.3</a>
|
||||
<span class="timestamp"> – <small>Nov. 8, 2011</small></span>
|
||||
</b>
|
||||
<ul>
|
||||
<li>
|
||||
Ahh, whitespace. CoffeeScript's compiled JS now tries to space things
|
||||
out and keep it readable, as you can see in the examples on this page.
|
||||
</li>
|
||||
<li>
|
||||
You can now call <tt>super</tt> in class level methods in class bodies,
|
||||
and bound class methods now preserve their correct context.
|
||||
</li>
|
||||
<li>
|
||||
JavaScript has always supported octal numbers <tt>010 is 8</tt>,
|
||||
and hexadecimal numbers <tt>0xf is 15</tt>, but CoffeeScript now
|
||||
also supports binary numbers: <tt>0b10 is 2</tt>.
|
||||
</li>
|
||||
<li>
|
||||
The CoffeeScript module has been nested under a subdirectory to make
|
||||
it easier to <tt>require</tt> individual components separately, without
|
||||
having to use <b>npm</b>. For example, after adding the CoffeeScript
|
||||
folder to your path: <tt>require('coffee-script/lexer')</tt>
|
||||
</li>
|
||||
<li>
|
||||
There's a new "link" feature in Try CoffeeScript on this webpage. Use
|
||||
it to get a shareable permalink for your example script.
|
||||
</li>
|
||||
<li>
|
||||
The <tt>coffee --watch</tt> feature now only works on Node.js 0.6.0
|
||||
and higher, but now also works properly on Windows.
|
||||
</li>
|
||||
<li>
|
||||
Lots of small bug fixes from
|
||||
<b><a href="https://github.com/michaelficarra">@michaelficarra</a></b>,
|
||||
<b><a href="https://github.com/geraldalewis">@geraldalewis</a></b>,
|
||||
<b><a href="https://github.com/satyr">@satyr</a></b>, and
|
||||
<b><a href="https://github.com/trevorburnham">@trevorburnham</a></b>.
|
||||
</li>
|
||||
</ul>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<b class="header" style="margin-top: 20px;">
|
||||
<a href="https://github.com/jashkenas/coffee-script/compare/1.1.1...1.1.2">1.1.2</a>
|
||||
<span class="timestamp"> – <small>August 4, 2011</small></span>
|
||||
</b>
|
||||
Fixes for block comment formatting, <tt>?=</tt> compilation, implicit calls
|
||||
against control structures, implicit invocation of a try/catch block,
|
||||
variadic arguments leaking from local scope, line numbers in syntax errors
|
||||
following heregexes, property access on parenthesized number literals,
|
||||
bound class methods and super with reserved names, a REPL overhaul,
|
||||
consecutive compiled semicolons, block comments in implicitly called objects,
|
||||
and a Chrome bug.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<b class="header" style="margin-top: 20px;">1.1.1
|
||||
<span class="timestamp"> – <small>May 10, 2011</small></span>
|
||||
</b>
|
||||
Bugfix release for classes with external constructor functions, see
|
||||
Bugfix release for classes with external constructor functions, see
|
||||
issue #1182.
|
||||
</p>
|
||||
|
||||
|
||||
<p>
|
||||
<b class="header" style="margin-top: 20px;">1.1.0
|
||||
<span class="timestamp"> – <small>May 1, 2011</small></span>
|
||||
</b>
|
||||
When running via <tt>coffee</tt> executable, <tt>process.argv</tt> and
|
||||
When running via the <tt>coffee</tt> executable, <tt>process.argv</tt> and
|
||||
friends now report <tt>coffee</tt> instead of <tt>node</tt>.
|
||||
Better compatibility with <b>Node.js 0.4.x</b> module lookup changes.
|
||||
The output in the REPL is now colorized, like Node's is.
|
||||
@@ -1512,6 +1635,7 @@ Expressions
|
||||
</div>
|
||||
|
||||
<script type="text/coffeescript">
|
||||
sourceFragment = "try:"
|
||||
|
||||
# Set up the compilation function, to run when you stop typing.
|
||||
compileSource = ->
|
||||
@@ -1528,6 +1652,9 @@ Expressions
|
||||
catch error
|
||||
$('#error').text(error.message).show()
|
||||
|
||||
# Update permalink
|
||||
$('#repl_permalink').attr 'href', "##{sourceFragment}#{encodeURIComponent source}"
|
||||
|
||||
# Listen for keypresses and recompile.
|
||||
$('#repl_source').keyup -> compileSource()
|
||||
|
||||
@@ -1574,11 +1701,21 @@ Expressions
|
||||
$('#open_webchat').click ->
|
||||
$(this).replaceWith $('<iframe src="http://webchat.freenode.net/?channels=coffeescript" width="625" height="400"></iframe>')
|
||||
|
||||
$("#repl_permalink").click (e) ->
|
||||
window.location = $(this).attr("href")
|
||||
false
|
||||
|
||||
# If source code is included in location.hash, display it.
|
||||
hash = decodeURIComponent location.hash.replace(/^#/, '')
|
||||
if hash.indexOf(sourceFragment) == 0
|
||||
src = hash.substr sourceFragment.length
|
||||
loadConsole src
|
||||
|
||||
compileSource()
|
||||
|
||||
</script>
|
||||
|
||||
<script src="documentation/vendor/jquery-1.4.2.js"></script>
|
||||
<script src="documentation/vendor/jquery-1.6.4.js"></script>
|
||||
<script src="extras/coffee-script.js"></script>
|
||||
|
||||
</body>
|
||||
|
||||
@@ -1,17 +1,13 @@
|
||||
var volume, winner;
|
||||
if (ignition === true) {
|
||||
launch();
|
||||
}
|
||||
if (band !== SpinalTap) {
|
||||
volume = 10;
|
||||
}
|
||||
if (answer !== false) {
|
||||
letTheWildRumpusBegin();
|
||||
}
|
||||
if (car.speed < limit) {
|
||||
accelerate();
|
||||
}
|
||||
if (pick === 47 || pick === 92 || pick === 13) {
|
||||
winner = true;
|
||||
}
|
||||
print(inspect("My name is " + this.name));
|
||||
|
||||
if (ignition === true) launch();
|
||||
|
||||
if (band !== SpinalTap) volume = 10;
|
||||
|
||||
if (answer !== false) letTheWildRumpusBegin();
|
||||
|
||||
if (car.speed < limit) accelerate();
|
||||
|
||||
if (pick === 47 || pick === 92 || pick === 13) winner = true;
|
||||
|
||||
print(inspect("My name is " + this.name));
|
||||
|
||||
@@ -1,6 +1,21 @@
|
||||
var food, _i, _len, _ref;
|
||||
var course, courses, dish, food, foods, _i, _j, _len, _len2, _len3, _ref;
|
||||
|
||||
_ref = ['toast', 'cheese', 'wine'];
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
food = _ref[_i];
|
||||
eat(food);
|
||||
}
|
||||
}
|
||||
|
||||
courses = ['salad', 'entree', 'dessert'];
|
||||
|
||||
for (course = 0, _len2 = courses.length; course < _len2; course++) {
|
||||
dish = courses[course];
|
||||
menu(course + 1, dish);
|
||||
}
|
||||
|
||||
foods = ['broccoli', 'spinach', 'chocolate'];
|
||||
|
||||
for (_j = 0, _len3 = foods.length; _j < _len3; _j++) {
|
||||
food = foods[_j];
|
||||
if (food !== 'chocolate') eat(food);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
|
||||
/*
|
||||
CoffeeScript Compiler v1.1.1
|
||||
CoffeeScript Compiler v1.1.3
|
||||
Released under the MIT License
|
||||
*/
|
||||
*/
|
||||
|
||||
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
var fs;
|
||||
|
||||
fs = require('fs');
|
||||
|
||||
option('-o', '--output [DIR]', 'directory for compiled code');
|
||||
|
||||
task('build:parser', 'rebuild the Jison parser', function(options) {
|
||||
var code, dir;
|
||||
require('jison');
|
||||
code = require('./lib/grammar').parser.generate();
|
||||
dir = options.output || 'lib';
|
||||
return fs.writeFile("" + dir + "/parser.js", code);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,44 +1,58 @@
|
||||
var Animal, Horse, Snake, sam, tom;
|
||||
var __hasProp = Object.prototype.hasOwnProperty, __extends = function(child, parent) {
|
||||
for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; }
|
||||
function ctor() { this.constructor = child; }
|
||||
ctor.prototype = parent.prototype;
|
||||
child.prototype = new ctor;
|
||||
child.__super__ = parent.prototype;
|
||||
return child;
|
||||
};
|
||||
var __hasProp = Object.prototype.hasOwnProperty, __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor; child.__super__ = parent.prototype; return child; };
|
||||
|
||||
Animal = (function() {
|
||||
|
||||
function Animal(name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
Animal.prototype.move = function(meters) {
|
||||
return alert(this.name + " moved " + meters + "m.");
|
||||
return alert(this.name + (" moved " + meters + "m."));
|
||||
};
|
||||
|
||||
return Animal;
|
||||
|
||||
})();
|
||||
|
||||
Snake = (function() {
|
||||
|
||||
__extends(Snake, Animal);
|
||||
|
||||
function Snake() {
|
||||
Snake.__super__.constructor.apply(this, arguments);
|
||||
}
|
||||
|
||||
Snake.prototype.move = function() {
|
||||
alert("Slithering...");
|
||||
return Snake.__super__.move.call(this, 5);
|
||||
};
|
||||
|
||||
return Snake;
|
||||
|
||||
})();
|
||||
|
||||
Horse = (function() {
|
||||
|
||||
__extends(Horse, Animal);
|
||||
|
||||
function Horse() {
|
||||
Horse.__super__.constructor.apply(this, arguments);
|
||||
}
|
||||
|
||||
Horse.prototype.move = function() {
|
||||
alert("Galloping...");
|
||||
return Horse.__super__.move.call(this, 45);
|
||||
};
|
||||
|
||||
return Horse;
|
||||
|
||||
})();
|
||||
|
||||
sam = new Snake("Sammy the Python");
|
||||
|
||||
tom = new Horse("Tommy the Palomino");
|
||||
|
||||
sam.move();
|
||||
tom.move();
|
||||
|
||||
tom.move();
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
var cholesterol, healthy;
|
||||
|
||||
cholesterol = 127;
|
||||
healthy = (200 > cholesterol && cholesterol > 60);
|
||||
|
||||
healthy = (200 > cholesterol && cholesterol > 60);
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
var date, mood;
|
||||
if (singing) {
|
||||
mood = greatlyImproved;
|
||||
}
|
||||
|
||||
if (singing) mood = greatlyImproved;
|
||||
|
||||
if (happy && knowsIt) {
|
||||
clapsHands();
|
||||
chaChaCha();
|
||||
} else {
|
||||
showIt();
|
||||
}
|
||||
|
||||
date = friday ? sue : jill;
|
||||
options || (options = defaults);
|
||||
|
||||
options || (options = defaults);
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
var fill;
|
||||
|
||||
fill = function(container, liquid) {
|
||||
if (liquid == null) {
|
||||
liquid = "coffee";
|
||||
}
|
||||
if (liquid == null) liquid = "coffee";
|
||||
return "Filling the " + container + " with " + liquid + "...";
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
var filename, _fn, _i, _len;
|
||||
|
||||
_fn = function(filename) {
|
||||
return fs.readFile(filename, function(err, contents) {
|
||||
return compile(filename, contents.toString());
|
||||
@@ -7,4 +8,4 @@ _fn = function(filename) {
|
||||
for (_i = 0, _len = list.length; _i < _len; _i++) {
|
||||
filename = list[_i];
|
||||
_fn(filename);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
var hi;
|
||||
|
||||
hi = function() {
|
||||
return [document.title, "Hello JavaScript"].join(": ");
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
var footprints, solipsism;
|
||||
|
||||
if ((typeof mind !== "undefined" && mind !== null) && !(typeof world !== "undefined" && world !== null)) {
|
||||
solipsism = true;
|
||||
}
|
||||
if (typeof speed !== "undefined" && speed !== null) {
|
||||
speed;
|
||||
} else {
|
||||
speed = 75;
|
||||
};
|
||||
footprints = typeof yeti !== "undefined" && yeti !== null ? yeti : "bear";
|
||||
|
||||
if (typeof speed === "undefined" || speed === null) speed = 75;
|
||||
|
||||
footprints = typeof yeti !== "undefined" && yeti !== null ? yeti : "bear";
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
var eldest, grade;
|
||||
|
||||
grade = function(student) {
|
||||
if (student.excellentWork) {
|
||||
return "A+";
|
||||
@@ -12,4 +13,5 @@ grade = function(student) {
|
||||
return "C";
|
||||
}
|
||||
};
|
||||
eldest = 24 > 21 ? "Liz" : "Ike";
|
||||
|
||||
eldest = 24 > 21 ? "Liz" : "Ike";
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
var one, six, three, two;
|
||||
six = (one = 1) + (two = 2) + (three = 3);
|
||||
|
||||
six = (one = 1) + (two = 2) + (three = 3);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
var globals, name;
|
||||
|
||||
globals = ((function() {
|
||||
var _results;
|
||||
_results = [];
|
||||
@@ -6,4 +7,4 @@ globals = ((function() {
|
||||
_results.push(name);
|
||||
}
|
||||
return _results;
|
||||
})()).slice(0, 10);
|
||||
})()).slice(0, 10);
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
|
||||
alert((function() {
|
||||
try {
|
||||
return nonexistent / void 0;
|
||||
} catch (error) {
|
||||
return "And the error is ... " + error;
|
||||
}
|
||||
})());
|
||||
})());
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
var Account;
|
||||
var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
|
||||
|
||||
Account = function(customer, cart) {
|
||||
var _this = this;
|
||||
this.customer = customer;
|
||||
this.cart = cart;
|
||||
return $('.shopping_cart').bind('click', __bind(function(event) {
|
||||
return this.customer.purchase(this.cart);
|
||||
}, this));
|
||||
};
|
||||
return $('.shopping_cart').bind('click', function(event) {
|
||||
return _this.customer.purchase(_this.cart);
|
||||
});
|
||||
};
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
var cube, square;
|
||||
|
||||
square = function(x) {
|
||||
return x * x;
|
||||
};
|
||||
|
||||
cube = function(x) {
|
||||
return square(x) * x;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
var html;
|
||||
html = '<strong>\n cup of coffeescript\n</strong>';
|
||||
|
||||
html = '<strong>\n cup of coffeescript\n</strong>';
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
var OPERATOR;
|
||||
OPERATOR = /^(?:[-=]>|[-+*\/%<>&|^!?=]=|>>>=?|([-+:])\1|([&|<>])\2=?|\?\.|\.{2,3})/;
|
||||
|
||||
OPERATOR = /^(?:[-=]>|[-+*\/%<>&|^!?=]=|>>>=?|([-+:])\1|([&|<>])\2=?|\?\.|\.{2,3})/;
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
var author, quote, sentence;
|
||||
|
||||
author = "Wittgenstein";
|
||||
|
||||
quote = "A picture is a fact. -- " + author;
|
||||
sentence = "" + (22 / 7) + " is a decent approximation of π";
|
||||
|
||||
sentence = "" + (22 / 7) + " is a decent approximation of π";
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
var city, forecast, temp, weatherReport, _ref;
|
||||
|
||||
weatherReport = function(location) {
|
||||
return [location, 72, "Mostly Sunny"];
|
||||
};
|
||||
_ref = weatherReport("Berkeley, CA"), city = _ref[0], temp = _ref[1], forecast = _ref[2];
|
||||
|
||||
_ref = weatherReport("Berkeley, CA"), city = _ref[0], temp = _ref[1], forecast = _ref[2];
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
var age, ages, child, yearsOld;
|
||||
|
||||
yearsOld = {
|
||||
max: 10,
|
||||
ida: 9,
|
||||
tim: 11
|
||||
};
|
||||
|
||||
ages = (function() {
|
||||
var _results;
|
||||
_results = [];
|
||||
for (child in yearsOld) {
|
||||
age = yearsOld[child];
|
||||
_results.push(child + " is " + age);
|
||||
_results.push("" + child + " is " + age);
|
||||
}
|
||||
return _results;
|
||||
})();
|
||||
})();
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
var city, futurists, name, street, _ref, _ref2;
|
||||
|
||||
futurists = {
|
||||
sculptor: "Umberto Boccioni",
|
||||
painter: "Vladimir Burliuk",
|
||||
@@ -7,4 +8,5 @@ futurists = {
|
||||
address: ["Via Roma 42R", "Bellagio, Italy 22021"]
|
||||
}
|
||||
};
|
||||
_ref = futurists.poet, name = _ref.name, _ref2 = _ref.address, street = _ref2[0], city = _ref2[1];
|
||||
|
||||
_ref = futurists.poet, name = _ref.name, (_ref2 = _ref.address, street = _ref2[0], city = _ref2[1]);
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
var bitlist, kids, singers, song;
|
||||
|
||||
song = ["do", "re", "mi", "fa", "so"];
|
||||
|
||||
singers = {
|
||||
Jagger: "Rock",
|
||||
Elvis: "Roll"
|
||||
};
|
||||
|
||||
bitlist = [1, 0, 1, 0, 0, 1, 1, 1, 0];
|
||||
|
||||
kids = {
|
||||
brother: {
|
||||
name: "Max",
|
||||
@@ -14,4 +18,4 @@ kids = {
|
||||
name: "Ida",
|
||||
age: 9
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
|
||||
$('.account').attr({
|
||||
"class": 'active'
|
||||
});
|
||||
log(object["class"]);
|
||||
|
||||
log(object["class"]);
|
||||
|
||||
@@ -1,14 +1,18 @@
|
||||
var cubes, list, math, num, number, opposite, race, square;
|
||||
var __slice = Array.prototype.slice;
|
||||
|
||||
number = 42;
|
||||
|
||||
opposite = true;
|
||||
if (opposite) {
|
||||
number = -42;
|
||||
}
|
||||
|
||||
if (opposite) number = -42;
|
||||
|
||||
square = function(x) {
|
||||
return x * x;
|
||||
};
|
||||
|
||||
list = [1, 2, 3, 4, 5];
|
||||
|
||||
math = {
|
||||
root: Math.sqrt,
|
||||
square: square,
|
||||
@@ -16,14 +20,15 @@ math = {
|
||||
return x * square(x);
|
||||
}
|
||||
};
|
||||
|
||||
race = function() {
|
||||
var runners, winner;
|
||||
winner = arguments[0], runners = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
|
||||
return print(winner, runners);
|
||||
};
|
||||
if (typeof elvis !== "undefined" && elvis !== null) {
|
||||
alert("I knew it!");
|
||||
}
|
||||
|
||||
if (typeof elvis !== "undefined" && elvis !== null) alert("I knew it!");
|
||||
|
||||
cubes = (function() {
|
||||
var _i, _len, _results;
|
||||
_results = [];
|
||||
@@ -32,4 +37,4 @@ cubes = (function() {
|
||||
_results.push(math.cube(num));
|
||||
}
|
||||
return _results;
|
||||
})();
|
||||
})();
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
var theBait, theSwitch, _ref;
|
||||
|
||||
theBait = 1000;
|
||||
|
||||
theSwitch = 0;
|
||||
_ref = [theSwitch, theBait], theBait = _ref[0], theSwitch = _ref[1];
|
||||
|
||||
_ref = [theSwitch, theBait], theBait = _ref[0], theSwitch = _ref[1];
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
var close, contents, open, tag, _i, _ref;
|
||||
var __slice = Array.prototype.slice;
|
||||
|
||||
tag = "<impossible>";
|
||||
_ref = tag.split(""), open = _ref[0], contents = 3 <= _ref.length ? __slice.call(_ref, 1, _i = _ref.length - 1) : (_i = 1, []), close = _ref[_i++];
|
||||
|
||||
_ref = tag.split(""), open = _ref[0], contents = 3 <= _ref.length ? __slice.call(_ref, 1, _i = _ref.length - 1) : (_i = 1, []), close = _ref[_i++];
|
||||
|
||||
3
documentation/js/prototypes.js
vendored
3
documentation/js/prototypes.js
vendored
@@ -1,3 +1,4 @@
|
||||
|
||||
String.prototype.dasherize = function() {
|
||||
return this.replace(/_/g, "-");
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
var countdown, num;
|
||||
|
||||
countdown = (function() {
|
||||
var _results;
|
||||
_results = [];
|
||||
@@ -6,4 +7,4 @@ countdown = (function() {
|
||||
_results.push(num);
|
||||
}
|
||||
return _results;
|
||||
})();
|
||||
})();
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
var changeNumbers, inner, outer;
|
||||
|
||||
outer = 1;
|
||||
|
||||
changeNumbers = function() {
|
||||
var inner;
|
||||
inner = -1;
|
||||
return outer = 10;
|
||||
};
|
||||
inner = changeNumbers();
|
||||
|
||||
inner = changeNumbers();
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
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);
|
||||
|
||||
middle = copy.slice(3, 7);
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
var zip, _ref;
|
||||
zip = typeof lottery.drawWinner === "function" ? (_ref = lottery.drawWinner().address) != null ? _ref.zipcode : void 0 : void 0;
|
||||
|
||||
zip = typeof lottery.drawWinner === "function" ? (_ref = lottery.drawWinner().address) != null ? _ref.zipcode : void 0 : void 0;
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
var awardMedals, contenders, gold, rest, silver;
|
||||
var __slice = Array.prototype.slice;
|
||||
|
||||
gold = silver = rest = "unknown";
|
||||
|
||||
awardMedals = function() {
|
||||
var first, others, second;
|
||||
first = arguments[0], second = arguments[1], others = 3 <= arguments.length ? __slice.call(arguments, 2) : [];
|
||||
@@ -8,8 +10,13 @@ awardMedals = function() {
|
||||
silver = second;
|
||||
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(null, contenders);
|
||||
|
||||
alert("Gold: " + gold);
|
||||
|
||||
alert("Silver: " + silver);
|
||||
alert("The Field: " + rest);
|
||||
|
||||
alert("The Field: " + rest);
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
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;
|
||||
|
||||
[].splice.apply(numbers, [3, 4].concat(_ref = [-3, -4, -5, -6])), _ref;
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
var mobyDick;
|
||||
mobyDick = "Call me Ishmael. Some years ago -- never mind how long precisely -- having little or no money in my purse, and nothing particular to interest me on shore, I thought I would sail about a little and see the watery part of the world...";
|
||||
|
||||
mobyDick = "Call me Ishmael. Some years ago -- never mind how long precisely -- having little or no money in my purse, and nothing particular to interest me on shore, I thought I would sail about a little and see the watery part of the world...";
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
switch (day) {
|
||||
case "Mon":
|
||||
go(work);
|
||||
@@ -20,4 +21,4 @@ switch (day) {
|
||||
break;
|
||||
default:
|
||||
go(work);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
try {
|
||||
allHellBreaksLoose();
|
||||
catsAndDogsLivingTogether();
|
||||
@@ -5,4 +6,4 @@ try {
|
||||
print(error);
|
||||
} finally {
|
||||
cleanUp();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
var lyrics, num;
|
||||
|
||||
if (this.studyingEconomics) {
|
||||
while (supply > demand) {
|
||||
buy();
|
||||
@@ -7,12 +8,14 @@ if (this.studyingEconomics) {
|
||||
sell();
|
||||
}
|
||||
}
|
||||
|
||||
num = 6;
|
||||
|
||||
lyrics = (function() {
|
||||
var _results;
|
||||
_results = [];
|
||||
while (num -= 1) {
|
||||
_results.push(num + " little monkeys, jumping on the bed. One fell out and bumped his head.");
|
||||
_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
6240
documentation/vendor/jquery-1.4.2.js
vendored
File diff suppressed because it is too large
Load Diff
9046
documentation/vendor/jquery-1.6.4.js
vendored
Normal file
9046
documentation/vendor/jquery-1.6.4.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
@@ -9,7 +9,7 @@ selection_sort = (list) ->
|
||||
min = i
|
||||
|
||||
# Check the rest of the array to see if anything is smaller.
|
||||
min = j if list[j] < list[min] for j in [i + 1...len]
|
||||
min = k for v, k in list[i+1...] when v < list[min]
|
||||
|
||||
# Swap if a smaller item has been found.
|
||||
[list[i], list[min]] = [list[min], list[i]] if i isnt min
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
EXTRAS:
|
||||
|
||||
"extras/coffee-script.js" is a concatenated and compressed version of the
|
||||
CoffeeScript compiler. To use it in the browser, include the script after any
|
||||
inline script tags of type "text/coffeescript" on the page. It will compile
|
||||
and evaluate all of the scripts in order.
|
||||
|
||||
File diff suppressed because one or more lines are too long
658
index.html
658
index.html
File diff suppressed because it is too large
Load Diff
@@ -1,107 +0,0 @@
|
||||
(function() {
|
||||
var Lexer, RESERVED, compile, fs, lexer, parser, path, vm, _ref;
|
||||
fs = require('fs');
|
||||
path = require('path');
|
||||
vm = require('vm');
|
||||
_ref = require('./lexer'), Lexer = _ref.Lexer, RESERVED = _ref.RESERVED;
|
||||
parser = require('./parser').parser;
|
||||
if (require.extensions) {
|
||||
require.extensions['.coffee'] = function(module, filename) {
|
||||
var content;
|
||||
content = compile(fs.readFileSync(filename, 'utf8'), {
|
||||
filename: filename
|
||||
});
|
||||
return module._compile(content, filename);
|
||||
};
|
||||
} else if (require.registerExtension) {
|
||||
require.registerExtension('.coffee', function(content) {
|
||||
return compile(content);
|
||||
});
|
||||
}
|
||||
exports.VERSION = '1.1.1';
|
||||
exports.RESERVED = RESERVED;
|
||||
exports.helpers = require('./helpers');
|
||||
exports.compile = compile = function(code, options) {
|
||||
if (options == null) {
|
||||
options = {};
|
||||
}
|
||||
try {
|
||||
return (parser.parse(lexer.tokenize(code))).compile(options);
|
||||
} catch (err) {
|
||||
if (options.filename) {
|
||||
err.message = "In " + options.filename + ", " + err.message;
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
};
|
||||
exports.tokens = function(code, options) {
|
||||
return lexer.tokenize(code, options);
|
||||
};
|
||||
exports.nodes = function(source, options) {
|
||||
if (typeof source === 'string') {
|
||||
return parser.parse(lexer.tokenize(source, options));
|
||||
} else {
|
||||
return parser.parse(source);
|
||||
}
|
||||
};
|
||||
exports.run = function(code, options) {
|
||||
var Module, root;
|
||||
root = module;
|
||||
while (root.parent) {
|
||||
root = root.parent;
|
||||
}
|
||||
root.filename = process.argv[1] = options.filename ? fs.realpathSync(options.filename) : '.';
|
||||
if (root.moduleCache) {
|
||||
root.moduleCache = {};
|
||||
}
|
||||
if (process.binding('natives').module) {
|
||||
Module = require('module').Module;
|
||||
root.paths = Module._nodeModulePaths(path.dirname(options.filename));
|
||||
}
|
||||
if (path.extname(root.filename) !== '.coffee' || require.extensions) {
|
||||
return root._compile(compile(code, options), root.filename);
|
||||
} else {
|
||||
return root._compile(code, root.filename);
|
||||
}
|
||||
};
|
||||
exports.eval = function(code, options) {
|
||||
var g, js, sandbox;
|
||||
if (options == null) {
|
||||
options = {};
|
||||
}
|
||||
sandbox = options.sandbox;
|
||||
if (!sandbox) {
|
||||
sandbox = {
|
||||
require: require,
|
||||
module: {
|
||||
exports: {}
|
||||
}
|
||||
};
|
||||
for (g in global) {
|
||||
sandbox[g] = global[g];
|
||||
}
|
||||
sandbox.global = sandbox;
|
||||
sandbox.global.global = sandbox.global.root = sandbox.global.GLOBAL = sandbox;
|
||||
}
|
||||
sandbox.__filename = options.filename || 'eval';
|
||||
sandbox.__dirname = path.dirname(sandbox.__filename);
|
||||
js = compile("_=(" + (code.trim()) + ")", options);
|
||||
return vm.runInNewContext(js, sandbox, sandbox.__filename);
|
||||
};
|
||||
lexer = new Lexer;
|
||||
parser.lexer = {
|
||||
lex: function() {
|
||||
var tag, _ref2;
|
||||
_ref2 = this.tokens[this.pos++] || [''], tag = _ref2[0], this.yytext = _ref2[1], this.yylineno = _ref2[2];
|
||||
return tag;
|
||||
},
|
||||
setInput: function(tokens) {
|
||||
this.tokens = tokens;
|
||||
return this.pos = 0;
|
||||
},
|
||||
upcomingInput: function() {
|
||||
return "";
|
||||
}
|
||||
};
|
||||
parser.yy = require('./nodes');
|
||||
}).call(this);
|
||||
@@ -1,27 +1,27 @@
|
||||
(function() {
|
||||
var CoffeeScript, runScripts;
|
||||
|
||||
CoffeeScript = require('./coffee-script');
|
||||
|
||||
CoffeeScript.require = require;
|
||||
|
||||
CoffeeScript.eval = function(code, options) {
|
||||
return eval(CoffeeScript.compile(code, options));
|
||||
};
|
||||
|
||||
CoffeeScript.run = function(code, options) {
|
||||
if (options == null) {
|
||||
options = {};
|
||||
}
|
||||
if (options == null) options = {};
|
||||
options.bare = true;
|
||||
return Function(CoffeeScript.compile(code, options))();
|
||||
};
|
||||
if (typeof window === "undefined" || window === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (typeof window === "undefined" || window === null) return;
|
||||
|
||||
CoffeeScript.load = function(url, callback) {
|
||||
var xhr;
|
||||
xhr = new (window.ActiveXObject || XMLHttpRequest)('Microsoft.XMLHTTP');
|
||||
xhr.open('GET', url, true);
|
||||
if ('overrideMimeType' in xhr) {
|
||||
xhr.overrideMimeType('text/plain');
|
||||
}
|
||||
if ('overrideMimeType' in xhr) xhr.overrideMimeType('text/plain');
|
||||
xhr.onreadystatechange = function() {
|
||||
var _ref;
|
||||
if (xhr.readyState === 4) {
|
||||
@@ -30,13 +30,12 @@
|
||||
} else {
|
||||
throw new Error("Could not load " + url);
|
||||
}
|
||||
if (callback) {
|
||||
return callback();
|
||||
}
|
||||
if (callback) return callback();
|
||||
}
|
||||
};
|
||||
return xhr.send(null);
|
||||
};
|
||||
|
||||
runScripts = function() {
|
||||
var coffees, execute, index, length, s, scripts;
|
||||
scripts = document.getElementsByTagName('script');
|
||||
@@ -45,9 +44,7 @@
|
||||
_results = [];
|
||||
for (_i = 0, _len = scripts.length; _i < _len; _i++) {
|
||||
s = scripts[_i];
|
||||
if (s.type === 'text/coffeescript') {
|
||||
_results.push(s);
|
||||
}
|
||||
if (s.type === 'text/coffeescript') _results.push(s);
|
||||
}
|
||||
return _results;
|
||||
})();
|
||||
@@ -67,9 +64,11 @@
|
||||
})();
|
||||
return null;
|
||||
};
|
||||
|
||||
if (window.addEventListener) {
|
||||
addEventListener('DOMContentLoaded', runScripts, false);
|
||||
} else {
|
||||
attachEvent('onload', runScripts);
|
||||
}
|
||||
|
||||
}).call(this);
|
||||
69
lib/cake.js → lib/coffee-script/cake.js
Executable file → Normal file
69
lib/cake.js → lib/coffee-script/cake.js
Executable file → Normal file
@@ -1,14 +1,24 @@
|
||||
(function() {
|
||||
var CoffeeScript, fs, helpers, missingTask, oparse, options, optparse, path, printTasks, switches, tasks;
|
||||
var CoffeeScript, cakefileDirectory, fs, helpers, missingTask, oparse, options, optparse, path, printTasks, switches, tasks;
|
||||
|
||||
fs = require('fs');
|
||||
|
||||
path = require('path');
|
||||
|
||||
helpers = require('./helpers');
|
||||
|
||||
optparse = require('./optparse');
|
||||
|
||||
CoffeeScript = require('./coffee-script');
|
||||
|
||||
tasks = {};
|
||||
|
||||
options = {};
|
||||
|
||||
switches = [];
|
||||
|
||||
oparse = null;
|
||||
|
||||
helpers.extend(global, {
|
||||
task: function(name, description, action) {
|
||||
var _ref;
|
||||
@@ -25,36 +35,31 @@
|
||||
return switches.push([letter, flag, description]);
|
||||
},
|
||||
invoke: function(name) {
|
||||
if (!tasks[name]) {
|
||||
missingTask(name);
|
||||
}
|
||||
if (!tasks[name]) missingTask(name);
|
||||
return tasks[name].action(options);
|
||||
}
|
||||
});
|
||||
|
||||
exports.run = function() {
|
||||
return path.exists('Cakefile', function(exists) {
|
||||
var arg, args, _i, _len, _ref, _results;
|
||||
if (!exists) {
|
||||
throw new Error("Cakefile not found in " + (process.cwd()));
|
||||
}
|
||||
args = process.argv.slice(2);
|
||||
CoffeeScript.run(fs.readFileSync('Cakefile').toString(), {
|
||||
filename: 'Cakefile'
|
||||
});
|
||||
oparse = new optparse.OptionParser(switches);
|
||||
if (!args.length) {
|
||||
return printTasks();
|
||||
}
|
||||
options = oparse.parse(args);
|
||||
_ref = options.arguments;
|
||||
_results = [];
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
arg = _ref[_i];
|
||||
_results.push(invoke(arg));
|
||||
}
|
||||
return _results;
|
||||
var arg, args, _i, _len, _ref, _results;
|
||||
global.__originalDirname = fs.realpathSync('.');
|
||||
process.chdir(cakefileDirectory(__originalDirname));
|
||||
args = process.argv.slice(2);
|
||||
CoffeeScript.run(fs.readFileSync('Cakefile').toString(), {
|
||||
filename: 'Cakefile'
|
||||
});
|
||||
oparse = new optparse.OptionParser(switches);
|
||||
if (!args.length) return printTasks();
|
||||
options = oparse.parse(args);
|
||||
_ref = options.arguments;
|
||||
_results = [];
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
arg = _ref[_i];
|
||||
_results.push(invoke(arg));
|
||||
}
|
||||
return _results;
|
||||
};
|
||||
|
||||
printTasks = function() {
|
||||
var desc, name, spaces, task;
|
||||
console.log('');
|
||||
@@ -65,12 +70,20 @@
|
||||
desc = task.description ? "# " + task.description : '';
|
||||
console.log("cake " + name + spaces + " " + desc);
|
||||
}
|
||||
if (switches.length) {
|
||||
return console.log(oparse.help());
|
||||
}
|
||||
if (switches.length) return console.log(oparse.help());
|
||||
};
|
||||
|
||||
missingTask = function(task) {
|
||||
console.log("No such task: \"" + task + "\"");
|
||||
return process.exit(1);
|
||||
};
|
||||
|
||||
cakefileDirectory = function(dir) {
|
||||
var parent;
|
||||
if (path.existsSync(path.join(dir, 'Cakefile'))) return dir;
|
||||
parent = path.normalize(path.join(dir, '..'));
|
||||
if (parent !== dir) return cakefileDirectory(parent);
|
||||
throw new Error("Cakefile not found in " + (process.cwd()));
|
||||
};
|
||||
|
||||
}).call(this);
|
||||
148
lib/coffee-script/coffee-script.js
Normal file
148
lib/coffee-script/coffee-script.js
Normal file
@@ -0,0 +1,148 @@
|
||||
(function() {
|
||||
var Lexer, RESERVED, compile, fs, lexer, parser, path, vm, _ref;
|
||||
var __hasProp = Object.prototype.hasOwnProperty;
|
||||
|
||||
fs = require('fs');
|
||||
|
||||
path = require('path');
|
||||
|
||||
_ref = require('./lexer'), Lexer = _ref.Lexer, RESERVED = _ref.RESERVED;
|
||||
|
||||
parser = require('./parser').parser;
|
||||
|
||||
vm = require('vm');
|
||||
|
||||
if (require.extensions) {
|
||||
require.extensions['.coffee'] = function(module, filename) {
|
||||
var content;
|
||||
content = compile(fs.readFileSync(filename, 'utf8'), {
|
||||
filename: filename
|
||||
});
|
||||
return module._compile(content, filename);
|
||||
};
|
||||
} else if (require.registerExtension) {
|
||||
require.registerExtension('.coffee', function(content) {
|
||||
return compile(content);
|
||||
});
|
||||
}
|
||||
|
||||
exports.VERSION = '1.1.3';
|
||||
|
||||
exports.RESERVED = RESERVED;
|
||||
|
||||
exports.helpers = require('./helpers');
|
||||
|
||||
exports.compile = compile = function(code, options) {
|
||||
if (options == null) options = {};
|
||||
try {
|
||||
return (parser.parse(lexer.tokenize(code))).compile(options);
|
||||
} catch (err) {
|
||||
if (options.filename) {
|
||||
err.message = "In " + options.filename + ", " + err.message;
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
};
|
||||
|
||||
exports.tokens = function(code, options) {
|
||||
return lexer.tokenize(code, options);
|
||||
};
|
||||
|
||||
exports.nodes = function(source, options) {
|
||||
if (typeof source === 'string') {
|
||||
return parser.parse(lexer.tokenize(source, options));
|
||||
} else {
|
||||
return parser.parse(source);
|
||||
}
|
||||
};
|
||||
|
||||
exports.run = function(code, options) {
|
||||
var mainModule;
|
||||
mainModule = require.main;
|
||||
mainModule.filename = process.argv[1] = options.filename ? fs.realpathSync(options.filename) : '.';
|
||||
mainModule.moduleCache && (mainModule.moduleCache = {});
|
||||
mainModule.paths = require('module')._nodeModulePaths(path.dirname(options.filename));
|
||||
if (path.extname(mainModule.filename) !== '.coffee' || require.extensions) {
|
||||
return mainModule._compile(compile(code, options), mainModule.filename);
|
||||
} else {
|
||||
return mainModule._compile(code, mainModule.filename);
|
||||
}
|
||||
};
|
||||
|
||||
exports.eval = function(code, options) {
|
||||
var Module, Script, js, k, o, r, sandbox, v, _i, _len, _module, _ref2, _ref3, _require;
|
||||
if (options == null) options = {};
|
||||
if (!(code = code.trim())) return;
|
||||
Script = vm.Script;
|
||||
if (Script) {
|
||||
if (options.sandbox != null) {
|
||||
if (options.sandbox instanceof Script.createContext().constructor) {
|
||||
sandbox = options.sandbox;
|
||||
} else {
|
||||
sandbox = Script.createContext();
|
||||
_ref2 = options.sandbox;
|
||||
for (k in _ref2) {
|
||||
if (!__hasProp.call(_ref2, k)) continue;
|
||||
v = _ref2[k];
|
||||
sandbox[k] = v;
|
||||
}
|
||||
}
|
||||
sandbox.global = sandbox.root = sandbox.GLOBAL = sandbox;
|
||||
} else {
|
||||
sandbox = global;
|
||||
}
|
||||
sandbox.__filename = options.filename || 'eval';
|
||||
sandbox.__dirname = path.dirname(sandbox.__filename);
|
||||
if (!(sandbox !== global || sandbox.module || sandbox.require)) {
|
||||
Module = require('module');
|
||||
sandbox.module = _module = new Module(options.modulename || 'eval');
|
||||
sandbox.require = _require = function(path) {
|
||||
return Module._load(path, _module, true);
|
||||
};
|
||||
_module.filename = sandbox.__filename;
|
||||
_ref3 = Object.getOwnPropertyNames(require);
|
||||
for (_i = 0, _len = _ref3.length; _i < _len; _i++) {
|
||||
r = _ref3[_i];
|
||||
if (r !== 'paths') _require[r] = require[r];
|
||||
}
|
||||
_require.paths = _module.paths = Module._nodeModulePaths(process.cwd());
|
||||
_require.resolve = function(request) {
|
||||
return Module._resolveFilename(request, _module);
|
||||
};
|
||||
}
|
||||
}
|
||||
o = {};
|
||||
for (k in options) {
|
||||
if (!__hasProp.call(options, k)) continue;
|
||||
v = options[k];
|
||||
o[k] = v;
|
||||
}
|
||||
o.bare = true;
|
||||
js = compile(code, o);
|
||||
if (sandbox === global) {
|
||||
return vm.runInThisContext(js);
|
||||
} else {
|
||||
return vm.runInContext(js, sandbox);
|
||||
}
|
||||
};
|
||||
|
||||
lexer = new Lexer;
|
||||
|
||||
parser.lexer = {
|
||||
lex: function() {
|
||||
var tag, _ref2;
|
||||
_ref2 = this.tokens[this.pos++] || [''], tag = _ref2[0], this.yytext = _ref2[1], this.yylineno = _ref2[2];
|
||||
return tag;
|
||||
},
|
||||
setInput: function(tokens) {
|
||||
this.tokens = tokens;
|
||||
return this.pos = 0;
|
||||
},
|
||||
upcomingInput: function() {
|
||||
return "";
|
||||
}
|
||||
};
|
||||
|
||||
parser.yy = require('./nodes');
|
||||
|
||||
}).call(this);
|
||||
@@ -1,106 +1,133 @@
|
||||
(function() {
|
||||
var BANNER, CoffeeScript, EventEmitter, SWITCHES, compileJoin, compileOptions, compileScript, compileScripts, compileStdio, contents, exec, forkNode, fs, helpers, lint, loadRequires, optionParser, optparse, opts, parseOptions, path, printLine, printTokens, printWarn, sources, spawn, usage, version, watch, writeJs, _ref;
|
||||
|
||||
fs = require('fs');
|
||||
|
||||
path = require('path');
|
||||
|
||||
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');
|
||||
return process.stderr.write(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'], ['-j', '--join [FILE]', '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 JavaScript Lint'], ['-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']];
|
||||
|
||||
BANNER = 'Usage: coffee [options] path/to/script.coffee\n\nIf called without options, `coffee` will run your script.';
|
||||
|
||||
SWITCHES = [['-b', '--bare', 'compile without a top-level function wrapper'], ['-c', '--compile', 'compile to JavaScript and save as .js files'], ['-e', '--eval', 'pass a string from the command line as input'], ['-h', '--help', 'display this help message'], ['-i', '--interactive', 'run an interactive CoffeeScript REPL'], ['-j', '--join [FILE]', 'concatenate the source CoffeeScript before compiling'], ['-l', '--lint', 'pipe the compiled JavaScript through JavaScript Lint'], ['-n', '--nodes', 'print out the parse tree that the parser produces'], ['--nodejs [ARGS]', 'pass options directly to the "node" binary'], ['-o', '--output [DIR]', 'set the output directory for compiled JavaScript'], ['-p', '--print', 'print out the compiled JavaScript'], ['-r', '--require [FILE*]', 'require a library before executing your script'], ['-s', '--stdio', 'listen for and compile scripts over stdio'], ['-t', '--tokens', 'print out the tokens that the lexer/rewriter produce'], ['-v', '--version', 'display the version number'], ['-w', '--watch', 'watch scripts for changes and rerun commands']];
|
||||
|
||||
opts = {};
|
||||
|
||||
sources = [];
|
||||
|
||||
contents = [];
|
||||
|
||||
optionParser = null;
|
||||
|
||||
exports.run = function() {
|
||||
parseOptions();
|
||||
if (opts.nodejs) {
|
||||
return forkNode();
|
||||
}
|
||||
if (opts.help) {
|
||||
return usage();
|
||||
}
|
||||
if (opts.version) {
|
||||
return version();
|
||||
}
|
||||
if (opts.require) {
|
||||
loadRequires();
|
||||
}
|
||||
if (opts.interactive) {
|
||||
return require('./repl');
|
||||
}
|
||||
if (opts.stdio) {
|
||||
return compileStdio();
|
||||
}
|
||||
if (opts.eval) {
|
||||
return compileScript(null, sources[0]);
|
||||
}
|
||||
if (!sources.length) {
|
||||
return require('./repl');
|
||||
}
|
||||
if (opts.run) {
|
||||
opts.literals = sources.splice(1).concat(opts.literals);
|
||||
}
|
||||
process.ARGV = process.argv = process.argv.slice(0, 2).concat(opts.literals);
|
||||
if (opts.nodejs) return forkNode();
|
||||
if (opts.help) return usage();
|
||||
if (opts.version) return version();
|
||||
if (opts.require) loadRequires();
|
||||
if (opts.interactive) return require('./repl');
|
||||
if (opts.stdio) return compileStdio();
|
||||
if (opts.eval) return compileScript(null, sources[0]);
|
||||
if (!sources.length) return require('./repl');
|
||||
if (opts.run) opts.literals = sources.splice(1).concat(opts.literals);
|
||||
process.argv = process.argv.slice(0, 2).concat(opts.literals);
|
||||
process.argv[0] = 'coffee';
|
||||
process.execPath = require.main.filename;
|
||||
return compileScripts();
|
||||
};
|
||||
|
||||
compileScripts = function() {
|
||||
var base, compile, source, _i, _len, _results;
|
||||
_results = [];
|
||||
var base, compile, remaining_files, source, trackCompleteFiles, trackUnprocessedFiles, unprocessed, _i, _j, _len, _len2, _results;
|
||||
unprocessed = [];
|
||||
remaining_files = function() {
|
||||
var total, x, _i, _len;
|
||||
total = 0;
|
||||
for (_i = 0, _len = unprocessed.length; _i < _len; _i++) {
|
||||
x = unprocessed[_i];
|
||||
total += x;
|
||||
}
|
||||
return total;
|
||||
};
|
||||
trackUnprocessedFiles = function(sourceIndex, fileCount) {
|
||||
var _ref2;
|
||||
if ((_ref2 = unprocessed[sourceIndex]) == null) unprocessed[sourceIndex] = 0;
|
||||
return unprocessed[sourceIndex] += fileCount;
|
||||
};
|
||||
trackCompleteFiles = function(sourceIndex, fileCount) {
|
||||
unprocessed[sourceIndex] -= fileCount;
|
||||
if (opts.join) {
|
||||
if (helpers.compact(contents).length > 0 && remaining_files() === 0) {
|
||||
return compileJoin();
|
||||
}
|
||||
}
|
||||
};
|
||||
for (_i = 0, _len = sources.length; _i < _len; _i++) {
|
||||
source = sources[_i];
|
||||
trackUnprocessedFiles(sources.indexOf(source), 1);
|
||||
}
|
||||
_results = [];
|
||||
for (_j = 0, _len2 = sources.length; _j < _len2; _j++) {
|
||||
source = sources[_j];
|
||||
base = path.join(source);
|
||||
compile = function(source, topLevel) {
|
||||
compile = function(source, sourceIndex, topLevel) {
|
||||
return path.exists(source, function(exists) {
|
||||
if (topLevel && !exists) {
|
||||
throw new Error("File not found: " + source);
|
||||
if (topLevel && !exists && source.slice(-7) !== '.coffee') {
|
||||
return compile("" + source + ".coffee", sourceIndex, topLevel);
|
||||
}
|
||||
if (topLevel && !exists) throw new Error("File not found: " + source);
|
||||
return fs.stat(source, function(err, stats) {
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
if (err) throw err;
|
||||
if (stats.isDirectory()) {
|
||||
return fs.readdir(source, function(err, files) {
|
||||
var file, _j, _len2, _results2;
|
||||
_results2 = [];
|
||||
for (_j = 0, _len2 = files.length; _j < _len2; _j++) {
|
||||
file = files[_j];
|
||||
_results2.push(compile(path.join(source, file)));
|
||||
var file, _k, _len3;
|
||||
if (err) throw err;
|
||||
trackUnprocessedFiles(sourceIndex, files.length);
|
||||
for (_k = 0, _len3 = files.length; _k < _len3; _k++) {
|
||||
file = files[_k];
|
||||
compile(path.join(source, file), sourceIndex);
|
||||
}
|
||||
return _results2;
|
||||
return trackCompleteFiles(sourceIndex, 1);
|
||||
});
|
||||
} else if (topLevel || path.extname(source) === '.coffee') {
|
||||
fs.readFile(source, function(err, code) {
|
||||
if (err) throw err;
|
||||
if (opts.join) {
|
||||
contents[sources.indexOf(source)] = code.toString();
|
||||
if (helpers.compact(contents).length > 0) {
|
||||
return compileJoin();
|
||||
}
|
||||
contents[sourceIndex] = helpers.compact([contents[sourceIndex], code.toString()]).join('\n');
|
||||
} else {
|
||||
return compileScript(source, code.toString(), base);
|
||||
compileScript(source, code.toString(), base);
|
||||
}
|
||||
return trackCompleteFiles(sourceIndex, 1);
|
||||
});
|
||||
if (opts.watch && !opts.join) {
|
||||
return watch(source, base);
|
||||
}
|
||||
if (opts.watch && !opts.join) return watch(source, base);
|
||||
} else {
|
||||
return trackCompleteFiles(sourceIndex, 1);
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
_results.push(compile(source, true));
|
||||
_results.push(compile(source, sources.indexOf(source), true));
|
||||
}
|
||||
return _results;
|
||||
};
|
||||
|
||||
compileScript = function(file, input, base) {
|
||||
var o, options, t, task;
|
||||
o = opts;
|
||||
@@ -131,34 +158,31 @@
|
||||
}
|
||||
} catch (err) {
|
||||
CoffeeScript.emit('failure', err, task);
|
||||
if (CoffeeScript.listeners('failure').length) {
|
||||
return;
|
||||
}
|
||||
if (o.watch) {
|
||||
return printLine(err.message);
|
||||
}
|
||||
printWarn(err.stack);
|
||||
if (CoffeeScript.listeners('failure').length) return;
|
||||
if (o.watch) return printLine(err.message);
|
||||
printWarn(err instanceof Error && err.stack || ("ERROR: " + err));
|
||||
return process.exit(1);
|
||||
}
|
||||
};
|
||||
|
||||
compileStdio = function() {
|
||||
var code, stdin;
|
||||
code = '';
|
||||
stdin = process.openStdin();
|
||||
stdin.on('data', function(buffer) {
|
||||
if (buffer) {
|
||||
return code += buffer.toString();
|
||||
}
|
||||
if (buffer) return code += buffer.toString();
|
||||
});
|
||||
return stdin.on('end', function() {
|
||||
return compileScript(null, code);
|
||||
});
|
||||
};
|
||||
|
||||
compileJoin = function() {
|
||||
var code;
|
||||
code = contents.join('\n');
|
||||
return compileScript(opts.join, code, opts.join);
|
||||
};
|
||||
|
||||
loadRequires = function() {
|
||||
var realFilename, req, _i, _len, _ref2;
|
||||
realFilename = module.filename;
|
||||
@@ -170,22 +194,28 @@
|
||||
}
|
||||
return module.filename = realFilename;
|
||||
};
|
||||
|
||||
watch = function(source, base) {
|
||||
return fs.watchFile(source, {
|
||||
persistent: true,
|
||||
interval: 500
|
||||
}, function(curr, prev) {
|
||||
if (curr.size === prev.size && curr.mtime.getTime() === prev.mtime.getTime()) {
|
||||
return;
|
||||
}
|
||||
return fs.readFile(source, function(err, code) {
|
||||
if (err) {
|
||||
throw err;
|
||||
return fs.stat(source, function(err, prevStats) {
|
||||
if (err) throw err;
|
||||
return fs.watch(source, function(event) {
|
||||
if (event === 'change') {
|
||||
return fs.stat(source, function(err, stats) {
|
||||
if (err) throw err;
|
||||
if (stats.size === prevStats.size && stats.mtime.getTime() === prevStats.mtime.getTime()) {
|
||||
return;
|
||||
}
|
||||
prevStats = stats;
|
||||
return fs.readFile(source, function(err, code) {
|
||||
if (err) throw err;
|
||||
return compileScript(source, code.toString(), base);
|
||||
});
|
||||
});
|
||||
}
|
||||
return compileScript(source, code.toString(), base);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
writeJs = function(source, js, base) {
|
||||
var baseDir, compile, dir, filename, jsPath, srcDir;
|
||||
filename = path.basename(source, path.extname(source)) + '.js';
|
||||
@@ -194,9 +224,7 @@
|
||||
dir = opts.output ? path.join(opts.output, baseDir) : srcDir;
|
||||
jsPath = path.join(dir, filename);
|
||||
compile = function() {
|
||||
if (js.length <= 0) {
|
||||
js = ' ';
|
||||
}
|
||||
if (js.length <= 0) js = ' ';
|
||||
return fs.writeFile(jsPath, js, function(err) {
|
||||
if (err) {
|
||||
return printLine(err.message);
|
||||
@@ -213,18 +241,20 @@
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
lint = function(file, js) {
|
||||
var conf, jsl, printIt;
|
||||
printIt = function(buffer) {
|
||||
return printLine(file + ':\t' + buffer.toString().trim());
|
||||
};
|
||||
conf = __dirname + '/../extras/jsl.conf';
|
||||
conf = __dirname + '/../../extras/jsl.conf';
|
||||
jsl = spawn('jsl', ['-nologo', '-stdin', '-conf', conf]);
|
||||
jsl.stdout.on('data', printIt);
|
||||
jsl.stderr.on('data', printIt);
|
||||
jsl.stdin.write(js);
|
||||
return jsl.stdin.end();
|
||||
};
|
||||
|
||||
printTokens = function(tokens) {
|
||||
var strings, tag, token, value;
|
||||
strings = (function() {
|
||||
@@ -239,6 +269,7 @@
|
||||
})();
|
||||
return printLine(strings.join(' '));
|
||||
};
|
||||
|
||||
parseOptions = function() {
|
||||
var o;
|
||||
optionParser = new optparse.OptionParser(SWITCHES, BANNER);
|
||||
@@ -248,12 +279,14 @@
|
||||
o.print = !!(o.print || (o.eval || o.stdio && o.compile));
|
||||
return sources = o.arguments;
|
||||
};
|
||||
|
||||
compileOptions = function(filename) {
|
||||
return {
|
||||
filename: filename,
|
||||
bare: opts.bare
|
||||
};
|
||||
};
|
||||
|
||||
forkNode = function() {
|
||||
var args, nodeArgs;
|
||||
nodeArgs = opts.nodejs.split(/\s+/);
|
||||
@@ -265,10 +298,13 @@
|
||||
customFds: [0, 1, 2]
|
||||
});
|
||||
};
|
||||
|
||||
usage = function() {
|
||||
return printLine((new optparse.OptionParser(SWITCHES, BANNER)).help());
|
||||
};
|
||||
|
||||
version = function() {
|
||||
return printLine("CoffeeScript version " + CoffeeScript.VERSION);
|
||||
};
|
||||
|
||||
}).call(this);
|
||||
@@ -1,18 +1,20 @@
|
||||
(function() {
|
||||
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) {
|
||||
var match;
|
||||
patternString = patternString.replace(/\s{2,}/g, ' ');
|
||||
if (!action) {
|
||||
return [patternString, '$$ = $1;', options];
|
||||
}
|
||||
if (!action) return [patternString, '$$ = $1;', options];
|
||||
action = (match = unwrap.exec(action)) ? match[1] : "(" + action + "())";
|
||||
action = action.replace(/\bnew /g, '$&yy.');
|
||||
action = action.replace(/\b(?:Block\.wrap|extend)\b/g, 'yy.$&');
|
||||
return [patternString, "$$ = " + action + ";", options];
|
||||
};
|
||||
|
||||
grammar = {
|
||||
Root: [
|
||||
o('', function() {
|
||||
@@ -60,9 +62,7 @@
|
||||
}), o('BOOL', function() {
|
||||
var val;
|
||||
val = new Literal($1);
|
||||
if ($1 === 'undefined') {
|
||||
val.isUndefined = true;
|
||||
}
|
||||
if ($1 === 'undefined') val.isUndefined = true;
|
||||
return val;
|
||||
})
|
||||
],
|
||||
@@ -139,7 +139,7 @@
|
||||
o('Identifier', function() {
|
||||
return new Value($1);
|
||||
}), o('Value Accessor', function() {
|
||||
return $1.push($2);
|
||||
return $1.add($2);
|
||||
}), o('Invocation Accessor', function() {
|
||||
return new Value($1, [$2]);
|
||||
}), o('ThisProperty')
|
||||
@@ -166,7 +166,7 @@
|
||||
}), o('?. Identifier', function() {
|
||||
return new Access($2, 'soak');
|
||||
}), o(':: Identifier', function() {
|
||||
return new Access($2, 'proto');
|
||||
return [new Access(new Literal('prototype')), new Access($2)];
|
||||
}), o('::', function() {
|
||||
return new Access(new Literal('prototype'));
|
||||
}), o('Index')
|
||||
@@ -178,10 +178,6 @@
|
||||
return extend($2, {
|
||||
soak: true
|
||||
});
|
||||
}), o('INDEX_PROTO Index', function() {
|
||||
return extend($2, {
|
||||
proto: true
|
||||
});
|
||||
})
|
||||
],
|
||||
IndexValue: [
|
||||
@@ -214,17 +210,17 @@
|
||||
return new Class;
|
||||
}), o('CLASS Block', function() {
|
||||
return new Class(null, null, $2);
|
||||
}), o('CLASS EXTENDS Value', function() {
|
||||
}), o('CLASS EXTENDS Expression', function() {
|
||||
return new Class(null, $3);
|
||||
}), o('CLASS EXTENDS Value Block', function() {
|
||||
}), o('CLASS EXTENDS Expression Block', function() {
|
||||
return new Class(null, $3, $4);
|
||||
}), o('CLASS SimpleAssignable', function() {
|
||||
return new Class($2);
|
||||
}), o('CLASS SimpleAssignable Block', function() {
|
||||
return new Class($2, null, $3);
|
||||
}), o('CLASS SimpleAssignable EXTENDS Value', function() {
|
||||
}), o('CLASS SimpleAssignable EXTENDS Expression', function() {
|
||||
return new Class($2, $4);
|
||||
}), o('CLASS SimpleAssignable EXTENDS Value Block', function() {
|
||||
}), o('CLASS SimpleAssignable EXTENDS Expression Block', function() {
|
||||
return new Class($2, $4, $5);
|
||||
})
|
||||
],
|
||||
@@ -558,8 +554,11 @@
|
||||
})
|
||||
]
|
||||
};
|
||||
|
||||
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() {
|
||||
@@ -570,22 +569,20 @@
|
||||
_ref = alt[0].split(' ');
|
||||
for (_j = 0, _len2 = _ref.length; _j < _len2; _j++) {
|
||||
token = _ref[_j];
|
||||
if (!grammar[token]) {
|
||||
tokens.push(token);
|
||||
}
|
||||
}
|
||||
if (name === 'Root') {
|
||||
alt[1] = "return " + alt[1];
|
||||
if (!grammar[token]) tokens.push(token);
|
||||
}
|
||||
if (name === 'Root') alt[1] = "return " + alt[1];
|
||||
_results.push(alt);
|
||||
}
|
||||
return _results;
|
||||
})();
|
||||
}
|
||||
|
||||
exports.parser = new Parser({
|
||||
tokens: tokens.join(' '),
|
||||
bnf: grammar,
|
||||
operators: operators.reverse(),
|
||||
startSymbol: 'Root'
|
||||
});
|
||||
|
||||
}).call(this);
|
||||
@@ -1,38 +1,40 @@
|
||||
(function() {
|
||||
var extend, flatten;
|
||||
|
||||
exports.starts = function(string, literal, start) {
|
||||
return literal === string.substr(start, literal.length);
|
||||
};
|
||||
|
||||
exports.ends = function(string, literal, back) {
|
||||
var len;
|
||||
len = literal.length;
|
||||
return literal === string.substr(string.length - len - (back || 0), len);
|
||||
};
|
||||
|
||||
exports.compact = function(array) {
|
||||
var item, _i, _len, _results;
|
||||
_results = [];
|
||||
for (_i = 0, _len = array.length; _i < _len; _i++) {
|
||||
item = array[_i];
|
||||
if (item) {
|
||||
_results.push(item);
|
||||
}
|
||||
if (item) _results.push(item);
|
||||
}
|
||||
return _results;
|
||||
};
|
||||
|
||||
exports.count = function(string, substr) {
|
||||
var num, pos;
|
||||
num = pos = 0;
|
||||
if (!substr.length) {
|
||||
return 1 / 0;
|
||||
}
|
||||
if (!substr.length) return 1 / 0;
|
||||
while (pos = 1 + string.indexOf(substr, pos)) {
|
||||
num++;
|
||||
}
|
||||
return num;
|
||||
};
|
||||
|
||||
exports.merge = function(options, overrides) {
|
||||
return extend(extend({}, options), overrides);
|
||||
};
|
||||
|
||||
extend = exports.extend = function(object, properties) {
|
||||
var key, val;
|
||||
for (key in properties) {
|
||||
@@ -41,6 +43,7 @@
|
||||
}
|
||||
return object;
|
||||
};
|
||||
|
||||
exports.flatten = flatten = function(array) {
|
||||
var element, flattened, _i, _len;
|
||||
flattened = [];
|
||||
@@ -54,13 +57,16 @@
|
||||
}
|
||||
return flattened;
|
||||
};
|
||||
|
||||
exports.del = function(obj, key) {
|
||||
var val;
|
||||
val = obj[key];
|
||||
delete obj[key];
|
||||
return val;
|
||||
};
|
||||
|
||||
exports.last = function(array, back) {
|
||||
return array[array.length - (back || 0) - 1];
|
||||
};
|
||||
|
||||
}).call(this);
|
||||
@@ -1,8 +1,10 @@
|
||||
(function() {
|
||||
var key, val, _ref;
|
||||
|
||||
_ref = require('./coffee-script');
|
||||
for (key in _ref) {
|
||||
val = _ref[key];
|
||||
exports[key] = val;
|
||||
}
|
||||
|
||||
}).call(this);
|
||||
@@ -1,23 +1,19 @@
|
||||
(function() {
|
||||
var ASSIGNED, BOOL, CALLABLE, CODE, COFFEE_ALIASES, COFFEE_ALIAS_MAP, COFFEE_KEYWORDS, COMMENT, COMPARE, COMPOUND_ASSIGN, HEREDOC, HEREDOC_ILLEGAL, HEREDOC_INDENT, HEREGEX, HEREGEX_OMIT, IDENTIFIER, INDEXABLE, JSTOKEN, JS_FORBIDDEN, JS_KEYWORDS, LINE_BREAK, LINE_CONTINUER, LOGIC, Lexer, MATH, MULTILINER, MULTI_DENT, NOT_REGEX, NOT_SPACED_REGEX, NO_NEWLINE, NUMBER, OPERATOR, REGEX, RELATION, RESERVED, Rewriter, SHIFT, SIMPLESTR, TRAILING_SPACES, UNARY, WHITESPACE, compact, count, key, last, starts, _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;
|
||||
};
|
||||
Rewriter = require('./rewriter').Rewriter;
|
||||
_ref = require('./helpers'), count = _ref.count, starts = _ref.starts, compact = _ref.compact, last = _ref.last;
|
||||
var BOOL, CALLABLE, CODE, COFFEE_ALIASES, COFFEE_ALIAS_MAP, COFFEE_KEYWORDS, COMMENT, COMPARE, COMPOUND_ASSIGN, HEREDOC, HEREDOC_ILLEGAL, HEREDOC_INDENT, HEREGEX, HEREGEX_OMIT, IDENTIFIER, INDEXABLE, INVERSES, JSTOKEN, JS_FORBIDDEN, JS_KEYWORDS, LINE_BREAK, LINE_CONTINUER, LOGIC, Lexer, MATH, MULTILINER, MULTI_DENT, NOT_REGEX, NOT_SPACED_REGEX, NUMBER, OPERATOR, REGEX, RELATION, RESERVED, Rewriter, SHIFT, SIMPLESTR, TRAILING_SPACES, UNARY, WHITESPACE, compact, count, key, last, starts, _ref, _ref2;
|
||||
var __hasProp = Object.prototype.hasOwnProperty, __indexOf = Array.prototype.indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (__hasProp.call(this, i) && this[i] === item) return i; } return -1; };
|
||||
|
||||
_ref = require('./rewriter'), Rewriter = _ref.Rewriter, INVERSES = _ref.INVERSES;
|
||||
|
||||
_ref2 = require('./helpers'), count = _ref2.count, starts = _ref2.starts, compact = _ref2.compact, last = _ref2.last;
|
||||
|
||||
exports.Lexer = Lexer = (function() {
|
||||
|
||||
function Lexer() {}
|
||||
|
||||
Lexer.prototype.tokenize = function(code, opts) {
|
||||
var i;
|
||||
if (opts == null) {
|
||||
opts = {};
|
||||
}
|
||||
if (WHITESPACE.test(code)) {
|
||||
code = "\n" + code;
|
||||
}
|
||||
var i, tag;
|
||||
if (opts == null) opts = {};
|
||||
if (WHITESPACE.test(code)) code = "\n" + code;
|
||||
code = code.replace(/\r/g, '').replace(TRAILING_SPACES, '');
|
||||
this.code = code;
|
||||
this.line = opts.line || 0;
|
||||
@@ -25,32 +21,31 @@
|
||||
this.indebt = 0;
|
||||
this.outdebt = 0;
|
||||
this.indents = [];
|
||||
this.ends = [];
|
||||
this.tokens = [];
|
||||
i = 0;
|
||||
while (this.chunk = code.slice(i)) {
|
||||
i += this.identifierToken() || this.commentToken() || this.whitespaceToken() || this.lineToken() || this.heredocToken() || this.stringToken() || this.numberToken() || this.regexToken() || this.jsToken() || this.literalToken();
|
||||
}
|
||||
this.closeIndentation();
|
||||
if (opts.rewrite === false) {
|
||||
return this.tokens;
|
||||
}
|
||||
if (tag = this.ends.pop()) this.error("missing " + tag);
|
||||
if (opts.rewrite === false) return this.tokens;
|
||||
return (new Rewriter).rewrite(this.tokens);
|
||||
};
|
||||
|
||||
Lexer.prototype.identifierToken = function() {
|
||||
var colon, forcedIdentifier, id, input, match, prev, tag, _ref2, _ref3;
|
||||
if (!(match = IDENTIFIER.exec(this.chunk))) {
|
||||
return 0;
|
||||
}
|
||||
var colon, forcedIdentifier, id, input, match, prev, tag, _ref3, _ref4;
|
||||
if (!(match = IDENTIFIER.exec(this.chunk))) return 0;
|
||||
input = match[0], id = match[1], colon = match[2];
|
||||
if (id === 'own' && this.tag() === 'FOR') {
|
||||
this.token('OWN', id);
|
||||
return id.length;
|
||||
}
|
||||
forcedIdentifier = colon || (prev = last(this.tokens)) && (((_ref2 = prev[0]) === '.' || _ref2 === '?.' || _ref2 === '::') || !prev.spaced && prev[0] === '@');
|
||||
forcedIdentifier = colon || (prev = last(this.tokens)) && (((_ref3 = prev[0]) === '.' || _ref3 === '?.' || _ref3 === '::') || !prev.spaced && prev[0] === '@');
|
||||
tag = 'IDENTIFIER';
|
||||
if (__indexOf.call(JS_KEYWORDS, id) >= 0 || !forcedIdentifier && __indexOf.call(COFFEE_KEYWORDS, id) >= 0) {
|
||||
if (!forcedIdentifier && (__indexOf.call(JS_KEYWORDS, id) >= 0 || __indexOf.call(COFFEE_KEYWORDS, id) >= 0)) {
|
||||
tag = id.toUpperCase();
|
||||
if (tag === 'WHEN' && (_ref3 = this.tag(), __indexOf.call(LINE_BREAK, _ref3) >= 0)) {
|
||||
if (tag === 'WHEN' && (_ref4 = this.tag(), __indexOf.call(LINE_BREAK, _ref4) >= 0)) {
|
||||
tag = 'LEADING_WHEN';
|
||||
} else if (tag === 'FOR') {
|
||||
this.seenFor = true;
|
||||
@@ -71,19 +66,17 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
if (__indexOf.call(JS_FORBIDDEN, id) >= 0) {
|
||||
if (__indexOf.call(['eval', 'arguments'].concat(JS_FORBIDDEN), id) >= 0) {
|
||||
if (forcedIdentifier) {
|
||||
tag = 'IDENTIFIER';
|
||||
id = new String(id);
|
||||
id.reserved = true;
|
||||
} else if (__indexOf.call(RESERVED, id) >= 0) {
|
||||
this.identifierError(id);
|
||||
this.error("reserved word \"" + word + "\"");
|
||||
}
|
||||
}
|
||||
if (!forcedIdentifier) {
|
||||
if (__indexOf.call(COFFEE_ALIASES, id) >= 0) {
|
||||
id = COFFEE_ALIAS_MAP[id];
|
||||
}
|
||||
if (__indexOf.call(COFFEE_ALIASES, id) >= 0) id = COFFEE_ALIAS_MAP[id];
|
||||
tag = (function() {
|
||||
switch (id) {
|
||||
case '!':
|
||||
@@ -109,33 +102,31 @@
|
||||
})();
|
||||
}
|
||||
this.token(tag, id);
|
||||
if (colon) {
|
||||
this.token(':', ':');
|
||||
}
|
||||
if (colon) this.token(':', ':');
|
||||
return input.length;
|
||||
};
|
||||
|
||||
Lexer.prototype.numberToken = function() {
|
||||
var match, number;
|
||||
if (!(match = NUMBER.exec(this.chunk))) {
|
||||
return 0;
|
||||
}
|
||||
var binaryLiteral, lexedLength, match, number;
|
||||
if (!(match = NUMBER.exec(this.chunk))) return 0;
|
||||
number = match[0];
|
||||
lexedLength = number.length;
|
||||
if (binaryLiteral = /0b([01]+)/.exec(number)) {
|
||||
number = (parseInt(binaryLiteral[1], 2)).toString();
|
||||
}
|
||||
this.token('NUMBER', number);
|
||||
return number.length;
|
||||
return lexedLength;
|
||||
};
|
||||
|
||||
Lexer.prototype.stringToken = function() {
|
||||
var match, string;
|
||||
switch (this.chunk.charAt(0)) {
|
||||
case "'":
|
||||
if (!(match = SIMPLESTR.exec(this.chunk))) {
|
||||
return 0;
|
||||
}
|
||||
if (!(match = SIMPLESTR.exec(this.chunk))) return 0;
|
||||
this.token('STRING', (string = match[0]).replace(MULTILINER, '\\\n'));
|
||||
break;
|
||||
case '"':
|
||||
if (!(string = this.balancedString(this.chunk, '"'))) {
|
||||
return 0;
|
||||
}
|
||||
if (!(string = this.balancedString(this.chunk, '"'))) return 0;
|
||||
if (0 < string.indexOf('#{', 1)) {
|
||||
this.interpolateString(string.slice(1, -1));
|
||||
} else {
|
||||
@@ -148,11 +139,10 @@
|
||||
this.line += count(string, '\n');
|
||||
return string.length;
|
||||
};
|
||||
|
||||
Lexer.prototype.heredocToken = function() {
|
||||
var doc, heredoc, match, quote;
|
||||
if (!(match = HEREDOC.exec(this.chunk))) {
|
||||
return 0;
|
||||
}
|
||||
if (!(match = HEREDOC.exec(this.chunk))) return 0;
|
||||
heredoc = match[0];
|
||||
quote = heredoc.charAt(0);
|
||||
doc = this.sanitizeHeredoc(match[2], {
|
||||
@@ -169,11 +159,10 @@
|
||||
this.line += count(heredoc, '\n');
|
||||
return heredoc.length;
|
||||
};
|
||||
|
||||
Lexer.prototype.commentToken = function() {
|
||||
var comment, here, match;
|
||||
if (!(match = this.chunk.match(COMMENT))) {
|
||||
return 0;
|
||||
}
|
||||
if (!(match = this.chunk.match(COMMENT))) return 0;
|
||||
comment = match[0], here = match[1];
|
||||
if (here) {
|
||||
this.token('HERECOMMENT', this.sanitizeHeredoc(here, {
|
||||
@@ -185,6 +174,7 @@
|
||||
this.line += count(comment, '\n');
|
||||
return comment.length;
|
||||
};
|
||||
|
||||
Lexer.prototype.jsToken = function() {
|
||||
var match, script;
|
||||
if (!(this.chunk.charAt(0) === '`' && (match = JSTOKEN.exec(this.chunk)))) {
|
||||
@@ -193,70 +183,73 @@
|
||||
this.token('JS', (script = match[0]).slice(1, -1));
|
||||
return script.length;
|
||||
};
|
||||
|
||||
Lexer.prototype.regexToken = function() {
|
||||
var match, prev, regex, _ref2;
|
||||
if (this.chunk.charAt(0) !== '/') {
|
||||
return 0;
|
||||
}
|
||||
var flags, length, match, prev, regex, _ref3, _ref4;
|
||||
if (this.chunk.charAt(0) !== '/') return 0;
|
||||
if (match = HEREGEX.exec(this.chunk)) {
|
||||
return this.heregexToken(match);
|
||||
length = this.heregexToken(match);
|
||||
this.line += count(match[0], '\n');
|
||||
return length;
|
||||
}
|
||||
prev = last(this.tokens);
|
||||
if (prev && (_ref2 = prev[0], __indexOf.call((prev.spaced ? NOT_REGEX : NOT_SPACED_REGEX), _ref2) >= 0)) {
|
||||
if (prev && (_ref3 = prev[0], __indexOf.call((prev.spaced ? NOT_REGEX : NOT_SPACED_REGEX), _ref3) >= 0)) {
|
||||
return 0;
|
||||
}
|
||||
if (!(match = REGEX.exec(this.chunk))) {
|
||||
return 0;
|
||||
if (!(match = REGEX.exec(this.chunk))) return 0;
|
||||
_ref4 = match, match = _ref4[0], regex = _ref4[1], flags = _ref4[2];
|
||||
if (regex.slice(0, 2) === '/*') {
|
||||
this.error('regular expressions cannot begin with `*`');
|
||||
}
|
||||
regex = match[0];
|
||||
this.token('REGEX', regex === '//' ? '/(?:)/' : regex);
|
||||
return regex.length;
|
||||
if (regex === '//') regex = '/(?:)/';
|
||||
this.token('REGEX', "" + regex + flags);
|
||||
return match.length;
|
||||
};
|
||||
|
||||
Lexer.prototype.heregexToken = function(match) {
|
||||
var body, flags, heregex, re, tag, tokens, value, _i, _len, _ref2, _ref3, _ref4, _ref5;
|
||||
var body, flags, heregex, re, tag, tokens, value, _i, _len, _ref3, _ref4, _ref5, _ref6;
|
||||
heregex = match[0], body = match[1], flags = match[2];
|
||||
if (0 > body.indexOf('#{')) {
|
||||
re = body.replace(HEREGEX_OMIT, '').replace(/\//g, '\\/');
|
||||
if (re.match(/^\*/)) {
|
||||
this.error('regular expressions cannot begin with `*`');
|
||||
}
|
||||
this.token('REGEX', "/" + (re || '(?:)') + "/" + flags);
|
||||
return heregex.length;
|
||||
}
|
||||
this.token('IDENTIFIER', 'RegExp');
|
||||
this.tokens.push(['CALL_START', '(']);
|
||||
tokens = [];
|
||||
_ref2 = this.interpolateString(body, {
|
||||
_ref3 = this.interpolateString(body, {
|
||||
regex: true
|
||||
});
|
||||
for (_i = 0, _len = _ref2.length; _i < _len; _i++) {
|
||||
_ref3 = _ref2[_i], tag = _ref3[0], value = _ref3[1];
|
||||
for (_i = 0, _len = _ref3.length; _i < _len; _i++) {
|
||||
_ref4 = _ref3[_i], tag = _ref4[0], value = _ref4[1];
|
||||
if (tag === 'TOKENS') {
|
||||
tokens.push.apply(tokens, value);
|
||||
} else {
|
||||
if (!(value = value.replace(HEREGEX_OMIT, ''))) {
|
||||
continue;
|
||||
}
|
||||
if (!(value = value.replace(HEREGEX_OMIT, ''))) continue;
|
||||
value = value.replace(/\\/g, '\\\\');
|
||||
tokens.push(['STRING', this.makeString(value, '"', true)]);
|
||||
}
|
||||
tokens.push(['+', '+']);
|
||||
}
|
||||
tokens.pop();
|
||||
if (((_ref4 = tokens[0]) != null ? _ref4[0] : void 0) !== 'STRING') {
|
||||
if (((_ref5 = tokens[0]) != null ? _ref5[0] : void 0) !== 'STRING') {
|
||||
this.tokens.push(['STRING', '""'], ['+', '+']);
|
||||
}
|
||||
(_ref5 = this.tokens).push.apply(_ref5, tokens);
|
||||
if (flags) {
|
||||
this.tokens.push([',', ','], ['STRING', '"' + flags + '"']);
|
||||
}
|
||||
(_ref6 = this.tokens).push.apply(_ref6, tokens);
|
||||
if (flags) this.tokens.push([',', ','], ['STRING', '"' + flags + '"']);
|
||||
this.token(')', ')');
|
||||
return heregex.length;
|
||||
};
|
||||
|
||||
Lexer.prototype.lineToken = function() {
|
||||
var diff, indent, match, noNewlines, prev, size;
|
||||
if (!(match = MULTI_DENT.exec(this.chunk))) {
|
||||
return 0;
|
||||
}
|
||||
if (!(match = MULTI_DENT.exec(this.chunk))) return 0;
|
||||
indent = match[0];
|
||||
this.line += count(indent, '\n');
|
||||
this.seenFor = false;
|
||||
prev = last(this.tokens, 1);
|
||||
size = indent.length - 1 - indent.lastIndexOf('\n');
|
||||
noNewlines = this.unfinished();
|
||||
@@ -277,6 +270,7 @@
|
||||
diff = size - this.indent + this.outdebt;
|
||||
this.token('INDENT', diff);
|
||||
this.indents.push(diff);
|
||||
this.ends.push('OUTDENT');
|
||||
this.outdebt = this.indebt = 0;
|
||||
} else {
|
||||
this.indebt = 0;
|
||||
@@ -285,7 +279,8 @@
|
||||
this.indent = size;
|
||||
return indent.length;
|
||||
};
|
||||
Lexer.prototype.outdentToken = function(moveOut, noNewlines, close) {
|
||||
|
||||
Lexer.prototype.outdentToken = function(moveOut, noNewlines) {
|
||||
var dent, len;
|
||||
while (moveOut > 0) {
|
||||
len = this.indents.length - 1;
|
||||
@@ -301,67 +296,69 @@
|
||||
dent = this.indents.pop() - this.outdebt;
|
||||
moveOut -= dent;
|
||||
this.outdebt = 0;
|
||||
this.pair('OUTDENT');
|
||||
this.token('OUTDENT', dent);
|
||||
}
|
||||
}
|
||||
if (dent) {
|
||||
this.outdebt -= moveOut;
|
||||
if (dent) this.outdebt -= moveOut;
|
||||
while (this.value() === ';') {
|
||||
this.tokens.pop();
|
||||
}
|
||||
if (!(this.tag() === 'TERMINATOR' || noNewlines)) {
|
||||
this.token('TERMINATOR', '\n');
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
Lexer.prototype.whitespaceToken = function() {
|
||||
var match, nline, prev;
|
||||
if (!((match = WHITESPACE.exec(this.chunk)) || (nline = this.chunk.charAt(0) === '\n'))) {
|
||||
return 0;
|
||||
}
|
||||
prev = last(this.tokens);
|
||||
if (prev) {
|
||||
prev[match ? 'spaced' : 'newLine'] = true;
|
||||
}
|
||||
if (prev) prev[match ? 'spaced' : 'newLine'] = true;
|
||||
if (match) {
|
||||
return match[0].length;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
Lexer.prototype.newlineToken = function() {
|
||||
if (this.tag() !== 'TERMINATOR') {
|
||||
this.token('TERMINATOR', '\n');
|
||||
}
|
||||
return this;
|
||||
};
|
||||
Lexer.prototype.suppressNewlines = function() {
|
||||
if (this.value() === '\\') {
|
||||
while (this.value() === ';') {
|
||||
this.tokens.pop();
|
||||
}
|
||||
if (this.tag() !== 'TERMINATOR') this.token('TERMINATOR', '\n');
|
||||
return this;
|
||||
};
|
||||
|
||||
Lexer.prototype.suppressNewlines = function() {
|
||||
if (this.value() === '\\') this.tokens.pop();
|
||||
return this;
|
||||
};
|
||||
|
||||
Lexer.prototype.literalToken = function() {
|
||||
var match, prev, tag, value, _ref2, _ref3, _ref4, _ref5;
|
||||
var match, prev, tag, value, _ref3, _ref4, _ref5, _ref6;
|
||||
if (match = OPERATOR.exec(this.chunk)) {
|
||||
value = match[0];
|
||||
if (CODE.test(value)) {
|
||||
this.tagParameters();
|
||||
}
|
||||
if (CODE.test(value)) this.tagParameters();
|
||||
} else {
|
||||
value = this.chunk.charAt(0);
|
||||
}
|
||||
tag = value;
|
||||
prev = last(this.tokens);
|
||||
if (value === '=' && prev) {
|
||||
if (!prev[1].reserved && (_ref2 = prev[1], __indexOf.call(JS_FORBIDDEN, _ref2) >= 0)) {
|
||||
this.assignmentError();
|
||||
if (!prev[1].reserved && (_ref3 = prev[1], __indexOf.call(JS_FORBIDDEN, _ref3) >= 0)) {
|
||||
this.error("reserved word \"" + (this.value()) + "\" can't be assigned");
|
||||
}
|
||||
if ((_ref3 = prev[1]) === '||' || _ref3 === '&&') {
|
||||
if ((_ref4 = prev[1]) === '||' || _ref4 === '&&') {
|
||||
prev[0] = 'COMPOUND_ASSIGN';
|
||||
prev[1] += '=';
|
||||
return value.length;
|
||||
}
|
||||
}
|
||||
if (value === ';') {
|
||||
this.seenFor = false;
|
||||
tag = 'TERMINATOR';
|
||||
} else if (__indexOf.call(MATH, value) >= 0) {
|
||||
tag = 'MATH';
|
||||
@@ -376,56 +373,56 @@
|
||||
} else if (__indexOf.call(LOGIC, value) >= 0 || value === '?' && (prev != null ? prev.spaced : void 0)) {
|
||||
tag = 'LOGIC';
|
||||
} else if (prev && !prev.spaced) {
|
||||
if (value === '(' && (_ref4 = prev[0], __indexOf.call(CALLABLE, _ref4) >= 0)) {
|
||||
if (prev[0] === '?') {
|
||||
prev[0] = 'FUNC_EXIST';
|
||||
}
|
||||
if (value === '(' && (_ref5 = prev[0], __indexOf.call(CALLABLE, _ref5) >= 0)) {
|
||||
if (prev[0] === '?') prev[0] = 'FUNC_EXIST';
|
||||
tag = 'CALL_START';
|
||||
} else if (value === '[' && (_ref5 = prev[0], __indexOf.call(INDEXABLE, _ref5) >= 0)) {
|
||||
} else if (value === '[' && (_ref6 = prev[0], __indexOf.call(INDEXABLE, _ref6) >= 0)) {
|
||||
tag = 'INDEX_START';
|
||||
switch (prev[0]) {
|
||||
case '?':
|
||||
prev[0] = 'INDEX_SOAK';
|
||||
break;
|
||||
case '::':
|
||||
prev[0] = 'INDEX_PROTO';
|
||||
}
|
||||
}
|
||||
}
|
||||
switch (value) {
|
||||
case '(':
|
||||
case '{':
|
||||
case '[':
|
||||
this.ends.push(INVERSES[value]);
|
||||
break;
|
||||
case ')':
|
||||
case '}':
|
||||
case ']':
|
||||
this.pair(value);
|
||||
}
|
||||
this.token(tag, value);
|
||||
return value.length;
|
||||
};
|
||||
|
||||
Lexer.prototype.sanitizeHeredoc = function(doc, options) {
|
||||
var attempt, herecomment, indent, match, _ref2;
|
||||
var attempt, herecomment, indent, match, _ref3;
|
||||
indent = options.indent, herecomment = options.herecomment;
|
||||
if (herecomment) {
|
||||
if (HEREDOC_ILLEGAL.test(doc)) {
|
||||
throw new Error("block comment cannot contain \"*/\", starting on line " + (this.line + 1));
|
||||
}
|
||||
if (doc.indexOf('\n') <= 0) {
|
||||
return doc;
|
||||
this.error("block comment cannot contain \"*/\", starting");
|
||||
}
|
||||
if (doc.indexOf('\n') <= 0) return doc;
|
||||
} else {
|
||||
while (match = HEREDOC_INDENT.exec(doc)) {
|
||||
attempt = match[1];
|
||||
if (indent === null || (0 < (_ref2 = attempt.length) && _ref2 < indent.length)) {
|
||||
if (indent === null || (0 < (_ref3 = attempt.length) && _ref3 < indent.length)) {
|
||||
indent = attempt;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (indent) {
|
||||
doc = doc.replace(RegExp("\\n" + indent, "g"), '\n');
|
||||
}
|
||||
if (!herecomment) {
|
||||
doc = doc.replace(/^\n/, '');
|
||||
}
|
||||
if (indent) doc = doc.replace(RegExp("\\n" + indent, "g"), '\n');
|
||||
if (!herecomment) doc = doc.replace(/^\n/, '');
|
||||
return doc;
|
||||
};
|
||||
|
||||
Lexer.prototype.tagParameters = function() {
|
||||
var i, stack, tok, tokens;
|
||||
if (this.tag() !== ')') {
|
||||
return this;
|
||||
}
|
||||
if (this.tag() !== ')') return this;
|
||||
stack = [];
|
||||
tokens = this.tokens;
|
||||
i = tokens.length;
|
||||
@@ -442,38 +439,36 @@
|
||||
} else if (tok[0] === '(') {
|
||||
tok[0] = 'PARAM_START';
|
||||
return this;
|
||||
} else {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
Lexer.prototype.closeIndentation = function() {
|
||||
return this.outdentToken(this.indent);
|
||||
};
|
||||
Lexer.prototype.identifierError = function(word) {
|
||||
throw SyntaxError("Reserved word \"" + word + "\" on line " + (this.line + 1));
|
||||
};
|
||||
Lexer.prototype.assignmentError = function() {
|
||||
throw SyntaxError("Reserved word \"" + (this.value()) + "\" on line " + (this.line + 1) + " can't be assigned");
|
||||
};
|
||||
|
||||
Lexer.prototype.balancedString = function(str, end) {
|
||||
var i, letter, prev, stack, _ref2;
|
||||
var i, letter, match, prev, stack, _ref3;
|
||||
stack = [end];
|
||||
for (i = 1, _ref2 = str.length; 1 <= _ref2 ? i < _ref2 : i > _ref2; 1 <= _ref2 ? i++ : i--) {
|
||||
for (i = 1, _ref3 = str.length; 1 <= _ref3 ? i < _ref3 : i > _ref3; 1 <= _ref3 ? i++ : i--) {
|
||||
switch (letter = str.charAt(i)) {
|
||||
case '\\':
|
||||
i++;
|
||||
continue;
|
||||
case end:
|
||||
stack.pop();
|
||||
if (!stack.length) {
|
||||
return str.slice(0, i + 1);
|
||||
}
|
||||
if (!stack.length) return str.slice(0, i + 1);
|
||||
end = stack[stack.length - 1];
|
||||
continue;
|
||||
}
|
||||
if (end === '}' && (letter === '"' || letter === "'")) {
|
||||
stack.push(end = letter);
|
||||
} else if (end === '}' && letter === '/' && (match = HEREGEX.exec(str.slice(i)) || REGEX.exec(str.slice(i)))) {
|
||||
i += match[0].length - 1;
|
||||
} else if (end === '}' && letter === '{') {
|
||||
stack.push(end = '}');
|
||||
} else if (end === '"' && prev === '#' && letter === '{') {
|
||||
@@ -481,13 +476,12 @@
|
||||
}
|
||||
prev = letter;
|
||||
}
|
||||
throw new Error("missing " + (stack.pop()) + ", starting on line " + (this.line + 1));
|
||||
return this.error("missing " + (stack.pop()) + ", starting");
|
||||
};
|
||||
|
||||
Lexer.prototype.interpolateString = function(str, options) {
|
||||
var expr, heredoc, i, inner, interpolated, len, letter, nested, pi, regex, tag, tokens, value, _len, _ref2, _ref3, _ref4;
|
||||
if (options == null) {
|
||||
options = {};
|
||||
}
|
||||
var expr, heredoc, i, inner, interpolated, len, letter, nested, pi, regex, tag, tokens, value, _len, _ref3, _ref4, _ref5;
|
||||
if (options == null) options = {};
|
||||
heredoc = options.heredoc, regex = options.regex;
|
||||
tokens = [];
|
||||
pi = 0;
|
||||
@@ -500,9 +494,7 @@
|
||||
if (!(letter === '#' && str.charAt(i + 1) === '{' && (expr = this.balancedString(str.slice(i + 1), '}')))) {
|
||||
continue;
|
||||
}
|
||||
if (pi < i) {
|
||||
tokens.push(['NEOSTRING', str.slice(pi, i)]);
|
||||
}
|
||||
if (pi < i) tokens.push(['NEOSTRING', str.slice(pi, i)]);
|
||||
inner = expr.slice(1, -1);
|
||||
if (inner.length) {
|
||||
nested = new Lexer().tokenize(inner, {
|
||||
@@ -510,7 +502,7 @@
|
||||
rewrite: false
|
||||
});
|
||||
nested.pop();
|
||||
if (((_ref2 = nested[0]) != null ? _ref2[0] : void 0) === 'TERMINATOR') {
|
||||
if (((_ref3 = nested[0]) != null ? _ref3[0] : void 0) === 'TERMINATOR') {
|
||||
nested.shift();
|
||||
}
|
||||
if (len = nested.length) {
|
||||
@@ -524,59 +516,60 @@
|
||||
i += expr.length;
|
||||
pi = i + 1;
|
||||
}
|
||||
if ((i > pi && pi < str.length)) {
|
||||
tokens.push(['NEOSTRING', str.slice(pi)]);
|
||||
}
|
||||
if (regex) {
|
||||
return tokens;
|
||||
}
|
||||
if (!tokens.length) {
|
||||
return this.token('STRING', '""');
|
||||
}
|
||||
if (tokens[0][0] !== 'NEOSTRING') {
|
||||
tokens.unshift(['', '']);
|
||||
}
|
||||
if (interpolated = tokens.length > 1) {
|
||||
this.token('(', '(');
|
||||
}
|
||||
if ((i > pi && pi < str.length)) tokens.push(['NEOSTRING', str.slice(pi)]);
|
||||
if (regex) return tokens;
|
||||
if (!tokens.length) return this.token('STRING', '""');
|
||||
if (tokens[0][0] !== 'NEOSTRING') tokens.unshift(['', '']);
|
||||
if (interpolated = tokens.length > 1) this.token('(', '(');
|
||||
for (i = 0, _len = tokens.length; i < _len; i++) {
|
||||
_ref3 = tokens[i], tag = _ref3[0], value = _ref3[1];
|
||||
if (i) {
|
||||
this.token('+', '+');
|
||||
}
|
||||
_ref4 = tokens[i], tag = _ref4[0], value = _ref4[1];
|
||||
if (i) this.token('+', '+');
|
||||
if (tag === 'TOKENS') {
|
||||
(_ref4 = this.tokens).push.apply(_ref4, value);
|
||||
(_ref5 = this.tokens).push.apply(_ref5, value);
|
||||
} else {
|
||||
this.token('STRING', this.makeString(value, '"', heredoc));
|
||||
}
|
||||
}
|
||||
if (interpolated) {
|
||||
this.token(')', ')');
|
||||
}
|
||||
if (interpolated) this.token(')', ')');
|
||||
return tokens;
|
||||
};
|
||||
|
||||
Lexer.prototype.pair = function(tag) {
|
||||
var size, wanted;
|
||||
if (tag !== (wanted = last(this.ends))) {
|
||||
if ('OUTDENT' !== wanted) this.error("unmatched " + tag);
|
||||
this.indent -= size = last(this.indents);
|
||||
this.outdentToken(size, true);
|
||||
return this.pair(tag);
|
||||
}
|
||||
return this.ends.pop();
|
||||
};
|
||||
|
||||
Lexer.prototype.token = function(tag, value) {
|
||||
return this.tokens.push([tag, value, this.line]);
|
||||
};
|
||||
|
||||
Lexer.prototype.tag = function(index, tag) {
|
||||
var tok;
|
||||
return (tok = last(this.tokens, index)) && (tag ? tok[0] = tag : tok[0]);
|
||||
};
|
||||
|
||||
Lexer.prototype.value = function(index, val) {
|
||||
var tok;
|
||||
return (tok = last(this.tokens, index)) && (val ? tok[1] = val : tok[1]);
|
||||
};
|
||||
|
||||
Lexer.prototype.unfinished = function() {
|
||||
var prev, value;
|
||||
return LINE_CONTINUER.test(this.chunk) || (prev = last(this.tokens, 1)) && prev[0] !== '.' && (value = this.value()) && !value.reserved && NO_NEWLINE.test(value) && !CODE.test(value) && !ASSIGNED.test(this.chunk);
|
||||
var _ref3;
|
||||
return LINE_CONTINUER.test(this.chunk) || ((_ref3 = this.tag()) === '\\' || _ref3 === '.' || _ref3 === '?.' || _ref3 === 'UNARY' || _ref3 === 'MATH' || _ref3 === '+' || _ref3 === '-' || _ref3 === 'SHIFT' || _ref3 === 'RELATION' || _ref3 === 'COMPARE' || _ref3 === 'LOGIC' || _ref3 === 'COMPOUND_ASSIGN' || _ref3 === 'THROW' || _ref3 === 'EXTENDS');
|
||||
};
|
||||
|
||||
Lexer.prototype.escapeLines = function(str, heredoc) {
|
||||
return str.replace(MULTILINER, heredoc ? '\\n' : '');
|
||||
};
|
||||
|
||||
Lexer.prototype.makeString = function(body, quote, heredoc) {
|
||||
if (!body) {
|
||||
return quote + quote;
|
||||
}
|
||||
if (!body) return quote + quote;
|
||||
body = body.replace(/\\([\s\S])/g, function(match, contents) {
|
||||
if (contents === '\n' || contents === quote) {
|
||||
return contents;
|
||||
@@ -587,10 +580,19 @@
|
||||
body = body.replace(RegExp("" + quote, "g"), '\\$&');
|
||||
return quote + this.escapeLines(body, heredoc) + quote;
|
||||
};
|
||||
|
||||
Lexer.prototype.error = function(message) {
|
||||
throw SyntaxError("" + message + " on line " + (this.line + 1));
|
||||
};
|
||||
|
||||
return Lexer;
|
||||
|
||||
})();
|
||||
|
||||
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'];
|
||||
|
||||
COFFEE_ALIAS_MAP = {
|
||||
and: '&&',
|
||||
or: '||',
|
||||
@@ -602,6 +604,7 @@
|
||||
on: 'true',
|
||||
off: 'false'
|
||||
};
|
||||
|
||||
COFFEE_ALIASES = (function() {
|
||||
var _results;
|
||||
_results = [];
|
||||
@@ -610,41 +613,75 @@
|
||||
}
|
||||
return _results;
|
||||
})();
|
||||
|
||||
COFFEE_KEYWORDS = COFFEE_KEYWORDS.concat(COFFEE_ALIASES);
|
||||
|
||||
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_\x7f-\uffff][$\w\x7f-\uffff]*)([^\n\S]*:(?!:))?/;
|
||||
NUMBER = /^0x[\da-f]+|^(?:\d+(\.\d+)?|\.\d+)(?:e[+-]?\d+)?/i;
|
||||
|
||||
NUMBER = /^0x[\da-f]+|^0b[01]+|^\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]*|(?:###)?$)|^(?:\s*#(?!##[^#]).*)+/;
|
||||
|
||||
CODE = /^[-=]>/;
|
||||
|
||||
MULTI_DENT = /^(?:\n[^\n\S]*)+/;
|
||||
|
||||
SIMPLESTR = /^'[^\\']*(?:\\.[^\\']*)*'/;
|
||||
|
||||
JSTOKEN = /^`[^\\`]*(?:\\.[^\\`]*)*`/;
|
||||
REGEX = /^\/(?![\s=])[^[\/\n\\]*(?:(?:\\[\s\S]|\[[^\]\n\\]*(?:\\[\s\S][^\]\n\\]*)*])[^[\/\n\\]*)*\/[imgy]{0,4}(?!\w)/;
|
||||
|
||||
REGEX = /^(\/(?![\s=])[^[\/\n\\]*(?:(?:\\[\s\S]|\[[^\]\n\\]*(?:\\[\s\S][^\]\n\\]*)*])[^[\/\n\\]*)*\/)([imgy]{0,4})(?!\w)/;
|
||||
|
||||
HEREGEX = /^\/{3}([\s\S]+?)\/{3}([imgy]{0,4})(?!\w)/;
|
||||
|
||||
HEREGEX_OMIT = /\s+(?:#.*)?/g;
|
||||
|
||||
MULTILINER = /\n/g;
|
||||
|
||||
HEREDOC_INDENT = /\n+([^\n\S]*)/g;
|
||||
|
||||
HEREDOC_ILLEGAL = /\*\//;
|
||||
ASSIGNED = /^\s*@?([$A-Za-z_][$\w\x7f-\uffff]*|['"].*['"])[^\n\S]*?[:=][^:=>]/;
|
||||
|
||||
LINE_CONTINUER = /^\s*(?:,|\??\.(?![.\d])|::)/;
|
||||
|
||||
TRAILING_SPACES = /\s+$/;
|
||||
NO_NEWLINE = /^(?:[-+*&|\/%=<>!.\\][<>=&|]*|and|or|is(?:nt)?|n(?:ot|ew)|delete|typeof|instanceof)$/;
|
||||
|
||||
COMPOUND_ASSIGN = ['-=', '+=', '/=', '*=', '%=', '||=', '&&=', '?=', '<<=', '>>=', '>>>=', '&=', '^=', '|='];
|
||||
|
||||
UNARY = ['!', '~', 'NEW', 'TYPEOF', 'DELETE', 'DO'];
|
||||
|
||||
LOGIC = ['&&', '||', '&', '|', '^'];
|
||||
|
||||
SHIFT = ['<<', '>>', '>>>'];
|
||||
|
||||
COMPARE = ['==', '!=', '<', '>', '<=', '>='];
|
||||
|
||||
MATH = ['*', '/', '%'];
|
||||
|
||||
RELATION = ['IN', 'OF', 'INSTANCEOF'];
|
||||
|
||||
BOOL = ['TRUE', 'FALSE', 'NULL', 'UNDEFINED'];
|
||||
|
||||
NOT_REGEX = ['NUMBER', 'REGEX', 'BOOL', '++', '--', ']'];
|
||||
|
||||
NOT_SPACED_REGEX = NOT_REGEX.concat(')', '}', 'THIS', 'IDENTIFIER', 'STRING');
|
||||
|
||||
CALLABLE = ['IDENTIFIER', 'STRING', 'REGEX', ')', ']', '}', '?', '::', '@', 'THIS', 'SUPER'];
|
||||
|
||||
INDEXABLE = CALLABLE.concat('NUMBER', 'BOOL');
|
||||
|
||||
LINE_BREAK = ['INDENT', 'OUTDENT', 'TERMINATOR'];
|
||||
|
||||
}).call(this);
|
||||
File diff suppressed because it is too large
Load Diff
35
lib/optparse.js → lib/coffee-script/optparse.js
Executable file → Normal file
35
lib/optparse.js → lib/coffee-script/optparse.js
Executable file → Normal file
@@ -1,21 +1,27 @@
|
||||
(function() {
|
||||
var LONG_FLAG, MULTI_FLAG, OPTIONAL, OptionParser, SHORT_FLAG, buildRule, buildRules, normalizeArguments;
|
||||
|
||||
exports.OptionParser = OptionParser = (function() {
|
||||
|
||||
function OptionParser(rules, banner) {
|
||||
this.banner = banner;
|
||||
this.rules = buildRules(rules);
|
||||
}
|
||||
|
||||
OptionParser.prototype.parse = function(args) {
|
||||
var arg, i, isOption, matchedRule, options, rule, value, _i, _len, _len2, _ref;
|
||||
var arg, i, isOption, matchedRule, options, originalArgs, pos, rule, value, _i, _len, _len2, _ref;
|
||||
options = {
|
||||
arguments: [],
|
||||
literals: []
|
||||
};
|
||||
originalArgs = args;
|
||||
args = normalizeArguments(args);
|
||||
for (i = 0, _len = args.length; i < _len; i++) {
|
||||
arg = args[i];
|
||||
if (arg === '--') {
|
||||
options.literals = args.slice(i + 1);
|
||||
pos = originalArgs.indexOf('--');
|
||||
options.arguments = [originalArgs[1 + pos]];
|
||||
options.literals = originalArgs.slice(2 + pos);
|
||||
break;
|
||||
}
|
||||
isOption = !!(arg.match(LONG_FLAG) || arg.match(SHORT_FLAG));
|
||||
@@ -34,18 +40,17 @@
|
||||
throw new Error("unrecognized option: " + arg);
|
||||
}
|
||||
if (!isOption) {
|
||||
options.arguments = args.slice(i);
|
||||
options.arguments = originalArgs.slice(originalArgs.indexOf(arg));
|
||||
break;
|
||||
}
|
||||
}
|
||||
return options;
|
||||
};
|
||||
|
||||
OptionParser.prototype.help = function() {
|
||||
var letPart, lines, rule, spaces, _i, _len, _ref;
|
||||
lines = [];
|
||||
if (this.banner) {
|
||||
lines.unshift("" + this.banner + "\n");
|
||||
}
|
||||
if (this.banner) lines.unshift("" + this.banner + "\n");
|
||||
_ref = this.rules;
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
rule = _ref[_i];
|
||||
@@ -56,29 +61,33 @@
|
||||
}
|
||||
return "\n" + (lines.join('\n')) + "\n";
|
||||
};
|
||||
|
||||
return OptionParser;
|
||||
|
||||
})();
|
||||
|
||||
LONG_FLAG = /^(--\w[\w\-]+)/;
|
||||
|
||||
SHORT_FLAG = /^(-\w)/;
|
||||
|
||||
MULTI_FLAG = /^-(\w{2,})/;
|
||||
|
||||
OPTIONAL = /\[(\w+(\*?))\]/;
|
||||
|
||||
buildRules = function(rules) {
|
||||
var tuple, _i, _len, _results;
|
||||
_results = [];
|
||||
for (_i = 0, _len = rules.length; _i < _len; _i++) {
|
||||
tuple = rules[_i];
|
||||
if (tuple.length < 3) {
|
||||
tuple.unshift(null);
|
||||
}
|
||||
if (tuple.length < 3) tuple.unshift(null);
|
||||
_results.push(buildRule.apply(null, tuple));
|
||||
}
|
||||
return _results;
|
||||
};
|
||||
|
||||
buildRule = function(shortFlag, longFlag, description, options) {
|
||||
var match;
|
||||
if (options == null) {
|
||||
options = {};
|
||||
}
|
||||
if (options == null) options = {};
|
||||
match = longFlag.match(OPTIONAL);
|
||||
longFlag = longFlag.match(LONG_FLAG)[1];
|
||||
return {
|
||||
@@ -90,6 +99,7 @@
|
||||
isList: !!(match && match[2])
|
||||
};
|
||||
};
|
||||
|
||||
normalizeArguments = function(args) {
|
||||
var arg, l, match, result, _i, _j, _len, _len2, _ref;
|
||||
args = args.slice(0);
|
||||
@@ -108,4 +118,5 @@
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
}).call(this);
|
||||
670
lib/coffee-script/parser.js
Executable file
670
lib/coffee-script/parser.js
Executable file
File diff suppressed because one or more lines are too long
149
lib/coffee-script/repl.js
Normal file
149
lib/coffee-script/repl.js
Normal file
@@ -0,0 +1,149 @@
|
||||
(function() {
|
||||
var ACCESSOR, CoffeeScript, Module, REPL_PROMPT, REPL_PROMPT_CONTINUATION, SIMPLEVAR, Script, autocomplete, backlog, completeAttribute, completeVariable, enableColours, error, getCompletions, inspect, readline, repl, run, stdin, stdout;
|
||||
|
||||
CoffeeScript = require('./coffee-script');
|
||||
|
||||
readline = require('readline');
|
||||
|
||||
inspect = require('util').inspect;
|
||||
|
||||
Script = require('vm').Script;
|
||||
|
||||
Module = require('module');
|
||||
|
||||
REPL_PROMPT = 'coffee> ';
|
||||
|
||||
REPL_PROMPT_CONTINUATION = '......> ';
|
||||
|
||||
enableColours = false;
|
||||
|
||||
if (process.platform !== 'win32') {
|
||||
enableColours = !process.env.NODE_DISABLE_COLORS;
|
||||
}
|
||||
|
||||
stdin = process.openStdin();
|
||||
|
||||
stdout = process.stdout;
|
||||
|
||||
error = function(err) {
|
||||
return stdout.write((err.stack || err.toString()) + '\n');
|
||||
};
|
||||
|
||||
backlog = '';
|
||||
|
||||
run = function(buffer) {
|
||||
var code, returnValue, _;
|
||||
if (!buffer.toString().trim() && !backlog) {
|
||||
repl.prompt();
|
||||
return;
|
||||
}
|
||||
code = backlog += buffer;
|
||||
if (code[code.length - 1] === '\\') {
|
||||
backlog = "" + backlog.slice(0, -1) + "\n";
|
||||
repl.setPrompt(REPL_PROMPT_CONTINUATION);
|
||||
repl.prompt();
|
||||
return;
|
||||
}
|
||||
repl.setPrompt(REPL_PROMPT);
|
||||
backlog = '';
|
||||
try {
|
||||
_ = global._;
|
||||
returnValue = CoffeeScript.eval("_=(" + code + "\n)", {
|
||||
filename: 'repl',
|
||||
modulename: 'repl'
|
||||
});
|
||||
if (returnValue === void 0) global._ = _;
|
||||
process.stdout.write(inspect(returnValue, false, 2, enableColours) + '\n');
|
||||
} catch (err) {
|
||||
error(err);
|
||||
}
|
||||
return repl.prompt();
|
||||
};
|
||||
|
||||
ACCESSOR = /\s*([\w\.]+)(?:\.(\w*))$/;
|
||||
|
||||
SIMPLEVAR = /\s*(\w*)$/i;
|
||||
|
||||
autocomplete = function(text) {
|
||||
return completeAttribute(text) || completeVariable(text) || [[], text];
|
||||
};
|
||||
|
||||
completeAttribute = function(text) {
|
||||
var all, completions, match, obj, prefix, val;
|
||||
if (match = text.match(ACCESSOR)) {
|
||||
all = match[0], obj = match[1], prefix = match[2];
|
||||
try {
|
||||
val = Script.runInThisContext(obj);
|
||||
} catch (error) {
|
||||
return;
|
||||
}
|
||||
completions = getCompletions(prefix, Object.getOwnPropertyNames(val));
|
||||
return [completions, prefix];
|
||||
}
|
||||
};
|
||||
|
||||
completeVariable = function(text) {
|
||||
var completions, free, keywords, possibilities, r, vars, _ref;
|
||||
free = (_ref = text.match(SIMPLEVAR)) != null ? _ref[1] : void 0;
|
||||
if (free != null) {
|
||||
vars = Script.runInThisContext('Object.getOwnPropertyNames(this)');
|
||||
keywords = (function() {
|
||||
var _i, _len, _ref2, _results;
|
||||
_ref2 = CoffeeScript.RESERVED;
|
||||
_results = [];
|
||||
for (_i = 0, _len = _ref2.length; _i < _len; _i++) {
|
||||
r = _ref2[_i];
|
||||
if (r.slice(0, 2) !== '__') _results.push(r);
|
||||
}
|
||||
return _results;
|
||||
})();
|
||||
possibilities = vars.concat(keywords);
|
||||
completions = getCompletions(free, possibilities);
|
||||
return [completions, free];
|
||||
}
|
||||
};
|
||||
|
||||
getCompletions = function(prefix, candidates) {
|
||||
var el, _i, _len, _results;
|
||||
_results = [];
|
||||
for (_i = 0, _len = candidates.length; _i < _len; _i++) {
|
||||
el = candidates[_i];
|
||||
if (el.indexOf(prefix) === 0) _results.push(el);
|
||||
}
|
||||
return _results;
|
||||
};
|
||||
|
||||
process.on('uncaughtException', error);
|
||||
|
||||
if (readline.createInterface.length < 3) {
|
||||
repl = readline.createInterface(stdin, autocomplete);
|
||||
stdin.on('data', function(buffer) {
|
||||
return repl.write(buffer);
|
||||
});
|
||||
} else {
|
||||
repl = readline.createInterface(stdin, stdout, autocomplete);
|
||||
}
|
||||
|
||||
repl.on('attemptClose', function() {
|
||||
if (backlog) {
|
||||
backlog = '';
|
||||
process.stdout.write('\n');
|
||||
repl.setPrompt(REPL_PROMPT);
|
||||
return repl.prompt();
|
||||
} else {
|
||||
return repl.close();
|
||||
}
|
||||
});
|
||||
|
||||
repl.on('close', function() {
|
||||
process.stdout.write('\n');
|
||||
return stdin.destroy();
|
||||
});
|
||||
|
||||
repl.on('line', run);
|
||||
|
||||
repl.setPrompt(REPL_PROMPT);
|
||||
|
||||
repl.prompt();
|
||||
|
||||
}).call(this);
|
||||
@@ -1,13 +1,11 @@
|
||||
(function() {
|
||||
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;
|
||||
var __hasProp = Object.prototype.hasOwnProperty, __indexOf = Array.prototype.indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (__hasProp.call(this, i) && this[i] === item) return i; } return -1; }, __slice = Array.prototype.slice;
|
||||
|
||||
exports.Rewriter = (function() {
|
||||
|
||||
function Rewriter() {}
|
||||
|
||||
Rewriter.prototype.rewrite = function(tokens) {
|
||||
this.tokens = tokens;
|
||||
this.removeLeadingNewlines();
|
||||
@@ -18,10 +16,9 @@
|
||||
this.tagPostfixConditionals();
|
||||
this.addImplicitBraces();
|
||||
this.addImplicitParentheses();
|
||||
this.ensureBalance(BALANCED_PAIRS);
|
||||
this.rewriteClosingParens();
|
||||
return this.tokens;
|
||||
};
|
||||
|
||||
Rewriter.prototype.scanTokens = function(block) {
|
||||
var i, token, tokens;
|
||||
tokens = this.tokens;
|
||||
@@ -31,6 +28,7 @@
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
Rewriter.prototype.detectEnd = function(i, condition, action) {
|
||||
var levels, token, tokens, _ref, _ref2;
|
||||
tokens = this.tokens;
|
||||
@@ -39,9 +37,7 @@
|
||||
if (levels === 0 && condition.call(this, token, i)) {
|
||||
return action.call(this, token, i);
|
||||
}
|
||||
if (!token || levels < 0) {
|
||||
return action.call(this, token, i - 1);
|
||||
}
|
||||
if (!token || levels < 0) return action.call(this, token, i - 1);
|
||||
if (_ref = token[0], __indexOf.call(EXPRESSION_START, _ref) >= 0) {
|
||||
levels += 1;
|
||||
} else if (_ref2 = token[0], __indexOf.call(EXPRESSION_END, _ref2) >= 0) {
|
||||
@@ -51,19 +47,17 @@
|
||||
}
|
||||
return i - 1;
|
||||
};
|
||||
|
||||
Rewriter.prototype.removeLeadingNewlines = function() {
|
||||
var i, tag, _len, _ref;
|
||||
_ref = this.tokens;
|
||||
for (i = 0, _len = _ref.length; i < _len; i++) {
|
||||
tag = _ref[i][0];
|
||||
if (tag !== 'TERMINATOR') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i) {
|
||||
return this.tokens.splice(0, i);
|
||||
if (tag !== 'TERMINATOR') break;
|
||||
}
|
||||
if (i) return this.tokens.splice(0, i);
|
||||
};
|
||||
|
||||
Rewriter.prototype.removeMidExpressionNewlines = function() {
|
||||
return this.scanTokens(function(token, i, tokens) {
|
||||
var _ref;
|
||||
@@ -74,6 +68,7 @@
|
||||
return 0;
|
||||
});
|
||||
};
|
||||
|
||||
Rewriter.prototype.closeOpenCalls = function() {
|
||||
var action, condition;
|
||||
condition = function(token, i) {
|
||||
@@ -84,12 +79,11 @@
|
||||
return this.tokens[token[0] === 'OUTDENT' ? i - 1 : i][0] = 'CALL_END';
|
||||
};
|
||||
return this.scanTokens(function(token, i) {
|
||||
if (token[0] === 'CALL_START') {
|
||||
this.detectEnd(i + 1, condition, action);
|
||||
}
|
||||
if (token[0] === 'CALL_START') this.detectEnd(i + 1, condition, action);
|
||||
return 1;
|
||||
});
|
||||
};
|
||||
|
||||
Rewriter.prototype.closeOpenIndexes = function() {
|
||||
var action, condition;
|
||||
condition = function(token, i) {
|
||||
@@ -100,12 +94,11 @@
|
||||
return token[0] = 'INDEX_END';
|
||||
};
|
||||
return this.scanTokens(function(token, i) {
|
||||
if (token[0] === 'INDEX_START') {
|
||||
this.detectEnd(i + 1, condition, action);
|
||||
}
|
||||
if (token[0] === 'INDEX_START') this.detectEnd(i + 1, condition, action);
|
||||
return 1;
|
||||
});
|
||||
};
|
||||
|
||||
Rewriter.prototype.addImplicitBraces = function() {
|
||||
var action, condition, stack, start, startIndent;
|
||||
stack = [];
|
||||
@@ -113,10 +106,8 @@
|
||||
startIndent = 0;
|
||||
condition = function(token, i) {
|
||||
var one, tag, three, two, _ref, _ref2;
|
||||
_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;
|
||||
}
|
||||
_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'));
|
||||
};
|
||||
@@ -153,32 +144,24 @@
|
||||
return 2;
|
||||
});
|
||||
};
|
||||
|
||||
Rewriter.prototype.addImplicitParentheses = function() {
|
||||
var action, noCall;
|
||||
noCall = false;
|
||||
action = function(token, i) {
|
||||
var idx;
|
||||
idx = token[0] === 'OUTDENT' ? i + 1 : i;
|
||||
return this.tokens.splice(idx, 0, ['CALL_END', ')', token[2]]);
|
||||
return this.tokens.splice(i, 0, ['CALL_END', ')', token[2]]);
|
||||
};
|
||||
return this.scanTokens(function(token, i, tokens) {
|
||||
var callObject, current, next, prev, seenSingle, tag, _ref, _ref2, _ref3;
|
||||
var callObject, current, next, prev, seenControl, seenSingle, tag, _ref, _ref2, _ref3;
|
||||
tag = token[0];
|
||||
if (tag === 'CLASS' || tag === 'IF') {
|
||||
noCall = true;
|
||||
}
|
||||
_ref = tokens.slice(i - 1, (i + 1 + 1) || 9e9), prev = _ref[0], current = _ref[1], next = _ref[2];
|
||||
if (tag === 'CLASS' || tag === 'IF') noCall = true;
|
||||
_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;
|
||||
}
|
||||
if (prev && !prev.spaced && tag === '?') {
|
||||
token.call = true;
|
||||
}
|
||||
if (token.fromThen) {
|
||||
return 1;
|
||||
}
|
||||
seenControl = false;
|
||||
if (__indexOf.call(LINEBREAKS, tag) >= 0) noCall = false;
|
||||
if (prev && !prev.spaced && tag === '?') token.call = true;
|
||||
if (token.fromThen) return 1;
|
||||
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;
|
||||
}
|
||||
@@ -186,23 +169,23 @@
|
||||
this.detectEnd(i + 1, function(token, i) {
|
||||
var post, _ref4;
|
||||
tag = token[0];
|
||||
if (!seenSingle && token.fromThen) {
|
||||
return true;
|
||||
}
|
||||
if (tag === 'IF' || tag === 'ELSE' || tag === '->' || tag === '=>') {
|
||||
if (!seenSingle && token.fromThen) return true;
|
||||
if (tag === 'IF' || tag === 'ELSE' || tag === 'CATCH' || tag === '->' || tag === '=>') {
|
||||
seenSingle = true;
|
||||
}
|
||||
if (tag === 'IF' || tag === 'ELSE' || tag === 'SWITCH' || tag === 'TRY') {
|
||||
seenControl = true;
|
||||
}
|
||||
if ((tag === '.' || tag === '?.' || tag === '::') && this.tag(i - 1) === 'OUTDENT') {
|
||||
return true;
|
||||
}
|
||||
return !token.generated && this.tag(i - 1) !== ',' && __indexOf.call(IMPLICIT_END, tag) >= 0 && (tag !== 'INDENT' || (this.tag(i - 2) !== 'CLASS' && (_ref4 = this.tag(i - 1), __indexOf.call(IMPLICIT_BLOCK, _ref4) < 0) && !((post = this.tokens[i + 1]) && post.generated && post[0] === '{')));
|
||||
return !token.generated && this.tag(i - 1) !== ',' && (__indexOf.call(IMPLICIT_END, tag) >= 0 || (tag === 'INDENT' && !seenControl)) && (tag !== 'INDENT' || (this.tag(i - 2) !== 'CLASS' && (_ref4 = this.tag(i - 1), __indexOf.call(IMPLICIT_BLOCK, _ref4) < 0) && !((post = this.tokens[i + 1]) && post.generated && post[0] === '{')));
|
||||
}, action);
|
||||
if (prev[0] === '?') {
|
||||
prev[0] = 'FUNC_EXIST';
|
||||
}
|
||||
if (prev[0] === '?') prev[0] = 'FUNC_EXIST';
|
||||
return 2;
|
||||
});
|
||||
};
|
||||
|
||||
Rewriter.prototype.addImplicitIndentation = function() {
|
||||
return this.scanTokens(function(token, i, tokens) {
|
||||
var action, condition, indent, outdent, starter, tag, _ref, _ref2;
|
||||
@@ -222,9 +205,7 @@
|
||||
if (__indexOf.call(SINGLE_LINERS, tag) >= 0 && this.tag(i + 1) !== 'INDENT' && !(tag === 'ELSE' && this.tag(i + 1) === 'IF')) {
|
||||
starter = tag;
|
||||
_ref2 = this.indentation(token), indent = _ref2[0], outdent = _ref2[1];
|
||||
if (starter === 'THEN') {
|
||||
indent.fromThen = true;
|
||||
}
|
||||
if (starter === 'THEN') indent.fromThen = true;
|
||||
indent.generated = outdent.generated = true;
|
||||
tokens.splice(i + 1, 0, indent);
|
||||
condition = function(token, i) {
|
||||
@@ -235,14 +216,13 @@
|
||||
return this.tokens.splice((this.tag(i - 1) === ',' ? i - 1 : i), 0, outdent);
|
||||
};
|
||||
this.detectEnd(i + 2, condition, action);
|
||||
if (tag === 'THEN') {
|
||||
tokens.splice(i, 1);
|
||||
}
|
||||
if (tag === 'THEN') tokens.splice(i, 1);
|
||||
return 1;
|
||||
}
|
||||
return 1;
|
||||
});
|
||||
};
|
||||
|
||||
Rewriter.prototype.tagPostfixConditionals = function() {
|
||||
var condition;
|
||||
condition = function(token, i) {
|
||||
@@ -251,109 +231,58 @@
|
||||
};
|
||||
return this.scanTokens(function(token, i) {
|
||||
var original;
|
||||
if (token[0] !== 'IF') {
|
||||
return 1;
|
||||
}
|
||||
if (token[0] !== 'IF') return 1;
|
||||
original = token;
|
||||
this.detectEnd(i + 1, condition, function(token, i) {
|
||||
if (token[0] !== 'INDENT') {
|
||||
return original[0] = 'POST_' + original[0];
|
||||
}
|
||||
if (token[0] !== 'INDENT') return original[0] = 'POST_' + original[0];
|
||||
});
|
||||
return 1;
|
||||
});
|
||||
};
|
||||
Rewriter.prototype.ensureBalance = function(pairs) {
|
||||
var close, level, levels, open, openLine, tag, token, _i, _j, _len, _len2, _ref, _ref2;
|
||||
levels = {};
|
||||
openLine = {};
|
||||
_ref = this.tokens;
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
token = _ref[_i];
|
||||
tag = token[0];
|
||||
for (_j = 0, _len2 = pairs.length; _j < _len2; _j++) {
|
||||
_ref2 = pairs[_j], open = _ref2[0], close = _ref2[1];
|
||||
levels[open] |= 0;
|
||||
if (tag === open) {
|
||||
if (levels[open]++ === 0) {
|
||||
openLine[open] = token[2];
|
||||
}
|
||||
} else if (tag === close && --levels[open] < 0) {
|
||||
throw Error("too many " + token[1] + " on line " + (token[2] + 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
for (open in levels) {
|
||||
level = levels[open];
|
||||
if (level > 0) {
|
||||
throw Error("unclosed " + open + " on line " + (openLine[open] + 1));
|
||||
}
|
||||
}
|
||||
return this;
|
||||
};
|
||||
Rewriter.prototype.rewriteClosingParens = function() {
|
||||
var debt, key, stack;
|
||||
stack = [];
|
||||
debt = {};
|
||||
for (key in INVERSES) {
|
||||
debt[key] = 0;
|
||||
}
|
||||
return this.scanTokens(function(token, i, tokens) {
|
||||
var inv, match, mtag, oppos, tag, val, _ref;
|
||||
if (_ref = (tag = token[0]), __indexOf.call(EXPRESSION_START, _ref) >= 0) {
|
||||
stack.push(token);
|
||||
return 1;
|
||||
}
|
||||
if (__indexOf.call(EXPRESSION_END, tag) < 0) {
|
||||
return 1;
|
||||
}
|
||||
if (debt[inv = INVERSES[tag]] > 0) {
|
||||
debt[inv] -= 1;
|
||||
tokens.splice(i, 1);
|
||||
return 0;
|
||||
}
|
||||
match = stack.pop();
|
||||
mtag = match[0];
|
||||
oppos = INVERSES[mtag];
|
||||
if (tag === oppos) {
|
||||
return 1;
|
||||
}
|
||||
debt[mtag] += 1;
|
||||
val = [oppos, mtag === 'INDENT' ? match[1] : oppos];
|
||||
if (this.tag(i + 2) === mtag) {
|
||||
tokens.splice(i + 3, 0, val);
|
||||
stack.push(match);
|
||||
} else {
|
||||
tokens.splice(i, 0, val);
|
||||
}
|
||||
return 1;
|
||||
});
|
||||
};
|
||||
|
||||
Rewriter.prototype.indentation = function(token) {
|
||||
return [['INDENT', 2, token[2]], ['OUTDENT', 2, token[2]]];
|
||||
};
|
||||
|
||||
Rewriter.prototype.tag = function(i) {
|
||||
var _ref;
|
||||
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 = {};
|
||||
|
||||
exports.INVERSES = INVERSES = {};
|
||||
|
||||
EXPRESSION_START = [];
|
||||
|
||||
EXPRESSION_END = [];
|
||||
|
||||
for (_i = 0, _len = BALANCED_PAIRS.length; _i < _len; _i++) {
|
||||
_ref = BALANCED_PAIRS[_i], left = _ref[0], rite = _ref[1];
|
||||
EXPRESSION_START.push(INVERSES[rite] = left);
|
||||
EXPRESSION_END.push(INVERSES[left] = rite);
|
||||
}
|
||||
|
||||
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', 'TRY', 'SWITCH', 'THIS', 'BOOL', 'UNARY', 'SUPER', '@', '->', '=>', '[', '(', '{', '--', '++'];
|
||||
|
||||
IMPLICIT_UNSPACED_CALL = ['+', '-'];
|
||||
|
||||
IMPLICIT_BLOCK = ['->', '=>', '{', '[', ','];
|
||||
IMPLICIT_END = ['POST_IF', 'FOR', 'WHILE', 'UNTIL', 'WHEN', 'BY', 'LOOP', 'TERMINATOR', 'INDENT'];
|
||||
|
||||
IMPLICIT_END = ['POST_IF', 'FOR', 'WHILE', 'UNTIL', 'WHEN', 'BY', 'LOOP', 'TERMINATOR'];
|
||||
|
||||
SINGLE_LINERS = ['ELSE', '->', '=>', 'TRY', 'FINALLY', 'THEN'];
|
||||
|
||||
SINGLE_CLOSERS = ['TERMINATOR', 'CATCH', 'FINALLY', 'ELSE', 'OUTDENT', 'LEADING_WHEN'];
|
||||
|
||||
LINEBREAKS = ['TERMINATOR', 'INDENT', 'OUTDENT'];
|
||||
|
||||
}).call(this);
|
||||
@@ -1,8 +1,12 @@
|
||||
(function() {
|
||||
var Scope, extend, last, _ref;
|
||||
|
||||
_ref = require('./helpers'), extend = _ref.extend, last = _ref.last;
|
||||
|
||||
exports.Scope = Scope = (function() {
|
||||
|
||||
Scope.root = null;
|
||||
|
||||
function Scope(parent, expressions, method) {
|
||||
this.parent = parent;
|
||||
this.expressions = expressions;
|
||||
@@ -14,15 +18,12 @@
|
||||
}
|
||||
];
|
||||
this.positions = {};
|
||||
if (!this.parent) {
|
||||
Scope.root = this;
|
||||
}
|
||||
if (!this.parent) Scope.root = this;
|
||||
}
|
||||
|
||||
Scope.prototype.add = function(name, type, immediate) {
|
||||
var pos;
|
||||
if (this.shared && !immediate) {
|
||||
return this.parent.add(name, type, immediate);
|
||||
}
|
||||
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,27 +33,25 @@
|
||||
}) - 1;
|
||||
}
|
||||
};
|
||||
|
||||
Scope.prototype.find = function(name, options) {
|
||||
if (this.check(name, options)) {
|
||||
return true;
|
||||
}
|
||||
if (this.check(name, options)) return true;
|
||||
this.add(name, 'var');
|
||||
return false;
|
||||
};
|
||||
|
||||
Scope.prototype.parameter = function(name) {
|
||||
if (this.shared && this.parent.check(name, true)) {
|
||||
return;
|
||||
}
|
||||
if (this.shared && this.parent.check(name, true)) return;
|
||||
return this.add(name, 'param');
|
||||
};
|
||||
|
||||
Scope.prototype.check = function(name, immediate) {
|
||||
var found, _ref2;
|
||||
found = !!this.type(name);
|
||||
if (found || immediate) {
|
||||
return found;
|
||||
}
|
||||
if (found || immediate) return found;
|
||||
return !!((_ref2 = this.parent) != null ? _ref2.check(name) : void 0);
|
||||
};
|
||||
|
||||
Scope.prototype.temporary = function(name, index) {
|
||||
if (name.length > 1) {
|
||||
return '_' + name + (index > 1 ? index : '');
|
||||
@@ -60,17 +59,17 @@
|
||||
return '_' + (index + parseInt(name, 36)).toString(36).replace(/\d/g, 'a');
|
||||
}
|
||||
};
|
||||
|
||||
Scope.prototype.type = function(name) {
|
||||
var v, _i, _len, _ref2;
|
||||
_ref2 = this.variables;
|
||||
for (_i = 0, _len = _ref2.length; _i < _len; _i++) {
|
||||
v = _ref2[_i];
|
||||
if (v.name === name) {
|
||||
return v.type;
|
||||
}
|
||||
if (v.name === name) return v.type;
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
Scope.prototype.freeVariable = function(type) {
|
||||
var index, temp;
|
||||
index = 0;
|
||||
@@ -80,6 +79,7 @@
|
||||
this.add(temp, 'var', true);
|
||||
return temp;
|
||||
};
|
||||
|
||||
Scope.prototype.assign = function(name, value) {
|
||||
this.add(name, {
|
||||
value: value,
|
||||
@@ -87,9 +87,11 @@
|
||||
});
|
||||
return this.hasAssignments = true;
|
||||
};
|
||||
|
||||
Scope.prototype.hasDeclarations = function() {
|
||||
return !!this.declaredVariables().length;
|
||||
};
|
||||
|
||||
Scope.prototype.declaredVariables = function() {
|
||||
var realVars, tempVars, v, _i, _len, _ref2;
|
||||
realVars = [];
|
||||
@@ -103,18 +105,20 @@
|
||||
}
|
||||
return realVars.sort().concat(tempVars.sort());
|
||||
};
|
||||
|
||||
Scope.prototype.assignedVariables = function() {
|
||||
var v, _i, _len, _ref2, _results;
|
||||
_ref2 = this.variables;
|
||||
_results = [];
|
||||
for (_i = 0, _len = _ref2.length; _i < _len; _i++) {
|
||||
v = _ref2[_i];
|
||||
if (v.type.assigned) {
|
||||
_results.push("" + v.name + " = " + v.type.value);
|
||||
}
|
||||
if (v.type.assigned) _results.push("" + v.name + " = " + v.type.value);
|
||||
}
|
||||
return _results;
|
||||
};
|
||||
|
||||
return Scope;
|
||||
|
||||
})();
|
||||
|
||||
}).call(this);
|
||||
676
lib/parser.js
676
lib/parser.js
File diff suppressed because one or more lines are too long
114
lib/repl.js
114
lib/repl.js
@@ -1,114 +0,0 @@
|
||||
(function() {
|
||||
var ACCESSOR, CoffeeScript, SIMPLEVAR, Script, autocomplete, backlog, completeAttribute, completeVariable, enableColours, error, getCompletions, getPropertyNames, inspect, readline, repl, run, stdin, stdout;
|
||||
var __hasProp = Object.prototype.hasOwnProperty;
|
||||
CoffeeScript = require('./coffee-script');
|
||||
readline = require('readline');
|
||||
inspect = require('util').inspect;
|
||||
Script = require('vm').Script;
|
||||
enableColours = false;
|
||||
if (process.platform !== 'win32') {
|
||||
enableColours = !process.env.NODE_DISABLE_COLORS;
|
||||
}
|
||||
stdin = process.openStdin();
|
||||
stdout = process.stdout;
|
||||
error = function(err) {
|
||||
return stdout.write((err.stack || err.toString()) + '\n\n');
|
||||
};
|
||||
backlog = '';
|
||||
run = (function() {
|
||||
var g, sandbox;
|
||||
sandbox = {
|
||||
require: require,
|
||||
module: {
|
||||
exports: {}
|
||||
}
|
||||
};
|
||||
for (g in global) {
|
||||
sandbox[g] = global[g];
|
||||
}
|
||||
sandbox.global = sandbox;
|
||||
sandbox.global.global = sandbox.global.root = sandbox.global.GLOBAL = sandbox;
|
||||
return function(buffer) {
|
||||
var code, val;
|
||||
code = backlog += '\n' + buffer.toString();
|
||||
if (code[code.length - 1] === '\\') {
|
||||
return backlog = backlog.slice(0, backlog.length - 1);
|
||||
}
|
||||
backlog = '';
|
||||
try {
|
||||
val = CoffeeScript.eval(code, {
|
||||
sandbox: sandbox,
|
||||
bare: true,
|
||||
filename: 'repl'
|
||||
});
|
||||
if (val !== void 0) {
|
||||
process.stdout.write(inspect(val, false, 2, enableColours) + '\n');
|
||||
}
|
||||
} catch (err) {
|
||||
error(err);
|
||||
}
|
||||
return repl.prompt();
|
||||
};
|
||||
})();
|
||||
ACCESSOR = /\s*([\w\.]+)(?:\.(\w*))$/;
|
||||
SIMPLEVAR = /\s*(\w*)$/i;
|
||||
autocomplete = function(text) {
|
||||
return completeAttribute(text) || completeVariable(text) || [[], text];
|
||||
};
|
||||
completeAttribute = function(text) {
|
||||
var all, completions, match, obj, prefix, val;
|
||||
if (match = text.match(ACCESSOR)) {
|
||||
all = match[0], obj = match[1], prefix = match[2];
|
||||
try {
|
||||
val = Script.runInThisContext(obj);
|
||||
} catch (error) {
|
||||
return [[], text];
|
||||
}
|
||||
completions = getCompletions(prefix, getPropertyNames(val));
|
||||
return [completions, prefix];
|
||||
}
|
||||
};
|
||||
completeVariable = function(text) {
|
||||
var completions, free, scope, _ref;
|
||||
if (free = (_ref = text.match(SIMPLEVAR)) != null ? _ref[1] : void 0) {
|
||||
scope = Script.runInThisContext('this');
|
||||
completions = getCompletions(free, CoffeeScript.RESERVED.concat(getPropertyNames(scope)));
|
||||
return [completions, free];
|
||||
}
|
||||
};
|
||||
getCompletions = function(prefix, candidates) {
|
||||
var el, _i, _len, _results;
|
||||
_results = [];
|
||||
for (_i = 0, _len = candidates.length; _i < _len; _i++) {
|
||||
el = candidates[_i];
|
||||
if (el.indexOf(prefix) === 0) {
|
||||
_results.push(el);
|
||||
}
|
||||
}
|
||||
return _results;
|
||||
};
|
||||
getPropertyNames = function(obj) {
|
||||
var name, _results;
|
||||
_results = [];
|
||||
for (name in obj) {
|
||||
if (!__hasProp.call(obj, name)) continue;
|
||||
_results.push(name);
|
||||
}
|
||||
return _results;
|
||||
};
|
||||
process.on('uncaughtException', error);
|
||||
if (readline.createInterface.length < 3) {
|
||||
repl = readline.createInterface(stdin, autocomplete);
|
||||
stdin.on('data', function(buffer) {
|
||||
return repl.write(buffer);
|
||||
});
|
||||
} else {
|
||||
repl = readline.createInterface(stdin, stdout, autocomplete);
|
||||
}
|
||||
repl.setPrompt('coffee> ');
|
||||
repl.on('close', function() {
|
||||
return stdin.destroy();
|
||||
});
|
||||
repl.on('line', run);
|
||||
repl.prompt();
|
||||
}).call(this);
|
||||
12
package.json
12
package.json
@@ -3,18 +3,18 @@
|
||||
"description": "Unfancy JavaScript",
|
||||
"keywords": ["javascript", "language", "coffeescript", "compiler"],
|
||||
"author": "Jeremy Ashkenas",
|
||||
"version": "1.1.1",
|
||||
"version": "1.1.3",
|
||||
"licenses": [{
|
||||
"type": "MIT",
|
||||
"url": "http://github.com/jashkenas/coffee-script/raw/master/LICENSE"
|
||||
}],
|
||||
"engines": {
|
||||
"node": ">=0.2.5"
|
||||
"node": ">=0.4.0"
|
||||
},
|
||||
"directories" : {
|
||||
"lib" : "./lib"
|
||||
"lib" : "./lib/coffee-script"
|
||||
},
|
||||
"main" : "./lib/coffee-script",
|
||||
"main" : "./lib/coffee-script/coffee-script",
|
||||
"bin": {
|
||||
"coffee": "./bin/coffee",
|
||||
"cake": "./bin/cake"
|
||||
@@ -23,5 +23,9 @@
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/jashkenas/coffee-script.git"
|
||||
},
|
||||
"devDependencies": {
|
||||
"uglify-js": "1.0.6",
|
||||
"jison": "0.2.11"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,10 +23,10 @@ CoffeeScript.load = (url, callback) ->
|
||||
xhr.onreadystatechange = ->
|
||||
if xhr.readyState is 4
|
||||
if xhr.status in [0, 200]
|
||||
CoffeeScript.run xhr.responseText
|
||||
CoffeeScript.run xhr.responseText
|
||||
else
|
||||
throw new Error "Could not load #{url}"
|
||||
callback() if callback
|
||||
callback() if callback
|
||||
xhr.send null
|
||||
|
||||
# Activate CoffeeScript in the browser by having it compile and evaluate
|
||||
|
||||
@@ -39,19 +39,19 @@ helpers.extend global,
|
||||
missingTask name unless tasks[name]
|
||||
tasks[name].action options
|
||||
|
||||
|
||||
# Run `cake`. Executes all of the tasks you pass, in order. Note that Node's
|
||||
# asynchrony may cause tasks to execute in a different order than you'd expect.
|
||||
# If no tasks are passed, print the help screen.
|
||||
# If no tasks are passed, print the help screen. Keep a reference to the
|
||||
# original directory name, when running Cake tasks from subdirectories.
|
||||
exports.run = ->
|
||||
path.exists 'Cakefile', (exists) ->
|
||||
throw new Error("Cakefile not found in #{process.cwd()}") unless exists
|
||||
args = process.argv.slice 2
|
||||
CoffeeScript.run fs.readFileSync('Cakefile').toString(), filename: 'Cakefile'
|
||||
oparse = new optparse.OptionParser switches
|
||||
return printTasks() unless args.length
|
||||
options = oparse.parse(args)
|
||||
invoke arg for arg in options.arguments
|
||||
global.__originalDirname = fs.realpathSync '.'
|
||||
process.chdir cakefileDirectory __originalDirname
|
||||
args = process.argv.slice 2
|
||||
CoffeeScript.run fs.readFileSync('Cakefile').toString(), filename: 'Cakefile'
|
||||
oparse = new optparse.OptionParser switches
|
||||
return printTasks() unless args.length
|
||||
options = oparse.parse(args)
|
||||
invoke arg for arg in options.arguments
|
||||
|
||||
# Display the list of Cake tasks in a format similar to `rake -T`
|
||||
printTasks = ->
|
||||
@@ -63,7 +63,15 @@ printTasks = ->
|
||||
console.log "cake #{name}#{spaces} #{desc}"
|
||||
console.log oparse.help() if switches.length
|
||||
|
||||
# Print an error and exit when attempting to all an undefined task.
|
||||
# Print an error and exit when attempting to call an undefined task.
|
||||
missingTask = (task) ->
|
||||
console.log "No such task: \"#{task}\""
|
||||
process.exit 1
|
||||
|
||||
# When `cake` is invoked, search in the current and all parent directories
|
||||
# to find the relevant Cakefile.
|
||||
cakefileDirectory = (dir) ->
|
||||
return dir if path.existsSync path.join dir, 'Cakefile'
|
||||
parent = path.normalize path.join dir, '..'
|
||||
return cakefileDirectory parent unless parent is dir
|
||||
throw new Error "Cakefile not found in #{process.cwd()}"
|
||||
|
||||
67
src/coffee-script.coffee
Executable file → Normal file
67
src/coffee-script.coffee
Executable file → Normal file
@@ -8,9 +8,9 @@
|
||||
|
||||
fs = require 'fs'
|
||||
path = require 'path'
|
||||
vm = require 'vm'
|
||||
{Lexer,RESERVED} = require './lexer'
|
||||
{parser} = require './parser'
|
||||
vm = require 'vm'
|
||||
|
||||
# TODO: Remove registerExtension when fully deprecated.
|
||||
if require.extensions
|
||||
@@ -21,7 +21,7 @@ else if require.registerExtension
|
||||
require.registerExtension '.coffee', (content) -> compile content
|
||||
|
||||
# The current CoffeeScript version number.
|
||||
exports.VERSION = '1.1.1'
|
||||
exports.VERSION = '1.1.3'
|
||||
|
||||
# Words that cannot be used as identifiers in CoffeeScript code
|
||||
exports.RESERVED = RESERVED
|
||||
@@ -54,44 +54,59 @@ exports.nodes = (source, options) ->
|
||||
# Compile and execute a string of CoffeeScript (on the server), correctly
|
||||
# setting `__filename`, `__dirname`, and relative `require()`.
|
||||
exports.run = (code, options) ->
|
||||
# We want the root module.
|
||||
root = module
|
||||
while root.parent
|
||||
root = root.parent
|
||||
mainModule = require.main
|
||||
|
||||
# Set the filename.
|
||||
root.filename = process.argv[1] =
|
||||
mainModule.filename = process.argv[1] =
|
||||
if options.filename then fs.realpathSync(options.filename) else '.'
|
||||
|
||||
# Clear the module cache.
|
||||
root.moduleCache = {} if root.moduleCache
|
||||
mainModule.moduleCache and= {}
|
||||
|
||||
# Assign paths for node_modules loading
|
||||
if process.binding('natives').module
|
||||
{Module} = require 'module'
|
||||
root.paths = Module._nodeModulePaths path.dirname options.filename
|
||||
mainModule.paths = require('module')._nodeModulePaths path.dirname options.filename
|
||||
|
||||
# Compile.
|
||||
if path.extname(root.filename) isnt '.coffee' or require.extensions
|
||||
root._compile compile(code, options), root.filename
|
||||
if path.extname(mainModule.filename) isnt '.coffee' or require.extensions
|
||||
mainModule._compile compile(code, options), mainModule.filename
|
||||
else
|
||||
root._compile code, root.filename
|
||||
mainModule._compile code, mainModule.filename
|
||||
|
||||
# Compile and evaluate a string of CoffeeScript (in a Node.js-like environment).
|
||||
# The CoffeeScript REPL uses this to run the input.
|
||||
exports.eval = (code, options = {}) ->
|
||||
sandbox = options.sandbox
|
||||
unless sandbox
|
||||
sandbox =
|
||||
require: require
|
||||
module : { exports: {} }
|
||||
sandbox[g] = global[g] for g of global
|
||||
sandbox.global = sandbox
|
||||
sandbox.global.global = sandbox.global.root = sandbox.global.GLOBAL = sandbox
|
||||
sandbox.__filename = options.filename || 'eval'
|
||||
sandbox.__dirname = path.dirname sandbox.__filename
|
||||
js = compile "_=(#{code.trim()})", options
|
||||
vm.runInNewContext js, sandbox, sandbox.__filename
|
||||
return unless code = code.trim()
|
||||
Script = vm.Script
|
||||
if Script
|
||||
if options.sandbox?
|
||||
if options.sandbox instanceof Script.createContext().constructor
|
||||
sandbox = options.sandbox
|
||||
else
|
||||
sandbox = Script.createContext()
|
||||
sandbox[k] = v for own k, v of options.sandbox
|
||||
sandbox.global = sandbox.root = sandbox.GLOBAL = sandbox
|
||||
else
|
||||
sandbox = global
|
||||
sandbox.__filename = options.filename || 'eval'
|
||||
sandbox.__dirname = path.dirname sandbox.__filename
|
||||
# define module/require only if they chose not to specify their own
|
||||
unless sandbox isnt global or sandbox.module or sandbox.require
|
||||
Module = require 'module'
|
||||
sandbox.module = _module = new Module(options.modulename || 'eval')
|
||||
sandbox.require = _require = (path) -> Module._load path, _module, true
|
||||
_module.filename = sandbox.__filename
|
||||
_require[r] = require[r] for r in Object.getOwnPropertyNames require when r isnt 'paths'
|
||||
# use the same hack node currently uses for their own REPL
|
||||
_require.paths = _module.paths = Module._nodeModulePaths process.cwd()
|
||||
_require.resolve = (request) -> Module._resolveFilename request, _module
|
||||
o = {}
|
||||
o[k] = v for own k, v of options
|
||||
o.bare = on # ensure return value
|
||||
js = compile code, o
|
||||
if sandbox is global
|
||||
vm.runInThisContext js
|
||||
else
|
||||
vm.runInContext js, sandbox
|
||||
|
||||
# Instantiate a Lexer for our use here.
|
||||
lexer = new Lexer
|
||||
|
||||
@@ -17,31 +17,33 @@ CoffeeScript = require './coffee-script'
|
||||
helpers.extend CoffeeScript, new EventEmitter
|
||||
|
||||
printLine = (line) -> process.stdout.write line + '\n'
|
||||
printWarn = (line) -> process.binding('stdio').writeError line + '\n'
|
||||
printWarn = (line) -> process.stderr.write line + '\n'
|
||||
|
||||
# The help banner that is printed when `coffee` is called without arguments.
|
||||
BANNER = '''
|
||||
Usage: coffee [options] path/to/script.coffee
|
||||
|
||||
If called without options, `coffee` will run your script.
|
||||
'''
|
||||
|
||||
# The list of all the valid option flags that `coffee` knows how to handle.
|
||||
SWITCHES = [
|
||||
['-b', '--bare', 'compile without a top-level function wrapper']
|
||||
['-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 [FILE]', '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 JavaScript Lint']
|
||||
['-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']
|
||||
['-e', '--eval', 'pass a string from the command line as input']
|
||||
['-h', '--help', 'display this help message']
|
||||
['-i', '--interactive', 'run an interactive CoffeeScript REPL']
|
||||
['-j', '--join [FILE]', 'concatenate the source CoffeeScript before compiling']
|
||||
['-l', '--lint', 'pipe the compiled JavaScript through JavaScript Lint']
|
||||
['-n', '--nodes', 'print out the parse tree that the parser produces']
|
||||
[ '--nodejs [ARGS]', 'pass options directly to the "node" binary']
|
||||
['-o', '--output [DIR]', 'set the output directory for compiled JavaScript']
|
||||
['-p', '--print', 'print out the compiled JavaScript']
|
||||
['-r', '--require [FILE*]', 'require a library before executing your script']
|
||||
['-s', '--stdio', 'listen for and compile scripts over stdio']
|
||||
['-t', '--tokens', 'print out the tokens that the lexer/rewriter produce']
|
||||
['-v', '--version', 'display the version number']
|
||||
['-w', '--watch', 'watch scripts for changes and rerun commands']
|
||||
]
|
||||
|
||||
# Top-level objects shared by all the functions.
|
||||
@@ -65,7 +67,7 @@ exports.run = ->
|
||||
return require './repl' unless sources.length
|
||||
if opts.run
|
||||
opts.literals = sources.splice(1).concat opts.literals
|
||||
process.ARGV = process.argv = process.argv.slice(0, 2).concat opts.literals
|
||||
process.argv = process.argv.slice(0, 2).concat opts.literals
|
||||
process.argv[0] = 'coffee'
|
||||
process.execPath = require.main.filename
|
||||
compileScripts()
|
||||
@@ -74,26 +76,49 @@ exports.run = ->
|
||||
# compile them. If a directory is passed, recursively compile all
|
||||
# '.coffee' extension source files in it and all subdirectories.
|
||||
compileScripts = ->
|
||||
unprocessed = []
|
||||
remaining_files = ->
|
||||
total = 0
|
||||
total += x for x in unprocessed
|
||||
total
|
||||
trackUnprocessedFiles = (sourceIndex, fileCount) ->
|
||||
unprocessed[sourceIndex] ?= 0
|
||||
unprocessed[sourceIndex] += fileCount
|
||||
trackCompleteFiles = (sourceIndex, fileCount) ->
|
||||
unprocessed[sourceIndex] -= fileCount
|
||||
if opts.join
|
||||
if helpers.compact(contents).length > 0 and remaining_files() == 0
|
||||
compileJoin()
|
||||
for source in sources
|
||||
trackUnprocessedFiles sources.indexOf(source), 1
|
||||
for source in sources
|
||||
base = path.join(source)
|
||||
compile = (source, topLevel) ->
|
||||
compile = (source, sourceIndex, topLevel) ->
|
||||
path.exists source, (exists) ->
|
||||
if topLevel and not exists and source[-7..] isnt '.coffee'
|
||||
return compile "#{source}.coffee", sourceIndex, topLevel
|
||||
throw new Error "File not found: #{source}" if topLevel and not exists
|
||||
fs.stat source, (err, stats) ->
|
||||
throw err if err
|
||||
if stats.isDirectory()
|
||||
fs.readdir source, (err, files) ->
|
||||
throw err if err
|
||||
trackUnprocessedFiles sourceIndex, files.length
|
||||
for file in files
|
||||
compile path.join(source, file)
|
||||
compile path.join(source, file), sourceIndex
|
||||
trackCompleteFiles sourceIndex, 1
|
||||
else if topLevel or path.extname(source) is '.coffee'
|
||||
fs.readFile source, (err, code) ->
|
||||
throw err if err
|
||||
if opts.join
|
||||
contents[sources.indexOf source] = code.toString()
|
||||
compileJoin() if helpers.compact(contents).length > 0
|
||||
contents[sourceIndex] = helpers.compact([contents[sourceIndex], code.toString()]).join('\n')
|
||||
else
|
||||
compileScript(source, code.toString(), base)
|
||||
trackCompleteFiles sourceIndex, 1
|
||||
watch source, base if opts.watch and not opts.join
|
||||
compile source, true
|
||||
else
|
||||
trackCompleteFiles sourceIndex, 1
|
||||
compile source, sources.indexOf(source), true
|
||||
|
||||
# Compile a single source script, containing the given code, according to the
|
||||
# requested options. If evaluating the script directly sets `__filename`,
|
||||
@@ -117,7 +142,7 @@ compileScript = (file, input, base) ->
|
||||
CoffeeScript.emit 'failure', err, task
|
||||
return if CoffeeScript.listeners('failure').length
|
||||
return printLine err.message if o.watch
|
||||
printWarn err.stack
|
||||
printWarn err instanceof Error and err.stack or "ERROR: #{err}"
|
||||
process.exit 1
|
||||
|
||||
# Attach the appropriate listeners to compile scripts incoming over **stdin**,
|
||||
@@ -143,15 +168,22 @@ loadRequires = ->
|
||||
require req for req in opts.require
|
||||
module.filename = realFilename
|
||||
|
||||
# Watch a source CoffeeScript file using `fs.watchFile`, recompiling it every
|
||||
# Watch a source CoffeeScript file using `fs.watch`, recompiling it every
|
||||
# time the file is updated. May be used in combination with other options,
|
||||
# such as `--lint` or `--print`.
|
||||
watch = (source, base) ->
|
||||
fs.watchFile source, {persistent: true, interval: 500}, (curr, prev) ->
|
||||
return if curr.size is prev.size and curr.mtime.getTime() is prev.mtime.getTime()
|
||||
fs.readFile source, (err, code) ->
|
||||
throw err if err
|
||||
compileScript(source, code.toString(), base)
|
||||
fs.stat source, (err, prevStats)->
|
||||
throw err if err
|
||||
fs.watch source, (event) ->
|
||||
if event is 'change'
|
||||
fs.stat source, (err, stats) ->
|
||||
throw err if err
|
||||
return if stats.size is prevStats.size and
|
||||
stats.mtime.getTime() is prevStats.mtime.getTime()
|
||||
prevStats = stats
|
||||
fs.readFile source, (err, code) ->
|
||||
throw err if err
|
||||
compileScript(source, code.toString(), base)
|
||||
|
||||
# Write out a JavaScript source file with the compiled code. By default, files
|
||||
# are written out in `cwd` as `.js` files with the same name, but the output
|
||||
@@ -176,7 +208,7 @@ writeJs = (source, js, base) ->
|
||||
# any errors or warnings that arise.
|
||||
lint = (file, js) ->
|
||||
printIt = (buffer) -> printLine file + ':\t' + buffer.toString().trim()
|
||||
conf = __dirname + '/../extras/jsl.conf'
|
||||
conf = __dirname + '/../../extras/jsl.conf'
|
||||
jsl = spawn 'jsl', ['-nologo', '-stdin', '-conf', conf]
|
||||
jsl.stdout.on 'data', printIt
|
||||
jsl.stderr.on 'data', printIt
|
||||
|
||||
@@ -84,7 +84,7 @@ grammar =
|
||||
|
||||
# All the different types of expressions in our language. The basic unit of
|
||||
# CoffeeScript is the **Expression** -- everything that can be an expression
|
||||
# is one. Block serve as the building blocks of many other rules, making
|
||||
# is one. Blocks serve as the building blocks of many other rules, making
|
||||
# them somewhat circular.
|
||||
Expression: [
|
||||
o 'Value'
|
||||
@@ -120,7 +120,7 @@ grammar =
|
||||
o 'STRING', -> new Literal $1
|
||||
]
|
||||
|
||||
# All of our immediate values. These can (in general), be passed straight
|
||||
# All of our immediate values. Generally these can be passed straight
|
||||
# through and printed to JavaScript.
|
||||
Literal: [
|
||||
o 'AlphaNumeric'
|
||||
@@ -201,6 +201,7 @@ grammar =
|
||||
o 'ParamVar = Expression', -> new Param $1, $3
|
||||
]
|
||||
|
||||
# Function Parameters
|
||||
ParamVar: [
|
||||
o 'Identifier'
|
||||
o 'ThisProperty'
|
||||
@@ -216,7 +217,7 @@ grammar =
|
||||
# Variables and properties that can be assigned to.
|
||||
SimpleAssignable: [
|
||||
o 'Identifier', -> new Value $1
|
||||
o 'Value Accessor', -> $1.push $2
|
||||
o 'Value Accessor', -> $1.add $2
|
||||
o 'Invocation Accessor', -> new Value $1, [$2]
|
||||
o 'ThisProperty'
|
||||
]
|
||||
@@ -243,7 +244,7 @@ grammar =
|
||||
Accessor: [
|
||||
o '. Identifier', -> new Access $2
|
||||
o '?. Identifier', -> new Access $2, 'soak'
|
||||
o ':: Identifier', -> new Access $2, 'proto'
|
||||
o ':: Identifier', -> [(new Access new Literal 'prototype'), new Access $2]
|
||||
o '::', -> new Access new Literal 'prototype'
|
||||
o 'Index'
|
||||
]
|
||||
@@ -252,9 +253,8 @@ grammar =
|
||||
Index: [
|
||||
o 'INDEX_START IndexValue INDEX_END', -> $2
|
||||
o 'INDEX_SOAK Index', -> extend $2, soak : yes
|
||||
o 'INDEX_PROTO Index', -> extend $2, proto: yes
|
||||
]
|
||||
|
||||
|
||||
IndexValue: [
|
||||
o 'Expression', -> new Index $1
|
||||
o 'Slice', -> new Slice $1
|
||||
@@ -278,14 +278,14 @@ grammar =
|
||||
# Class definitions have optional bodies of prototype property assignments,
|
||||
# and optional references to the superclass.
|
||||
Class: [
|
||||
o 'CLASS', -> new Class
|
||||
o 'CLASS Block', -> new Class null, null, $2
|
||||
o 'CLASS EXTENDS Value', -> new Class null, $3
|
||||
o 'CLASS EXTENDS Value Block', -> new Class null, $3, $4
|
||||
o 'CLASS SimpleAssignable', -> new Class $2
|
||||
o 'CLASS SimpleAssignable Block', -> new Class $2, null, $3
|
||||
o 'CLASS SimpleAssignable EXTENDS Value', -> new Class $2, $4
|
||||
o 'CLASS SimpleAssignable EXTENDS Value Block', -> new Class $2, $4, $5
|
||||
o 'CLASS', -> new Class
|
||||
o 'CLASS Block', -> new Class null, null, $2
|
||||
o 'CLASS EXTENDS Expression', -> new Class null, $3
|
||||
o 'CLASS EXTENDS Expression Block', -> new Class null, $3, $4
|
||||
o 'CLASS SimpleAssignable', -> new Class $2
|
||||
o 'CLASS SimpleAssignable Block', -> new Class $2, null, $3
|
||||
o 'CLASS SimpleAssignable EXTENDS Expression', -> new Class $2, $4
|
||||
o 'CLASS SimpleAssignable EXTENDS Expression Block', -> new Class $2, $4, $5
|
||||
]
|
||||
|
||||
# Ordinary function invocation, or a chained series of calls.
|
||||
@@ -354,7 +354,7 @@ grammar =
|
||||
o 'ArgList OptComma INDENT ArgList OptComma OUTDENT', -> $1.concat $4
|
||||
]
|
||||
|
||||
# Valid arguments are Block or Splats.
|
||||
# Valid arguments are Blocks or Splats.
|
||||
Arg: [
|
||||
o 'Expression'
|
||||
o 'Splat'
|
||||
@@ -573,7 +573,7 @@ operators = [
|
||||
# Wrapping Up
|
||||
# -----------
|
||||
|
||||
# Finally, now what we have our **grammar** and our **operators**, we can create
|
||||
# Finally, now that we have our **grammar** and our **operators**, we can create
|
||||
# our **Jison.Parser**. 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".
|
||||
|
||||
110
src/lexer.coffee
110
src/lexer.coffee
@@ -7,7 +7,7 @@
|
||||
#
|
||||
# Which is a format that can be fed directly into [Jison](http://github.com/zaach/jison).
|
||||
|
||||
{Rewriter} = require './rewriter'
|
||||
{Rewriter, INVERSES} = require './rewriter'
|
||||
|
||||
# Import the helpers we need.
|
||||
{count, starts, compact, last} = require './helpers'
|
||||
@@ -41,6 +41,7 @@ exports.Lexer = class Lexer
|
||||
@indebt = 0 # The over-indentation at the current level.
|
||||
@outdebt = 0 # The under-outdentation at the current level.
|
||||
@indents = [] # The stack of all current indentation levels.
|
||||
@ends = [] # The stack for pairing up tokens.
|
||||
@tokens = [] # Stream of parsed tokens in the form `['TYPE', value, line]`.
|
||||
|
||||
# At every position, run through this list of attempted matches,
|
||||
@@ -60,6 +61,7 @@ exports.Lexer = class Lexer
|
||||
@literalToken()
|
||||
|
||||
@closeIndentation()
|
||||
@error "missing #{tag}" if tag = @ends.pop()
|
||||
return @tokens if opts.rewrite is off
|
||||
(new Rewriter).rewrite @tokens
|
||||
|
||||
@@ -84,8 +86,7 @@ exports.Lexer = class Lexer
|
||||
not prev.spaced and prev[0] is '@')
|
||||
tag = 'IDENTIFIER'
|
||||
|
||||
if id in JS_KEYWORDS or
|
||||
not forcedIdentifier and id in COFFEE_KEYWORDS
|
||||
if not forcedIdentifier and (id in JS_KEYWORDS or id in COFFEE_KEYWORDS)
|
||||
tag = id.toUpperCase()
|
||||
if tag is 'WHEN' and @tag() in LINE_BREAK
|
||||
tag = 'LEADING_WHEN'
|
||||
@@ -105,13 +106,13 @@ exports.Lexer = class Lexer
|
||||
@tokens.pop()
|
||||
id = '!' + id
|
||||
|
||||
if id in JS_FORBIDDEN
|
||||
if id in ['eval', 'arguments'].concat JS_FORBIDDEN
|
||||
if forcedIdentifier
|
||||
tag = 'IDENTIFIER'
|
||||
id = new String id
|
||||
id.reserved = yes
|
||||
else if id in RESERVED
|
||||
@identifierError id
|
||||
@error "reserved word \"#{word}\""
|
||||
|
||||
unless forcedIdentifier
|
||||
id = COFFEE_ALIAS_MAP[id] if id in COFFEE_ALIASES
|
||||
@@ -132,8 +133,11 @@ exports.Lexer = class Lexer
|
||||
numberToken: ->
|
||||
return 0 unless match = NUMBER.exec @chunk
|
||||
number = match[0]
|
||||
lexedLength = number.length
|
||||
if binaryLiteral = /0b([01]+)/.exec number
|
||||
number = (parseInt binaryLiteral[1], 2).toString()
|
||||
@token 'NUMBER', number
|
||||
number.length
|
||||
lexedLength
|
||||
|
||||
# Matches strings, including multi-line strings. Ensures that quotation marks
|
||||
# are balanced within the string's contents, and within nested interpolations.
|
||||
@@ -189,19 +193,26 @@ exports.Lexer = class Lexer
|
||||
# JavaScript and Ruby.
|
||||
regexToken: ->
|
||||
return 0 if @chunk.charAt(0) isnt '/'
|
||||
return @heregexToken match if match = HEREGEX.exec @chunk
|
||||
if match = HEREGEX.exec @chunk
|
||||
length = @heregexToken match
|
||||
@line += count match[0], '\n'
|
||||
return length
|
||||
|
||||
prev = last @tokens
|
||||
return 0 if prev and (prev[0] in (if prev.spaced then NOT_REGEX else NOT_SPACED_REGEX))
|
||||
return 0 unless match = REGEX.exec @chunk
|
||||
[regex] = match
|
||||
@token 'REGEX', if regex is '//' then '/(?:)/' else regex
|
||||
regex.length
|
||||
[match, regex, flags] = match
|
||||
if regex[..1] is '/*' then @error 'regular expressions cannot begin with `*`'
|
||||
if regex is '//' then regex = '/(?:)/'
|
||||
@token 'REGEX', "#{regex}#{flags}"
|
||||
match.length
|
||||
|
||||
# Matches multiline extended regular expressions.
|
||||
heregexToken: (match) ->
|
||||
[heregex, body, flags] = match
|
||||
if 0 > body.indexOf '#{'
|
||||
re = body.replace(HEREGEX_OMIT, '').replace(/\//g, '\\/')
|
||||
if re.match /^\*/ then @error 'regular expressions cannot begin with `*`'
|
||||
@token 'REGEX', "/#{ re or '(?:)' }/#{flags}"
|
||||
return heregex.length
|
||||
@token 'IDENTIFIER', 'RegExp'
|
||||
@@ -236,6 +247,7 @@ exports.Lexer = class Lexer
|
||||
return 0 unless match = MULTI_DENT.exec @chunk
|
||||
indent = match[0]
|
||||
@line += count indent, '\n'
|
||||
@seenFor = no
|
||||
prev = last @tokens, 1
|
||||
size = indent.length - 1 - indent.lastIndexOf '\n'
|
||||
noNewlines = @unfinished()
|
||||
@@ -250,6 +262,7 @@ exports.Lexer = class Lexer
|
||||
diff = size - @indent + @outdebt
|
||||
@token 'INDENT', diff
|
||||
@indents.push diff
|
||||
@ends .push 'OUTDENT'
|
||||
@outdebt = @indebt = 0
|
||||
else
|
||||
@indebt = 0
|
||||
@@ -259,7 +272,7 @@ exports.Lexer = class Lexer
|
||||
|
||||
# Record an outdent token or multiple tokens, if we happen to be moving back
|
||||
# inwards past several recorded indents.
|
||||
outdentToken: (moveOut, noNewlines, close) ->
|
||||
outdentToken: (moveOut, noNewlines) ->
|
||||
while moveOut > 0
|
||||
len = @indents.length - 1
|
||||
if @indents[len] is undefined
|
||||
@@ -274,8 +287,10 @@ exports.Lexer = class Lexer
|
||||
dent = @indents.pop() - @outdebt
|
||||
moveOut -= dent
|
||||
@outdebt = 0
|
||||
@pair 'OUTDENT'
|
||||
@token 'OUTDENT', dent
|
||||
@outdebt -= moveOut if dent
|
||||
@tokens.pop() while @value() is ';'
|
||||
@token 'TERMINATOR', '\n' unless @tag() is 'TERMINATOR' or noNewlines
|
||||
this
|
||||
|
||||
@@ -290,6 +305,7 @@ exports.Lexer = class Lexer
|
||||
|
||||
# Generate a newline token. Consecutive newlines get merged together.
|
||||
newlineToken: ->
|
||||
@tokens.pop() while @value() is ';'
|
||||
@token 'TERMINATOR', '\n' unless @tag() is 'TERMINATOR'
|
||||
this
|
||||
|
||||
@@ -313,12 +329,15 @@ exports.Lexer = class Lexer
|
||||
tag = value
|
||||
prev = last @tokens
|
||||
if value is '=' and prev
|
||||
@assignmentError() if not prev[1].reserved and prev[1] in JS_FORBIDDEN
|
||||
if not prev[1].reserved and prev[1] in JS_FORBIDDEN
|
||||
@error "reserved word \"#{@value()}\" can't be assigned"
|
||||
if prev[1] in ['||', '&&']
|
||||
prev[0] = 'COMPOUND_ASSIGN'
|
||||
prev[1] += '='
|
||||
return value.length
|
||||
if value is ';' then tag = 'TERMINATOR'
|
||||
if value is ';'
|
||||
@seenFor = no
|
||||
tag = 'TERMINATOR'
|
||||
else if value in MATH then tag = 'MATH'
|
||||
else if value in COMPARE then tag = 'COMPARE'
|
||||
else if value in COMPOUND_ASSIGN then tag = 'COMPOUND_ASSIGN'
|
||||
@@ -333,7 +352,9 @@ exports.Lexer = class Lexer
|
||||
tag = 'INDEX_START'
|
||||
switch prev[0]
|
||||
when '?' then prev[0] = 'INDEX_SOAK'
|
||||
when '::' then prev[0] = 'INDEX_PROTO'
|
||||
switch value
|
||||
when '(', '{', '[' then @ends.push INVERSES[value]
|
||||
when ')', '}', ']' then @pair value
|
||||
@token tag, value
|
||||
value.length
|
||||
|
||||
@@ -346,7 +367,7 @@ exports.Lexer = class Lexer
|
||||
{indent, herecomment} = options
|
||||
if herecomment
|
||||
if HEREDOC_ILLEGAL.test doc
|
||||
throw new Error "block comment cannot contain \"*/\", starting on line #{@line + 1}"
|
||||
@error "block comment cannot contain \"*/\", starting"
|
||||
return doc if doc.indexOf('\n') <= 0
|
||||
else
|
||||
while match = HEREDOC_INDENT.exec doc
|
||||
@@ -374,22 +395,13 @@ exports.Lexer = class Lexer
|
||||
else if tok[0] is '('
|
||||
tok[0] = 'PARAM_START'
|
||||
return this
|
||||
else return this
|
||||
this
|
||||
|
||||
# Close up all remaining open blocks at the end of the file.
|
||||
closeIndentation: ->
|
||||
@outdentToken @indent
|
||||
|
||||
# The error for when you try to use a forbidden word in JavaScript as
|
||||
# an identifier.
|
||||
identifierError: (word) ->
|
||||
throw SyntaxError "Reserved word \"#{word}\" on line #{@line + 1}"
|
||||
|
||||
# The error for when you try to assign to a reserved word in JavaScript,
|
||||
# like "function" or "default".
|
||||
assignmentError: ->
|
||||
throw SyntaxError "Reserved word \"#{@value()}\" on line #{@line + 1} can't be assigned"
|
||||
|
||||
# Matches a balanced group such as a single or double-quoted string. Pass in
|
||||
# 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
|
||||
@@ -409,13 +421,14 @@ exports.Lexer = class Lexer
|
||||
continue
|
||||
if end is '}' and letter in ['"', "'"]
|
||||
stack.push end = letter
|
||||
else if end is '}' and letter is '/' and match = (HEREGEX.exec(str.slice i) or REGEX.exec(str.slice i))
|
||||
i += match[0].length - 1
|
||||
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 }"
|
||||
|
||||
@error "missing #{ stack.pop() }, starting"
|
||||
|
||||
# Expand variables and expressions inside double-quoted strings using
|
||||
# Ruby-like notation for substitution of arbitrary expressions.
|
||||
@@ -464,6 +477,21 @@ exports.Lexer = class Lexer
|
||||
@token ')', ')' if interpolated
|
||||
tokens
|
||||
|
||||
# Pairs up a closing token, ensuring that all listed pairs of tokens are
|
||||
# correctly balanced throughout the course of the token stream.
|
||||
pair: (tag) ->
|
||||
unless tag is wanted = last @ends
|
||||
@error "unmatched #{tag}" unless 'OUTDENT' is wanted
|
||||
# Auto-close INDENT to support syntax like this:
|
||||
#
|
||||
# el.click((event) ->
|
||||
# el.hide())
|
||||
#
|
||||
@indent -= size = last @indents
|
||||
@outdentToken size, true
|
||||
return @pair tag
|
||||
@ends.pop()
|
||||
|
||||
# Helpers
|
||||
# -------
|
||||
|
||||
@@ -482,9 +510,8 @@ exports.Lexer = class Lexer
|
||||
# Are we in the midst of an unfinished expression?
|
||||
unfinished: ->
|
||||
LINE_CONTINUER.test(@chunk) or
|
||||
(prev = last @tokens, 1) and prev[0] isnt '.' and
|
||||
(value = @value()) and not value.reserved and
|
||||
NO_NEWLINE.test(value) and not CODE.test(value) and not ASSIGNED.test(@chunk)
|
||||
@tag() in ['\\', '.', '?.', 'UNARY', 'MATH', '+', '-', 'SHIFT', 'RELATION'
|
||||
'COMPARE', 'LOGIC', 'COMPOUND_ASSIGN', 'THROW', 'EXTENDS']
|
||||
|
||||
# Converts newlines for string literals.
|
||||
escapeLines: (str, heredoc) ->
|
||||
@@ -497,6 +524,10 @@ exports.Lexer = class Lexer
|
||||
if contents in ['\n', quote] then contents else match
|
||||
body = body.replace /// #{quote} ///g, '\\$&'
|
||||
quote + @escapeLines(body, heredoc) + quote
|
||||
|
||||
# Throws a syntax error on the current `@line`.
|
||||
error: (message) ->
|
||||
throw SyntaxError "#{message} on line #{ @line + 1}"
|
||||
|
||||
# Constants
|
||||
# ---------
|
||||
@@ -523,7 +554,7 @@ COFFEE_ALIAS_MAP =
|
||||
no : 'false'
|
||||
on : 'true'
|
||||
off : 'false'
|
||||
|
||||
|
||||
COFFEE_ALIASES = (key for key of COFFEE_ALIAS_MAP)
|
||||
COFFEE_KEYWORDS = COFFEE_KEYWORDS.concat COFFEE_ALIASES
|
||||
|
||||
@@ -550,7 +581,8 @@ IDENTIFIER = /// ^
|
||||
|
||||
NUMBER = ///
|
||||
^ 0x[\da-f]+ | # hex
|
||||
^ (?: \d+(\.\d+)? | \.\d+ ) (?:e[+-]?\d+)? # decimal
|
||||
^ 0b[01]+ | # binary
|
||||
^ \d*\.?\d+ (?:e[+-]?\d+)? # decimal
|
||||
///i
|
||||
|
||||
HEREDOC = /// ^ ("""|''') ([\s\S]*?) (?:\n[^\n\S]*)? \1 ///
|
||||
@@ -579,7 +611,7 @@ JSTOKEN = /^`[^\\`]*(?:\\.[^\\`]*)*`/
|
||||
|
||||
# Regex-matching-regexes.
|
||||
REGEX = /// ^
|
||||
/ (?! [\s=] ) # disallow leading whitespace or equals signs
|
||||
(/ (?! [\s=] ) # disallow leading whitespace or equals signs
|
||||
[^ [ / \n \\ ]* # every other thing
|
||||
(?:
|
||||
(?: \\[\s\S] # anything escaped
|
||||
@@ -589,7 +621,7 @@ REGEX = /// ^
|
||||
]
|
||||
) [^ [ / \n \\ ]*
|
||||
)*
|
||||
/ [imgy]{0,4} (?!\w)
|
||||
/) ([imgy]{0,4}) (?!\w)
|
||||
///
|
||||
|
||||
HEREGEX = /// ^ /{3} ([\s\S]+?) /{3} ([imgy]{0,4}) (?!\w) ///
|
||||
@@ -603,18 +635,10 @@ HEREDOC_INDENT = /\n+([^\n\S]*)/g
|
||||
|
||||
HEREDOC_ILLEGAL = /\*\//
|
||||
|
||||
ASSIGNED = /^\s*@?([$A-Za-z_][$\w\x7f-\uffff]*|['"].*['"])[^\n\S]*?[:=][^:=>]/
|
||||
|
||||
LINE_CONTINUER = /// ^ \s* (?: , | \??\.(?![.\d]) | :: ) ///
|
||||
|
||||
TRAILING_SPACES = /\s+$/
|
||||
|
||||
NO_NEWLINE = /// ^ (?: # non-capturing group
|
||||
[-+*&|/%=<>!.\\][<>=&|]* | # symbol operators
|
||||
and | or | is(?:nt)? | n(?:ot|ew) | # word operators
|
||||
delete | typeof | instanceof
|
||||
) $ ///
|
||||
|
||||
# Compound assignment tokens.
|
||||
COMPOUND_ASSIGN = [
|
||||
'-=', '+=', '/=', '*=', '%=', '||=', '&&=', '?=', '<<=', '>>=', '>>>=', '&=', '^=', '|='
|
||||
@@ -653,7 +677,7 @@ NOT_REGEX = ['NUMBER', 'REGEX', 'BOOL', '++', '--', ']']
|
||||
# force a division parse:
|
||||
NOT_SPACED_REGEX = NOT_REGEX.concat ')', '}', 'THIS', 'IDENTIFIER', 'STRING'
|
||||
|
||||
# Tokens which could legitimately be invoked or indexed. A opening
|
||||
# Tokens which could legitimately be invoked or indexed. An opening
|
||||
# parentheses or bracket following these tokens will be recorded as the start
|
||||
# of a function invocation or indexing operation.
|
||||
CALLABLE = ['IDENTIFIER', 'STRING', 'REGEX', ')', ']', '}', '?', '::', '@', 'THIS', 'SUPER']
|
||||
|
||||
475
src/nodes.coffee
475
src/nodes.coffee
@@ -4,6 +4,7 @@
|
||||
# the syntax tree into a string of JavaScript code, call `compile()` on the root.
|
||||
|
||||
{Scope} = require './scope'
|
||||
{RESERVED} = require './lexer'
|
||||
|
||||
# Import the helpers we plan to use.
|
||||
{compact, flatten, extend, merge, del, starts, ends, last} = require './helpers'
|
||||
@@ -75,8 +76,12 @@ exports.Base = class Base
|
||||
# Construct a node that returns the current node's result.
|
||||
# Note that this is overridden for smarter behavior for
|
||||
# many statement nodes (e.g. If, For)...
|
||||
makeReturn: ->
|
||||
new Return this
|
||||
makeReturn: (res) ->
|
||||
me = @unwrapAll()
|
||||
if res
|
||||
new Call new Literal("#{res}.push"), [me]
|
||||
else
|
||||
new Return me
|
||||
|
||||
# Does this node, or any of its children, contain a node of a certain kind?
|
||||
# Recursively traverses down the *children* of the nodes, yielding to a block
|
||||
@@ -188,19 +193,19 @@ exports.Block = class Block extends Base
|
||||
for exp in @expressions
|
||||
return exp if exp.jumps o
|
||||
|
||||
# An Block node does not return its entire body, rather it
|
||||
# A Block node does not return its entire body, rather it
|
||||
# ensures that the final expression is returned.
|
||||
makeReturn: ->
|
||||
makeReturn: (res) ->
|
||||
len = @expressions.length
|
||||
while len--
|
||||
expr = @expressions[len]
|
||||
if expr not instanceof Comment
|
||||
@expressions[len] = expr.makeReturn()
|
||||
@expressions[len] = expr.makeReturn res
|
||||
@expressions.splice(len, 1) if expr instanceof Return and not expr.expression
|
||||
break
|
||||
this
|
||||
|
||||
# An **Block** is the only node that can serve as the root.
|
||||
# A **Block** is the only node that can serve as the root.
|
||||
compile: (o = {}, level) ->
|
||||
if o.scope then super o, level else @compileRoot o
|
||||
|
||||
@@ -214,13 +219,22 @@ exports.Block = class Block extends Base
|
||||
for node in @expressions
|
||||
node = node.unwrapAll()
|
||||
node = (node.unfoldSoak(o) or node)
|
||||
if top
|
||||
if node instanceof Block
|
||||
# This is a nested block. We don't do anything special here like enclose
|
||||
# it in a new scope; we just compile the statements in this block along with
|
||||
# our own
|
||||
codes.push node.compileNode o
|
||||
else if top
|
||||
node.front = true
|
||||
code = node.compile o
|
||||
codes.push if node.isStatement o then code else @tab + code + ';'
|
||||
codes.push if node.isStatement o then code else "#{@tab}#{code};"
|
||||
else
|
||||
codes.push node.compile o, LEVEL_LIST
|
||||
return codes.join '\n' if top
|
||||
if top
|
||||
if @spaced
|
||||
return '\n' + codes.join('\n\n') + '\n'
|
||||
else
|
||||
return codes.join '\n'
|
||||
code = codes.join(', ') or 'void 0'
|
||||
if codes.length > 1 and o.level >= LEVEL_LIST then "(#{code})" else code
|
||||
|
||||
@@ -232,8 +246,11 @@ exports.Block = class Block extends Base
|
||||
o.indent = @tab = if o.bare then '' else TAB
|
||||
o.scope = new Scope null, this, null
|
||||
o.level = LEVEL_TOP
|
||||
@spaced = yes
|
||||
code = @compileWithDeclarations o
|
||||
if o.bare then code else "(function() {\n#{code}\n}).call(this);\n"
|
||||
# the `1` below accounts for `arguments`, always "in scope"
|
||||
return code if o.bare or o.scope.variables.length <= 1
|
||||
"(function() {\n#{code}\n}).call(this);\n"
|
||||
|
||||
# Compile the expressions body for the contents of a function, with
|
||||
# declarations of all inner variables pushed up to the top.
|
||||
@@ -245,18 +262,22 @@ exports.Block = class Block extends Base
|
||||
o = merge(o, level: LEVEL_TOP)
|
||||
if i
|
||||
rest = @expressions.splice i, @expressions.length
|
||||
code = @compileNode o
|
||||
code = @compileNode(o)
|
||||
@expressions = rest
|
||||
post = @compileNode o
|
||||
{scope} = o
|
||||
if scope.expressions is this
|
||||
if o.scope.hasDeclarations()
|
||||
declars = o.scope.hasDeclarations()
|
||||
assigns = scope.hasAssignments
|
||||
if (declars or assigns) and i
|
||||
code += '\n'
|
||||
if declars
|
||||
code += "#{@tab}var #{ scope.declaredVariables().join(', ') };\n"
|
||||
if scope.hasAssignments
|
||||
if assigns
|
||||
code += "#{@tab}var #{ multident scope.assignedVariables().join(', '), @tab };\n"
|
||||
code + post
|
||||
|
||||
# Wrap up the given nodes as an **Block**, unless it already happens
|
||||
# Wrap up the given nodes as a **Block**, unless it already happens
|
||||
# to be one.
|
||||
@wrap: (nodes) ->
|
||||
return nodes[0] if nodes.length is 1 and nodes[0] instanceof Block
|
||||
@@ -271,7 +292,7 @@ exports.Literal = class Literal extends Base
|
||||
constructor: (@value) ->
|
||||
|
||||
makeReturn: ->
|
||||
if @isStatement() then this else new Return this
|
||||
if @isStatement() then this else super
|
||||
|
||||
isAssignable: ->
|
||||
IDENTIFIER.test @value
|
||||
@@ -291,7 +312,9 @@ exports.Literal = class Literal extends Base
|
||||
compileNode: (o) ->
|
||||
code = if @isUndefined
|
||||
if o.level >= LEVEL_ACCESS then '(void 0)' else 'void 0'
|
||||
else if @value.reserved
|
||||
else if @value is 'this'
|
||||
if o.scope.method?.bound then o.scope.method.context else @value
|
||||
else if @value.reserved and "#{@value}" not in ['eval', 'arguments']
|
||||
"\"#{@value}\""
|
||||
else
|
||||
@value
|
||||
@@ -319,7 +342,7 @@ exports.Return = class Return extends Base
|
||||
if expr and expr not instanceof Return then expr.compile o, level else super o, level
|
||||
|
||||
compileNode: (o) ->
|
||||
@tab + "return#{ if @expression then ' ' + @expression.compile(o, LEVEL_PAREN) else '' };"
|
||||
@tab + "return#{[" #{@expression.compile o, LEVEL_PAREN}" if @expression]};"
|
||||
|
||||
#### Value
|
||||
|
||||
@@ -335,9 +358,9 @@ exports.Value = class Value extends Base
|
||||
|
||||
children: ['base', 'properties']
|
||||
|
||||
# Add a property access to the list.
|
||||
push: (prop) ->
|
||||
@properties.push prop
|
||||
# Add a property (or *properties* ) `Access` to the list.
|
||||
add: (props) ->
|
||||
@properties = @properties.concat props
|
||||
this
|
||||
|
||||
hasProperties: ->
|
||||
@@ -364,9 +387,6 @@ exports.Value = class Value extends Base
|
||||
isSplice: ->
|
||||
last(@properties) instanceof Slice
|
||||
|
||||
makeReturn: ->
|
||||
if @properties.length then super() else @base.makeReturn()
|
||||
|
||||
# The value can be unwrapped as its inner node, if there are no attached
|
||||
# properties.
|
||||
unwrap: ->
|
||||
@@ -379,7 +399,7 @@ exports.Value = class Value extends Base
|
||||
name = last @properties
|
||||
if @properties.length < 2 and not @base.isComplex() and not name?.isComplex()
|
||||
return [this, this] # `a` `a.b`
|
||||
base = new Value @base, @properties.slice 0, -1
|
||||
base = new Value @base, @properties[...-1]
|
||||
if base.isComplex() # `a().b`
|
||||
bref = new Literal o.scope.freeVariable 'base'
|
||||
base = new Value new Parens new Assign bref, base
|
||||
@@ -388,7 +408,7 @@ exports.Value = class Value extends Base
|
||||
nref = new Literal o.scope.freeVariable 'name'
|
||||
name = new Index new Assign nref, name.index
|
||||
nref = new Index nref
|
||||
[base.push(name), new Value(bref or base.base, [nref or name])]
|
||||
[base.add(name), new Value(bref or base.base, [nref or name])]
|
||||
|
||||
# We compile a value to JavaScript by compiling and joining each property.
|
||||
# Things get much more interesting if the chain of properties has *soak*
|
||||
@@ -398,7 +418,7 @@ exports.Value = class Value extends Base
|
||||
@base.front = @front
|
||||
props = @properties
|
||||
code = @base.compile o, if props.length then LEVEL_ACCESS else null
|
||||
code = "(#{code})" if props[0] instanceof Access and @isSimpleNumber()
|
||||
code = "#{code}." if (@base instanceof Parens or props.length) and SIMPLENUM.test code
|
||||
code += prop.compile o for prop in props
|
||||
code
|
||||
|
||||
@@ -411,8 +431,8 @@ exports.Value = class Value extends Base
|
||||
return ifn
|
||||
for prop, i in @properties when prop.soak
|
||||
prop.soak = off
|
||||
fst = new Value @base, @properties.slice 0, i
|
||||
snd = new Value @base, @properties.slice i
|
||||
fst = new Value @base, @properties[...i]
|
||||
snd = new Value @base, @properties[i..]
|
||||
if fst.isComplex()
|
||||
ref = new Literal o.scope.freeVariable 'ref'
|
||||
fst = new Parens new Assign ref, fst
|
||||
@@ -432,7 +452,7 @@ exports.Comment = class Comment extends Base
|
||||
makeReturn: THIS
|
||||
|
||||
compileNode: (o, level) ->
|
||||
code = '/*' + multident(@comment, @tab) + '*/'
|
||||
code = '/*' + multident(@comment, @tab) + "\n#{@tab}*/"
|
||||
code = o.indent + code if (level or o.level) is LEVEL_TOP
|
||||
code
|
||||
|
||||
@@ -450,8 +470,8 @@ exports.Call = class Call extends Base
|
||||
|
||||
# Tag this invocation as creating a new instance.
|
||||
newInstance: ->
|
||||
base = @variable.base or @variable
|
||||
if base instanceof Call
|
||||
base = @variable?.base or @variable
|
||||
if base instanceof Call and not base.isNew
|
||||
base.newInstance()
|
||||
else
|
||||
@isNew = true
|
||||
@@ -463,9 +483,12 @@ exports.Call = class Call extends Base
|
||||
{method} = o.scope
|
||||
throw SyntaxError 'cannot call super outside of a function.' unless method
|
||||
{name} = method
|
||||
throw SyntaxError 'cannot call super on an anonymous function.' unless name
|
||||
throw SyntaxError 'cannot call super on an anonymous function.' unless name?
|
||||
if method.klass
|
||||
"#{method.klass}.__super__.#{name}"
|
||||
accesses = [new Access(new Literal '__super__')]
|
||||
accesses.push new Access new Literal 'constructor' if method.static
|
||||
accesses.push new Access new Literal name
|
||||
(new Value (new Literal method.klass), accesses).compile o
|
||||
else
|
||||
"#{name}.__super__.constructor"
|
||||
|
||||
@@ -511,7 +534,7 @@ exports.Call = class Call extends Base
|
||||
continue
|
||||
obj = null
|
||||
for prop in node.base.properties
|
||||
if prop instanceof Assign
|
||||
if prop instanceof Assign or prop instanceof Comment
|
||||
nodes.push obj = new Obj properties = [], true if not obj
|
||||
properties.push prop
|
||||
else
|
||||
@@ -577,7 +600,6 @@ exports.Extends = class Extends extends Base
|
||||
|
||||
# Hooks one constructor into another's prototype chain.
|
||||
compile: (o) ->
|
||||
utility 'hasProp'
|
||||
new Call(new Value(new Literal utility 'extends'), [@child, @parent]).compile o
|
||||
|
||||
#### Access
|
||||
@@ -587,14 +609,13 @@ exports.Extends = class Extends extends Base
|
||||
exports.Access = class Access extends Base
|
||||
constructor: (@name, tag) ->
|
||||
@name.asKey = yes
|
||||
@proto = if tag is 'proto' then '.prototype' else ''
|
||||
@soak = tag is 'soak'
|
||||
|
||||
children: ['name']
|
||||
|
||||
compile: (o) ->
|
||||
name = @name.compile o
|
||||
@proto + if IS_STRING.test name then "[#{name}]" else ".#{name}"
|
||||
if IDENTIFIER.test name then ".#{name}" else "[#{name}]"
|
||||
|
||||
isComplex: NO
|
||||
|
||||
@@ -607,7 +628,7 @@ exports.Index = class Index extends Base
|
||||
children: ['index']
|
||||
|
||||
compile: (o) ->
|
||||
(if @proto then '.prototype' else '') + "[#{ @index.compile o, LEVEL_PAREN }]"
|
||||
"[#{ @index.compile o, LEVEL_PAREN }]"
|
||||
|
||||
isComplex: ->
|
||||
@index.isComplex()
|
||||
@@ -628,41 +649,48 @@ exports.Range = class Range extends Base
|
||||
# Compiles the range's source variables -- where it starts and where it ends.
|
||||
# But only if they need to be cached to avoid double evaluation.
|
||||
compileVariables: (o) ->
|
||||
o = merge(o, top: true)
|
||||
[@from, @fromVar] = @from.cache o, LEVEL_LIST
|
||||
[@to, @toVar] = @to.cache o, LEVEL_LIST
|
||||
[@fromNum, @toNum] = [@fromVar.match(SIMPLENUM), @toVar.match(SIMPLENUM)]
|
||||
parts = []
|
||||
parts.push @from if @from isnt @fromVar
|
||||
parts.push @to if @to isnt @toVar
|
||||
o = merge o, top: true
|
||||
[@fromC, @fromVar] = @from.cache o, LEVEL_LIST
|
||||
[@toC, @toVar] = @to.cache o, LEVEL_LIST
|
||||
[@step, @stepVar] = step.cache o, LEVEL_LIST if step = del o, 'step'
|
||||
[@fromNum, @toNum] = [@fromVar.match(SIMPLENUM), @toVar.match(SIMPLENUM)]
|
||||
@stepNum = @stepVar.match(SIMPLENUM) if @stepVar
|
||||
|
||||
# When compiled normally, the range returns the contents of the *for loop*
|
||||
# needed to iterate over the values in the range. Used by comprehensions.
|
||||
compileNode: (o) ->
|
||||
@compileVariables o
|
||||
@compileVariables o unless @fromVar
|
||||
return @compileArray(o) unless o.index
|
||||
return @compileSimple(o) if @fromNum and @toNum
|
||||
|
||||
# Set up endpoints.
|
||||
known = @fromNum and @toNum
|
||||
idx = del o, 'index'
|
||||
step = del o, 'step'
|
||||
stepvar = o.scope.freeVariable "step" if step
|
||||
varPart = "#{idx} = #{@from}" + ( if @to isnt @toVar then ", #{@to}" else '' ) + if step then ", #{stepvar} = #{step.compile(o)}" else ''
|
||||
cond = "#{@fromVar} <= #{@toVar}"
|
||||
condPart = "#{cond} ? #{idx} <#{@equals} #{@toVar} : #{idx} >#{@equals} #{@toVar}"
|
||||
stepPart = if step then "#{idx} += #{stepvar}" else "#{cond} ? #{idx}++ : #{idx}--"
|
||||
varPart = "#{idx} = #{@fromC}"
|
||||
varPart += ", #{@toC}" if @toC isnt @toVar
|
||||
varPart += ", #{@step}" if @step isnt @stepVar
|
||||
[lt, gt] = ["#{idx} <#{@equals}", "#{idx} >#{@equals}"]
|
||||
|
||||
# Generate the condition.
|
||||
condPart = if @stepNum
|
||||
if +@stepNum > 0 then "#{lt} #{@toVar}" else "#{gt} #{@toVar}"
|
||||
else if known
|
||||
[from, to] = [+@fromNum, +@toNum]
|
||||
if from <= to then "#{lt} #{to}" else "#{gt} #{to}"
|
||||
else
|
||||
cond = "#{@fromVar} <= #{@toVar}"
|
||||
"#{cond} ? #{lt} #{@toVar} : #{gt} #{@toVar}"
|
||||
|
||||
# Generate the step.
|
||||
stepPart = if @stepVar
|
||||
"#{idx} += #{@stepVar}"
|
||||
else if known
|
||||
if from <= to then "#{idx}++" else "#{idx}--"
|
||||
else
|
||||
"#{cond} ? #{idx}++ : #{idx}--"
|
||||
|
||||
# The final loop body.
|
||||
"#{varPart}; #{condPart}; #{stepPart}"
|
||||
|
||||
# Compile a simple range comprehension, with integers.
|
||||
compileSimple: (o) ->
|
||||
[from, to] = [+@fromNum, +@toNum]
|
||||
idx = del o, 'index'
|
||||
step = del o, 'step'
|
||||
stepvar = o.scope.freeVariable "step" if step
|
||||
varPart = "#{idx} = #{from}"
|
||||
varPart += ", #{stepvar} = #{step.compile(o)}" if step
|
||||
condPart = if from <= to then "#{idx} <#{@equals} #{to}" else "#{idx} >#{@equals} #{to}"
|
||||
stepPart = "#{idx} += #{stepvar}" if step
|
||||
stepPart = ( if from <= to then "#{idx}++" else "#{idx}--" ) if not step
|
||||
"#{varPart}; #{condPart}; #{stepPart}"
|
||||
|
||||
# When used as a value, expand the range into the equivalent array.
|
||||
compileArray: (o) ->
|
||||
@@ -676,13 +704,15 @@ exports.Range = class Range extends Base
|
||||
pre = "\n#{idt}#{result} = [];"
|
||||
if @fromNum and @toNum
|
||||
o.index = i
|
||||
body = @compileSimple o
|
||||
body = @compileNode o
|
||||
else
|
||||
vars = "#{i} = #{@from}" + if @to isnt @toVar then ", #{@to}" else ''
|
||||
vars = "#{i} = #{@fromC}" + if @toC isnt @toVar then ", #{@toC}" else ''
|
||||
cond = "#{@fromVar} <= #{@toVar}"
|
||||
body = "var #{vars}; #{cond} ? #{i} <#{@equals} #{@toVar} : #{i} >#{@equals} #{@toVar}; #{cond} ? #{i}++ : #{i}--"
|
||||
post = "{ #{result}.push(#{i}); }\n#{idt}return #{result};\n#{o.indent}"
|
||||
"(function() {#{pre}\n#{idt}for (#{body})#{post}}).apply(this, arguments)"
|
||||
hasArgs = (node) -> node?.contains (n) -> n instanceof Literal and n.value is 'arguments' and not n.asKey
|
||||
args = ', arguments' if hasArgs(@from) or hasArgs(@to)
|
||||
"(function() {#{pre}\n#{idt}for (#{body})#{post}}).apply(this#{args ? ''})"
|
||||
|
||||
#### Slice
|
||||
|
||||
@@ -702,14 +732,14 @@ exports.Slice = class Slice extends Base
|
||||
compileNode: (o) ->
|
||||
{to, from} = @range
|
||||
fromStr = from and from.compile(o, LEVEL_PAREN) or '0'
|
||||
compiled = to and to.compile o, LEVEL_PAREN
|
||||
compiled = to and to.compile o, LEVEL_ACCESS
|
||||
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"
|
||||
"#{compiled} + 1 || 9e9"
|
||||
".slice(#{ fromStr }#{ toStr or '' })"
|
||||
|
||||
#### Obj
|
||||
@@ -815,13 +845,13 @@ exports.Class = class Class extends Base
|
||||
addBoundFunctions: (o) ->
|
||||
if @boundFuncs.length
|
||||
for bvar in @boundFuncs
|
||||
bname = bvar.compile o
|
||||
@ctor.body.unshift new Literal "this.#{bname} = #{utility 'bind'}(this.#{bname}, this)"
|
||||
lhs = (new Value (new Literal "this"), [new Access bvar]).compile o
|
||||
@ctor.body.unshift new Literal "#{lhs} = #{utility 'bind'}(#{lhs}, this)"
|
||||
|
||||
# Merge the properties from a top-level object as prototypal properties
|
||||
# on the class.
|
||||
addProperties: (node, name, o) ->
|
||||
props = node.base.properties.slice 0
|
||||
props = node.base.properties[0..]
|
||||
exprs = while assign = props.shift()
|
||||
if assign instanceof Assign
|
||||
base = assign.variable.base
|
||||
@@ -838,11 +868,13 @@ exports.Class = class Class extends Base
|
||||
@externalCtor = o.scope.freeVariable 'class'
|
||||
assign = new Assign new Literal(@externalCtor), func
|
||||
else
|
||||
unless assign.variable.this
|
||||
assign.variable = new Value(new Literal(name), [new Access(base, 'proto')])
|
||||
if func instanceof Code and func.bound
|
||||
@boundFuncs.push base
|
||||
func.bound = no
|
||||
if assign.variable.this
|
||||
func.static = yes
|
||||
else
|
||||
assign.variable = new Value(new Literal(name), [(new Access new Literal 'prototype'), new Access base ])
|
||||
if func instanceof Code and func.bound
|
||||
@boundFuncs.push base
|
||||
func.bound = no
|
||||
assign
|
||||
compact exprs
|
||||
|
||||
@@ -874,11 +906,13 @@ exports.Class = class Class extends Base
|
||||
compileNode: (o) ->
|
||||
decl = @determineName()
|
||||
name = decl or @name or '_Class'
|
||||
name = "_#{name}" if name.reserved
|
||||
lname = new Literal name
|
||||
|
||||
@setContext name
|
||||
@walkBody name, o
|
||||
@ensureConstructor name
|
||||
@body.spaced = yes
|
||||
@body.expressions.unshift new Extends lname, @parent if @parent
|
||||
@body.expressions.unshift @ctor unless @ctor instanceof Code
|
||||
@body.expressions.push lname
|
||||
@@ -895,12 +929,13 @@ exports.Class = class Class extends Base
|
||||
exports.Assign = class Assign extends Base
|
||||
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\x7f-\uffff]*)$/
|
||||
@subpattern = options and options.subpattern
|
||||
|
||||
children: ['variable', 'value']
|
||||
|
||||
isStatement: (o) ->
|
||||
o?.level is LEVEL_TOP and @context? and "?" in @context
|
||||
|
||||
assigns: (name) ->
|
||||
@[if @context is 'object' then 'value' else 'variable'].assigns name
|
||||
|
||||
@@ -917,16 +952,17 @@ exports.Assign = class Assign extends Base
|
||||
return @compileSplice o if @variable.isSplice()
|
||||
return @compileConditional o if @context in ['||=', '&&=', '?=']
|
||||
name = @variable.compile o, LEVEL_LIST
|
||||
unless @context or @variable.isAssignable()
|
||||
throw SyntaxError "\"#{ @variable.compile o }\" cannot be assigned."
|
||||
unless @context or isValue and (@variable.namespaced or @variable.hasProperties())
|
||||
if @param
|
||||
o.scope.add name, 'var'
|
||||
else
|
||||
o.scope.find name
|
||||
if @value instanceof Code and match = @METHOD_DEF.exec name
|
||||
@value.name = match[2]
|
||||
unless @context
|
||||
unless (varBase = @variable.unwrapAll()).isAssignable()
|
||||
throw SyntaxError "\"#{ @variable.compile o }\" cannot be assigned."
|
||||
unless varBase.hasProperties?()
|
||||
if @param
|
||||
o.scope.add name, 'var'
|
||||
else
|
||||
o.scope.find name
|
||||
if @value instanceof Code and match = METHOD_DEF.exec name
|
||||
@value.klass = match[1] if match[1]
|
||||
@value.name = match[2] ? match[3] ? match[4] ? match[5]
|
||||
val = @value.compile o, LEVEL_LIST
|
||||
return "#{name}: #{val}" if @context is 'object'
|
||||
val = name + " #{ @context or '=' } " + val
|
||||
@@ -959,7 +995,9 @@ exports.Assign = class Assign extends Base
|
||||
acc = IDENTIFIER.test idx.unwrap().value or 0
|
||||
value = new Value value
|
||||
value.properties.push new (if acc then Access else Index) idx
|
||||
return new Assign(obj, value).compile o
|
||||
if obj.unwrap().value in ['arguments','eval'].concat RESERVED
|
||||
throw new SyntaxError "assignment to a reserved word: #{obj.compile o} = #{value.compile o}"
|
||||
return new Assign(obj, value, null, param: @param).compile o, LEVEL_TOP
|
||||
vvar = value.compile o, LEVEL_LIST
|
||||
assigns = []
|
||||
splat = false
|
||||
@@ -980,6 +1018,8 @@ exports.Assign = class Assign extends Base
|
||||
else
|
||||
idx = if obj.this then obj.properties[0].name else obj
|
||||
if not splat and obj instanceof Splat
|
||||
name = obj.name.unwrap().value
|
||||
obj = obj.unwrap()
|
||||
val = "#{olen} <= #{vvar}.length ? #{ utility 'slice' }.call(#{vvar}, #{i}"
|
||||
if rest = olen - i - 1
|
||||
ivar = o.scope.freeVariable 'i'
|
||||
@@ -989,18 +1029,21 @@ exports.Assign = class Assign extends Base
|
||||
val = new Literal val
|
||||
splat = "#{ivar}++"
|
||||
else
|
||||
name = obj.unwrap().value
|
||||
if obj instanceof Splat
|
||||
obj = obj.name.compile o
|
||||
throw SyntaxError \
|
||||
"multiple splats are disallowed in an assignment: #{obj} ..."
|
||||
throw new SyntaxError \
|
||||
"multiple splats are disallowed in an assignment: #{obj}..."
|
||||
if typeof idx is 'number'
|
||||
idx = new Literal splat or idx
|
||||
acc = no
|
||||
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, null, param: @param).compile o, LEVEL_TOP
|
||||
assigns.push vvar unless top
|
||||
if name? and name in ['arguments','eval'].concat RESERVED
|
||||
throw new SyntaxError "assignment to a reserved word: #{obj.compile o} = #{val.compile o}"
|
||||
assigns.push new Assign(obj, val, null, param: @param, subpattern: yes).compile o, LEVEL_LIST
|
||||
assigns.push vvar unless top or @subpattern
|
||||
code = assigns.join ', '
|
||||
if o.level < LEVEL_LIST then code else "(#{code})"
|
||||
|
||||
@@ -1009,7 +1052,8 @@ exports.Assign = class Assign extends Base
|
||||
# more than once.
|
||||
compileConditional: (o) ->
|
||||
[left, rite] = @variable.cacheReference o
|
||||
new Op(@context.slice(0, -1), left, new Assign(rite, @value, '=')).compile o
|
||||
if "?" in @context then o.isExistentialEquals = true
|
||||
new Op(@context[0...-1], left, new Assign(rite, @value, '=') ).compile o
|
||||
|
||||
# Compile the assignment from an array splice literal, using JavaScript's
|
||||
# `Array#splice` method.
|
||||
@@ -1022,7 +1066,7 @@ exports.Assign = class Assign extends Base
|
||||
to = +to.compile(o) - +fromRef
|
||||
to += 1 unless exclusive
|
||||
else
|
||||
to = to.compile(o) + ' - ' + fromRef
|
||||
to = to.compile(o, LEVEL_ACCESS) + ' - ' + fromRef
|
||||
to += ' + 1' unless exclusive
|
||||
else
|
||||
to = "9e9"
|
||||
@@ -1040,7 +1084,7 @@ exports.Code = class Code extends Base
|
||||
@params = params or []
|
||||
@body = body or new Block
|
||||
@bound = tag is 'boundfunc'
|
||||
@context = 'this' if @bound
|
||||
@context = '_this' if @bound
|
||||
|
||||
children: ['params', 'body']
|
||||
|
||||
@@ -1050,18 +1094,18 @@ exports.Code = class Code extends Base
|
||||
|
||||
# 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 `=>`
|
||||
# the JavaScript `arguments` object. If the function is bound with the `=>`
|
||||
# arrow, generates a wrapper that saves the current value of `this` through
|
||||
# a closure.
|
||||
compileNode: (o) ->
|
||||
o.scope = new Scope o.scope, @body, this
|
||||
o.scope.shared = del o, 'sharedScope'
|
||||
o.scope.shared = del(o, 'sharedScope')
|
||||
o.indent += TAB
|
||||
delete o.bare
|
||||
vars = []
|
||||
exprs = []
|
||||
for param in @params when param.splat
|
||||
o.scope.add param.name.value, 'var' if param.name.value
|
||||
o.scope.add p.name.value, 'var', yes for p in @params when p.name.value
|
||||
splats = new Assign new Value(new Arr(p.asReference o for p in @params)),
|
||||
new Value new Literal 'arguments'
|
||||
break
|
||||
@@ -1082,6 +1126,11 @@ exports.Code = class Code extends Base
|
||||
@body.expressions.unshift exprs... if exprs.length
|
||||
o.scope.parameter vars[i] = v.compile o for v, i in vars unless splats
|
||||
@body.makeReturn() unless wasEmpty or @noReturn
|
||||
if @bound
|
||||
if o.scope.parent.method?.bound
|
||||
@bound = o.scope.parent.method.context
|
||||
else
|
||||
o.scope.parent.assign '_this', 'this'
|
||||
idt = o.indent
|
||||
code = 'function'
|
||||
code += ' ' + @name if @ctor
|
||||
@@ -1089,7 +1138,6 @@ exports.Code = class Code extends Base
|
||||
code += "\n#{ @body.compileWithDeclarations o }\n#{@tab}" unless @body.isEmpty()
|
||||
code += '}'
|
||||
return @tab + code if @ctor
|
||||
return utility('bind') + "(#{code}, #{@context})" if @bound
|
||||
if @front or (o.level >= LEVEL_ACCESS) then "(#{code})" else code
|
||||
|
||||
# Short-circuit `traverseChildren` method to prevent it from crossing scope boundaries
|
||||
@@ -1143,8 +1191,10 @@ exports.Splat = class Splat extends Base
|
||||
|
||||
compile: (o) ->
|
||||
if @index? then @compileParam o else @name.compile o
|
||||
|
||||
unwrap: -> @name
|
||||
|
||||
# Utility function that converts arbitrary number of elements, mixed with
|
||||
# Utility function that converts an arbitrary number of elements, mixed with
|
||||
# splats, to a proper array.
|
||||
@compileSplattedArray: (o, list, apply) ->
|
||||
index = -1
|
||||
@@ -1154,14 +1204,14 @@ exports.Splat = class Splat extends Base
|
||||
code = list[0].compile o, LEVEL_LIST
|
||||
return code if apply
|
||||
return "#{ utility 'slice' }.call(#{code})"
|
||||
args = list.slice index
|
||||
args = list[index..]
|
||||
for node, i in args
|
||||
code = node.compile o, LEVEL_LIST
|
||||
args[i] = if node instanceof Splat
|
||||
then "#{ utility 'slice' }.call(#{code})"
|
||||
else "[#{code}]"
|
||||
return args[0] + ".concat(#{ args.slice(1).join ', ' })" if index is 0
|
||||
base = (node.compile o, LEVEL_LIST for node in list.slice 0, index)
|
||||
return args[0] + ".concat(#{ args[1..].join ', ' })" if index is 0
|
||||
base = (node.compile o, LEVEL_LIST for node in list[0...index])
|
||||
"[#{ base.join ', ' }].concat(#{ args.join ', ' })"
|
||||
|
||||
#### While
|
||||
@@ -1178,9 +1228,12 @@ exports.While = class While extends Base
|
||||
|
||||
isStatement: YES
|
||||
|
||||
makeReturn: ->
|
||||
@returns = yes
|
||||
this
|
||||
makeReturn: (res) ->
|
||||
if res
|
||||
super
|
||||
else
|
||||
@returns = yes
|
||||
this
|
||||
|
||||
addBody: (@body) ->
|
||||
this
|
||||
@@ -1202,11 +1255,14 @@ exports.While = class While extends Base
|
||||
if body.isEmpty()
|
||||
body = ''
|
||||
else
|
||||
if o.level > LEVEL_TOP or @returns
|
||||
rvar = o.scope.freeVariable 'results'
|
||||
if @returns
|
||||
body.makeReturn rvar = o.scope.freeVariable 'results'
|
||||
set = "#{@tab}#{rvar} = [];\n"
|
||||
body = Push.wrap rvar, body if body
|
||||
body = Block.wrap [new If @guard, body] if @guard
|
||||
if @guard
|
||||
if body.expressions.length > 1
|
||||
body.expressions.unshift new If (new Parens @guard).invert(), new Literal "continue"
|
||||
else
|
||||
body = Block.wrap [new If @guard, body] if @guard
|
||||
body = "\n#{ body.compile o, LEVEL_TOP }\n#{@tab}"
|
||||
code = set + @tab + "while (#{ @condition.compile o, LEVEL_PAREN }) {#{body}}"
|
||||
if @returns
|
||||
@@ -1218,14 +1274,14 @@ exports.While = class While extends Base
|
||||
# Simple Arithmetic and logical operations. Performs some conversion from
|
||||
# CoffeeScript operations into their JavaScript equivalents.
|
||||
exports.Op = class Op extends Base
|
||||
constructor: (op, first, second, flip) ->
|
||||
constructor: (op, first, second, flip ) ->
|
||||
return new In first, second if op is 'in'
|
||||
if op is 'do'
|
||||
call = new Call first, first.params or []
|
||||
call.do = yes
|
||||
return call
|
||||
if op is 'new'
|
||||
return first.newInstance() if first instanceof Call and not first.do
|
||||
return first.newInstance() if first instanceof Call and not first.do and not first.isNew
|
||||
first = new Parens first if first instanceof Code and first.bound or first.do
|
||||
@operator = CONVERSIONS[op] or op
|
||||
@first = first
|
||||
@@ -1251,6 +1307,9 @@ exports.Op = class Op extends Base
|
||||
isUnary: ->
|
||||
not @second
|
||||
|
||||
isComplex: ->
|
||||
not (@isUnary() and (@operator in ['+', '-'])) or @first.isComplex()
|
||||
|
||||
# Am I capable of
|
||||
# [Python-style comparison chaining](http://docs.python.org/reference/expressions.html#notin)?
|
||||
isChainable: ->
|
||||
@@ -1286,11 +1345,14 @@ exports.Op = class Op extends Base
|
||||
unfoldSoak: (o) ->
|
||||
@operator in ['++', '--', 'delete'] and unfoldSoak o, this, 'first'
|
||||
|
||||
compileNode: (o) ->
|
||||
compileNode: (o) ->
|
||||
isChain = @isChainable() and @first.isChainable()
|
||||
# In chains, there's no need to wrap bare obj literals in parens,
|
||||
# as the chained expression is wrapped.
|
||||
@first.front = @front unless isChain
|
||||
return @compileUnary o if @isUnary()
|
||||
return @compileChain o if @isChainable() and @first.isChainable()
|
||||
return @compileChain o if isChain
|
||||
return @compileExistence o if @operator is '?'
|
||||
@first.front = @front
|
||||
code = @first.compile(o, LEVEL_OP) + ' ' + @operator + ' ' +
|
||||
@second.compile(o, LEVEL_OP)
|
||||
if o.level <= LEVEL_OP then code else "(#{code})"
|
||||
@@ -1318,9 +1380,11 @@ exports.Op = class Op extends Base
|
||||
# Compile a unary **Op**.
|
||||
compileUnary: (o) ->
|
||||
parts = [op = @operator]
|
||||
plusMinus = op in ['+', '-']
|
||||
parts.push ' ' if op in ['new', 'typeof', 'delete'] or
|
||||
op in ['+', '-'] and @first instanceof Op and @first.operator is op
|
||||
@first = new Parens @first if op is 'new' and @first.isStatement o
|
||||
plusMinus and @first instanceof Op and @first.operator is op
|
||||
if (plusMinus && @first instanceof Op) or (op is 'new' and @first.isStatement o)
|
||||
@first = new Parens @first
|
||||
parts.push @first.compile o, LEVEL_OP
|
||||
parts.reverse() if @flip
|
||||
parts.join ''
|
||||
@@ -1338,16 +1402,19 @@ exports.In = class In extends Base
|
||||
|
||||
compileNode: (o) ->
|
||||
if @array instanceof Value and @array.isArray()
|
||||
@compileOrTest o
|
||||
else
|
||||
@compileLoopTest o
|
||||
for obj in @array.base.objects when obj instanceof Splat
|
||||
hasSplat = yes
|
||||
break
|
||||
# `compileOrTest` only if we have an array literal with no splats
|
||||
return @compileOrTest o unless hasSplat
|
||||
@compileLoopTest o
|
||||
|
||||
compileOrTest: (o) ->
|
||||
return "#{!!@negated}" if @array.base.objects.length is 0
|
||||
[sub, ref] = @object.cache o, LEVEL_OP
|
||||
[cmp, cnj] = if @negated then [' !== ', ' && '] else [' === ', ' || ']
|
||||
tests = for item, i in @array.base.objects
|
||||
(if i then ref else sub) + cmp + item.compile o, LEVEL_OP
|
||||
return 'false' if tests.length is 0
|
||||
(if i then ref else sub) + cmp + item.compile o, LEVEL_ACCESS
|
||||
tests = tests.join cnj
|
||||
if o.level < LEVEL_OP then tests else "(#{tests})"
|
||||
|
||||
@@ -1374,9 +1441,9 @@ exports.Try = class Try extends Base
|
||||
|
||||
jumps: (o) -> @attempt.jumps(o) or @recovery?.jumps(o)
|
||||
|
||||
makeReturn: ->
|
||||
@attempt = @attempt .makeReturn() if @attempt
|
||||
@recovery = @recovery.makeReturn() if @recovery
|
||||
makeReturn: (res) ->
|
||||
@attempt = @attempt .makeReturn res if @attempt
|
||||
@recovery = @recovery.makeReturn res if @recovery
|
||||
this
|
||||
|
||||
# Compilation is more or less as you would expect -- the *finally* clause
|
||||
@@ -1384,15 +1451,19 @@ exports.Try = class Try extends Base
|
||||
compileNode: (o) ->
|
||||
o.indent += TAB
|
||||
errorPart = if @error then " (#{ @error.compile o }) " else ' '
|
||||
tryPart = @attempt.compile o, LEVEL_TOP
|
||||
|
||||
catchPart = if @recovery
|
||||
o.scope.add @error.value, 'param' unless o.scope.check @error.value
|
||||
" catch#{errorPart}{\n#{ @recovery.compile o, LEVEL_TOP }\n#{@tab}}"
|
||||
else unless @ensure or @recovery
|
||||
' catch (_e) {}'
|
||||
"""
|
||||
#{@tab}try {
|
||||
#{ @attempt.compile o, LEVEL_TOP }
|
||||
#{@tab}}#{ catchPart or '' }
|
||||
""" + if @ensure then " finally {\n#{ @ensure.compile o, LEVEL_TOP }\n#{@tab}}" else ''
|
||||
' catch (_error) {}'
|
||||
|
||||
ensurePart = if @ensure then " finally {\n#{ @ensure.compile o, LEVEL_TOP }\n#{@tab}}" else ''
|
||||
|
||||
"""#{@tab}try {
|
||||
#{tryPart}
|
||||
#{@tab}}#{ catchPart or '' }#{ensurePart}"""
|
||||
|
||||
#### Throw
|
||||
|
||||
@@ -1424,15 +1495,14 @@ exports.Existence = class Existence extends Base
|
||||
invert: NEGATE
|
||||
|
||||
compileNode: (o) ->
|
||||
@expression.front = @front
|
||||
code = @expression.compile o, LEVEL_OP
|
||||
code = if IDENTIFIER.test(code) and not o.scope.check code
|
||||
if @negated
|
||||
"typeof #{code} === \"undefined\" || #{code} === null"
|
||||
else
|
||||
"typeof #{code} !== \"undefined\" && #{code} !== null"
|
||||
if IDENTIFIER.test(code) and not o.scope.check code
|
||||
[cmp, cnj] = if @negated then ['===', '||'] else ['!==', '&&']
|
||||
code = "typeof #{code} #{cmp} \"undefined\" #{cnj} #{code} #{cmp} null"
|
||||
else
|
||||
sym = if @negated then '==' else '!='
|
||||
"#{code} #{sym} null"
|
||||
# do not use strict equality here; it will break existing code
|
||||
code = "#{code} #{if @negated then '==' else '!='} null"
|
||||
if o.level <= LEVEL_COND then code else "(#{code})"
|
||||
|
||||
#### Parens
|
||||
@@ -1449,7 +1519,6 @@ exports.Parens = class Parens extends Base
|
||||
|
||||
unwrap : -> @body
|
||||
isComplex : -> @body.isComplex()
|
||||
makeReturn: -> @body.makeReturn()
|
||||
|
||||
compileNode: (o) ->
|
||||
expr = @body.unwrap()
|
||||
@@ -1470,7 +1539,7 @@ exports.Parens = class Parens extends Base
|
||||
# Unlike Python array comprehensions, they can be multi-line, and you can pass
|
||||
# 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
|
||||
exports.For = class For extends While
|
||||
constructor: (body, source) ->
|
||||
{@source, @guard, @step, @name, @index} = source
|
||||
@body = Block.wrap [body]
|
||||
@@ -1486,14 +1555,6 @@ exports.For = class For extends Base
|
||||
|
||||
children: ['body', 'source', 'guard', 'step']
|
||||
|
||||
isStatement: YES
|
||||
|
||||
jumps: While::jumps
|
||||
|
||||
makeReturn: ->
|
||||
@returns = yes
|
||||
this
|
||||
|
||||
# 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
|
||||
@@ -1534,16 +1595,19 @@ exports.For = class For extends Base
|
||||
if @returns
|
||||
resultPart = "#{@tab}#{rvar} = [];\n"
|
||||
returnResult = "\n#{@tab}return #{rvar};"
|
||||
body = Push.wrap rvar, body
|
||||
body.makeReturn rvar
|
||||
if @guard
|
||||
body = Block.wrap [new If @guard, body]
|
||||
if body.expressions.length > 1
|
||||
body.expressions.unshift new If (new Parens @guard).invert(), new Literal "continue"
|
||||
else
|
||||
body = Block.wrap [new If @guard, body] if @guard
|
||||
if @pattern
|
||||
body.expressions.unshift new Assign @name, new Literal "#{svar}[#{ivar}]"
|
||||
defPart += @pluckDirectCall o, body
|
||||
varPart = "\n#{idt1}#{namePart};" if namePart
|
||||
if @object
|
||||
forPart = "#{ivar} in #{svar}"
|
||||
guardPart = "\n#{idt1}if (!#{utility('hasProp')}.call(#{svar}, #{ivar})) continue;" if @own
|
||||
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
|
||||
"""
|
||||
@@ -1566,7 +1630,6 @@ exports.For = class For extends Base
|
||||
base = new Value ref
|
||||
if val.base
|
||||
[val.base, base] = [base, val]
|
||||
args.unshift new Literal 'this'
|
||||
body.expressions[idx] = new Call base, expr.args
|
||||
defs += @tab + new Assign(ref, fn).compile(o, LEVEL_TOP) + ';\n'
|
||||
defs
|
||||
@@ -1586,9 +1649,10 @@ exports.Switch = class Switch extends Base
|
||||
return block if block.jumps o
|
||||
@otherwise?.jumps o
|
||||
|
||||
makeReturn: ->
|
||||
pair[1].makeReturn() for pair in @cases
|
||||
@otherwise?.makeReturn()
|
||||
makeReturn: (res) ->
|
||||
pair[1].makeReturn res for pair in @cases
|
||||
@otherwise or= new Block [new Literal 'void 0'] if res
|
||||
@otherwise?.makeReturn res
|
||||
this
|
||||
|
||||
compileNode: (o) ->
|
||||
@@ -1646,23 +1710,38 @@ exports.If = class If extends Base
|
||||
compileNode: (o) ->
|
||||
if @isStatement o then @compileStatement o else @compileExpression o
|
||||
|
||||
makeReturn: ->
|
||||
@body and= new Block [@body.makeReturn()]
|
||||
@elseBody and= new Block [@elseBody.makeReturn()]
|
||||
makeReturn: (res) ->
|
||||
@elseBody or= new Block [new Literal 'void 0'] if res
|
||||
@body and= new Block [@body.makeReturn res]
|
||||
@elseBody and= new Block [@elseBody.makeReturn res]
|
||||
this
|
||||
|
||||
ensureBlock: (node) ->
|
||||
if node instanceof Block then node else new Block [node]
|
||||
|
||||
# Compile the **If** as a regular *if-else* statement. Flattened chains
|
||||
# Compile the `If` as a regular *if-else* statement. Flattened chains
|
||||
# force inner *else* bodies into statement form.
|
||||
compileStatement: (o) ->
|
||||
child = del o, 'chainChild'
|
||||
exeq = del o, 'isExistentialEquals'
|
||||
|
||||
if exeq
|
||||
return new If(@condition.invert(), @elseBodyNode(), type: 'if').compile o
|
||||
|
||||
cond = @condition.compile o, LEVEL_PAREN
|
||||
o.indent += TAB
|
||||
body = @ensureBlock(@body).compile o
|
||||
body = "\n#{body}\n#{@tab}" if body
|
||||
ifPart = "if (#{cond}) {#{body}}"
|
||||
body = @ensureBlock(@body)
|
||||
bodyc = body.compile o
|
||||
if (
|
||||
1 is body.expressions?.length and
|
||||
!@elseBody and !child and
|
||||
bodyc and cond and
|
||||
-1 is (bodyc.indexOf '\n') and
|
||||
80 > cond.length + bodyc.length
|
||||
)
|
||||
return "#{@tab}if (#{cond}) #{bodyc.replace /^\s+/, ''}"
|
||||
bodyc = "\n#{bodyc}\n#{@tab}" if bodyc
|
||||
ifPart = "if (#{cond}) {#{bodyc}}"
|
||||
ifPart = @tab + ifPart unless child
|
||||
return ifPart unless @elseBody
|
||||
ifPart + ' else ' + if @isChain
|
||||
@@ -1672,7 +1751,7 @@ exports.If = class If extends Base
|
||||
else
|
||||
"{\n#{ @elseBody.compile o, LEVEL_TOP }\n#{@tab}}"
|
||||
|
||||
# Compile the If as a conditional operator.
|
||||
# Compile the `If` as a conditional operator.
|
||||
compileExpression: (o) ->
|
||||
cond = @condition.compile o, LEVEL_COND
|
||||
body = @bodyNode().compile o, LEVEL_LIST
|
||||
@@ -1688,15 +1767,6 @@ exports.If = class If extends Base
|
||||
# Faux-nodes are never created by the grammar, but are used during code
|
||||
# generation to generate other combinations of nodes.
|
||||
|
||||
#### Push
|
||||
|
||||
# The **Push** creates the tree for `array.push(value)`,
|
||||
# which is helpful for recording the result arrays from comprehensions.
|
||||
Push =
|
||||
wrap: (name, exps) ->
|
||||
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
|
||||
|
||||
# A faux-node used to wrap an expressions body in a closure.
|
||||
@@ -1738,37 +1808,25 @@ UTILITIES =
|
||||
|
||||
# Correctly set up a prototype chain for inheritance, including a reference
|
||||
# to the superclass for `super()` calls, and copies of any static properties.
|
||||
extends: '''
|
||||
function(child, parent) {
|
||||
for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; }
|
||||
function ctor() { this.constructor = child; }
|
||||
ctor.prototype = parent.prototype;
|
||||
child.prototype = new ctor;
|
||||
child.__super__ = parent.prototype;
|
||||
return child;
|
||||
}
|
||||
'''
|
||||
extends: -> """
|
||||
function(child, parent) { for (var key in parent) { if (#{utility 'hasProp'}.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor; child.__super__ = parent.prototype; return child; }
|
||||
"""
|
||||
|
||||
# Create a function bound to the current value of "this".
|
||||
bind: '''
|
||||
bind: -> '''
|
||||
function(fn, me){ return function(){ return fn.apply(me, arguments); }; }
|
||||
'''
|
||||
|
||||
# Discover if an item is in an array.
|
||||
indexOf: '''
|
||||
Array.prototype.indexOf || function(item) {
|
||||
for (var i = 0, l = this.length; i < l; i++) {
|
||||
if (this[i] === item) return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
'''
|
||||
indexOf: -> """
|
||||
Array.prototype.indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (#{utility 'hasProp'}.call(this, i) && this[i] === item) return i; } return -1; }
|
||||
"""
|
||||
|
||||
# Shortcuts to speed up the lookup time for native functions.
|
||||
hasProp: 'Object.prototype.hasOwnProperty'
|
||||
slice : 'Array.prototype.slice'
|
||||
hasProp: -> 'Object.prototype.hasOwnProperty'
|
||||
slice : -> 'Array.prototype.slice'
|
||||
|
||||
# Levels indicates a node's position in the AST. Useful for knowing if
|
||||
# Levels indicate a node's position in the AST. Useful for knowing if
|
||||
# parens are necessary or superfluous.
|
||||
LEVEL_TOP = 1 # ...;
|
||||
LEVEL_PAREN = 2 # (...)
|
||||
@@ -1780,8 +1838,24 @@ LEVEL_ACCESS = 6 # ...[0]
|
||||
# Tabs are two spaces for pretty printing.
|
||||
TAB = ' '
|
||||
|
||||
IDENTIFIER = /^[$A-Za-z_\x7f-\uffff][$\w\x7f-\uffff]*$/
|
||||
IDENTIFIER_STR = "[$A-Za-z_\\x7f-\\uffff][$\\w\\x7f-\\uffff]*"
|
||||
IDENTIFIER = /// ^ #{IDENTIFIER_STR} $ ///
|
||||
SIMPLENUM = /^[+-]?\d+$/
|
||||
METHOD_DEF = ///
|
||||
^
|
||||
(?:
|
||||
(#{IDENTIFIER_STR})
|
||||
\.prototype
|
||||
(?:
|
||||
\.(#{IDENTIFIER_STR})
|
||||
| \[("(?:[^\\"\r\n]|\\.)*"|'(?:[^\\'\r\n]|\\.)*')\]
|
||||
| \[(0x[\da-fA-F]+ | \d*\.?\d+ (?:[eE][+-]?\d+)?)\]
|
||||
)
|
||||
)
|
||||
|
|
||||
(#{IDENTIFIER_STR})
|
||||
$
|
||||
///
|
||||
|
||||
# Is a literal value a string?
|
||||
IS_STRING = /^['"]/
|
||||
@@ -1792,8 +1866,9 @@ IS_STRING = /^['"]/
|
||||
# Helper for ensuring that utility functions are assigned at the top level.
|
||||
utility = (name) ->
|
||||
ref = "__#{name}"
|
||||
Scope.root.assign ref, UTILITIES[name]
|
||||
Scope.root.assign ref, UTILITIES[name]()
|
||||
ref
|
||||
|
||||
multident = (code, tab) ->
|
||||
code.replace /\n/g, '$&' + tab
|
||||
code = code.replace /\n/g, '$&' + tab
|
||||
code.replace /\s+$/, ''
|
||||
|
||||
@@ -17,7 +17,7 @@ exports.OptionParser = class OptionParser
|
||||
@rules = buildRules rules
|
||||
|
||||
# Parse the list of arguments, populating an `options` object with all of the
|
||||
# specified options, and returning it. `options.arguments` will be an array
|
||||
# specified options, and return it. `options.arguments` will be an array
|
||||
# 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
|
||||
@@ -25,10 +25,13 @@ exports.OptionParser = class OptionParser
|
||||
# for interpreting the options object.
|
||||
parse: (args) ->
|
||||
options = arguments: [], literals: []
|
||||
args = normalizeArguments args
|
||||
originalArgs = args
|
||||
args = normalizeArguments args
|
||||
for arg, i in args
|
||||
if arg is '--'
|
||||
options.literals = args[(i + 1)..]
|
||||
pos = originalArgs.indexOf '--'
|
||||
options.arguments = [originalArgs[1 + pos]]
|
||||
options.literals = originalArgs[(2 + pos)..]
|
||||
break
|
||||
isOption = !!(arg.match(LONG_FLAG) or arg.match(SHORT_FLAG))
|
||||
matchedRule = no
|
||||
@@ -40,7 +43,7 @@ exports.OptionParser = class OptionParser
|
||||
break
|
||||
throw new Error "unrecognized option: #{arg}" if isOption and not matchedRule
|
||||
if not isOption
|
||||
options.arguments = args.slice i
|
||||
options.arguments = originalArgs[(originalArgs.indexOf arg)..]
|
||||
break
|
||||
options
|
||||
|
||||
|
||||
@@ -9,10 +9,13 @@ CoffeeScript = require './coffee-script'
|
||||
readline = require 'readline'
|
||||
{inspect} = require 'util'
|
||||
{Script} = require 'vm'
|
||||
Module = require 'module'
|
||||
|
||||
# REPL Setup
|
||||
|
||||
# Config
|
||||
REPL_PROMPT = 'coffee> '
|
||||
REPL_PROMPT_CONTINUATION = '......> '
|
||||
enableColours = no
|
||||
unless process.platform is 'win32'
|
||||
enableColours = not process.env.NODE_DISABLE_COLORS
|
||||
@@ -23,7 +26,7 @@ stdout = process.stdout
|
||||
|
||||
# Log an error.
|
||||
error = (err) ->
|
||||
stdout.write (err.stack or err.toString()) + '\n\n'
|
||||
stdout.write (err.stack or err.toString()) + '\n'
|
||||
|
||||
# The current backlog of multi-line code.
|
||||
backlog = ''
|
||||
@@ -31,29 +34,30 @@ backlog = ''
|
||||
# The main REPL function. **run** 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.
|
||||
run = do ->
|
||||
sandbox =
|
||||
require: require
|
||||
module : { exports: {} }
|
||||
sandbox[g] = global[g] for g of global
|
||||
sandbox.global = sandbox
|
||||
sandbox.global.global = sandbox.global.root = sandbox.global.GLOBAL = sandbox
|
||||
(buffer) ->
|
||||
code = backlog += '\n' + buffer.toString()
|
||||
if code[code.length - 1] is '\\'
|
||||
return backlog = backlog[0...backlog.length - 1]
|
||||
backlog = ''
|
||||
try
|
||||
val = CoffeeScript.eval code, {
|
||||
sandbox,
|
||||
bare: on,
|
||||
filename: 'repl'
|
||||
}
|
||||
unless val is undefined
|
||||
process.stdout.write inspect(val, no, 2, enableColours) + '\n'
|
||||
catch err
|
||||
error err
|
||||
run = (buffer) ->
|
||||
if !buffer.toString().trim() and !backlog
|
||||
repl.prompt()
|
||||
return
|
||||
code = backlog += buffer
|
||||
if code[code.length - 1] is '\\'
|
||||
backlog = "#{backlog[...-1]}\n"
|
||||
repl.setPrompt REPL_PROMPT_CONTINUATION
|
||||
repl.prompt()
|
||||
return
|
||||
repl.setPrompt REPL_PROMPT
|
||||
backlog = ''
|
||||
try
|
||||
_ = global._
|
||||
returnValue = CoffeeScript.eval "_=(#{code}\n)", {
|
||||
filename: 'repl'
|
||||
modulename: 'repl'
|
||||
}
|
||||
if returnValue is undefined
|
||||
global._ = _
|
||||
process.stdout.write inspect(returnValue, no, 2, enableColours) + '\n'
|
||||
catch err
|
||||
error err
|
||||
repl.prompt()
|
||||
|
||||
## Autocompletion
|
||||
|
||||
@@ -72,25 +76,24 @@ completeAttribute = (text) ->
|
||||
try
|
||||
val = Script.runInThisContext obj
|
||||
catch error
|
||||
return [[], text]
|
||||
completions = getCompletions prefix, getPropertyNames val
|
||||
return
|
||||
completions = getCompletions prefix, Object.getOwnPropertyNames val
|
||||
[completions, prefix]
|
||||
|
||||
# Attempt to autocomplete an in-scope free variable: `one`.
|
||||
completeVariable = (text) ->
|
||||
if free = text.match(SIMPLEVAR)?[1]
|
||||
scope = Script.runInThisContext 'this'
|
||||
completions = getCompletions free, CoffeeScript.RESERVED.concat(getPropertyNames scope)
|
||||
free = (text.match SIMPLEVAR)?[1]
|
||||
if free?
|
||||
vars = Script.runInThisContext 'Object.getOwnPropertyNames(this)'
|
||||
keywords = (r for r in CoffeeScript.RESERVED when r[0..1] isnt '__')
|
||||
possibilities = vars.concat keywords
|
||||
completions = getCompletions free, possibilities
|
||||
[completions, free]
|
||||
|
||||
# Return elements of candidates for which `prefix` is a prefix.
|
||||
getCompletions = (prefix, candidates) ->
|
||||
(el for el in candidates when el.indexOf(prefix) is 0)
|
||||
|
||||
# Return all "own" properties of an object.
|
||||
getPropertyNames = (obj) ->
|
||||
(name for own name of obj)
|
||||
|
||||
# Make sure that uncaught exceptions don't kill the REPL.
|
||||
process.on 'uncaughtException', error
|
||||
|
||||
@@ -101,7 +104,20 @@ if readline.createInterface.length < 3
|
||||
else
|
||||
repl = readline.createInterface stdin, stdout, autocomplete
|
||||
|
||||
repl.setPrompt 'coffee> '
|
||||
repl.on 'close', -> stdin.destroy()
|
||||
repl.on 'line', run
|
||||
repl.on 'attemptClose', ->
|
||||
if backlog
|
||||
backlog = ''
|
||||
process.stdout.write '\n'
|
||||
repl.setPrompt REPL_PROMPT
|
||||
repl.prompt()
|
||||
else
|
||||
repl.close()
|
||||
|
||||
repl.on 'close', ->
|
||||
process.stdout.write '\n'
|
||||
stdin.destroy()
|
||||
|
||||
repl.on 'line', run
|
||||
|
||||
repl.setPrompt REPL_PROMPT
|
||||
repl.prompt()
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
# the resulting parse table. Instead of making the parser handle it all, we take
|
||||
# a series of passes over the token stream, using this **Rewriter** to convert
|
||||
# shorthand into the unambiguous long form, add implicit indentation and
|
||||
# parentheses, balance incorrect nestings, and generally clean things up.
|
||||
# parentheses, and generally clean things up.
|
||||
|
||||
# The **Rewriter** class is used by the [Lexer](lexer.html), directly against
|
||||
# its internal array of tokens.
|
||||
@@ -26,8 +26,6 @@ class exports.Rewriter
|
||||
@tagPostfixConditionals()
|
||||
@addImplicitBraces()
|
||||
@addImplicitParentheses()
|
||||
@ensureBalance BALANCED_PAIRS
|
||||
@rewriteClosingParens()
|
||||
@tokens
|
||||
|
||||
# Rewrite the token stream, looking one token ahead and behind.
|
||||
@@ -133,19 +131,18 @@ class exports.Rewriter
|
||||
# deal with them.
|
||||
addImplicitParentheses: ->
|
||||
noCall = no
|
||||
action = (token, i) ->
|
||||
idx = if token[0] is 'OUTDENT' then i + 1 else i
|
||||
@tokens.splice idx, 0, ['CALL_END', ')', token[2]]
|
||||
action = (token, i) -> @tokens.splice i, 0, ['CALL_END', ')', token[2]]
|
||||
@scanTokens (token, i, tokens) ->
|
||||
tag = token[0]
|
||||
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
|
||||
token.call = yes if prev and not prev.spaced and tag is '?'
|
||||
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
|
||||
seenControl = no
|
||||
noCall = no if tag in LINEBREAKS
|
||||
token.call = yes if prev and not prev.spaced and tag is '?'
|
||||
return 1 if token.fromThen
|
||||
return 1 unless callObject or
|
||||
prev?.spaced and (prev.call or prev[0] in IMPLICIT_FUNC) and
|
||||
@@ -154,9 +151,11 @@ class exports.Rewriter
|
||||
@detectEnd i + 1, (token, i) ->
|
||||
[tag] = token
|
||||
return yes if not seenSingle and token.fromThen
|
||||
seenSingle = yes if tag in ['IF', 'ELSE', '->', '=>']
|
||||
seenSingle = yes if tag in ['IF', 'ELSE', 'CATCH', '->', '=>']
|
||||
seenControl = yes if tag in ['IF', 'ELSE', 'SWITCH', 'TRY']
|
||||
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
|
||||
not token.generated and @tag(i - 1) isnt ',' and (tag in IMPLICIT_END or
|
||||
(tag is 'INDENT' and not seenControl)) and
|
||||
(tag isnt 'INDENT' or
|
||||
(@tag(i - 2) isnt 'CLASS' and @tag(i - 1) not in IMPLICIT_BLOCK and
|
||||
not ((post = @tokens[i + 1]) and post.generated and post[0] is '{')))
|
||||
@@ -208,65 +207,6 @@ class exports.Rewriter
|
||||
original[0] = 'POST_' + original[0] if token[0] isnt 'INDENT'
|
||||
1
|
||||
|
||||
# Ensure that all listed pairs of tokens are correctly balanced throughout
|
||||
# the course of the token stream.
|
||||
ensureBalance: (pairs) ->
|
||||
levels = {}
|
||||
openLine = {}
|
||||
for token in @tokens
|
||||
[tag] = token
|
||||
for [open, close] in pairs
|
||||
levels[open] |= 0
|
||||
if tag is open
|
||||
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 open, level of levels when level > 0
|
||||
throw Error "unclosed #{ open } on line #{openLine[open] + 1}"
|
||||
this
|
||||
|
||||
# We'd like to support syntax like this:
|
||||
#
|
||||
# el.click((event) ->
|
||||
# el.hide())
|
||||
#
|
||||
# In order to accomplish this, move outdents that follow closing parens
|
||||
# inwards, safely. The steps to accomplish this are:
|
||||
#
|
||||
# 1. Check that all paired tokens are balanced and in order.
|
||||
# 2. Rewrite the stream with a stack: if you see an `EXPRESSION_START`, add it
|
||||
# to the stack. If you see an `EXPRESSION_END`, pop the stack and replace
|
||||
# it with the inverse of what we've just popped.
|
||||
# 3. Keep track of "debt" for tokens that we manufacture, to make sure we end
|
||||
# up balanced in the end.
|
||||
# 4. Be careful not to alter array or parentheses delimiters with overzealous
|
||||
# rewriting.
|
||||
rewriteClosingParens: ->
|
||||
stack = []
|
||||
debt = {}
|
||||
debt[key] = 0 for key of INVERSES
|
||||
@scanTokens (token, i, tokens) ->
|
||||
if (tag = token[0]) in EXPRESSION_START
|
||||
stack.push token
|
||||
return 1
|
||||
return 1 unless tag in EXPRESSION_END
|
||||
if debt[inv = INVERSES[tag]] > 0
|
||||
debt[inv] -= 1
|
||||
tokens.splice i, 1
|
||||
return 0
|
||||
match = stack.pop()
|
||||
mtag = match[0]
|
||||
oppos = INVERSES[mtag]
|
||||
return 1 if tag is oppos
|
||||
debt[mtag] += 1
|
||||
val = [oppos, if mtag is 'INDENT' then match[1] else oppos]
|
||||
if @tag(i + 2) is mtag
|
||||
tokens.splice i + 3, 0, val
|
||||
stack.push match
|
||||
else
|
||||
tokens.splice i, 0, val
|
||||
1
|
||||
|
||||
# Generate the indentation tokens, based on another token on the same line.
|
||||
indentation: (token) ->
|
||||
[['INDENT', 2, token[2]], ['OUTDENT', 2, token[2]]]
|
||||
@@ -290,7 +230,7 @@ BALANCED_PAIRS = [
|
||||
|
||||
# The inverse mappings of `BALANCED_PAIRS` we're trying to fix up, so we can
|
||||
# look things up from either end.
|
||||
INVERSES = {}
|
||||
exports.INVERSES = INVERSES = {}
|
||||
|
||||
# The tokens that signal the start/end of a balanced pair.
|
||||
EXPRESSION_START = []
|
||||
@@ -319,7 +259,7 @@ IMPLICIT_UNSPACED_CALL = ['+', '-']
|
||||
IMPLICIT_BLOCK = ['->', '=>', '{', '[', ',']
|
||||
|
||||
# Tokens that always mark the end of an implicit call for single-liners.
|
||||
IMPLICIT_END = ['POST_IF', 'FOR', 'WHILE', 'UNTIL', 'WHEN', 'BY', 'LOOP', 'TERMINATOR', 'INDENT']
|
||||
IMPLICIT_END = ['POST_IF', 'FOR', 'WHILE', 'UNTIL', 'WHEN', 'BY', 'LOOP', 'TERMINATOR']
|
||||
|
||||
# Single-line flavors of block expressions that have unclosed endings.
|
||||
# The grammar can't disambiguate them, so we insert the implicit indentation.
|
||||
|
||||
@@ -14,7 +14,7 @@ exports.Scope = class Scope
|
||||
@root: null
|
||||
|
||||
# Initialize a scope with its parent, for lookups up the chain,
|
||||
# as well as a reference to the **Block** node is belongs to, which is
|
||||
# as well as a reference to the **Block** node it belongs to, which is
|
||||
# where it should declare its variables, and a reference to the function that
|
||||
# it wraps.
|
||||
constructor: (@parent, @expressions, @method) ->
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user