mirror of
https://github.com/jashkenas/coffeescript.git
synced 2026-01-13 08:47:55 -05:00
Compare commits
217 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ff7e729b84 | ||
|
|
a21606e348 | ||
|
|
4bd657160d | ||
|
|
be8d812919 | ||
|
|
e40d25e4bd | ||
|
|
2a7a26482a | ||
|
|
3d6cdfa636 | ||
|
|
15a2b7d69a | ||
|
|
9ff8433f21 | ||
|
|
1c7d51a2c4 | ||
|
|
49020208f9 | ||
|
|
6f32fe27f8 | ||
|
|
7a16db9ad3 | ||
|
|
2f8a29b5a0 | ||
|
|
64b5ccc524 | ||
|
|
4fc4edc7a0 | ||
|
|
358edfb21f | ||
|
|
577daf5457 | ||
|
|
afa3bb4191 | ||
|
|
e81810d845 | ||
|
|
c57ebffe6f | ||
|
|
e281133f12 | ||
|
|
92878558c6 | ||
|
|
ec449158c6 | ||
|
|
eefa004b8f | ||
|
|
77a75ed365 | ||
|
|
364ec2a694 | ||
|
|
9a8a707016 | ||
|
|
7a5f014014 | ||
|
|
5ca5a504a4 | ||
|
|
cb45c8feac | ||
|
|
7d79d73b58 | ||
|
|
7c426db36a | ||
|
|
744638ed08 | ||
|
|
9bc7cd7904 | ||
|
|
d83bbfb1d5 | ||
|
|
4ad9e82f50 | ||
|
|
677c7edf3f | ||
|
|
e56af4967c | ||
|
|
1f7af35368 | ||
|
|
08ab4abd43 | ||
|
|
a810eb29db | ||
|
|
3881324007 | ||
|
|
af3b356d70 | ||
|
|
24676eea71 | ||
|
|
7e2eb997a8 | ||
|
|
ec570c46bf | ||
|
|
8eedfe4bc6 | ||
|
|
800fb81d1b | ||
|
|
e020f5849c | ||
|
|
698784e103 | ||
|
|
f7345ffaac | ||
|
|
b7faa4a7f2 | ||
|
|
0fcfb80be4 | ||
|
|
38a9b7166b | ||
|
|
3b28f52ff7 | ||
|
|
7725fe338e | ||
|
|
2ed66f6e8b | ||
|
|
9aaf789c21 | ||
|
|
d5cf339b83 | ||
|
|
6bc7b56e6e | ||
|
|
e4db6d47c2 | ||
|
|
ce4e00e5ae | ||
|
|
06ca2ef726 | ||
|
|
8d853a6d58 | ||
|
|
de768aefc3 | ||
|
|
4b284f6687 | ||
|
|
d0948e5586 | ||
|
|
b0a45e5b93 | ||
|
|
6f91331626 | ||
|
|
4ecb1bb2ed | ||
|
|
3bcca99cba | ||
|
|
5612a59b30 | ||
|
|
88ea66b4c9 | ||
|
|
b61399fbde | ||
|
|
a8db2bcf10 | ||
|
|
e14f4c5db1 | ||
|
|
1948b0c7c7 | ||
|
|
4b4b0e630e | ||
|
|
d9071a80a0 | ||
|
|
969740a263 | ||
|
|
0222d90fa3 | ||
|
|
a133e018cc | ||
|
|
c2d1ae06c5 | ||
|
|
59e41f195b | ||
|
|
7987d4e5ce | ||
|
|
a8e331a778 | ||
|
|
eb97652537 | ||
|
|
0a4fe7ed97 | ||
|
|
676e893c14 | ||
|
|
e37056192b | ||
|
|
8321f6bfe3 | ||
|
|
b3d1c238eb | ||
|
|
61d9bd7e5e | ||
|
|
1fbb6e8734 | ||
|
|
59de6b505a | ||
|
|
ea1411cd07 | ||
|
|
c5fd64c72a | ||
|
|
45f442bd73 | ||
|
|
b8a4adbdc7 | ||
|
|
47fdcebb01 | ||
|
|
8cdd8de360 | ||
|
|
7402aea9f2 | ||
|
|
300c711af1 | ||
|
|
39b8bbc39b | ||
|
|
90f96af720 | ||
|
|
710b2b5fdc | ||
|
|
a577b81eb3 | ||
|
|
a5478b0712 | ||
|
|
12587d8295 | ||
|
|
e17bb4ff11 | ||
|
|
aba19841ee | ||
|
|
0288dba46c | ||
|
|
5a306785ba | ||
|
|
c200b95f6a | ||
|
|
2cccd621ea | ||
|
|
385b18f588 | ||
|
|
bf1f9f4b95 | ||
|
|
4c3271728d | ||
|
|
57231ae75d | ||
|
|
97c2a70593 | ||
|
|
485346f0e5 | ||
|
|
a8d4c3a567 | ||
|
|
dfb3a13246 | ||
|
|
f84eb9ed47 | ||
|
|
8136c5f3de | ||
|
|
45669e08c6 | ||
|
|
a5db69e1af | ||
|
|
8aceef20e1 | ||
|
|
7e3c71ed19 | ||
|
|
9d09bee6fb | ||
|
|
cd6ee373ff | ||
|
|
4d0acc9b02 | ||
|
|
393fbf1b66 | ||
|
|
3324b03a5d | ||
|
|
eb91f9922d | ||
|
|
9a7420ccd0 | ||
|
|
be72120311 | ||
|
|
c452c3a101 | ||
|
|
0b3bb66708 | ||
|
|
d0d0fa4d10 | ||
|
|
6222ed622f | ||
|
|
1a03e98057 | ||
|
|
46cea93fc3 | ||
|
|
d64b8fd9d8 | ||
|
|
c051daee2f | ||
|
|
ae70d10996 | ||
|
|
52e6399e02 | ||
|
|
ac05f62f2f | ||
|
|
4d935efd09 | ||
|
|
fa8cc7976a | ||
|
|
ee4e34bf6d | ||
|
|
c8e0f8b149 | ||
|
|
b47188763c | ||
|
|
5e5c9df5c4 | ||
|
|
1a97f599dd | ||
|
|
3b264c9572 | ||
|
|
144c096ae6 | ||
|
|
adbcd320b2 | ||
|
|
17ba44056e | ||
|
|
502abade7c | ||
|
|
b746c9018e | ||
|
|
92af641827 | ||
|
|
b5606a247d | ||
|
|
d62baf5a5d | ||
|
|
e17567866a | ||
|
|
76f9596f22 | ||
|
|
2a3a713811 | ||
|
|
175ebb3cd8 | ||
|
|
95367a4a63 | ||
|
|
8950c3c4c8 | ||
|
|
2d1abd099d | ||
|
|
a894db35fd | ||
|
|
328a14014c | ||
|
|
315a2c63fa | ||
|
|
ca4ea7649d | ||
|
|
08c877ec7b | ||
|
|
212ad45be4 | ||
|
|
e9b37c7578 | ||
|
|
1438cecfad | ||
|
|
49824ce1a6 | ||
|
|
bc0ec9dc07 | ||
|
|
5957b9f155 | ||
|
|
72e6e828f1 | ||
|
|
01b4393fa7 | ||
|
|
bf2a5386f9 | ||
|
|
fb4d4a609b | ||
|
|
1cddb2aa88 | ||
|
|
aac9679282 | ||
|
|
90472685e8 | ||
|
|
7bb764b3e4 | ||
|
|
1aed9c545f | ||
|
|
c937e49689 | ||
|
|
0d860516ac | ||
|
|
4ced1d65b4 | ||
|
|
92540d5e85 | ||
|
|
ea982a627e | ||
|
|
835ecac8db | ||
|
|
c3bbb48041 | ||
|
|
2e842f0146 | ||
|
|
8de2fb9009 | ||
|
|
17e177405a | ||
|
|
ef67561fb3 | ||
|
|
df97effb9c | ||
|
|
8317960f81 | ||
|
|
065bf54094 | ||
|
|
f36acc27e5 | ||
|
|
491ad6de95 | ||
|
|
3eedf8ed1b | ||
|
|
75b260e495 | ||
|
|
2351948291 | ||
|
|
538e518d76 | ||
|
|
de955dacc4 | ||
|
|
19ed63129e | ||
|
|
2e744a1c1b | ||
|
|
89534b88b1 | ||
|
|
c9b6e82e2c |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,3 +1,4 @@
|
||||
raw
|
||||
presentation
|
||||
test.coffee
|
||||
parser.output
|
||||
|
||||
75
Cakefile
75
Cakefile
@@ -1,12 +1,22 @@
|
||||
fs: require 'fs'
|
||||
helpers: require('./lib/helpers').helpers
|
||||
CoffeeScript: require './lib/coffee-script'
|
||||
fs: require 'fs'
|
||||
{helpers}: require('./lib/helpers')
|
||||
CoffeeScript: require './lib/coffee-script'
|
||||
{spawn, exec}: require('child_process')
|
||||
|
||||
# ANSI Terminal Colors.
|
||||
red: '\033[0;31m'
|
||||
green: '\033[0;32m'
|
||||
reset: '\033[0m'
|
||||
|
||||
# Run a CoffeeScript through our node/coffee interpreter.
|
||||
run: (args) ->
|
||||
proc: process.createChildProcess 'bin/coffee', args
|
||||
proc.addListener 'error', (err) -> if err then puts err
|
||||
proc: spawn 'bin/coffee', args
|
||||
proc.stderr.addListener 'data', (buffer) -> puts buffer.toString()
|
||||
proc.addListener 'exit', (status) -> process.exit(1) if status != 0
|
||||
|
||||
# Log a message with a color.
|
||||
log: (message, color, explanation) ->
|
||||
puts "$color$message$reset ${explanation or ''}"
|
||||
|
||||
option '-p', '--prefix [DIR]', 'set the installation prefix for `cake install`'
|
||||
|
||||
@@ -14,13 +24,19 @@ task 'install', 'install CoffeeScript into /usr/local (or --prefix)', (options)
|
||||
base: options.prefix or '/usr/local'
|
||||
lib: "$base/lib/coffee-script"
|
||||
bin: "$base/bin"
|
||||
node: "~/.node_libraries/coffee-script"
|
||||
puts "Installing CoffeeScript to $lib"
|
||||
puts "Linking to $node"
|
||||
puts "Linking 'coffee' to $bin/coffee"
|
||||
exec([
|
||||
"mkdir -p $lib $bin"
|
||||
"cp -rf bin lib LICENSE README package.json src vendor $lib"
|
||||
"ln -sf $lib/bin/coffee $base/bin/coffee"
|
||||
"ln -sf $lib/bin/cake $base/bin/cake"
|
||||
"cp -rf bin lib LICENSE README package.json src $lib"
|
||||
"ln -sf $lib/bin/coffee $bin/coffee"
|
||||
"ln -sf $lib/bin/cake $bin/cake"
|
||||
"mkdir -p ~/.node_libraries"
|
||||
"ln -sf $lib/lib $node"
|
||||
].join(' && '), (err, stdout, stderr) ->
|
||||
if err then print stderr
|
||||
if err then print stderr else log 'done', green
|
||||
)
|
||||
|
||||
|
||||
@@ -38,11 +54,11 @@ task 'build:full', 'rebuild the source twice, and run the tests', ->
|
||||
|
||||
|
||||
task 'build:parser', 'rebuild the Jison parser (run build first)', ->
|
||||
require.paths.unshift 'vendor/jison/lib'
|
||||
require 'jison'
|
||||
parser: require('./lib/grammar').parser
|
||||
js: parser.generate()
|
||||
parser_path: 'lib/parser.js'
|
||||
fs.writeFile parser_path, js
|
||||
parserPath: 'lib/parser.js'
|
||||
fs.writeFile parserPath, js
|
||||
|
||||
|
||||
task 'build:ultraviolet', 'build and install the Ultraviolet syntax highlighter', ->
|
||||
@@ -70,31 +86,34 @@ task 'doc:underscore', 'rebuild the Underscore.coffee documentation page', ->
|
||||
throw err if err
|
||||
|
||||
|
||||
task 'loc', 'count the lines of source code in CoffeeScript', ->
|
||||
exec "cat src/*.coffee | grep -v '^\\( *#\\|\\s*$\\)' | wc -l | tr -s ' '", (err, stdout) ->
|
||||
print stdout
|
||||
|
||||
|
||||
task 'test', 'run the CoffeeScript language test suite', ->
|
||||
helpers.extend global, require 'assert'
|
||||
passed_tests: failed_tests: 0
|
||||
start_time: new Date()
|
||||
original_ok: ok
|
||||
passedTests: failedTests: 0
|
||||
startTime: new Date
|
||||
originalOk: ok
|
||||
helpers.extend global, {
|
||||
ok: (args...) -> passed_tests += 1; original_ok(args...)
|
||||
ok: (args...) -> passedTests += 1; originalOk(args...)
|
||||
CoffeeScript: CoffeeScript
|
||||
}
|
||||
red: '\033[0;31m'
|
||||
green: '\033[0;32m'
|
||||
reset: '\033[0m'
|
||||
on_exit: ->
|
||||
time: ((new Date() - start_time) / 1000).toFixed(2)
|
||||
message: "passed $passed_tests tests in $time seconds$reset"
|
||||
puts(if failed_tests then "${red}failed $failed_tests and $message" else "$green$message")
|
||||
process.addListener 'exit', on_exit
|
||||
process.addListener 'exit', ->
|
||||
time: ((new Date - startTime) / 1000).toFixed(2)
|
||||
message: "passed $passedTests tests in $time seconds$reset"
|
||||
if failedTests
|
||||
log "failed $failedTests and $message", red
|
||||
else
|
||||
log message, green
|
||||
fs.readdir 'test', (err, files) ->
|
||||
files.forEach (file) ->
|
||||
return unless file.match(/\.coffee$/i)
|
||||
source: path.join 'test', file
|
||||
fs.readFile source, (err, code) ->
|
||||
try
|
||||
CoffeeScript.run code, {source: source}
|
||||
CoffeeScript.run code.toString(), {source: source}
|
||||
catch err
|
||||
failed_tests += 1
|
||||
puts "${red}failed:${reset} $source"
|
||||
puts err.stack
|
||||
failedTests += 1
|
||||
log "failed $source", red, '\n' + err.stack.toString()
|
||||
|
||||
7
README
7
README
@@ -25,6 +25,9 @@
|
||||
Install Node.js, and then the CoffeeScript compiler:
|
||||
sudo bin/cake install
|
||||
|
||||
Or, if you have the Node Package Manager installed:
|
||||
sudo npm install coffee-script
|
||||
|
||||
Compile a script:
|
||||
coffee /path/to/script.coffee
|
||||
|
||||
@@ -50,9 +53,11 @@
|
||||
Mathieu D'Amours (matehat)
|
||||
Chris Hoffman (cehoffman)
|
||||
Jason Huggins (hugs)
|
||||
Tim Jones (Tesco)
|
||||
Timothy Jones (Tesco)
|
||||
Chris Lloyd (chrislloyd)
|
||||
Matt Lyon (mattly)
|
||||
Jeff Olson (olsonjeffery)
|
||||
Nathan Ostgard (noonat)
|
||||
Samuel Reis (grgh)
|
||||
Tom Robinson (tlrobinson)
|
||||
Tim Smart (Tim-Smart)
|
||||
|
||||
12
Rakefile
12
Rakefile
@@ -4,6 +4,16 @@ require 'rake/testtask'
|
||||
require 'rubygems'
|
||||
require 'yui/compressor'
|
||||
|
||||
HEADER = <<-EOS
|
||||
/**
|
||||
* CoffeeScript Compiler v0.7.2
|
||||
* http://coffeescript.org
|
||||
*
|
||||
* Copyright 2010, Jeremy Ashkenas
|
||||
* Released under the MIT License
|
||||
*/
|
||||
EOS
|
||||
|
||||
desc "Build the documentation page"
|
||||
task :doc do
|
||||
source = 'documentation/index.html.erb'
|
||||
@@ -26,6 +36,6 @@ task :browser do
|
||||
sources = %w(helpers.js rewriter.js lexer.js parser.js scope.js nodes.js coffee-script.js)
|
||||
code = sources.map {|s| File.read('lib/' + s) }.join('')
|
||||
code = YUI::JavaScriptCompressor.new.compress(code)
|
||||
File.open('extras/coffee-script.js', 'w+') {|f| f.write(code) }
|
||||
File.open('extras/coffee-script.js', 'w+') {|f| f.write(HEADER + code) }
|
||||
end
|
||||
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
launch() if ignition is on
|
||||
|
||||
volume: 10 if band isnt spinal_tap
|
||||
volume: 10 if band isnt SpinalTap
|
||||
|
||||
let_the_wild_rumpus_begin() unless answer is no
|
||||
letTheWildRumpusBegin() unless answer is no
|
||||
|
||||
if car.speed < speed_limit then accelerate()
|
||||
if car.speed < limit then accelerate()
|
||||
|
||||
winner: yes if pick in [47, 92, 13]
|
||||
|
||||
print "My name is " + @name
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
url: "documentation/coffee/binding.coffee"
|
||||
|
||||
get_source: jQuery.get <- jQuery, url
|
||||
|
||||
get_source (response) -> alert response
|
||||
@@ -1,3 +1,3 @@
|
||||
task 'test', 'run each of the unit tests', ->
|
||||
for test in test_files
|
||||
for test in files
|
||||
fs.readFile test, (err, code) -> eval coffee.compile code
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
mood: greatly_improved if singing
|
||||
mood: greatlyImproved if singing
|
||||
|
||||
if happy and knows_it
|
||||
claps_hands()
|
||||
cha_cha_cha()
|
||||
if happy and knowsIt
|
||||
clapsHands()
|
||||
chaChaCha()
|
||||
|
||||
date: if friday then sue else jill
|
||||
|
||||
expensive: or do_the_math()
|
||||
options: or defaultOptions
|
||||
@@ -1,8 +1,8 @@
|
||||
grade: (student) ->
|
||||
if student.excellent_work
|
||||
if student.excellentWork
|
||||
"A+"
|
||||
else if student.okay_stuff
|
||||
if student.tried_hard then "B" else "B-"
|
||||
else if student.okayStuff
|
||||
if student.triedHard then "B" else "B-"
|
||||
else
|
||||
"C"
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
weather_report: (location) ->
|
||||
weatherReport: (location) ->
|
||||
# Make an Ajax request to fetch the weather...
|
||||
[location, 72, "Mostly Sunny"]
|
||||
|
||||
[city, temp, forecast]: weather_report "Berkeley, CA"
|
||||
[city, temp, forecast]: weatherReport "Berkeley, CA"
|
||||
@@ -1,4 +1,4 @@
|
||||
years_old: {max: 10, ida: 9, tim: 11}
|
||||
yearsOld: {max: 10, ida: 9, tim: 11}
|
||||
|
||||
ages: for child, age of years_old
|
||||
ages: for child, age of yearsOld
|
||||
child + " is " + age
|
||||
@@ -10,4 +10,4 @@ futurists: {
|
||||
}
|
||||
}
|
||||
|
||||
{poet: {name: poet, address: [street, city]}}: futurists
|
||||
{poet: {name, address: [street, city]}}: futurists
|
||||
1
documentation/coffee/objects_reserved.coffee
Normal file
1
documentation/coffee/objects_reserved.coffee
Normal file
@@ -0,0 +1 @@
|
||||
$('.account').css {class: 'active'}
|
||||
@@ -1,9 +1,9 @@
|
||||
# Assignment:
|
||||
number: 42
|
||||
opposite_day: true
|
||||
opposite: true
|
||||
|
||||
# Conditions:
|
||||
number: -42 if opposite_day
|
||||
number: -42 if opposite
|
||||
|
||||
# Functions:
|
||||
square: (x) -> x * x
|
||||
@@ -26,4 +26,4 @@ race: (winner, runners...) ->
|
||||
alert "I knew it!" if elvis?
|
||||
|
||||
# Array comprehensions:
|
||||
cubed_list: math.cube num for num in list
|
||||
cubes: math.cube num for num in list
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
bait: 1000
|
||||
and_switch: 0
|
||||
theBait: 1000
|
||||
theSwitch: 0
|
||||
|
||||
[bait, and_switch]: [and_switch, bait]
|
||||
[theBait, theSwitch]: [theSwitch, theBait]
|
||||
@@ -1,6 +1,6 @@
|
||||
countdown: num for num in [10..1]
|
||||
countdown: num for num in [10..1] by -1
|
||||
|
||||
egg_delivery: ->
|
||||
deliverEggs: ->
|
||||
for i in [0...eggs.length] by 12
|
||||
dozen_eggs: eggs[i...i+12]
|
||||
deliver new egg_carton(dozen)
|
||||
dozen: eggs[i...i+12]
|
||||
deliver new eggCarton(dozen)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
num: 1
|
||||
change_numbers: ->
|
||||
new_num: -1
|
||||
num: 10
|
||||
new_num: change_numbers()
|
||||
outer: 1
|
||||
changeNumbers: ->
|
||||
inner: -1
|
||||
outer: 10
|
||||
inner: changeNumbers()
|
||||
@@ -1,6 +1,6 @@
|
||||
numbers: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
|
||||
|
||||
three_to_six: numbers[3..6]
|
||||
threeToSix: numbers[3..6]
|
||||
|
||||
numbers_copy: numbers[0...numbers.length]
|
||||
copy: numbers[0...numbers.length]
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
lottery.draw_winner()?.address?.zipcode
|
||||
lottery.drawWinner()?.address?.zipcode
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
gold: silver: the_field: "unknown"
|
||||
gold: silver: rest: "unknown"
|
||||
|
||||
award_medals: (first, second, rest...) ->
|
||||
gold: first
|
||||
silver: second
|
||||
the_field: rest
|
||||
awardMedals: (first, second, rest...) ->
|
||||
gold: first
|
||||
silver: second
|
||||
rest: rest
|
||||
|
||||
contenders: [
|
||||
"Michael Phelps"
|
||||
@@ -18,8 +18,8 @@ contenders: [
|
||||
"Usain Bolt"
|
||||
]
|
||||
|
||||
award_medals contenders...
|
||||
awardMedals contenders...
|
||||
|
||||
alert "Gold: " + gold
|
||||
alert "Silver: " + silver
|
||||
alert "The Field: " + the_field
|
||||
alert "The Field: " + rest
|
||||
@@ -1,4 +1,4 @@
|
||||
moby_dick: "Call me Ishmael. Some years ago --
|
||||
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
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
switch day
|
||||
when "Mon" then go_to_work()
|
||||
when "Tue" then go_to_the_park()
|
||||
when "Thu" then go_ice_fishing()
|
||||
when "Mon" then goToWork()
|
||||
when "Tue" then goToThePark()
|
||||
when "Thu" then goIceFishing()
|
||||
when "Fri", "Sat"
|
||||
if day is bingo_day
|
||||
go_to_bingo()
|
||||
go_dancing()
|
||||
when "Sun" then go_to_church()
|
||||
else go_to_work()
|
||||
if day is bingoDay
|
||||
goToBingo()
|
||||
goDancing()
|
||||
when "Sun" then goToChurch()
|
||||
else goToWork()
|
||||
@@ -1,7 +1,7 @@
|
||||
try
|
||||
all_hell_breaks_loose()
|
||||
cats_and_dogs_living_together()
|
||||
allHellBreaksLoose()
|
||||
catsAndDogsLivingTogether()
|
||||
catch error
|
||||
print error
|
||||
finally
|
||||
clean_up()
|
||||
cleanUp()
|
||||
@@ -1,10 +1,10 @@
|
||||
# Econ 101
|
||||
if this.studying_economics
|
||||
while supply > demand then buy()
|
||||
while supply < demand then sell()
|
||||
if this.studyingEconomics
|
||||
buy() while supply > demand
|
||||
sell() until supply > demand
|
||||
|
||||
# Nursery Rhyme
|
||||
num: 6
|
||||
lyrics: while num -= 1
|
||||
lyrics: while num: - 1
|
||||
num + " little monkeys, jumping on the bed.
|
||||
One fell out and bumped his head."
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<!DOCTYPE html> <html> <head> <title>cake.coffee</title> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <link rel="stylesheet" media="all" href="docco.css" /> </head> <body> <div id="container"> <div id="background"></div> <div id="jump_to"> Jump To … <div id="jump_wrapper"> <div id="jump_page"> <a class="source" href="cake.html"> cake.coffee </a> <a class="source" href="coffee-script.html"> coffee-script.coffee </a> <a class="source" href="command.html"> command.coffee </a> <a class="source" href="grammar.html"> grammar.coffee </a> <a class="source" href="helpers.html"> helpers.coffee </a> <a class="source" href="lexer.html"> lexer.coffee </a> <a class="source" href="nodes.html"> nodes.coffee </a> <a class="source" href="optparse.html"> optparse.coffee </a> <a class="source" href="repl.html"> repl.coffee </a> <a class="source" href="rewriter.html"> rewriter.coffee </a> <a class="source" href="scope.html"> scope.coffee </a> </div> </div> </div> <table cellpadding="0" cellspacing="0"> <thead> <tr> <th class="docs"> <h1> cake.coffee </h1> </th> <th class="code"> </th> </tr> </thead> <tbody> <tr id="section-1"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-1">#</a> </div> <p><code>cake</code> is a simplified version of <a href="http://www.gnu.org/software/make/">Make</a>
|
||||
<!DOCTYPE html> <html> <head> <title>cake.coffee</title> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <link rel="stylesheet" media="all" href="docco.css" /> </head> <body> <div id="container"> <div id="background"></div> <div id="jump_to"> Jump To … <div id="jump_wrapper"> <div id="jump_page"> <a class="source" href="cake.html"> cake.coffee </a> <a class="source" href="coffee-script.html"> coffee-script.coffee </a> <a class="source" href="command.html"> command.coffee </a> <a class="source" href="grammar.html"> grammar.coffee </a> <a class="source" href="helpers.html"> helpers.coffee </a> <a class="source" href="index.html"> index.coffee </a> <a class="source" href="lexer.html"> lexer.coffee </a> <a class="source" href="nodes.html"> nodes.coffee </a> <a class="source" href="optparse.html"> optparse.coffee </a> <a class="source" href="repl.html"> repl.coffee </a> <a class="source" href="rewriter.html"> rewriter.coffee </a> <a class="source" href="scope.html"> scope.coffee </a> </div> </div> </div> <table cellpadding="0" cellspacing="0"> <thead> <tr> <th class="docs"> <h1> cake.coffee </h1> </th> <th class="code"> </th> </tr> </thead> <tbody> <tr id="section-1"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-1">#</a> </div> <p><code>cake</code> is a simplified version of <a href="http://www.gnu.org/software/make/">Make</a>
|
||||
(<a href="http://rake.rubyforge.org/">Rake</a>, <a href="http://github.com/280north/jake">Jake</a>)
|
||||
for CoffeeScript. You define tasks with names and descriptions in a Cakefile,
|
||||
and can call them from the command line, or invoke them from other tasks.</p>
|
||||
@@ -11,13 +11,14 @@ current directory's Cakefile.</p> </td> <td class="code"
|
||||
<span class="nv">CoffeeScript: </span><span class="nx">require</span> <span class="s1">'./coffee-script'</span></pre></div> </td> </tr> <tr id="section-3"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-3">#</a> </div> <p>Keep track of the list of defined tasks, the accepted options, and so on.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">tasks: </span><span class="p">{}</span>
|
||||
<span class="nv">options: </span><span class="p">{}</span>
|
||||
<span class="nv">switches: </span><span class="p">[]</span>
|
||||
<span class="nv">oparse: </span><span class="kc">null</span></pre></div> </td> </tr> <tr id="section-4"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-4">#</a> </div> <p>Mixin the top-level Cake functions for Cakefiles to use directly.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nx">helpers</span><span class="p">.</span><span class="nx">extend</span> <span class="nx">global</span><span class="p">,</span> <span class="p">{</span></pre></div> </td> </tr> <tr id="section-5"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-5">#</a> </div> <p>Define a Cake task with a short name, a sentence description,
|
||||
<span class="nv">oparse: </span><span class="kc">null</span></pre></div> </td> </tr> <tr id="section-4"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-4">#</a> </div> <p>Mixin the top-level Cake functions for Cakefiles to use directly.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nx">helpers</span><span class="p">.</span><span class="nx">extend</span> <span class="nx">global</span><span class="p">,</span> <span class="p">{</span></pre></div> </td> </tr> <tr id="section-5"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-5">#</a> </div> <p>Define a Cake task with a short name, an optional sentence description,
|
||||
and the function to run as the action itself.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">task: </span><span class="p">(</span><span class="nx">name</span><span class="p">,</span> <span class="nx">description</span><span class="p">,</span> <span class="nx">action</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nx">tasks</span><span class="p">[</span><span class="nx">name</span><span class="p">]</span><span class="o">:</span> <span class="p">{</span><span class="nv">name: </span><span class="nx">name</span><span class="p">,</span> <span class="nv">description: </span><span class="nx">description</span><span class="p">,</span> <span class="nv">action: </span><span class="nx">action</span><span class="p">}</span></pre></div> </td> </tr> <tr id="section-6"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-6">#</a> </div> <p>Define an option that the Cakefile accepts. The parsed options hash,
|
||||
<span class="p">[</span><span class="nx">action</span><span class="p">,</span> <span class="nx">description</span><span class="p">]</span><span class="o">:</span> <span class="p">[</span><span class="nx">description</span><span class="p">,</span> <span class="nx">action</span><span class="p">]</span> <span class="nx">unless</span> <span class="nx">action</span>
|
||||
<span class="nx">tasks</span><span class="p">[</span><span class="nx">name</span><span class="p">]</span><span class="o">:</span> <span class="p">{</span><span class="nx">name</span><span class="p">,</span> <span class="nx">description</span><span class="p">,</span> <span class="nx">action</span><span class="p">}</span></pre></div> </td> </tr> <tr id="section-6"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-6">#</a> </div> <p>Define an option that the Cakefile accepts. The parsed options hash,
|
||||
containing all of the command-line options passed, will be made available
|
||||
as the first argument to the action.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">option: </span><span class="p">(</span><span class="nx">letter</span><span class="p">,</span> <span class="nx">flag</span><span class="p">,</span> <span class="nx">description</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nx">switches</span><span class="p">.</span><span class="nx">push</span> <span class="p">[</span><span class="nx">letter</span><span class="p">,</span> <span class="nx">flag</span><span class="p">,</span> <span class="nx">description</span><span class="p">]</span></pre></div> </td> </tr> <tr id="section-7"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-7">#</a> </div> <p>Invoke another task in the current Cakefile.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">invoke: </span><span class="p">(</span><span class="nx">name</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nx">no_such_task</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">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>
|
||||
|
||||
<span class="p">}</span></pre></div> </td> </tr> <tr id="section-8"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-8">#</a> </div> <p>Run <code>cake</code>. Executes all of the tasks you pass, in order. Note that Node's
|
||||
@@ -26,18 +27,19 @@ If no tasks are passed, print the help screen.</p> </td>
|
||||
<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="mi">2</span><span class="p">...</span><span class="nx">process</span><span class="p">.</span><span class="nx">argv</span><span class="p">.</span><span class="nx">length</span><span class="p">]</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="p">{</span><span class="nv">source: </span><span class="s1">'Cakefile'</span><span class="p">}</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="p">{</span><span class="nv">source: </span><span class="s1">'Cakefile'</span><span class="p">}</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">print_tasks</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="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="octowrap"> <a class="octothorpe" 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">print_tasks: </span><span class="o">-></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="octowrap"> <a class="octothorpe" 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">puts</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="p">(</span><span class="s1">' '</span> <span class="k">for</span> <span class="nx">i</span> <span class="k">in</span> <span class="p">[</span><span class="mi">0</span><span class="p">..</span><span class="nx">spaces</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="nx">puts</span> <span class="s2">"cake $name$spaces # ${task.description}"</span>
|
||||
<span class="nx">puts</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="octowrap"> <a class="octothorpe" 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">no_such_task: </span><span class="p">(</span><span class="nx">task</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nx">process</span><span class="p">.</span><span class="nx">stdio</span><span class="p">.</span><span class="nx">writeError</span> <span class="s2">"No such task: \"$task\"\n"</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">puts</span> <span class="s2">"cake $name$spaces $desc"</span>
|
||||
<span class="nx">puts</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="octowrap"> <a class="octothorpe" 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">puts</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>
|
||||
|
||||
</pre></div> </td> </tr> </tbody> </table> </div> </body> </html>
|
||||
@@ -1,4 +1,4 @@
|
||||
<!DOCTYPE html> <html> <head> <title>coffee-script.coffee</title> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <link rel="stylesheet" media="all" href="docco.css" /> </head> <body> <div id="container"> <div id="background"></div> <div id="jump_to"> Jump To … <div id="jump_wrapper"> <div id="jump_page"> <a class="source" href="cake.html"> cake.coffee </a> <a class="source" href="coffee-script.html"> coffee-script.coffee </a> <a class="source" href="command.html"> command.coffee </a> <a class="source" href="grammar.html"> grammar.coffee </a> <a class="source" href="helpers.html"> helpers.coffee </a> <a class="source" href="lexer.html"> lexer.coffee </a> <a class="source" href="nodes.html"> nodes.coffee </a> <a class="source" href="optparse.html"> optparse.coffee </a> <a class="source" href="repl.html"> repl.coffee </a> <a class="source" href="rewriter.html"> rewriter.coffee </a> <a class="source" href="scope.html"> scope.coffee </a> </div> </div> </div> <table cellpadding="0" cellspacing="0"> <thead> <tr> <th class="docs"> <h1> coffee-script.coffee </h1> </th> <th class="code"> </th> </tr> </thead> <tbody> <tr id="section-1"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-1">#</a> </div> <p>CoffeeScript can be used both on the server, as a command-line compiler based
|
||||
<!DOCTYPE html> <html> <head> <title>coffee-script.coffee</title> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <link rel="stylesheet" media="all" href="docco.css" /> </head> <body> <div id="container"> <div id="background"></div> <div id="jump_to"> Jump To … <div id="jump_wrapper"> <div id="jump_page"> <a class="source" href="cake.html"> cake.coffee </a> <a class="source" href="coffee-script.html"> coffee-script.coffee </a> <a class="source" href="command.html"> command.coffee </a> <a class="source" href="grammar.html"> grammar.coffee </a> <a class="source" href="helpers.html"> helpers.coffee </a> <a class="source" href="index.html"> index.coffee </a> <a class="source" href="lexer.html"> lexer.coffee </a> <a class="source" href="nodes.html"> nodes.coffee </a> <a class="source" href="optparse.html"> optparse.coffee </a> <a class="source" href="repl.html"> repl.coffee </a> <a class="source" href="rewriter.html"> rewriter.coffee </a> <a class="source" href="scope.html"> scope.coffee </a> </div> </div> </div> <table cellpadding="0" cellspacing="0"> <thead> <tr> <th class="docs"> <h1> coffee-script.coffee </h1> </th> <th class="code"> </th> </tr> </thead> <tbody> <tr id="section-1"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-1">#</a> </div> <p>CoffeeScript can be used both on the server, as a command-line compiler based
|
||||
on Node.js/V8, or to run CoffeeScripts directly in the browser. This module
|
||||
contains the main entry functions for tokenzing, parsing, and compiling source
|
||||
CoffeeScript into JavaScript.</p>
|
||||
@@ -16,13 +16,13 @@ execute all scripts present in <code>text/coffeescript</code> tags.</p>
|
||||
<span class="k">this</span><span class="p">.</span><span class="nv">exports: </span><span class="k">this</span><span class="p">.</span><span class="nv">CoffeeScript: </span><span class="p">{}</span>
|
||||
<span class="nv">Lexer: </span> <span class="k">this</span><span class="p">.</span><span class="nx">Lexer</span>
|
||||
<span class="nv">parser: </span> <span class="k">this</span><span class="p">.</span><span class="nx">parser</span>
|
||||
<span class="nv">helpers: </span> <span class="k">this</span><span class="p">.</span><span class="nx">helpers</span></pre></div> </td> </tr> <tr id="section-3"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-3">#</a> </div> <p>The current CoffeeScript version number.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.VERSION: </span><span class="s1">'0.6.0'</span></pre></div> </td> </tr> <tr id="section-4"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-4">#</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><span class="p">()</span></pre></div> </td> </tr> <tr id="section-5"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-5">#</a> </div> <p>Compile a string of CoffeeScript code to JavaScript, using the Coffee/Jison
|
||||
<span class="nv">helpers: </span> <span class="k">this</span><span class="p">.</span><span class="nx">helpers</span></pre></div> </td> </tr> <tr id="section-3"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-3">#</a> </div> <p>The current CoffeeScript version number.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.VERSION: </span><span class="s1">'0.7.2'</span></pre></div> </td> </tr> <tr id="section-4"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-4">#</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-5"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-5">#</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="nx">options</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nv">options: </span><span class="o">or</span> <span class="p">{}</span>
|
||||
<span class="k">try</span>
|
||||
<span class="p">(</span><span class="nx">parser</span><span class="p">.</span><span class="nx">parse</span> <span class="nx">lexer</span><span class="p">.</span><span class="nx">tokenize</span> <span class="nx">code</span><span class="p">).</span><span class="nx">compile</span> <span class="nx">options</span>
|
||||
<span class="k">catch</span> <span class="nx">err</span>
|
||||
<span class="nv">err.message: </span><span class="s2">"In ${options.source}, ${err.message}"</span> <span class="k">if</span> <span class="nx">options</span><span class="p">.</span><span class="nx">source</span>
|
||||
<span class="nv">err.message: </span><span class="s2">"In $options.source, $err.message"</span> <span class="k">if</span> <span class="nx">options</span><span class="p">.</span><span class="nx">source</span>
|
||||
<span class="k">throw</span> <span class="nx">err</span></pre></div> </td> </tr> <tr id="section-6"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-6">#</a> </div> <p>Tokenize a string of CoffeeScript code, and return the array of tokens.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.tokens: </span><span class="p">(</span><span class="nx">code</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nx">lexer</span><span class="p">.</span><span class="nx">tokenize</span> <span class="nx">code</span></pre></div> </td> </tr> <tr id="section-7"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-7">#</a> </div> <p>Tokenize and parse a string of CoffeeScript code, and return the AST. You can
|
||||
then compile it by calling <code>.compile()</code> on the root, or traverse it by using
|
||||
@@ -32,11 +32,7 @@ setting <code>__filename</code>, <code>__dirname</code>, and relative <code>requ
|
||||
<span class="nv">module.filename: __filename: </span><span class="nx">options</span><span class="p">.</span><span class="nx">source</span>
|
||||
<span class="nv">__dirname: </span><span class="nx">path</span><span class="p">.</span><span class="nx">dirname</span><span class="p">(</span><span class="nx">__filename</span><span class="p">)</span>
|
||||
<span class="nb">eval</span> <span class="nx">exports</span><span class="p">.</span><span class="nx">compile</span> <span class="nx">code</span><span class="p">,</span> <span class="nx">options</span>
|
||||
<span class="p">)</span></pre></div> </td> </tr> <tr id="section-9"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-9">#</a> </div> <p>Extend CoffeeScript with a custom language extension. It should hook in to
|
||||
the <strong>Lexer</strong> (as a peer of any of the lexer's tokenizing methods), and
|
||||
push a token on to the stack that contains a <strong>Node</strong> as the value (as a
|
||||
peer of the nodes in <a href="nodes.html">nodes.coffee</a>).</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.extend: </span><span class="p">(</span><span class="nx">func</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nx">Lexer</span><span class="p">.</span><span class="nx">extensions</span><span class="p">.</span><span class="nx">push</span> <span class="nx">func</span></pre></div> </td> </tr> <tr id="section-10"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-10">#</a> </div> <p>The real Lexer produces a generic stream of tokens. This object provides a
|
||||
<span class="p">)</span></pre></div> </td> </tr> <tr id="section-9"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-9">#</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="p">{</span>
|
||||
<span class="nv">lex: </span><span class="o">-></span>
|
||||
@@ -49,17 +45,16 @@ directly as a "Jison lexer".</p> </td> <td class="code">
|
||||
<span class="vi">@tokens: </span><span class="nx">tokens</span>
|
||||
<span class="vi">@pos: </span><span class="mi">0</span>
|
||||
<span class="nv">upcomingInput: </span><span class="o">-></span> <span class="s2">""</span>
|
||||
<span class="nv">showPosition: </span><span class="o">-></span> <span class="nx">@pos</span>
|
||||
<span class="p">}</span></pre></div> </td> </tr> <tr id="section-11"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-11">#</a> </div> <p>Activate CoffeeScript in the browser by having it compile and evaluate
|
||||
<span class="p">}</span></pre></div> </td> </tr> <tr id="section-10"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-10">#</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. Unfortunately, the text contents of remote scripts cannot be
|
||||
accessed from the browser, so only inline script tags will work.</p> </td> <td class="code"> <div class="highlight"><pre><span class="k">if</span> <span class="nb">document</span><span class="o">?</span> <span class="o">and</span> <span class="nb">document</span><span class="p">.</span><span class="nx">getElementsByTagName</span>
|
||||
<span class="nv">process_scripts: </span><span class="o">-></span>
|
||||
<span class="nv">processScripts: </span><span class="o">-></span>
|
||||
<span class="k">for</span> <span class="nx">tag</span> <span class="k">in</span> <span class="nb">document</span><span class="p">.</span><span class="nx">getElementsByTagName</span><span class="p">(</span><span class="s1">'script'</span><span class="p">)</span> <span class="k">when</span> <span class="nx">tag</span><span class="p">.</span><span class="nx">type</span> <span class="o">is</span> <span class="s1">'text/coffeescript'</span>
|
||||
<span class="nb">eval</span> <span class="nx">exports</span><span class="p">.</span><span class="nx">compile</span> <span class="nx">tag</span><span class="p">.</span><span class="nx">innerHTML</span>
|
||||
<span class="k">if</span> <span class="nb">window</span><span class="p">.</span><span class="nx">addEventListener</span>
|
||||
<span class="nb">window</span><span class="p">.</span><span class="nx">addEventListener</span> <span class="s1">'load'</span><span class="p">,</span> <span class="nx">process_scripts</span><span class="p">,</span> <span class="kc">false</span>
|
||||
<span class="nb">window</span><span class="p">.</span><span class="nx">addEventListener</span> <span class="s1">'load'</span><span class="p">,</span> <span class="nx">processScripts</span><span class="p">,</span> <span class="kc">false</span>
|
||||
<span class="k">else</span> <span class="k">if</span> <span class="nb">window</span><span class="p">.</span><span class="nx">attachEvent</span>
|
||||
<span class="nb">window</span><span class="p">.</span><span class="nx">attachEvent</span> <span class="s1">'onload'</span><span class="p">,</span> <span class="nx">process_scripts</span>
|
||||
<span class="nb">window</span><span class="p">.</span><span class="nx">attachEvent</span> <span class="s1">'onload'</span><span class="p">,</span> <span class="nx">processScripts</span>
|
||||
|
||||
</pre></div> </td> </tr> </tbody> </table> </div> </body> </html>
|
||||
@@ -1,11 +1,12 @@
|
||||
<!DOCTYPE html> <html> <head> <title>command.coffee</title> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <link rel="stylesheet" media="all" href="docco.css" /> </head> <body> <div id="container"> <div id="background"></div> <div id="jump_to"> Jump To … <div id="jump_wrapper"> <div id="jump_page"> <a class="source" href="cake.html"> cake.coffee </a> <a class="source" href="coffee-script.html"> coffee-script.coffee </a> <a class="source" href="command.html"> command.coffee </a> <a class="source" href="grammar.html"> grammar.coffee </a> <a class="source" href="helpers.html"> helpers.coffee </a> <a class="source" href="lexer.html"> lexer.coffee </a> <a class="source" href="nodes.html"> nodes.coffee </a> <a class="source" href="optparse.html"> optparse.coffee </a> <a class="source" href="repl.html"> repl.coffee </a> <a class="source" href="rewriter.html"> rewriter.coffee </a> <a class="source" href="scope.html"> scope.coffee </a> </div> </div> </div> <table cellpadding="0" cellspacing="0"> <thead> <tr> <th class="docs"> <h1> command.coffee </h1> </th> <th class="code"> </th> </tr> </thead> <tbody> <tr id="section-1"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-1">#</a> </div> <p>The <code>coffee</code> utility. Handles command-line compilation of CoffeeScript
|
||||
<!DOCTYPE html> <html> <head> <title>command.coffee</title> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <link rel="stylesheet" media="all" href="docco.css" /> </head> <body> <div id="container"> <div id="background"></div> <div id="jump_to"> Jump To … <div id="jump_wrapper"> <div id="jump_page"> <a class="source" href="cake.html"> cake.coffee </a> <a class="source" href="coffee-script.html"> coffee-script.coffee </a> <a class="source" href="command.html"> command.coffee </a> <a class="source" href="grammar.html"> grammar.coffee </a> <a class="source" href="helpers.html"> helpers.coffee </a> <a class="source" href="index.html"> index.coffee </a> <a class="source" href="lexer.html"> lexer.coffee </a> <a class="source" href="nodes.html"> nodes.coffee </a> <a class="source" href="optparse.html"> optparse.coffee </a> <a class="source" href="repl.html"> repl.coffee </a> <a class="source" href="rewriter.html"> rewriter.coffee </a> <a class="source" href="scope.html"> scope.coffee </a> </div> </div> </div> <table cellpadding="0" cellspacing="0"> <thead> <tr> <th class="docs"> <h1> command.coffee </h1> </th> <th class="code"> </th> </tr> </thead> <tbody> <tr id="section-1"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-1">#</a> </div> <p>The <code>coffee</code> utility. Handles command-line compilation of CoffeeScript
|
||||
into various forms: saved into <code>.js</code> files or printed to stdout, piped to
|
||||
<a href="http://javascriptlint.com/">JSLint</a> or recompiled every time the source is
|
||||
saved, printed as a token stream or as the syntax tree, or launch an
|
||||
interactive REPL.</p> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-2"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-2">#</a> </div> <p>External dependencies.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">fs: </span> <span class="nx">require</span> <span class="s1">'fs'</span>
|
||||
<span class="nv">path: </span> <span class="nx">require</span> <span class="s1">'path'</span>
|
||||
<span class="nv">optparse: </span> <span class="nx">require</span> <span class="s1">'./optparse'</span>
|
||||
<span class="nv">CoffeeScript: </span><span class="nx">require</span> <span class="s1">'./coffee-script'</span></pre></div> </td> </tr> <tr id="section-3"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-3">#</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>
|
||||
interactive REPL.</p> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-2"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-2">#</a> </div> <p>External dependencies.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">fs: </span> <span class="nx">require</span> <span class="s1">'fs'</span>
|
||||
<span class="nv">path: </span> <span class="nx">require</span> <span class="s1">'path'</span>
|
||||
<span class="nv">optparse: </span> <span class="nx">require</span> <span class="s1">'./optparse'</span>
|
||||
<span class="nv">CoffeeScript: </span> <span class="nx">require</span> <span class="s1">'./coffee-script'</span>
|
||||
<span class="p">{</span><span class="nx">spawn</span><span class="p">,</span> <span class="nx">exec</span><span class="p">}</span><span class="o">:</span> <span class="nx">require</span><span class="p">(</span><span class="s1">'child_process'</span><span class="p">)</span></pre></div> </td> </tr> <tr id="section-3"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-3">#</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"> coffee compiles CoffeeScript source files into JavaScript.</span>
|
||||
|
||||
<span class="s1"> Usage:</span>
|
||||
@@ -26,90 +27,105 @@ interactive REPL.</p> </td> <td class="code">
|
||||
<span class="p">[</span><span class="s1">'-h'</span><span class="p">,</span> <span class="s1">'--help'</span><span class="p">,</span> <span class="s1">'display this help message'</span><span class="p">]</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-5"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-5">#</a> </div> <p>Top-level objects shared by all the functions.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">options: </span><span class="p">{}</span>
|
||||
<span class="nv">sources: </span><span class="p">[]</span>
|
||||
<span class="nv">option_parser: </span><span class="kc">null</span></pre></div> </td> </tr> <tr id="section-6"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-6">#</a> </div> <p>Run <code>coffee</code> by parsing passed options and determining what action to take.
|
||||
<span class="nv">optionParser: </span><span class="kc">null</span></pre></div> </td> </tr> <tr id="section-6"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-6">#</a> </div> <p>Run <code>coffee</code> by parsing passed options and determining what action to take.
|
||||
Many flags cause us to divert before compiling anything. Flags passed after
|
||||
<code>--</code> will be passed verbatim to your script as arguments in <code>process.argv</code></p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.run: </span><span class="o">-></span>
|
||||
<span class="nx">parse_options</span><span class="p">()</span>
|
||||
<span class="nx">parseOptions</span><span class="p">()</span>
|
||||
<span class="k">return</span> <span class="nx">usage</span><span class="p">()</span> <span class="k">if</span> <span class="nx">options</span><span class="p">.</span><span class="nx">help</span>
|
||||
<span class="k">return</span> <span class="nx">version</span><span class="p">()</span> <span class="k">if</span> <span class="nx">options</span><span class="p">.</span><span class="nx">version</span>
|
||||
<span class="k">return</span> <span class="nx">require</span> <span class="s1">'./repl'</span> <span class="k">if</span> <span class="nx">options</span><span class="p">.</span><span class="nx">interactive</span>
|
||||
<span class="k">return</span> <span class="nx">compile_stdio</span><span class="p">()</span> <span class="k">if</span> <span class="nx">options</span><span class="p">.</span><span class="nx">stdio</span>
|
||||
<span class="k">return</span> <span class="nx">compile_script</span> <span class="s1">'console'</span><span class="p">,</span> <span class="nx">sources</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="k">if</span> <span class="nx">options</span><span class="p">.</span><span class="nb">eval</span>
|
||||
<span class="k">return</span> <span class="nx">usage</span><span class="p">()</span> <span class="nx">unless</span> <span class="nx">sources</span><span class="p">.</span><span class="nx">length</span>
|
||||
<span class="k">return</span> <span class="nx">compileStdio</span><span class="p">()</span> <span class="k">if</span> <span class="nx">options</span><span class="p">.</span><span class="nx">stdio</span>
|
||||
<span class="k">return</span> <span class="nx">compileScript</span> <span class="s1">'console'</span><span class="p">,</span> <span class="nx">sources</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="k">if</span> <span class="nx">options</span><span class="p">.</span><span class="nb">eval</span>
|
||||
<span class="k">return</span> <span class="nx">require</span> <span class="s1">'./repl'</span> <span class="nx">unless</span> <span class="nx">sources</span><span class="p">.</span><span class="nx">length</span>
|
||||
<span class="nv">separator: </span><span class="nx">sources</span><span class="p">.</span><span class="nx">indexOf</span> <span class="s1">'--'</span>
|
||||
<span class="nv">flags: </span><span class="p">[]</span>
|
||||
<span class="k">if</span> <span class="nx">separator</span> <span class="o">>=</span> <span class="mi">0</span>
|
||||
<span class="nv">flags: </span><span class="nx">sources</span><span class="p">[(</span><span class="nx">separator</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)...</span><span class="nx">sources</span><span class="p">.</span><span class="nx">length</span><span class="p">]</span>
|
||||
<span class="nv">flags: </span> <span class="nx">sources</span><span class="p">[(</span><span class="nx">separator</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)...</span><span class="nx">sources</span><span class="p">.</span><span class="nx">length</span><span class="p">]</span>
|
||||
<span class="nv">sources: </span><span class="nx">sources</span><span class="p">[</span><span class="mi">0</span><span class="p">...</span><span class="nx">separator</span><span class="p">]</span>
|
||||
<span class="k">if</span> <span class="nx">options</span><span class="p">.</span><span class="nx">run</span>
|
||||
<span class="nv">flags: </span> <span class="nx">sources</span><span class="p">[</span><span class="mi">1</span><span class="p">..</span><span class="nx">sources</span><span class="p">.</span><span class="nx">length</span><span class="p">].</span><span class="nx">concat</span> <span class="nx">flags</span>
|
||||
<span class="nv">sources: </span><span class="p">[</span><span class="nx">sources</span><span class="p">[</span><span class="mi">0</span><span class="p">]]</span>
|
||||
<span class="nv">process.ARGV: process.argv: </span><span class="nx">flags</span>
|
||||
<span class="nx">watch_scripts</span><span class="p">()</span> <span class="k">if</span> <span class="nx">options</span><span class="p">.</span><span class="nx">watch</span>
|
||||
<span class="nx">compile_scripts</span><span class="p">()</span></pre></div> </td> </tr> <tr id="section-7"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-7">#</a> </div> <p>Asynchronously read in each CoffeeScript in a list of source files and
|
||||
compile them.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">compile_scripts: </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="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">throw</span> <span class="k">new</span> <span class="nb">Error</span> <span class="s2">"File not found: $source"</span> <span class="nx">unless</span> <span class="nx">exists</span>
|
||||
<span class="nx">fs</span><span class="p">.</span><span class="nx">readFile</span> <span class="nx">source</span><span class="p">,</span> <span class="p">(</span><span class="nx">err</span><span class="p">,</span> <span class="nx">code</span><span class="p">)</span> <span class="o">-></span> <span class="nx">compile_script</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">compile</span><span class="p">(</span><span class="nx">source</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></pre></div> </td> </tr> <tr id="section-8"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-8">#</a> </div> <p>Compile a single source script, containing the given code, according to the
|
||||
requested options. Both compile_scripts and watch_scripts share this method
|
||||
in common. 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">compile_script: </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="o">-></span>
|
||||
<span class="nx">compileScripts</span><span class="p">()</span></pre></div> </td> </tr> <tr id="section-7"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-7">#</a> </div> <p>Asynchronously read in each CoffeeScript in a list of source files and
|
||||
compile them. If a directory is passed, recursively compile all
|
||||
'.coffee' extension source files in it and all subdirectories.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">compileScripts: </span><span class="o">-></span>
|
||||
<span class="k">for</span> <span class="nx">source</span> <span class="k">in</span> <span class="nx">sources</span>
|
||||
<span class="nv">base: </span><span class="nx">source</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="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">throw</span> <span class="k">new</span> <span class="nb">Error</span> <span class="s2">"File not found: $source"</span> <span class="nx">unless</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">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">for</span> <span class="nx">file</span> <span class="k">in</span> <span class="nx">files</span>
|
||||
<span class="nx">compile</span> <span class="nx">path</span><span class="p">.</span><span class="nx">join</span><span class="p">(</span><span class="nx">source</span><span class="p">,</span> <span class="nx">file</span><span class="p">)</span>
|
||||
<span class="k">else</span> <span class="k">if</span> <span class="nx">topLevel</span> <span class="o">or</span> <span class="nx">path</span><span class="p">.</span><span class="nx">extname</span><span class="p">(</span><span class="nx">source</span><span class="p">)</span> <span class="o">is</span> <span class="s1">'.coffee'</span>
|
||||
<span class="nx">fs</span><span class="p">.</span><span class="nx">readFile</span> <span class="nx">source</span><span class="p">,</span> <span class="p">(</span><span class="nx">err</span><span class="p">,</span> <span class="nx">code</span><span class="p">)</span> <span class="o">-></span> <span class="nx">compileScript</span><span class="p">(</span><span class="nx">source</span><span class="p">,</span> <span class="nx">code</span><span class="p">.</span><span class="nx">toString</span><span class="p">(),</span> <span class="nx">base</span><span class="p">)</span>
|
||||
<span class="nx">watch</span> <span class="nx">source</span><span class="p">,</span> <span class="nx">base</span> <span class="k">if</span> <span class="nx">options</span><span class="p">.</span><span class="nx">watch</span>
|
||||
<span class="nx">compile</span> <span class="nx">source</span><span class="p">,</span> <span class="kc">true</span></pre></div> </td> </tr> <tr id="section-8"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-8">#</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">source</span><span class="p">,</span> <span class="nx">code</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">options</span>
|
||||
<span class="nv">code_opts: </span><span class="nx">compile_options</span> <span class="nx">source</span>
|
||||
<span class="nv">codeOpts: </span><span class="nx">compileOptions</span> <span class="nx">source</span>
|
||||
<span class="k">try</span>
|
||||
<span class="k">if</span> <span class="nx">o</span><span class="p">.</span><span class="nx">tokens</span> <span class="k">then</span> <span class="nx">print_tokens</span> <span class="nx">CoffeeScript</span><span class="p">.</span><span class="nx">tokens</span> <span class="nx">code</span>
|
||||
<span class="k">if</span> <span class="nx">o</span><span class="p">.</span><span class="nx">tokens</span> <span class="k">then</span> <span class="nx">printTokens</span> <span class="nx">CoffeeScript</span><span class="p">.</span><span class="nx">tokens</span> <span class="nx">code</span>
|
||||
<span class="k">else</span> <span class="k">if</span> <span class="nx">o</span><span class="p">.</span><span class="nx">nodes</span> <span class="k">then</span> <span class="nx">puts</span> <span class="nx">CoffeeScript</span><span class="p">.</span><span class="nx">nodes</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="k">else</span> <span class="k">if</span> <span class="nx">o</span><span class="p">.</span><span class="nx">run</span> <span class="k">then</span> <span class="nx">CoffeeScript</span><span class="p">.</span><span class="nx">run</span> <span class="nx">code</span><span class="p">,</span> <span class="nx">code_opts</span>
|
||||
<span class="k">else</span> <span class="k">if</span> <span class="nx">o</span><span class="p">.</span><span class="nx">run</span> <span class="k">then</span> <span class="nx">CoffeeScript</span><span class="p">.</span><span class="nx">run</span> <span class="nx">code</span><span class="p">,</span> <span class="nx">codeOpts</span>
|
||||
<span class="k">else</span>
|
||||
<span class="nv">js: </span><span class="nx">CoffeeScript</span><span class="p">.</span><span class="nx">compile</span> <span class="nx">code</span><span class="p">,</span> <span class="nx">code_opts</span>
|
||||
<span class="k">if</span> <span class="nx">o</span><span class="p">.</span><span class="nx">print</span> <span class="k">then</span> <span class="nx">process</span><span class="p">.</span><span class="nx">stdio</span><span class="p">.</span><span class="nx">write</span> <span class="nx">js</span>
|
||||
<span class="k">else</span> <span class="k">if</span> <span class="nx">o</span><span class="p">.</span><span class="nx">compile</span> <span class="k">then</span> <span class="nx">write_js</span> <span class="nx">source</span><span class="p">,</span> <span class="nx">js</span>
|
||||
<span class="nv">js: </span><span class="nx">CoffeeScript</span><span class="p">.</span><span class="nx">compile</span> <span class="nx">code</span><span class="p">,</span> <span class="nx">codeOpts</span>
|
||||
<span class="k">if</span> <span class="nx">o</span><span class="p">.</span><span class="nx">print</span> <span class="k">then</span> <span class="nx">print</span> <span class="nx">js</span>
|
||||
<span class="k">else</span> <span class="k">if</span> <span class="nx">o</span><span class="p">.</span><span class="nx">compile</span> <span class="k">then</span> <span class="nx">writeJs</span> <span class="nx">source</span><span class="p">,</span> <span class="nx">js</span><span class="p">,</span> <span class="nx">base</span>
|
||||
<span class="k">else</span> <span class="k">if</span> <span class="nx">o</span><span class="p">.</span><span class="nx">lint</span> <span class="k">then</span> <span class="nx">lint</span> <span class="nx">js</span>
|
||||
<span class="k">catch</span> <span class="nx">err</span>
|
||||
<span class="k">if</span> <span class="nx">o</span><span class="p">.</span><span class="nx">watch</span> <span class="k">then</span> <span class="nx">puts</span> <span class="nx">err</span><span class="p">.</span><span class="nx">message</span> <span class="k">else</span> <span class="k">throw</span> <span class="nx">err</span></pre></div> </td> </tr> <tr id="section-9"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-9">#</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">compile_stdio: </span><span class="o">-></span>
|
||||
<span class="nx">error</span><span class="p">(</span><span class="nx">err</span><span class="p">.</span><span class="nx">stack</span><span class="p">)</span> <span class="o">and</span> <span class="nx">process</span><span class="p">.</span><span class="nx">exit</span> <span class="mi">1</span> <span class="nx">unless</span> <span class="nx">o</span><span class="p">.</span><span class="nx">watch</span>
|
||||
<span class="nx">puts</span> <span class="nx">err</span><span class="p">.</span><span class="nx">message</span></pre></div> </td> </tr> <tr id="section-9"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-9">#</a> </div> <p>Attach the appropriate listeners to compile scripts incoming over <strong>stdin</strong>,
|
||||
and write them back to <strong>stdout</strong>.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">compileStdio: </span><span class="o">-></span>
|
||||
<span class="nv">code: </span><span class="s1">''</span>
|
||||
<span class="nx">process</span><span class="p">.</span><span class="nx">stdio</span><span class="p">.</span><span class="nx">open</span><span class="p">()</span>
|
||||
<span class="nx">process</span><span class="p">.</span><span class="nx">stdio</span><span class="p">.</span><span class="nx">addListener</span> <span class="s1">'data'</span><span class="p">,</span> <span class="p">(</span><span class="nx">string</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nv">code: </span><span class="o">+</span> <span class="nx">string</span> <span class="k">if</span> <span class="nx">string</span>
|
||||
<span class="nx">process</span><span class="p">.</span><span class="nx">stdio</span><span class="p">.</span><span class="nx">addListener</span> <span class="s1">'close'</span><span class="p">,</span> <span class="o">-></span>
|
||||
<span class="nx">compile_script</span> <span class="s1">'stdio'</span><span class="p">,</span> <span class="nx">code</span></pre></div> </td> </tr> <tr id="section-10"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-10">#</a> </div> <p>Watch a list of source CoffeeScript files using <code>fs.watchFile</code>, recompiling
|
||||
them every time the files are 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_scripts: </span><span class="o">-></span>
|
||||
<span class="nv">watch: </span><span class="p">(</span><span class="nx">source</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="nv">persistent: </span><span class="kc">true</span><span class="p">,</span> <span class="nv">interval: </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">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="nx">compile_script</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">watch</span><span class="p">(</span><span class="nx">source</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></pre></div> </td> </tr> <tr id="section-11"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-11">#</a> </div> <p>Write out a JavaScript source file with the compiled code. By default, files
|
||||
<span class="nv">stdin: </span><span class="nx">process</span><span class="p">.</span><span class="nx">openStdin</span><span class="p">()</span>
|
||||
<span class="nx">stdin</span><span class="p">.</span><span class="nx">addListener</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="nv">code: </span><span class="o">+</span> <span class="nx">buffer</span><span class="p">.</span><span class="nx">toString</span><span class="p">()</span> <span class="k">if</span> <span class="nx">buffer</span>
|
||||
<span class="nx">stdin</span><span class="p">.</span><span class="nx">addListener</span> <span class="s1">'end'</span><span class="p">,</span> <span class="o">-></span>
|
||||
<span class="nx">compileScript</span> <span class="s1">'stdio'</span><span class="p">,</span> <span class="nx">code</span></pre></div> </td> </tr> <tr id="section-10"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-10">#</a> </div> <p>Watch a source CoffeeScript file using <code>fs.watchFile</code>, recompiling it every
|
||||
time the file is updated. May be used in combination with other options,
|
||||
such as <code>--lint</code> or <code>--print</code>.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">watch: </span><span class="p">(</span><span class="nx">source</span><span class="p">,</span> <span class="nx">base</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nx">fs</span><span class="p">.</span><span class="nx">watchFile</span> <span class="nx">source</span><span class="p">,</span> <span class="p">{</span><span class="nv">persistent: </span><span class="kc">true</span><span class="p">,</span> <span class="nv">interval: </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">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="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-11"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-11">#</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">write_js: </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="o">-></span>
|
||||
directory can be customized with <code>--output</code>.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">writeJs: </span><span class="p">(</span><span class="nx">source</span><span class="p">,</span> <span class="nx">js</span><span class="p">,</span> <span class="nx">base</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nv">filename: </span><span class="nx">path</span><span class="p">.</span><span class="nx">basename</span><span class="p">(</span><span class="nx">source</span><span class="p">,</span> <span class="nx">path</span><span class="p">.</span><span class="nx">extname</span><span class="p">(</span><span class="nx">source</span><span class="p">))</span> <span class="o">+</span> <span class="s1">'.js'</span>
|
||||
<span class="nv">dir: </span> <span class="nx">options</span><span class="p">.</span><span class="nx">output</span> <span class="o">or</span> <span class="nx">path</span><span class="p">.</span><span class="nx">dirname</span><span class="p">(</span><span class="nx">source</span><span class="p">)</span>
|
||||
<span class="nv">js_path: </span> <span class="nx">path</span><span class="p">.</span><span class="nx">join</span> <span class="nx">dir</span><span class="p">,</span> <span class="nx">filename</span>
|
||||
<span class="nx">fs</span><span class="p">.</span><span class="nx">writeFile</span> <span class="nx">js_path</span><span class="p">,</span> <span class="nx">js</span></pre></div> </td> </tr> <tr id="section-12"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-12">#</a> </div> <p>Pipe compiled JS through JSLint (requires a working <code>jsl</code> command), printing
|
||||
<span class="nv">srcDir: </span> <span class="nx">path</span><span class="p">.</span><span class="nx">dirname</span> <span class="nx">source</span>
|
||||
<span class="nv">baseDir: </span> <span class="nx">srcDir</span><span class="p">.</span><span class="nx">substring</span> <span class="nx">base</span><span class="p">.</span><span class="nx">length</span>
|
||||
<span class="nv">dir: </span> <span class="k">if</span> <span class="nx">options</span><span class="p">.</span><span class="nx">output</span> <span class="k">then</span> <span class="nx">path</span><span class="p">.</span><span class="nx">join</span> <span class="nx">options</span><span class="p">.</span><span class="nx">output</span><span class="p">,</span> <span class="nx">baseDir</span> <span class="k">else</span> <span class="nx">srcDir</span>
|
||||
<span class="nv">jsPath: </span> <span class="nx">path</span><span class="p">.</span><span class="nx">join</span> <span class="nx">dir</span><span class="p">,</span> <span class="nx">filename</span>
|
||||
<span class="nv">compile: </span> <span class="o">-></span>
|
||||
<span class="nx">fs</span><span class="p">.</span><span class="nx">writeFile</span> <span class="nx">jsPath</span><span class="p">,</span> <span class="nx">js</span><span class="p">,</span> <span class="p">(</span><span class="nx">err</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nx">puts</span> <span class="s2">"Compiled $source"</span> <span class="k">if</span> <span class="nx">options</span><span class="p">.</span><span class="nx">compile</span> <span class="o">and</span> <span class="nx">options</span><span class="p">.</span><span class="nx">watch</span>
|
||||
<span class="nx">path</span><span class="p">.</span><span class="nx">exists</span> <span class="nx">dir</span><span class="p">,</span> <span class="p">(</span><span class="nx">exists</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="k">if</span> <span class="nx">exists</span> <span class="k">then</span> <span class="nx">compile</span><span class="p">()</span> <span class="k">else</span> <span class="nx">exec</span> <span class="s2">"mkdir -p $dir"</span><span class="p">,</span> <span class="nx">compile</span></pre></div> </td> </tr> <tr id="section-12"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-12">#</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">js</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nv">jsl: </span><span class="nx">process</span><span class="p">.</span><span class="nx">createChildProcess</span><span class="p">(</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="nx">jsl</span><span class="p">.</span><span class="nx">addListener</span> <span class="s1">'output'</span><span class="p">,</span> <span class="p">(</span><span class="nx">result</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nx">puts</span> <span class="nx">result</span><span class="p">.</span><span class="nx">replace</span><span class="p">(</span><span class="sr">/\n/g</span><span class="p">,</span> <span class="s1">''</span><span class="p">)</span> <span class="k">if</span> <span class="nx">result</span>
|
||||
<span class="nx">jsl</span><span class="p">.</span><span class="nx">addListener</span> <span class="s1">'error'</span><span class="p">,</span> <span class="p">(</span><span class="nx">result</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nx">puts</span> <span class="nx">result</span> <span class="k">if</span> <span class="nx">result</span>
|
||||
<span class="nx">jsl</span><span class="p">.</span><span class="nx">write</span> <span class="nx">js</span>
|
||||
<span class="nx">jsl</span><span class="p">.</span><span class="nx">close</span><span class="p">()</span></pre></div> </td> </tr> <tr id="section-13"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-13">#</a> </div> <p>Pretty-print a stream of tokens.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">print_tokens: </span><span class="p">(</span><span class="nx">tokens</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">print</span> <span class="nx">buffer</span><span class="p">.</span><span class="nx">toString</span><span class="p">()</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="nx">jsl</span><span class="p">.</span><span class="nx">stdout</span><span class="p">.</span><span class="nx">addListener</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="nx">addListener</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">stdin</span><span class="p">.</span><span class="nx">write</span> <span class="nx">js</span>
|
||||
<span class="nx">jsl</span><span class="p">.</span><span class="nx">stdin</span><span class="p">.</span><span class="nx">end</span><span class="p">()</span></pre></div> </td> </tr> <tr id="section-13"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-13">#</a> </div> <p>Pretty-print a stream of tokens.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">printTokens: </span><span class="p">(</span><span class="nx">tokens</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nv">strings: </span><span class="k">for</span> <span class="nx">token</span> <span class="k">in</span> <span class="nx">tokens</span>
|
||||
<span class="p">[</span><span class="nx">tag</span><span class="p">,</span> <span class="nx">value</span><span class="p">]</span><span class="o">:</span> <span class="p">[</span><span class="nx">token</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="nx">token</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="nx">toString</span><span class="p">().</span><span class="nx">replace</span><span class="p">(</span><span class="sr">/\n/</span><span class="p">,</span> <span class="s1">'\\n'</span><span class="p">)]</span>
|
||||
<span class="s2">"[$tag $value]"</span>
|
||||
<span class="nx">puts</span> <span class="nx">strings</span><span class="p">.</span><span class="nx">join</span><span class="p">(</span><span class="s1">' '</span><span class="p">)</span></pre></div> </td> </tr> <tr id="section-14"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-14">#</a> </div> <p>Use the <a href="optparse.html">OptionParser module</a> to extract all options from
|
||||
<code>process.argv</code> that are specified in <code>SWITCHES</code>.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">parse_options: </span><span class="o">-></span>
|
||||
<span class="nv">option_parser: </span><span class="k">new</span> <span class="nx">optparse</span><span class="p">.</span><span class="nx">OptionParser</span> <span class="nx">SWITCHES</span><span class="p">,</span> <span class="nx">BANNER</span>
|
||||
<span class="nv">o: options: </span> <span class="nx">option_parser</span><span class="p">.</span><span class="nx">parse</span><span class="p">(</span><span class="nx">process</span><span class="p">.</span><span class="nx">argv</span><span class="p">)</span>
|
||||
<code>process.argv</code> that are specified in <code>SWITCHES</code>.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">parseOptions: </span><span class="o">-></span>
|
||||
<span class="nv">optionParser: </span> <span class="k">new</span> <span class="nx">optparse</span><span class="p">.</span><span class="nx">OptionParser</span> <span class="nx">SWITCHES</span><span class="p">,</span> <span class="nx">BANNER</span>
|
||||
<span class="nv">o: options: </span> <span class="nx">optionParser</span><span class="p">.</span><span class="nx">parse</span><span class="p">(</span><span class="nx">process</span><span class="p">.</span><span class="nx">argv</span><span class="p">[</span><span class="mi">2</span><span class="p">...</span><span class="nx">process</span><span class="p">.</span><span class="nx">argv</span><span class="p">.</span><span class="nx">length</span><span class="p">])</span>
|
||||
<span class="nv">options.run: </span> <span class="o">not</span> <span class="p">(</span><span class="nx">o</span><span class="p">.</span><span class="nx">compile</span> <span class="o">or</span> <span class="nx">o</span><span class="p">.</span><span class="nx">print</span> <span class="o">or</span> <span class="nx">o</span><span class="p">.</span><span class="nx">lint</span><span class="p">)</span>
|
||||
<span class="nv">options.print: </span><span class="o">!!</span> <span class="p">(</span><span class="nx">o</span><span class="p">.</span><span class="nx">print</span> <span class="o">or</span> <span class="p">(</span><span class="nx">o</span><span class="p">.</span><span class="nb">eval</span> <span class="o">or</span> <span class="nx">o</span><span class="p">.</span><span class="nx">stdio</span> <span class="o">and</span> <span class="nx">o</span><span class="p">.</span><span class="nx">compile</span><span class="p">))</span>
|
||||
<span class="nv">sources: </span> <span class="nx">options</span><span class="p">.</span><span class="nx">arguments</span><span class="p">[</span><span class="mi">2</span><span class="p">...</span><span class="nx">options</span><span class="p">.</span><span class="nx">arguments</span><span class="p">.</span><span class="nx">length</span><span class="p">]</span></pre></div> </td> </tr> <tr id="section-15"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-15">#</a> </div> <p>The compile-time options to pass to the CoffeeScript compiler.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">compile_options: </span><span class="p">(</span><span class="nx">source</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nv">o: </span><span class="p">{</span><span class="nv">source: </span><span class="nx">source</span><span class="p">}</span>
|
||||
<span class="nx">o</span><span class="p">[</span><span class="s1">'no_wrap'</span><span class="p">]</span><span class="o">:</span> <span class="nx">options</span><span class="p">[</span><span class="s1">'no-wrap'</span><span class="p">]</span>
|
||||
<span class="nv">sources: </span> <span class="nx">options</span><span class="p">.</span><span class="nx">arguments</span></pre></div> </td> </tr> <tr id="section-15"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-15">#</a> </div> <p>The compile-time options to pass to the CoffeeScript compiler.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">compileOptions: </span><span class="p">(</span><span class="nx">source</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nv">o: </span><span class="p">{</span><span class="nx">source</span><span class="p">}</span>
|
||||
<span class="nv">o.noWrap: </span><span class="nx">options</span><span class="p">[</span><span class="s1">'no-wrap'</span><span class="p">]</span>
|
||||
<span class="nx">o</span></pre></div> </td> </tr> <tr id="section-16"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-16">#</a> </div> <p>Print the <code>--help</code> usage message and exit.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">usage: </span><span class="o">-></span>
|
||||
<span class="nx">puts</span> <span class="nx">option_parser</span><span class="p">.</span><span class="nx">help</span><span class="p">()</span>
|
||||
<span class="nx">puts</span> <span class="nx">optionParser</span><span class="p">.</span><span class="nx">help</span><span class="p">()</span>
|
||||
<span class="nx">process</span><span class="p">.</span><span class="nx">exit</span> <span class="mi">0</span></pre></div> </td> </tr> <tr id="section-17"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-17">#</a> </div> <p>Print the <code>--version</code> message and exit.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">version: </span><span class="o">-></span>
|
||||
<span class="nx">puts</span> <span class="s2">"CoffeeScript version ${CoffeeScript.VERSION}"</span>
|
||||
<span class="nx">puts</span> <span class="s2">"CoffeeScript version $CoffeeScript.VERSION"</span>
|
||||
<span class="nx">process</span><span class="p">.</span><span class="nx">exit</span> <span class="mi">0</span>
|
||||
|
||||
</pre></div> </td> </tr> </tbody> </table> </div> </body> </html>
|
||||
@@ -1,4 +1,4 @@
|
||||
<!DOCTYPE html> <html> <head> <title>grammar.coffee</title> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <link rel="stylesheet" media="all" href="docco.css" /> </head> <body> <div id="container"> <div id="background"></div> <div id="jump_to"> Jump To … <div id="jump_wrapper"> <div id="jump_page"> <a class="source" href="cake.html"> cake.coffee </a> <a class="source" href="coffee-script.html"> coffee-script.coffee </a> <a class="source" href="command.html"> command.coffee </a> <a class="source" href="grammar.html"> grammar.coffee </a> <a class="source" href="helpers.html"> helpers.coffee </a> <a class="source" href="lexer.html"> lexer.coffee </a> <a class="source" href="nodes.html"> nodes.coffee </a> <a class="source" href="optparse.html"> optparse.coffee </a> <a class="source" href="repl.html"> repl.coffee </a> <a class="source" href="rewriter.html"> rewriter.coffee </a> <a class="source" href="scope.html"> scope.coffee </a> </div> </div> </div> <table cellpadding="0" cellspacing="0"> <thead> <tr> <th class="docs"> <h1> grammar.coffee </h1> </th> <th class="code"> </th> </tr> </thead> <tbody> <tr id="section-1"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-1">#</a> </div> <p>The CoffeeScript parser is generated by <a href="http://github.com/zaach/jison">Jison</a>
|
||||
<!DOCTYPE html> <html> <head> <title>grammar.coffee</title> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <link rel="stylesheet" media="all" href="docco.css" /> </head> <body> <div id="container"> <div id="background"></div> <div id="jump_to"> Jump To … <div id="jump_wrapper"> <div id="jump_page"> <a class="source" href="cake.html"> cake.coffee </a> <a class="source" href="coffee-script.html"> coffee-script.coffee </a> <a class="source" href="command.html"> command.coffee </a> <a class="source" href="grammar.html"> grammar.coffee </a> <a class="source" href="helpers.html"> helpers.coffee </a> <a class="source" href="index.html"> index.coffee </a> <a class="source" href="lexer.html"> lexer.coffee </a> <a class="source" href="nodes.html"> nodes.coffee </a> <a class="source" href="optparse.html"> optparse.coffee </a> <a class="source" href="repl.html"> repl.coffee </a> <a class="source" href="rewriter.html"> rewriter.coffee </a> <a class="source" href="scope.html"> scope.coffee </a> </div> </div> </div> <table cellpadding="0" cellspacing="0"> <thead> <tr> <th class="docs"> <h1> grammar.coffee </h1> </th> <th class="code"> </th> </tr> </thead> <tbody> <tr id="section-1"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-1">#</a> </div> <p>The CoffeeScript parser is generated by <a href="http://github.com/zaach/jison">Jison</a>
|
||||
from this grammar file. Jison is a bottom-up parser generator, similar in
|
||||
style to <a href="http://www.gnu.org/software/bison">Bison</a>, implemented in JavaScript.
|
||||
It can recognize <a href="http://en.wikipedia.org/wiki/LR_grammar">LALR(1), LR(0), SLR(1), and LR(1)</a>
|
||||
@@ -18,10 +18,10 @@ wrapper and just returning the value directly.</p> </td>
|
||||
<a href="http://github.com/creationix">Tim Caswell</a>. For every rule in the grammar,
|
||||
we pass the pattern-defining string, the action to run, and extra options,
|
||||
optionally. If no action is specified, we simply pass the value of the
|
||||
previous nonterminal.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">o: </span><span class="p">(</span><span class="nx">pattern_string</span><span class="p">,</span> <span class="nx">action</span><span class="p">,</span> <span class="nx">options</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="k">return</span> <span class="p">[</span><span class="nx">pattern_string</span><span class="p">,</span> <span class="s1">'$$ = $1;'</span><span class="p">,</span> <span class="nx">options</span><span class="p">]</span> <span class="nx">unless</span> <span class="nx">action</span>
|
||||
previous nonterminal.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">o: </span><span class="p">(</span><span class="nx">patternString</span><span class="p">,</span> <span class="nx">action</span><span class="p">,</span> <span class="nx">options</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="k">return</span> <span class="p">[</span><span class="nx">patternString</span><span class="p">,</span> <span class="s1">'$$ = $1;'</span><span class="p">,</span> <span class="nx">options</span><span class="p">]</span> <span class="nx">unless</span> <span class="nx">action</span>
|
||||
<span class="nv">action: </span><span class="k">if</span> <span class="nv">match: </span><span class="p">(</span><span class="nx">action</span> <span class="o">+</span> <span class="s1">''</span><span class="p">).</span><span class="nx">match</span><span class="p">(</span><span class="nx">unwrap</span><span class="p">)</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="s2">"($action())"</span>
|
||||
<span class="p">[</span><span class="nx">pattern_string</span><span class="p">,</span> <span class="s2">"$$ = $action;"</span><span class="p">,</span> <span class="nx">options</span><span class="p">]</span></pre></div> </td> </tr> <tr id="section-6"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-6">#</a> </div> <h2>Grammatical Rules</h2> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-7"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-7">#</a> </div> <p>In all of the rules that follow, you'll see the name of the nonterminal as
|
||||
<span class="p">[</span><span class="nx">patternString</span><span class="p">,</span> <span class="s2">"$$ = $action;"</span><span class="p">,</span> <span class="nx">options</span><span class="p">]</span></pre></div> </td> </tr> <tr id="section-6"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-6">#</a> </div> <h2>Grammatical Rules</h2> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-7"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-7">#</a> </div> <p>In all of the rules that follow, you'll see the name of the nonterminal as
|
||||
the key to a list of alternative matches. With each match's action, the
|
||||
dollar-sign variables are provided by Jison as references to the value of
|
||||
their numeric position, so in this rule:</p>
|
||||
@@ -33,29 +33,33 @@ their numeric position, so in this rule:</p>
|
||||
for the <code>UNLESS</code> terminal, and <code>$3</code> would be the value of the second
|
||||
<code>Expression</code>.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">grammar: </span><span class="p">{</span></pre></div> </td> </tr> <tr id="section-8"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-8">#</a> </div> <p>The <strong>Root</strong> is the top-level node in the syntax tree. Since we parse bottom-up,
|
||||
all parsing must end here.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">Root: </span><span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s2">""</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Expressions</span><span class="p">()</span>
|
||||
<span class="nx">o</span> <span class="s2">"TERMINATOR"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Expressions</span><span class="p">()</span>
|
||||
<span class="nx">o</span> <span class="s2">"Expressions"</span>
|
||||
<span class="nx">o</span> <span class="s2">""</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Expressions</span>
|
||||
<span class="nx">o</span> <span class="s2">"TERMINATOR"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Expressions</span>
|
||||
<span class="nx">o</span> <span class="s2">"Body"</span>
|
||||
<span class="nx">o</span> <span class="s2">"Block TERMINATOR"</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-9"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-9">#</a> </div> <p>Any list of expressions or method body, seperated by line breaks or
|
||||
semicolons.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">Expressions: </span><span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s2">"Expression"</span><span class="p">,</span> <span class="o">-></span> <span class="nx">Expressions</span><span class="p">.</span><span class="nx">wrap</span> <span class="p">[</span><span class="nx">$1</span><span class="p">]</span>
|
||||
<span class="nx">o</span> <span class="s2">"Expressions TERMINATOR Expression"</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">$3</span>
|
||||
<span class="nx">o</span> <span class="s2">"Expressions TERMINATOR"</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-10"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-10">#</a> </div> <p>All the different types of expressions in our language. The basic unit of
|
||||
CoffeeScript is the <strong>Expression</strong> -- you'll notice that there is no
|
||||
"statement" nonterminal. Expressions serve as the building blocks
|
||||
of many other rules, making them somewhat circular.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">Expression: </span><span class="p">[</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-9"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-9">#</a> </div> <p>Any list of statements and expressions, seperated by line breaks or semicolons.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">Body: </span><span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s2">"Line"</span><span class="p">,</span> <span class="o">-></span> <span class="nx">Expressions</span><span class="p">.</span><span class="nx">wrap</span> <span class="p">[</span><span class="nx">$1</span><span class="p">]</span>
|
||||
<span class="nx">o</span> <span class="s2">"Body TERMINATOR Line"</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">$3</span>
|
||||
<span class="nx">o</span> <span class="s2">"Body TERMINATOR"</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-10"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-10">#</a> </div> <p>Expressions and statements, which make up a line in a body.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">Line: </span><span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s2">"Expression"</span>
|
||||
<span class="nx">o</span> <span class="s2">"Statement"</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-11"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-11">#</a> </div> <p>Pure statements which cannot be expressions.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">Statement: </span><span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s2">"Return"</span>
|
||||
<span class="nx">o</span> <span class="s2">"Throw"</span>
|
||||
<span class="nx">o</span> <span class="s2">"BREAK"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">LiteralNode</span> <span class="nx">$1</span>
|
||||
<span class="nx">o</span> <span class="s2">"CONTINUE"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">LiteralNode</span> <span class="nx">$1</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-12"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" 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. Expressions serve as the building blocks of many other rules, making
|
||||
them somewhat circular.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">Expression: </span><span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s2">"Value"</span>
|
||||
<span class="nx">o</span> <span class="s2">"Call"</span>
|
||||
<span class="nx">o</span> <span class="s2">"Curry"</span>
|
||||
<span class="nx">o</span> <span class="s2">"Code"</span>
|
||||
<span class="nx">o</span> <span class="s2">"Operation"</span>
|
||||
<span class="nx">o</span> <span class="s2">"Assign"</span>
|
||||
<span class="nx">o</span> <span class="s2">"If"</span>
|
||||
<span class="nx">o</span> <span class="s2">"Try"</span>
|
||||
<span class="nx">o</span> <span class="s2">"Throw"</span>
|
||||
<span class="nx">o</span> <span class="s2">"Return"</span>
|
||||
<span class="nx">o</span> <span class="s2">"While"</span>
|
||||
<span class="nx">o</span> <span class="s2">"For"</span>
|
||||
<span class="nx">o</span> <span class="s2">"Switch"</span>
|
||||
@@ -64,77 +68,77 @@ of many other rules, making them somewhat circular.</p> </td>
|
||||
<span class="nx">o</span> <span class="s2">"Splat"</span>
|
||||
<span class="nx">o</span> <span class="s2">"Existence"</span>
|
||||
<span class="nx">o</span> <span class="s2">"Comment"</span>
|
||||
<span class="nx">o</span> <span class="s2">"Extension"</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-11"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-11">#</a> </div> <p>A an indented block of expressions. Note that the <a href="rewriter.html">Rewriter</a>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-13"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-13">#</a> </div> <p>A an indented block of expressions. Note that the <a href="rewriter.html">Rewriter</a>
|
||||
will convert some postfix forms into blocks for us, by adjusting the
|
||||
token stream.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">Block: </span><span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s2">"INDENT Expressions OUTDENT"</span><span class="p">,</span> <span class="o">-></span> <span class="nx">$2</span>
|
||||
<span class="nx">o</span> <span class="s2">"INDENT OUTDENT"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Expressions</span><span class="p">()</span>
|
||||
<span class="nx">o</span> <span class="s2">"INDENT Body OUTDENT"</span><span class="p">,</span> <span class="o">-></span> <span class="nx">$2</span>
|
||||
<span class="nx">o</span> <span class="s2">"INDENT OUTDENT"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Expressions</span>
|
||||
<span class="nx">o</span> <span class="s2">"TERMINATOR Comment"</span><span class="p">,</span> <span class="o">-></span> <span class="nx">Expressions</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-12"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-12">#</a> </div> <p>A literal identifier, a variable name or property.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">Identifier: </span><span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s2">"IDENTIFIER"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">LiteralNode</span> <span class="nx">yytext</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-13"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-13">#</a> </div> <p>Alphanumerics are separated from the other <strong>Literal</strong> matchers because
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-14"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-14">#</a> </div> <p>A literal identifier, a variable name or property.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">Identifier: </span><span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s2">"IDENTIFIER"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">LiteralNode</span> <span class="nx">$1</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-15"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-15">#</a> </div> <p>Alphanumerics are separated from the other <strong>Literal</strong> matchers because
|
||||
they can also serve as keys in object literals.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">AlphaNumeric: </span><span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s2">"NUMBER"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">LiteralNode</span> <span class="nx">yytext</span>
|
||||
<span class="nx">o</span> <span class="s2">"STRING"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">LiteralNode</span> <span class="nx">yytext</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-14"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-14">#</a> </div> <p>All of our immediate values. These can (in general), be passed straight
|
||||
<span class="nx">o</span> <span class="s2">"NUMBER"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">LiteralNode</span> <span class="nx">$1</span>
|
||||
<span class="nx">o</span> <span class="s2">"STRING"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">LiteralNode</span> <span class="nx">$1</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-16"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-16">#</a> </div> <p>All of our immediate values. These can (in general), be passed straight
|
||||
through and printed to JavaScript.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">Literal: </span><span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s2">"AlphaNumeric"</span>
|
||||
<span class="nx">o</span> <span class="s2">"JS"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">LiteralNode</span> <span class="nx">yytext</span>
|
||||
<span class="nx">o</span> <span class="s2">"REGEX"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">LiteralNode</span> <span class="nx">yytext</span>
|
||||
<span class="nx">o</span> <span class="s2">"BREAK"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">LiteralNode</span> <span class="nx">yytext</span>
|
||||
<span class="nx">o</span> <span class="s2">"CONTINUE"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">LiteralNode</span> <span class="nx">yytext</span>
|
||||
<span class="nx">o</span> <span class="s2">"JS"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">LiteralNode</span> <span class="nx">$1</span>
|
||||
<span class="nx">o</span> <span class="s2">"REGEX"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">LiteralNode</span> <span class="nx">$1</span>
|
||||
<span class="nx">o</span> <span class="s2">"TRUE"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">LiteralNode</span> <span class="kc">true</span>
|
||||
<span class="nx">o</span> <span class="s2">"FALSE"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">LiteralNode</span> <span class="kc">false</span>
|
||||
<span class="nx">o</span> <span class="s2">"YES"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">LiteralNode</span> <span class="kc">true</span>
|
||||
<span class="nx">o</span> <span class="s2">"NO"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">LiteralNode</span> <span class="kc">false</span>
|
||||
<span class="nx">o</span> <span class="s2">"ON"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">LiteralNode</span> <span class="kc">true</span>
|
||||
<span class="nx">o</span> <span class="s2">"OFF"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">LiteralNode</span> <span class="kc">false</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-15"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-15">#</a> </div> <p>Assignment of a variable, property, or index to a value.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">Assign: </span><span class="p">[</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-17"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-17">#</a> </div> <p>Assignment of a variable, property, or index to a value.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">Assign: </span><span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s2">"Assignable ASSIGN Expression"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">AssignNode</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-16"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-16">#</a> </div> <p>Assignment when it happens within an object literal. The difference from
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-18"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-18">#</a> </div> <p>Assignment when it happens within an object literal. The difference from
|
||||
the ordinary <strong>Assign</strong> is that these allow numbers and strings as keys.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">AssignObj: </span><span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s2">"Identifier"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">ValueNode</span> <span class="nx">$1</span>
|
||||
<span class="nx">o</span> <span class="s2">"AlphaNumeric"</span>
|
||||
<span class="nx">o</span> <span class="s2">"Identifier ASSIGN Expression"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">AssignNode</span> <span class="k">new</span> <span class="nx">ValueNode</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="s1">'object'</span>
|
||||
<span class="nx">o</span> <span class="s2">"AlphaNumeric ASSIGN Expression"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">AssignNode</span> <span class="k">new</span> <span class="nx">ValueNode</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="s1">'object'</span>
|
||||
<span class="nx">o</span> <span class="s2">"Comment"</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-17"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-17">#</a> </div> <p>A return statement from a function body.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">Return: </span><span class="p">[</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-19"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-19">#</a> </div> <p>A return statement from a function body.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">Return: </span><span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s2">"RETURN Expression"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">ReturnNode</span> <span class="nx">$2</span>
|
||||
<span class="nx">o</span> <span class="s2">"RETURN"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">ReturnNode</span> <span class="k">new</span> <span class="nx">ValueNode</span> <span class="k">new</span> <span class="nx">LiteralNode</span> <span class="s1">'null'</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-18"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-18">#</a> </div> <p>A comment. Because CoffeeScript passes comments through to JavaScript, we
|
||||
have to parse comments like any other construct, and identify all of the
|
||||
positions in which they can occur in the grammar.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">Comment: </span><span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s2">"COMMENT"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">CommentNode</span> <span class="nx">yytext</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-19"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-19">#</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="nv">Existence: </span><span class="p">[</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-20"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-20">#</a> </div> <p>A block comment.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">Comment: </span><span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s2">"HERECOMMENT"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">CommentNode</span> <span class="nx">$1</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-21"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-21">#</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="nv">Existence: </span><span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s2">"Expression ?"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">ExistenceNode</span> <span class="nx">$1</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-20"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-20">#</a> </div> <p>The <strong>Code</strong> node is the function literal. It's defined by an indented block
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-22"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-22">#</a> </div> <p>The <strong>Code</strong> node is the function literal. It's defined by an indented block
|
||||
of <strong>Expressions</strong> preceded by a function arrow, with an optional parameter
|
||||
list.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">Code: </span><span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s2">"PARAM_START ParamList PARAM_END FuncGlyph Block"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">CodeNode</span> <span class="nx">$2</span><span class="p">,</span> <span class="nx">$5</span><span class="p">,</span> <span class="nx">$4</span>
|
||||
<span class="nx">o</span> <span class="s2">"FuncGlyph Block"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">CodeNode</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-21"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-21">#</a> </div> <p>CoffeeScript has two different symbols for functions. <code>-></code> is for ordinary
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-23"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-23">#</a> </div> <p>CoffeeScript has two different symbols for functions. <code>-></code> is for ordinary
|
||||
functions, and <code>=></code> is for functions bound to the current value of <em>this</em>.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">FuncGlyph: </span><span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s2">"->"</span><span class="p">,</span> <span class="o">-></span> <span class="s1">'func'</span>
|
||||
<span class="nx">o</span> <span class="s2">"=>"</span><span class="p">,</span> <span class="o">-></span> <span class="s1">'boundfunc'</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-22"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-22">#</a> </div> <p>The list of parameters that a function accepts can be of any length.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">ParamList: </span><span class="p">[</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-24"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-24">#</a> </div> <p>An optional, trailing comma.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">OptComma: </span><span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s1">''</span>
|
||||
<span class="nx">o</span> <span class="s1">','</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-25"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-25">#</a> </div> <p>The list of parameters that a function accepts can be of any length.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">ParamList: </span><span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s2">""</span><span class="p">,</span> <span class="o">-></span> <span class="p">[]</span>
|
||||
<span class="nx">o</span> <span class="s2">"Param"</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="s2">"ParamList , Param"</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="p">[</span><span class="nx">$3</span><span class="p">]</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-23"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-23">#</a> </div> <p>A single parameter in a function definition can be ordinary, or a splat
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-26"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-26">#</a> </div> <p>A single parameter in a function definition can be ordinary, or a splat
|
||||
that hoovers up the remaining arguments.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">Param: </span><span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s2">"PARAM"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">LiteralNode</span> <span class="nx">yytext</span>
|
||||
<span class="nx">o</span> <span class="s2">"PARAM"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">LiteralNode</span> <span class="nx">$1</span>
|
||||
<span class="nx">o</span> <span class="s2">"Param . . ."</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">SplatNode</span> <span class="nx">$1</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-24"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-24">#</a> </div> <p>A splat that occurs outside of a parameter list.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">Splat: </span><span class="p">[</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-27"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" 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="nv">Splat: </span><span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s2">"Expression . . ."</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">SplatNode</span> <span class="nx">$1</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-25"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-25">#</a> </div> <p>Variables and properties that can be assigned to.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">SimpleAssignable: </span><span class="p">[</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-28"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" 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="nv">SimpleAssignable: </span><span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s2">"Identifier"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">ValueNode</span> <span class="nx">$1</span>
|
||||
<span class="nx">o</span> <span class="s2">"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="s2">"Invocation Accessor"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">ValueNode</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="s2">"ThisProperty"</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-26"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-26">#</a> </div> <p>Everything that can be assigned to.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">Assignable: </span><span class="p">[</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-29"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-29">#</a> </div> <p>Everything that can be assigned to.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">Assignable: </span><span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s2">"SimpleAssignable"</span>
|
||||
<span class="nx">o</span> <span class="s2">"Array"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">ValueNode</span> <span class="nx">$1</span>
|
||||
<span class="nx">o</span> <span class="s2">"Object"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">ValueNode</span> <span class="nx">$1</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-27"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-27">#</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="octowrap"> <a class="octothorpe" 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="nv">Value: </span><span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s2">"Assignable"</span>
|
||||
<span class="nx">o</span> <span class="s2">"Literal"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">ValueNode</span> <span class="nx">$1</span>
|
||||
@@ -142,7 +146,7 @@ as functions, indexed into, named as a class, etc.</p> </td>
|
||||
<span class="nx">o</span> <span class="s2">"Range"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">ValueNode</span> <span class="nx">$1</span>
|
||||
<span class="nx">o</span> <span class="s2">"This"</span>
|
||||
<span class="nx">o</span> <span class="s2">"NULL"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">ValueNode</span> <span class="k">new</span> <span class="nx">LiteralNode</span> <span class="s1">'null'</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-28"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-28">#</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="octowrap"> <a class="octothorpe" 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="nv">Accessor: </span><span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s2">"PROPERTY_ACCESS Identifier"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">AccessorNode</span> <span class="nx">$2</span>
|
||||
<span class="nx">o</span> <span class="s2">"PROTOTYPE_ACCESS Identifier"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">AccessorNode</span> <span class="nx">$2</span><span class="p">,</span> <span class="s1">'prototype'</span>
|
||||
@@ -150,159 +154,158 @@ or by array index or slice.</p> </td> <td class="code">
|
||||
<span class="nx">o</span> <span class="s2">"SOAK_ACCESS Identifier"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">AccessorNode</span> <span class="nx">$2</span><span class="p">,</span> <span class="s1">'soak'</span>
|
||||
<span class="nx">o</span> <span class="s2">"Index"</span>
|
||||
<span class="nx">o</span> <span class="s2">"Slice"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">SliceNode</span> <span class="nx">$1</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-29"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-29">#</a> </div> <p>Indexing into an object or array using bracket notation.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">Index: </span><span class="p">[</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-32"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" 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="nv">Index: </span><span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s2">"INDEX_START Expression INDEX_END"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">IndexNode</span> <span class="nx">$2</span>
|
||||
<span class="nx">o</span> <span class="s2">"SOAKED_INDEX_START Expression SOAKED_INDEX_END"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">IndexNode</span> <span class="nx">$2</span><span class="p">,</span> <span class="s1">'soak'</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-30"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-30">#</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="s2">"{ AssignList }"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">ObjectNode</span> <span class="nx">$2</span>
|
||||
<span class="nx">o</span> <span class="s2">"{ IndentedAssignList }"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">ObjectNode</span> <span class="nx">$2</span>
|
||||
<span class="nx">o</span> <span class="s2">"{ AssignList , }"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">ObjectNode</span> <span class="nx">$2</span>
|
||||
<span class="nx">o</span> <span class="s2">"{ IndentedAssignList , }"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">ObjectNode</span> <span class="nx">$2</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-31"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-31">#</a> </div> <p>Assignment of properties within an object literal can be separated by
|
||||
<span class="nx">o</span> <span class="s2">"INDEX_SOAK Index"</span><span class="p">,</span> <span class="o">-></span> <span class="nv">$2.soakNode: </span><span class="kc">yes</span><span class="p">;</span> <span class="nx">$2</span>
|
||||
<span class="nx">o</span> <span class="s2">"INDEX_PROTO Index"</span><span class="p">,</span> <span class="o">-></span> <span class="nv">$2.proto: </span><span class="kc">yes</span><span class="p">;</span> <span class="nx">$2</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-33"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" 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="s2">"{ AssignList OptComma }"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">ObjectNode</span> <span class="nx">$2</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-34"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" 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="nv">AssignList: </span><span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s2">""</span><span class="p">,</span> <span class="o">-></span> <span class="p">[]</span>
|
||||
<span class="nx">o</span> <span class="s2">"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="s2">"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="p">[</span><span class="nx">$3</span><span class="p">]</span>
|
||||
<span class="nx">o</span> <span class="s2">"AssignList 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="p">[</span><span class="nx">$3</span><span class="p">]</span>
|
||||
<span class="nx">o</span> <span class="s2">"AssignList , 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="p">[</span><span class="nx">$4</span><span class="p">]</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-32"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-32">#</a> </div> <p>An <strong>AssignList</strong> within a block indentation.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">IndentedAssignList: </span><span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s2">"INDENT AssignList OUTDENT"</span><span class="p">,</span> <span class="o">-></span> <span class="nx">$2</span>
|
||||
<span class="nx">o</span> <span class="s2">"INDENT AssignList , OUTDENT"</span><span class="p">,</span> <span class="o">-></span> <span class="nx">$2</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-33"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-33">#</a> </div> <p>Class definitions have optional bodies of prototype property assignments,
|
||||
<span class="nx">o</span> <span class="s2">"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="p">[</span><span class="nx">$4</span><span class="p">]</span>
|
||||
<span class="nx">o</span> <span class="s2">"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-35"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" 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="nv">Class: </span><span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s2">"CLASS SimpleAssignable"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">ClassNode</span> <span class="nx">$2</span>
|
||||
<span class="nx">o</span> <span class="s2">"CLASS SimpleAssignable EXTENDS Value"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">ClassNode</span> <span class="nx">$2</span><span class="p">,</span> <span class="nx">$4</span>
|
||||
<span class="nx">o</span> <span class="s2">"CLASS SimpleAssignable INDENT ClassBody OUTDENT"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">ClassNode</span> <span class="nx">$2</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="s2">"CLASS SimpleAssignable EXTENDS Value INDENT ClassBody OUTDENT"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">ClassNode</span> <span class="nx">$2</span><span class="p">,</span> <span class="nx">$4</span><span class="p">,</span> <span class="nx">$6</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-34"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-34">#</a> </div> <p>Assignments that can happen directly inside a class declaration.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">ClassAssign: </span><span class="p">[</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-36"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-36">#</a> </div> <p>Assignments that can happen directly inside a class declaration.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">ClassAssign: </span><span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s2">"AssignObj"</span><span class="p">,</span> <span class="o">-></span> <span class="nx">$1</span>
|
||||
<span class="nx">o</span> <span class="s2">"ThisProperty ASSIGN Expression"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">AssignNode</span> <span class="k">new</span> <span class="nx">ValueNode</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="s1">'this'</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-35"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-35">#</a> </div> <p>A list of assignments to a class.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">ClassBody: </span><span class="p">[</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-37"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-37">#</a> </div> <p>A list of assignments to a class.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">ClassBody: </span><span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s2">""</span><span class="p">,</span> <span class="o">-></span> <span class="p">[]</span>
|
||||
<span class="nx">o</span> <span class="s2">"ClassAssign"</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="s2">"ClassBody TERMINATOR ClassAssign"</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="p">]</span></pre></div> </td> </tr> <tr id="section-36"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-36">#</a> </div> <p>The three flavors of function call: normal, object instantiation with <code>new</code>,
|
||||
<span class="nx">o</span> <span class="s2">"ClassBody TERMINATOR ClassAssign"</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="p">]</span></pre></div> </td> </tr> <tr id="section-38"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-38">#</a> </div> <p>The three flavors of function call: normal, object instantiation with <code>new</code>,
|
||||
and calling <code>super()</code></p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">Call: </span><span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s2">"Invocation"</span>
|
||||
<span class="nx">o</span> <span class="s2">"NEW Invocation"</span><span class="p">,</span> <span class="o">-></span> <span class="nx">$2</span><span class="p">.</span><span class="nx">new_instance</span><span class="p">()</span>
|
||||
<span class="nx">o</span> <span class="s2">"Super"</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-37"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-37">#</a> </div> <p>Binds a function call to a context and/or arguments.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">Curry: </span><span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s2">"Value <- Arguments"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">CurryNode</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-38"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-38">#</a> </div> <p>Extending an object by setting its prototype chain to reference a parent
|
||||
<span class="nx">o</span> <span class="s2">"NEW Invocation"</span><span class="p">,</span> <span class="o">-></span> <span class="nx">$2</span><span class="p">.</span><span class="nx">newInstance</span><span class="p">()</span>
|
||||
<span class="nx">o</span> <span class="s2">"NEW Value"</span><span class="p">,</span> <span class="o">-></span> <span class="p">(</span><span class="k">new</span> <span class="nx">CallNode</span><span class="p">(</span><span class="nx">$2</span><span class="p">,</span> <span class="p">[])).</span><span class="nx">newInstance</span><span class="p">()</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-39"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-39">#</a> </div> <p>Extending an object by setting its prototype chain to reference a parent
|
||||
object.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">Extends: </span><span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s2">"SimpleAssignable EXTENDS Value"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">ExtendsNode</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-39"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-39">#</a> </div> <p>Ordinary function invocation, or a chained series of calls.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">Invocation: </span><span class="p">[</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-40"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-40">#</a> </div> <p>Ordinary function invocation, or a chained series of calls.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">Invocation: </span><span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s2">"Value Arguments"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">CallNode</span> <span class="nx">$1</span><span class="p">,</span> <span class="nx">$2</span>
|
||||
<span class="nx">o</span> <span class="s2">"Invocation Arguments"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">CallNode</span> <span class="nx">$1</span><span class="p">,</span> <span class="nx">$2</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-40"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-40">#</a> </div> <p>The list of arguments to a function call.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">Arguments: </span><span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s2">"CALL_START ArgList CALL_END"</span><span class="p">,</span> <span class="o">-></span> <span class="nx">$2</span>
|
||||
<span class="nx">o</span> <span class="s2">"CALL_START ArgList , 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-41"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-41">#</a> </div> <p>Calling super.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">Super: </span><span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s2">"SUPER CALL_START ArgList CALL_END"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">CallNode</span> <span class="s1">'super'</span><span class="p">,</span> <span class="nx">$3</span>
|
||||
<span class="nx">o</span> <span class="s2">"SUPER CALL_START ArgList , CALL_END"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">CallNode</span> <span class="s1">'super'</span><span class="p">,</span> <span class="nx">$3</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-42"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-42">#</a> </div> <p>A reference to the <em>this</em> current object.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">This: </span><span class="p">[</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-41"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-41">#</a> </div> <p>The list of arguments to a function call.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">Arguments: </span><span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s2">"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-42"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-42">#</a> </div> <p>Calling super.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">Super: </span><span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s2">"SUPER Arguments"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">CallNode</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-43"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-43">#</a> </div> <p>A reference to the <em>this</em> current object.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">This: </span><span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s2">"THIS"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">ValueNode</span> <span class="k">new</span> <span class="nx">LiteralNode</span> <span class="s1">'this'</span>
|
||||
<span class="nx">o</span> <span class="s2">"@"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">ValueNode</span> <span class="k">new</span> <span class="nx">LiteralNode</span> <span class="s1">'this'</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-43"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-43">#</a> </div> <p>A reference to a property on <em>this</em>.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">ThisProperty: </span><span class="p">[</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-44"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-44">#</a> </div> <p>A reference to a property on <em>this</em>.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">ThisProperty: </span><span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s2">"@ Identifier"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">ValueNode</span> <span class="k">new</span> <span class="nx">LiteralNode</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">AccessorNode</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-44"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-44">#</a> </div> <p>The CoffeeScript range literal.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">Range: </span><span class="p">[</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-45"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-45">#</a> </div> <p>The CoffeeScript range literal.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">Range: </span><span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s2">"[ Expression . . Expression ]"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">RangeNode</span> <span class="nx">$2</span><span class="p">,</span> <span class="nx">$5</span>
|
||||
<span class="nx">o</span> <span class="s2">"[ Expression . . . Expression ]"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">RangeNode</span> <span class="nx">$2</span><span class="p">,</span> <span class="nx">$6</span><span class="p">,</span> <span class="kc">true</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-45"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-45">#</a> </div> <p>The slice literal.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">Slice: </span><span class="p">[</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-46"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-46">#</a> </div> <p>The slice literal.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">Slice: </span><span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s2">"INDEX_START Expression . . Expression INDEX_END"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">RangeNode</span> <span class="nx">$2</span><span class="p">,</span> <span class="nx">$5</span>
|
||||
<span class="nx">o</span> <span class="s2">"INDEX_START Expression . . . Expression INDEX_END"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">RangeNode</span> <span class="nx">$2</span><span class="p">,</span> <span class="nx">$6</span><span class="p">,</span> <span class="kc">true</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-46"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-46">#</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="s2">"[ ArgList ]"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">ArrayNode</span> <span class="nx">$2</span>
|
||||
<span class="nx">o</span> <span class="s2">"[ ArgList , ]"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">ArrayNode</span> <span class="nx">$2</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-47"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-47">#</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-47"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-47">#</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="s2">"[ ArgList OptComma ]"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">ArrayNode</span> <span class="nx">$2</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-48"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-48">#</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="nv">ArgList: </span><span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s2">""</span><span class="p">,</span> <span class="o">-></span> <span class="p">[]</span>
|
||||
<span class="nx">o</span> <span class="s2">"Expression"</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="s2">"INDENT Expression"</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">o</span> <span class="s2">"ArgList , Expression"</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="p">[</span><span class="nx">$3</span><span class="p">]</span>
|
||||
<span class="nx">o</span> <span class="s2">"ArgList TERMINATOR Expression"</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="p">[</span><span class="nx">$3</span><span class="p">]</span>
|
||||
<span class="nx">o</span> <span class="s2">"ArgList , TERMINATOR Expression"</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="p">[</span><span class="nx">$4</span><span class="p">]</span>
|
||||
<span class="nx">o</span> <span class="s2">"ArgList , INDENT Expression"</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="p">[</span><span class="nx">$4</span><span class="p">]</span>
|
||||
<span class="nx">o</span> <span class="s2">"ArgList OUTDENT"</span>
|
||||
<span class="nx">o</span> <span class="s2">"ArgList , OUTDENT"</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-48"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-48">#</a> </div> <p>Just simple, comma-separated, required arguments (no fancy syntax). We need
|
||||
<span class="nx">o</span> <span class="s2">"ArgList OptComma TERMINATOR Expression"</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="p">[</span><span class="nx">$4</span><span class="p">]</span>
|
||||
<span class="nx">o</span> <span class="s2">"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-49"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-49">#</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="nv">SimpleArgs: </span><span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s2">"Expression"</span>
|
||||
<span class="nx">o</span> <span class="s2">"SimpleArgs , Expression"</span><span class="p">,</span> <span class="o">-></span>
|
||||
<span class="k">if</span> <span class="nx">$1</span> <span class="k">instanceof</span> <span class="nb">Array</span> <span class="k">then</span> <span class="nx">$1</span><span class="p">.</span><span class="nx">concat</span><span class="p">([</span><span class="nx">$3</span><span class="p">])</span> <span class="k">else</span> <span class="p">[</span><span class="nx">$1</span><span class="p">].</span><span class="nx">concat</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="octowrap"> <a class="octothorpe" href="#section-49">#</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="nv">Try: </span><span class="p">[</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-50"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-50">#</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="nv">Try: </span><span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s2">"TRY Block Catch"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">TryNode</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="s2">"TRY Block FINALLY Block"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">TryNode</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="s2">"TRY Block Catch FINALLY Block"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">TryNode</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-50"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-50">#</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="nv">Catch: </span><span class="p">[</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-51"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-51">#</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="nv">Catch: </span><span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s2">"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-51"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-51">#</a> </div> <p>Throw an exception object.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">Throw: </span><span class="p">[</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-52"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-52">#</a> </div> <p>Throw an exception object.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">Throw: </span><span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s2">"THROW Expression"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">ThrowNode</span> <span class="nx">$2</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-52"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-52">#</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-53"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-53">#</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="nv">Parenthetical: </span><span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s2">"( Expression )"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">ParentheticalNode</span> <span class="nx">$2</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-53"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-53">#</a> </div> <p>A language extension to CoffeeScript from the outside. We simply pass
|
||||
it through unaltered.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">Extension: </span><span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s2">"EXTENSION"</span><span class="p">,</span> <span class="o">-></span> <span class="nx">yytext</span>
|
||||
<span class="nx">o</span> <span class="s2">"( Line )"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">ParentheticalNode</span> <span class="nx">$2</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-54"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-54">#</a> </div> <p>The condition portion of a while loop.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">WhileSource: </span><span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s2">"WHILE Expression"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">WhileNode</span> <span class="nx">$2</span>
|
||||
<span class="nx">o</span> <span class="s2">"WHILE Expression WHEN Expression"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">WhileNode</span> <span class="nx">$2</span><span class="p">,</span> <span class="p">{</span><span class="nv">filter : </span><span class="nx">$4</span><span class="p">}</span>
|
||||
<span class="nx">o</span> <span class="s2">"WHILE Expression WHEN Expression"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">WhileNode</span> <span class="nx">$2</span><span class="p">,</span> <span class="p">{</span><span class="nv">guard : </span><span class="nx">$4</span><span class="p">}</span>
|
||||
<span class="nx">o</span> <span class="s2">"UNTIL Expression"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">WhileNode</span> <span class="nx">$2</span><span class="p">,</span> <span class="p">{</span><span class="nv">invert: </span><span class="kc">true</span><span class="p">}</span>
|
||||
<span class="nx">o</span> <span class="s2">"UNTIL Expression WHEN Expression"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">WhileNode</span> <span class="nx">$2</span><span class="p">,</span> <span class="p">{</span><span class="nv">invert: </span><span class="kc">true</span><span class="p">,</span> <span class="nv">guard: </span><span class="nx">$4</span><span class="p">}</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-55"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-55">#</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="nv">While: </span><span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s2">"WhileSource Block"</span><span class="p">,</span> <span class="o">-></span> <span class="nx">$1</span><span class="p">.</span><span class="nx">add_body</span> <span class="nx">$2</span>
|
||||
<span class="nx">o</span> <span class="s2">"Expression WhileSource"</span><span class="p">,</span> <span class="o">-></span> <span class="nx">$2</span><span class="p">.</span><span class="nx">add_body</span> <span class="nx">Expressions</span><span class="p">.</span><span class="nx">wrap</span> <span class="p">[</span><span class="nx">$1</span><span class="p">]</span>
|
||||
<span class="nx">o</span> <span class="s2">"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="s2">"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">Expressions</span><span class="p">.</span><span class="nx">wrap</span> <span class="p">[</span><span class="nx">$1</span><span class="p">]</span>
|
||||
<span class="nx">o</span> <span class="s2">"Expression 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">Expressions</span><span class="p">.</span><span class="nx">wrap</span> <span class="p">[</span><span class="nx">$1</span><span class="p">]</span>
|
||||
<span class="nx">o</span> <span class="s2">"Loop"</span><span class="p">,</span> <span class="o">-></span> <span class="nx">$1</span>
|
||||
<span class="p">]</span>
|
||||
|
||||
<span class="nv">Loop: </span><span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s2">"LOOP Block"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">WhileNode</span><span class="p">(</span><span class="k">new</span> <span class="nx">LiteralNode</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="s2">"LOOP Expression"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">WhileNode</span><span class="p">(</span><span class="k">new</span> <span class="nx">LiteralNode</span> <span class="s1">'true'</span><span class="p">).</span><span class="nx">addBody</span> <span class="nx">Expressions</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-56"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-56">#</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="nv">For: </span><span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s2">"Statement FOR ForVariables ForSource"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">ForNode</span> <span class="nx">$1</span><span class="p">,</span> <span class="nx">$4</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="s2">"Expression FOR ForVariables ForSource"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">ForNode</span> <span class="nx">$1</span><span class="p">,</span> <span class="nx">$4</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="s2">"FOR ForVariables ForSource Block"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">ForNode</span> <span class="nx">$4</span><span class="p">,</span> <span class="nx">$3</span><span class="p">,</span> <span class="nx">$2</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="nx">$2</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-57"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-57">#</a> </div> <p>An array or range comprehension has variables for the current element and
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-57"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-57">#</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="nv">ForValue: </span><span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s2">"Identifier"</span>
|
||||
<span class="nx">o</span> <span class="s2">"Array"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">ValueNode</span> <span class="nx">$1</span>
|
||||
<span class="nx">o</span> <span class="s2">"Object"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">ValueNode</span> <span class="nx">$1</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-58"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-58">#</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="nv">ForVariables: </span><span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s2">"Identifier"</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="s2">"Identifier , Identifier"</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-58"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-58">#</a> </div> <p>The source of a comprehension is an array or object with an optional filter
|
||||
<span class="nx">o</span> <span class="s2">"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="s2">"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-59"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-59">#</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="nv">ForSource: </span><span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s2">"IN Expression"</span><span class="p">,</span> <span class="o">-></span> <span class="p">{</span><span class="nv">source: </span><span class="nx">$2</span><span class="p">}</span>
|
||||
<span class="nx">o</span> <span class="s2">"OF Expression"</span><span class="p">,</span> <span class="o">-></span> <span class="p">{</span><span class="nv">source: </span><span class="nx">$2</span><span class="p">,</span> <span class="nv">object: </span><span class="kc">true</span><span class="p">}</span>
|
||||
<span class="nx">o</span> <span class="s2">"IN Expression WHEN Expression"</span><span class="p">,</span> <span class="o">-></span> <span class="p">{</span><span class="nv">source: </span><span class="nx">$2</span><span class="p">,</span> <span class="nv">filter: </span><span class="nx">$4</span><span class="p">}</span>
|
||||
<span class="nx">o</span> <span class="s2">"OF Expression WHEN Expression"</span><span class="p">,</span> <span class="o">-></span> <span class="p">{</span><span class="nv">source: </span><span class="nx">$2</span><span class="p">,</span> <span class="nv">filter: </span><span class="nx">$4</span><span class="p">,</span> <span class="nv">object: </span><span class="kc">true</span><span class="p">}</span>
|
||||
<span class="nx">o</span> <span class="s2">"IN Expression WHEN Expression"</span><span class="p">,</span> <span class="o">-></span> <span class="p">{</span><span class="nv">source: </span><span class="nx">$2</span><span class="p">,</span> <span class="nv">guard: </span><span class="nx">$4</span><span class="p">}</span>
|
||||
<span class="nx">o</span> <span class="s2">"OF Expression WHEN Expression"</span><span class="p">,</span> <span class="o">-></span> <span class="p">{</span><span class="nv">source: </span><span class="nx">$2</span><span class="p">,</span> <span class="nv">guard: </span><span class="nx">$4</span><span class="p">,</span> <span class="nv">object: </span><span class="kc">true</span><span class="p">}</span>
|
||||
<span class="nx">o</span> <span class="s2">"IN Expression BY Expression"</span><span class="p">,</span> <span class="o">-></span> <span class="p">{</span><span class="nv">source: </span><span class="nx">$2</span><span class="p">,</span> <span class="nv">step: </span> <span class="nx">$4</span><span class="p">}</span>
|
||||
<span class="nx">o</span> <span class="s2">"IN Expression WHEN Expression BY Expression"</span><span class="p">,</span> <span class="o">-></span> <span class="p">{</span><span class="nv">source: </span><span class="nx">$2</span><span class="p">,</span> <span class="nv">filter: </span><span class="nx">$4</span><span class="p">;</span> <span class="nv">step: </span> <span class="nx">$6</span><span class="p">}</span>
|
||||
<span class="nx">o</span> <span class="s2">"IN Expression BY Expression WHEN Expression"</span><span class="p">,</span> <span class="o">-></span> <span class="p">{</span><span class="nv">source: </span><span class="nx">$2</span><span class="p">,</span> <span class="nv">step: </span> <span class="nx">$4</span><span class="p">,</span> <span class="nv">filter: </span><span class="nx">$6</span><span class="p">}</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-59"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-59">#</a> </div> <p>The CoffeeScript switch/when/else block replaces the JavaScript
|
||||
<span class="nx">o</span> <span class="s2">"IN Expression WHEN Expression BY Expression"</span><span class="p">,</span> <span class="o">-></span> <span class="p">{</span><span class="nv">source: </span><span class="nx">$2</span><span class="p">,</span> <span class="nv">guard: </span><span class="nx">$4</span><span class="p">,</span> <span class="nv">step: </span> <span class="nx">$6</span><span class="p">}</span>
|
||||
<span class="nx">o</span> <span class="s2">"IN Expression BY Expression WHEN Expression"</span><span class="p">,</span> <span class="o">-></span> <span class="p">{</span><span class="nv">source: </span><span class="nx">$2</span><span class="p">,</span> <span class="nv">step: </span> <span class="nx">$4</span><span class="p">,</span> <span class="nv">guard: </span><span class="nx">$6</span><span class="p">}</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-60"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-60">#</a> </div> <p>The CoffeeScript switch/when/else block replaces the JavaScript
|
||||
switch/case/default by compiling into an if-else chain.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">Switch: </span><span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s2">"SWITCH Expression INDENT Whens OUTDENT"</span><span class="p">,</span> <span class="o">-></span> <span class="nx">$4</span><span class="p">.</span><span class="nx">rewrite_condition</span> <span class="nx">$2</span>
|
||||
<span class="nx">o</span> <span class="s2">"SWITCH Expression INDENT Whens ELSE Block OUTDENT"</span><span class="p">,</span> <span class="o">-></span> <span class="nx">$4</span><span class="p">.</span><span class="nx">rewrite_condition</span><span class="p">(</span><span class="nx">$2</span><span class="p">).</span><span class="nx">add_else</span> <span class="nx">$6</span><span class="p">,</span> <span class="kc">true</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-60"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-60">#</a> </div> <p>The inner list of whens is left recursive. At code-generation time, the
|
||||
<span class="nx">o</span> <span class="s2">"SWITCH Expression INDENT Whens OUTDENT"</span><span class="p">,</span> <span class="o">-></span> <span class="nx">$4</span><span class="p">.</span><span class="nx">switchesOver</span> <span class="nx">$2</span>
|
||||
<span class="nx">o</span> <span class="s2">"SWITCH Expression INDENT Whens ELSE Block OUTDENT"</span><span class="p">,</span> <span class="o">-></span> <span class="nx">$4</span><span class="p">.</span><span class="nx">switchesOver</span><span class="p">(</span><span class="nx">$2</span><span class="p">).</span><span class="nx">addElse</span> <span class="nx">$6</span><span class="p">,</span> <span class="kc">true</span>
|
||||
<span class="nx">o</span> <span class="s2">"SWITCH INDENT Whens OUTDENT"</span><span class="p">,</span> <span class="o">-></span> <span class="nx">$3</span>
|
||||
<span class="nx">o</span> <span class="s2">"SWITCH INDENT Whens ELSE Block OUTDENT"</span><span class="p">,</span> <span class="o">-></span> <span class="nx">$3</span><span class="p">.</span><span class="nx">addElse</span> <span class="nx">$5</span><span class="p">,</span> <span class="kc">true</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-61"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-61">#</a> </div> <p>The inner list of whens is left recursive. At code-generation time, the
|
||||
IfNode will rewrite them into a proper chain.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">Whens: </span><span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s2">"When"</span>
|
||||
<span class="nx">o</span> <span class="s2">"Whens When"</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="p">]</span></pre></div> </td> </tr> <tr id="section-61"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-61">#</a> </div> <p>An individual <strong>When</strong> clause, with action.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">When: </span><span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s2">"LEADING_WHEN SimpleArgs Block"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">IfNode</span> <span class="nx">$2</span><span class="p">,</span> <span class="nx">$3</span><span class="p">,</span> <span class="kc">null</span><span class="p">,</span> <span class="p">{</span><span class="nv">statement: </span><span class="kc">true</span><span class="p">}</span>
|
||||
<span class="nx">o</span> <span class="s2">"LEADING_WHEN SimpleArgs Block TERMINATOR"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">IfNode</span> <span class="nx">$2</span><span class="p">,</span> <span class="nx">$3</span><span class="p">,</span> <span class="kc">null</span><span class="p">,</span> <span class="p">{</span><span class="nv">statement: </span><span class="kc">true</span><span class="p">}</span>
|
||||
<span class="nx">o</span> <span class="s2">"Comment TERMINATOR When"</span><span class="p">,</span> <span class="o">-></span> <span class="nv">$3.comment: </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="octowrap"> <a class="octothorpe" href="#section-62">#</a> </div> <p>The most basic form of <em>if</em> is a condition and an action. The following
|
||||
<span class="nx">o</span> <span class="s2">"Whens When"</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">$2</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-62"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-62">#</a> </div> <p>An individual <strong>When</strong> clause, with action.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">When: </span><span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s2">"LEADING_WHEN SimpleArgs Block"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">IfNode</span> <span class="nx">$2</span><span class="p">,</span> <span class="nx">$3</span><span class="p">,</span> <span class="p">{</span><span class="nv">statement: </span><span class="kc">true</span><span class="p">}</span>
|
||||
<span class="nx">o</span> <span class="s2">"LEADING_WHEN SimpleArgs Block TERMINATOR"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">IfNode</span> <span class="nx">$2</span><span class="p">,</span> <span class="nx">$3</span><span class="p">,</span> <span class="p">{</span><span class="nv">statement: </span><span class="kc">true</span><span class="p">}</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-63"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-63">#</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="nv">IfStart: </span><span class="p">[</span>
|
||||
ambiguity.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">IfBlock: </span><span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s2">"IF Expression Block"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">IfNode</span> <span class="nx">$2</span><span class="p">,</span> <span class="nx">$3</span>
|
||||
<span class="nx">o</span> <span class="s2">"IfStart ElsIf"</span><span class="p">,</span> <span class="o">-></span> <span class="nx">$1</span><span class="p">.</span><span class="nx">add_else</span> <span class="nx">$2</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-63"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-63">#</a> </div> <p>An <strong>IfStart</strong> can optionally be followed by an else block.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">IfBlock: </span><span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s2">"IfStart"</span>
|
||||
<span class="nx">o</span> <span class="s2">"IfStart ELSE Block"</span><span class="p">,</span> <span class="o">-></span> <span class="nx">$1</span><span class="p">.</span><span class="nx">add_else</span> <span class="nx">$3</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-64"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-64">#</a> </div> <p>An <em>else if</em> continuation of the <em>if</em> expression.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">ElsIf: </span><span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s2">"ELSE IF Expression Block"</span><span class="p">,</span> <span class="o">-></span> <span class="p">(</span><span class="k">new</span> <span class="nx">IfNode</span><span class="p">(</span><span class="nx">$3</span><span class="p">,</span> <span class="nx">$4</span><span class="p">)).</span><span class="nx">force_statement</span><span class="p">()</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-65"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-65">#</a> </div> <p>The full complement of <em>if</em> expressions, including postfix one-liner
|
||||
<span class="nx">o</span> <span class="s2">"UNLESS Expression Block"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">IfNode</span> <span class="nx">$2</span><span class="p">,</span> <span class="nx">$3</span><span class="p">,</span> <span class="p">{</span><span class="nv">invert: </span><span class="kc">true</span><span class="p">}</span>
|
||||
<span class="nx">o</span> <span class="s2">"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="p">(</span><span class="k">new</span> <span class="nx">IfNode</span><span class="p">(</span><span class="nx">$4</span><span class="p">,</span> <span class="nx">$5</span><span class="p">)).</span><span class="nx">forceStatement</span><span class="p">()</span>
|
||||
<span class="nx">o</span> <span class="s2">"IfBlock ELSE Block"</span><span class="p">,</span> <span class="o">-></span> <span class="nx">$1</span><span class="p">.</span><span class="nx">addElse</span> <span class="nx">$3</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-64"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-64">#</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="nv">If: </span><span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s2">"IfBlock"</span>
|
||||
<span class="nx">o</span> <span class="s2">"Expression IF Expression"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">IfNode</span> <span class="nx">$3</span><span class="p">,</span> <span class="nx">Expressions</span><span class="p">.</span><span class="nx">wrap</span><span class="p">([</span><span class="nx">$1</span><span class="p">]),</span> <span class="kc">null</span><span class="p">,</span> <span class="p">{</span><span class="nv">statement: </span><span class="kc">true</span><span class="p">}</span>
|
||||
<span class="nx">o</span> <span class="s2">"Expression UNLESS Expression"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">IfNode</span> <span class="nx">$3</span><span class="p">,</span> <span class="nx">Expressions</span><span class="p">.</span><span class="nx">wrap</span><span class="p">([</span><span class="nx">$1</span><span class="p">]),</span> <span class="kc">null</span><span class="p">,</span> <span class="p">{</span><span class="nv">statement: </span><span class="kc">true</span><span class="p">,</span> <span class="nv">invert: </span><span class="kc">true</span><span class="p">}</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-66"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-66">#</a> </div> <p>Arithmetic and logical operators, working on one or more operands.
|
||||
<span class="nx">o</span> <span class="s2">"Statement IF Expression"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">IfNode</span> <span class="nx">$3</span><span class="p">,</span> <span class="nx">Expressions</span><span class="p">.</span><span class="nx">wrap</span><span class="p">([</span><span class="nx">$1</span><span class="p">]),</span> <span class="p">{</span><span class="nv">statement: </span><span class="kc">true</span><span class="p">}</span>
|
||||
<span class="nx">o</span> <span class="s2">"Expression IF Expression"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">IfNode</span> <span class="nx">$3</span><span class="p">,</span> <span class="nx">Expressions</span><span class="p">.</span><span class="nx">wrap</span><span class="p">([</span><span class="nx">$1</span><span class="p">]),</span> <span class="p">{</span><span class="nv">statement: </span><span class="kc">true</span><span class="p">}</span>
|
||||
<span class="nx">o</span> <span class="s2">"Statement UNLESS Expression"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">IfNode</span> <span class="nx">$3</span><span class="p">,</span> <span class="nx">Expressions</span><span class="p">.</span><span class="nx">wrap</span><span class="p">([</span><span class="nx">$1</span><span class="p">]),</span> <span class="p">{</span><span class="nv">statement: </span><span class="kc">true</span><span class="p">,</span> <span class="nv">invert: </span><span class="kc">true</span><span class="p">}</span>
|
||||
<span class="nx">o</span> <span class="s2">"Expression UNLESS Expression"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">IfNode</span> <span class="nx">$3</span><span class="p">,</span> <span class="nx">Expressions</span><span class="p">.</span><span class="nx">wrap</span><span class="p">([</span><span class="nx">$1</span><span class="p">]),</span> <span class="p">{</span><span class="nv">statement: </span><span class="kc">true</span><span class="p">,</span> <span class="nv">invert: </span><span class="kc">true</span><span class="p">}</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-65"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-65">#</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>
|
||||
@@ -344,7 +347,7 @@ rules are necessary.</p> </td> <td class="code">
|
||||
|
||||
<span class="nx">o</span> <span class="s2">"Expression && Expression"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">OpNode</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="s2">"Expression || Expression"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">OpNode</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="s2">"Expression ? Expression"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">OpNode</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="s2">"Expression OP? Expression"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">OpNode</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="s2">"Expression -= Expression"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">OpNode</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="s2">"Expression += Expression"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">OpNode</span> <span class="s1">'+='</span><span class="p">,</span> <span class="nx">$1</span><span class="p">,</span> <span class="nx">$3</span>
|
||||
@@ -356,10 +359,13 @@ rules are necessary.</p> </td> <td class="code">
|
||||
<span class="nx">o</span> <span class="s2">"Expression ?= Expression"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">OpNode</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="s2">"Expression INSTANCEOF Expression"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">OpNode</span> <span class="s1">'instanceof'</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="s2">"Expression IN Expression"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">OpNode</span> <span class="s1">'in'</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="s2">"Expression IN Expression"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">InNode</span> <span class="nx">$1</span><span class="p">,</span> <span class="nx">$3</span>
|
||||
<span class="nx">o</span> <span class="s2">"Expression OF Expression"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">OpNode</span> <span class="s1">'in'</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="s2">"Expression ! IN Expression"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">OpNode</span> <span class="s1">'!'</span><span class="p">,</span> <span class="k">new</span> <span class="nx">InNode</span> <span class="nx">$1</span><span class="p">,</span> <span class="nx">$4</span>
|
||||
<span class="nx">o</span> <span class="s2">"Expression ! OF Expression"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">OpNode</span> <span class="s1">'!'</span><span class="p">,</span> <span class="k">new</span> <span class="nx">ParentheticalNode</span> <span class="k">new</span> <span class="nx">OpNode</span> <span class="s1">'in'</span><span class="p">,</span> <span class="nx">$1</span><span class="p">,</span> <span class="nx">$4</span>
|
||||
<span class="p">]</span>
|
||||
|
||||
<span class="p">}</span></pre></div> </td> </tr> <tr id="section-67"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-67">#</a> </div> <h2>Precedence</h2> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-68"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-68">#</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-66"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-66">#</a> </div> <h2>Precedence</h2> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-67"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-67">#</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)
|
||||
@@ -378,17 +384,17 @@ down. Following these rules is what makes <code>2 + 3 * 4</code> parse as:</p>
|
||||
<span class="p">[</span><span class="s2">"left"</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="p">[</span><span class="s2">"right"</span><span class="p">,</span> <span class="s1">'DELETE'</span><span class="p">,</span> <span class="s1">'INSTANCEOF'</span><span class="p">,</span> <span class="s1">'TYPEOF'</span><span class="p">]</span>
|
||||
<span class="p">[</span><span class="s2">"left"</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="s2">"left"</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="s2">"left"</span><span class="p">,</span> <span class="s1">'&&'</span><span class="p">,</span> <span class="s1">'||'</span><span class="p">,</span> <span class="s1">'OP?'</span><span class="p">]</span>
|
||||
<span class="p">[</span><span class="s2">"right"</span><span class="p">,</span> <span class="s1">'-='</span><span class="p">,</span> <span class="s1">'+='</span><span class="p">,</span> <span class="s1">'/='</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="p">[</span><span class="s2">"left"</span><span class="p">,</span> <span class="s1">'.'</span><span class="p">]</span>
|
||||
<span class="p">[</span><span class="s2">"right"</span><span class="p">,</span> <span class="s1">'INDENT'</span><span class="p">]</span>
|
||||
<span class="p">[</span><span class="s2">"left"</span><span class="p">,</span> <span class="s1">'OUTDENT'</span><span class="p">]</span>
|
||||
<span class="p">[</span><span class="s2">"right"</span><span class="p">,</span> <span class="s1">'WHEN'</span><span class="p">,</span> <span class="s1">'LEADING_WHEN'</span><span class="p">,</span> <span class="s1">'IN'</span><span class="p">,</span> <span class="s1">'OF'</span><span class="p">,</span> <span class="s1">'BY'</span><span class="p">,</span> <span class="s1">'THROW'</span><span class="p">]</span>
|
||||
<span class="p">[</span><span class="s2">"right"</span><span class="p">,</span> <span class="s1">'FOR'</span><span class="p">,</span> <span class="s1">'NEW'</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="s2">"right"</span><span class="p">,</span> <span class="s1">'FOR'</span><span class="p">,</span> <span class="s1">'WHILE'</span><span class="p">,</span> <span class="s1">'UNTIL'</span><span class="p">,</span> <span class="s1">'LOOP'</span><span class="p">,</span> <span class="s1">'NEW'</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="s2">"left"</span><span class="p">,</span> <span class="s1">'EXTENDS'</span><span class="p">]</span>
|
||||
<span class="p">[</span><span class="s2">"right"</span><span class="p">,</span> <span class="s1">'ASSIGN'</span><span class="p">,</span> <span class="s1">'RETURN'</span><span class="p">]</span>
|
||||
<span class="p">[</span><span class="s2">"right"</span><span class="p">,</span> <span class="s1">'->'</span><span class="p">,</span> <span class="s1">'=>'</span><span class="p">,</span> <span class="s1">'<-'</span><span class="p">,</span> <span class="s1">'UNLESS'</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">'WHILE'</span><span class="p">]</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-69"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-69">#</a> </div> <h2>Wrapping Up</h2> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-70"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-70">#</a> </div> <p>Finally, now what we have our <strong>grammar</strong> and our <strong>operators</strong>, we can create
|
||||
<span class="p">[</span><span class="s2">"right"</span><span class="p">,</span> <span class="s1">'->'</span><span class="p">,</span> <span class="s1">'=>'</span><span class="p">,</span> <span class="s1">'UNLESS'</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="p">]</span></pre></div> </td> </tr> <tr id="section-68"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-68">#</a> </div> <h2>Wrapping Up</h2> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-69"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-69">#</a> </div> <p>Finally, now what we have our <strong>grammar</strong> and our <strong>operators</strong>, we can create
|
||||
our <strong>Jison.Parser</strong>. We do this by processing all of our rules, recording all
|
||||
terminals (every symbol which does not appear as the name of a rule above)
|
||||
as "tokens".</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">tokens: </span><span class="p">[]</span>
|
||||
@@ -397,7 +403,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-71"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-71">#</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-70"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-70">#</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> <span class="p">{</span>
|
||||
|
||||
@@ -1,59 +1,36 @@
|
||||
<!DOCTYPE html> <html> <head> <title>helpers.coffee</title> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <link rel="stylesheet" media="all" href="docco.css" /> </head> <body> <div id="container"> <div id="background"></div> <div id="jump_to"> Jump To … <div id="jump_wrapper"> <div id="jump_page"> <a class="source" href="cake.html"> cake.coffee </a> <a class="source" href="coffee-script.html"> coffee-script.coffee </a> <a class="source" href="command.html"> command.coffee </a> <a class="source" href="grammar.html"> grammar.coffee </a> <a class="source" href="helpers.html"> helpers.coffee </a> <a class="source" href="lexer.html"> lexer.coffee </a> <a class="source" href="nodes.html"> nodes.coffee </a> <a class="source" href="optparse.html"> optparse.coffee </a> <a class="source" href="repl.html"> repl.coffee </a> <a class="source" href="rewriter.html"> rewriter.coffee </a> <a class="source" href="scope.html"> scope.coffee </a> </div> </div> </div> <table cellpadding="0" cellspacing="0"> <thead> <tr> <th class="docs"> <h1> helpers.coffee </h1> </th> <th class="code"> </th> </tr> </thead> <tbody> <tr id="section-1"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-1">#</a> </div> <p>This file contains the common helper functions that we'd like to share among
|
||||
<!DOCTYPE html> <html> <head> <title>helpers.coffee</title> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <link rel="stylesheet" media="all" href="docco.css" /> </head> <body> <div id="container"> <div id="background"></div> <div id="jump_to"> Jump To … <div id="jump_wrapper"> <div id="jump_page"> <a class="source" href="cake.html"> cake.coffee </a> <a class="source" href="coffee-script.html"> coffee-script.coffee </a> <a class="source" href="command.html"> command.coffee </a> <a class="source" href="grammar.html"> grammar.coffee </a> <a class="source" href="helpers.html"> helpers.coffee </a> <a class="source" href="index.html"> index.coffee </a> <a class="source" href="lexer.html"> lexer.coffee </a> <a class="source" href="nodes.html"> nodes.coffee </a> <a class="source" href="optparse.html"> optparse.coffee </a> <a class="source" href="repl.html"> repl.coffee </a> <a class="source" href="rewriter.html"> rewriter.coffee </a> <a class="source" href="scope.html"> scope.coffee </a> </div> </div> </div> <table cellpadding="0" cellspacing="0"> <thead> <tr> <th class="docs"> <h1> helpers.coffee </h1> </th> <th class="code"> </th> </tr> </thead> <tbody> <tr id="section-1"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-1">#</a> </div> <p>This file contains the common helper functions that we'd like to share among
|
||||
the <strong>Lexer</strong>, <strong>Rewriter</strong>, and the <strong>Nodes</strong>. Merge objects, flatten
|
||||
arrays, count characters, that sort of thing.</p> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-2"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-2">#</a> </div> <p>Set up exported variables for both <strong>Node.js</strong> and the browser.</p> </td> <td class="code"> <div class="highlight"><pre><span class="k">this</span><span class="p">.</span><span class="nv">exports: </span><span class="k">this</span> <span class="nx">unless</span> <span class="nx">process</span><span class="o">?</span>
|
||||
<span class="nv">helpers: exports.helpers: </span><span class="p">{}</span></pre></div> </td> </tr> <tr id="section-3"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-3">#</a> </div> <p>Does a list include a value?</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">helpers.include: include: </span><span class="p">(</span><span class="nx">list</span><span class="p">,</span> <span class="nx">value</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nx">list</span><span class="p">.</span><span class="nx">indexOf</span><span class="p">(</span><span class="nx">value</span><span class="p">)</span> <span class="o">>=</span> <span class="mi">0</span></pre></div> </td> </tr> <tr id="section-4"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-4">#</a> </div> <p>Peek at the beginning of a given string to see if it matches a sequence.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">helpers.starts: starts: </span><span class="p">(</span><span class="nx">string</span><span class="p">,</span> <span class="nx">literal</span><span class="p">,</span> <span class="nx">start</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nx">string</span><span class="p">.</span><span class="nx">substring</span><span class="p">(</span><span class="nx">start</span><span class="p">,</span> <span class="p">(</span><span class="nx">start</span> <span class="o">or</span> <span class="mi">0</span><span class="p">)</span> <span class="o">+</span> <span class="nx">literal</span><span class="p">.</span><span class="nx">length</span><span class="p">)</span> <span class="o">is</span> <span class="nx">literal</span></pre></div> </td> </tr> <tr id="section-5"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-5">#</a> </div> <p>Trim out all falsy values from an array.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">helpers.compact: compact: </span><span class="p">(</span><span class="nx">array</span><span class="p">)</span> <span class="o">-></span> <span class="nx">item</span> <span class="k">for</span> <span class="nx">item</span> <span class="k">in</span> <span class="nx">array</span> <span class="k">when</span> <span class="nx">item</span></pre></div> </td> </tr> <tr id="section-6"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-6">#</a> </div> <p>Count the number of occurences of a character in a string.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">helpers.count: count: </span><span class="p">(</span><span class="nx">string</span><span class="p">,</span> <span class="nx">letter</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nv">helpers: exports.helpers: </span><span class="p">{}</span></pre></div> </td> </tr> <tr id="section-3"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-3">#</a> </div> <p>Cross-browser indexOf, so that IE can join the party.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">helpers.indexOf: indexOf: </span><span class="p">(</span><span class="nx">array</span><span class="p">,</span> <span class="nx">item</span><span class="p">,</span> <span class="nx">from</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="k">return</span> <span class="nx">array</span><span class="p">.</span><span class="nx">indexOf</span> <span class="nx">item</span><span class="p">,</span> <span class="nx">from</span> <span class="k">if</span> <span class="nx">array</span><span class="p">.</span><span class="nx">indexOf</span>
|
||||
<span class="k">for</span> <span class="nx">other</span><span class="p">,</span> <span class="nx">index</span> <span class="k">in</span> <span class="nx">array</span>
|
||||
<span class="k">if</span> <span class="nx">other</span> <span class="o">is</span> <span class="nx">item</span> <span class="o">and</span> <span class="p">(</span><span class="o">not</span> <span class="nx">from</span> <span class="o">or</span> <span class="p">(</span><span class="nx">from</span> <span class="o"><=</span> <span class="nx">index</span><span class="p">))</span>
|
||||
<span class="k">return</span> <span class="nx">index</span>
|
||||
<span class="o">-</span><span class="mi">1</span></pre></div> </td> </tr> <tr id="section-4"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-4">#</a> </div> <p>Does a list include a value?</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">helpers.include: include: </span><span class="p">(</span><span class="nx">list</span><span class="p">,</span> <span class="nx">value</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nx">indexOf</span><span class="p">(</span><span class="nx">list</span><span class="p">,</span> <span class="nx">value</span><span class="p">)</span> <span class="o">>=</span> <span class="mi">0</span></pre></div> </td> </tr> <tr id="section-5"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-5">#</a> </div> <p>Peek at the beginning of a given string to see if it matches a sequence.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">helpers.starts: starts: </span><span class="p">(</span><span class="nx">string</span><span class="p">,</span> <span class="nx">literal</span><span class="p">,</span> <span class="nx">start</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nx">string</span><span class="p">.</span><span class="nx">substring</span><span class="p">(</span><span class="nx">start</span><span class="p">,</span> <span class="p">(</span><span class="nx">start</span> <span class="o">or</span> <span class="mi">0</span><span class="p">)</span> <span class="o">+</span> <span class="nx">literal</span><span class="p">.</span><span class="nx">length</span><span class="p">)</span> <span class="o">is</span> <span class="nx">literal</span></pre></div> </td> </tr> <tr id="section-6"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-6">#</a> </div> <p>Trim out all falsy values from an array.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">helpers.compact: compact: </span><span class="p">(</span><span class="nx">array</span><span class="p">)</span> <span class="o">-></span> <span class="nx">item</span> <span class="k">for</span> <span class="nx">item</span> <span class="k">in</span> <span class="nx">array</span> <span class="k">when</span> <span class="nx">item</span></pre></div> </td> </tr> <tr id="section-7"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-7">#</a> </div> <p>Count the number of occurences of a character in a string.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">helpers.count: count: </span><span class="p">(</span><span class="nx">string</span><span class="p">,</span> <span class="nx">letter</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nv">num: </span><span class="mi">0</span>
|
||||
<span class="nv">pos: </span><span class="nx">string</span><span class="p">.</span><span class="nx">indexOf</span><span class="p">(</span><span class="nx">letter</span><span class="p">)</span>
|
||||
<span class="nv">pos: </span><span class="nx">indexOf</span> <span class="nx">string</span><span class="p">,</span> <span class="nx">letter</span>
|
||||
<span class="k">while</span> <span class="nx">pos</span> <span class="o">isnt</span> <span class="o">-</span><span class="mi">1</span>
|
||||
<span class="nv">num: </span><span class="o">+</span> <span class="mi">1</span>
|
||||
<span class="nv">pos: </span><span class="nx">string</span><span class="p">.</span><span class="nx">indexOf</span><span class="p">(</span><span class="nx">letter</span><span class="p">,</span> <span class="nx">pos</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span>
|
||||
<span class="nx">num</span></pre></div> </td> </tr> <tr id="section-7"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-7">#</a> </div> <p>Merge objects, returning a fresh copy with attributes from both sides.
|
||||
<span class="nv">pos: </span><span class="nx">indexOf</span> <span class="nx">string</span><span class="p">,</span> <span class="nx">letter</span><span class="p">,</span> <span class="nx">pos</span> <span class="o">+</span> <span class="mi">1</span>
|
||||
<span class="nx">num</span></pre></div> </td> </tr> <tr id="section-8"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-8">#</a> </div> <p>Merge objects, returning a fresh copy with attributes from both sides.
|
||||
Used every time <code>BaseNode#compile</code> is called, to allow properties in the
|
||||
options hash to propagate down the tree without polluting other branches.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">helpers.merge: merge: </span><span class="p">(</span><span class="nx">options</span><span class="p">,</span> <span class="nx">overrides</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nv">fresh: </span><span class="p">{}</span>
|
||||
<span class="p">(</span><span class="nx">fresh</span><span class="p">[</span><span class="nx">key</span><span class="p">]</span><span class="o">:</span> <span class="nx">val</span><span class="p">)</span> <span class="k">for</span> <span class="nx">key</span><span class="p">,</span> <span class="nx">val</span> <span class="k">of</span> <span class="nx">options</span>
|
||||
<span class="p">(</span><span class="nx">fresh</span><span class="p">[</span><span class="nx">key</span><span class="p">]</span><span class="o">:</span> <span class="nx">val</span><span class="p">)</span> <span class="k">for</span> <span class="nx">key</span><span class="p">,</span> <span class="nx">val</span> <span class="k">of</span> <span class="nx">overrides</span> <span class="k">if</span> <span class="nx">overrides</span>
|
||||
<span class="nx">fresh</span></pre></div> </td> </tr> <tr id="section-8"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-8">#</a> </div> <p>Extend a source object with the properties of another object (shallow copy).
|
||||
<span class="nx">fresh</span></pre></div> </td> </tr> <tr id="section-9"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-9">#</a> </div> <p>Extend a source object with the properties of another object (shallow copy).
|
||||
We use this to simulate Node's deprecated <code>process.mixin</code></p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">helpers.extend: extend: </span><span class="p">(</span><span class="nx">object</span><span class="p">,</span> <span class="nx">properties</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="p">(</span><span class="nx">object</span><span class="p">[</span><span class="nx">key</span><span class="p">]</span><span class="o">:</span> <span class="nx">val</span><span class="p">)</span> <span class="k">for</span> <span class="nx">key</span><span class="p">,</span> <span class="nx">val</span> <span class="k">of</span> <span class="nx">properties</span></pre></div> </td> </tr> <tr id="section-9"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-9">#</a> </div> <p>Return a completely flattened version of an array. Handy for getting a
|
||||
<span class="p">(</span><span class="nx">object</span><span class="p">[</span><span class="nx">key</span><span class="p">]</span><span class="o">:</span> <span class="nx">val</span><span class="p">)</span> <span class="k">for</span> <span class="nx">key</span><span class="p">,</span> <span class="nx">val</span> <span class="k">of</span> <span class="nx">properties</span></pre></div> </td> </tr> <tr id="section-10"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-10">#</a> </div> <p>Return a completely flattened version of an array. Handy for getting a
|
||||
list of <code>children</code> from the nodes.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">helpers.flatten: flatten: </span><span class="p">(</span><span class="nx">array</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nv">memo: </span><span class="p">[]</span>
|
||||
<span class="k">for</span> <span class="nx">item</span> <span class="k">in</span> <span class="nx">array</span>
|
||||
<span class="k">if</span> <span class="nx">item</span> <span class="k">instanceof</span> <span class="nb">Array</span> <span class="k">then</span> <span class="nv">memo: </span><span class="nx">memo</span><span class="p">.</span><span class="nx">concat</span><span class="p">(</span><span class="nx">item</span><span class="p">)</span> <span class="k">else</span> <span class="nx">memo</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="nx">item</span><span class="p">)</span>
|
||||
<span class="nx">memo</span></pre></div> </td> </tr> <tr id="section-10"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-10">#</a> </div> <p>Delete a key from an object, returning the value. Useful when a node is
|
||||
<span class="nx">memo</span></pre></div> </td> </tr> <tr id="section-11"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-11">#</a> </div> <p>Delete a key from an object, returning the value. Useful when a node is
|
||||
looking for a particular method in an options hash.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">helpers.del: del: </span><span class="p">(</span><span class="nx">obj</span><span class="p">,</span> <span class="nx">key</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nv">val: </span><span class="nx">obj</span><span class="p">[</span><span class="nx">key</span><span class="p">]</span>
|
||||
<span class="k">delete</span> <span class="nx">obj</span><span class="p">[</span><span class="nx">key</span><span class="p">]</span>
|
||||
<span class="nx">val</span></pre></div> </td> </tr> <tr id="section-11"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-11">#</a> </div> <p>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
|
||||
interpolations within strings, ad infinitum.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">helpers.balanced_string: balanced_string: </span><span class="p">(</span><span class="nx">str</span><span class="p">,</span> <span class="nx">delimited</span><span class="p">,</span> <span class="nx">options</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nv">options: </span><span class="o">or</span> <span class="p">{}</span>
|
||||
<span class="nv">slash: </span><span class="nx">delimited</span><span class="p">[</span><span class="mi">0</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="nv">levels: </span><span class="p">[]</span>
|
||||
<span class="nv">i: </span><span class="mi">0</span>
|
||||
<span class="k">while</span> <span class="nx">i</span> <span class="o"><</span> <span class="nx">str</span><span class="p">.</span><span class="nx">length</span>
|
||||
<span class="k">if</span> <span class="nx">levels</span><span class="p">.</span><span class="nx">length</span> <span class="o">and</span> <span class="nx">starts</span> <span class="nx">str</span><span class="p">,</span> <span class="s1">'\\'</span><span class="p">,</span> <span class="nx">i</span>
|
||||
<span class="nv">i: </span><span class="o">+</span> <span class="mi">1</span>
|
||||
<span class="k">else</span>
|
||||
<span class="k">for</span> <span class="nx">pair</span> <span class="k">in</span> <span class="nx">delimited</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="o">:</span> <span class="nx">pair</span>
|
||||
<span class="k">if</span> <span class="nx">levels</span><span class="p">.</span><span class="nx">length</span> <span class="o">and</span> <span class="nx">starts</span><span class="p">(</span><span class="nx">str</span><span class="p">,</span> <span class="nx">close</span><span class="p">,</span> <span class="nx">i</span><span class="p">)</span> <span class="o">and</span> <span class="nx">levels</span><span class="p">[</span><span class="nx">levels</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="nx">pair</span>
|
||||
<span class="nx">levels</span><span class="p">.</span><span class="nx">pop</span><span class="p">()</span>
|
||||
<span class="nv">i: </span><span class="o">+</span> <span class="nx">close</span><span class="p">.</span><span class="nx">length</span> <span class="o">-</span> <span class="mi">1</span>
|
||||
<span class="nv">i: </span><span class="o">+</span> <span class="mi">1</span> <span class="nx">unless</span> <span class="nx">levels</span><span class="p">.</span><span class="nx">length</span>
|
||||
<span class="k">break</span>
|
||||
<span class="k">else</span> <span class="k">if</span> <span class="nx">starts</span> <span class="nx">str</span><span class="p">,</span> <span class="nx">open</span><span class="p">,</span> <span class="nx">i</span>
|
||||
<span class="nx">levels</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="nx">pair</span><span class="p">)</span>
|
||||
<span class="nv">i: </span><span class="o">+</span> <span class="nx">open</span><span class="p">.</span><span class="nx">length</span> <span class="o">-</span> <span class="mi">1</span>
|
||||
<span class="k">break</span>
|
||||
<span class="k">break</span> <span class="k">if</span> <span class="o">not</span> <span class="nx">levels</span><span class="p">.</span><span class="nx">length</span> <span class="o">or</span> <span class="nx">slash</span> <span class="o">and</span> <span class="nx">starts</span> <span class="nx">str</span><span class="p">,</span> <span class="s1">'\n'</span><span class="p">,</span> <span class="nx">i</span>
|
||||
<span class="nv">i: </span><span class="o">+</span> <span class="mi">1</span>
|
||||
<span class="k">if</span> <span class="nx">levels</span><span class="p">.</span><span class="nx">length</span>
|
||||
<span class="k">return</span> <span class="kc">false</span> <span class="k">if</span> <span class="nx">slash</span>
|
||||
<span class="k">throw</span> <span class="k">new</span> <span class="nb">Error</span> <span class="s2">"SyntaxError: Unterminated ${levels.pop()[0]} starting on line ${@line + 1}"</span>
|
||||
<span class="k">if</span> <span class="o">not</span> <span class="nx">i</span> <span class="k">then</span> <span class="kc">false</span> <span class="k">else</span> <span class="nx">str</span><span class="p">.</span><span class="nx">substring</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="nx">i</span><span class="p">)</span>
|
||||
<span class="nx">val</span>
|
||||
|
||||
</pre></div> </td> </tr> </tbody> </table> </div> </body> </html>
|
||||
3
documentation/docs/index.html
Normal file
3
documentation/docs/index.html
Normal file
@@ -0,0 +1,3 @@
|
||||
<!DOCTYPE html> <html> <head> <title>index.coffee</title> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <link rel="stylesheet" media="all" href="docco.css" /> </head> <body> <div id="container"> <div id="background"></div> <div id="jump_to"> Jump To … <div id="jump_wrapper"> <div id="jump_page"> <a class="source" href="cake.html"> cake.coffee </a> <a class="source" href="coffee-script.html"> coffee-script.coffee </a> <a class="source" href="command.html"> command.coffee </a> <a class="source" href="grammar.html"> grammar.coffee </a> <a class="source" href="helpers.html"> helpers.coffee </a> <a class="source" href="index.html"> index.coffee </a> <a class="source" href="lexer.html"> lexer.coffee </a> <a class="source" href="nodes.html"> nodes.coffee </a> <a class="source" href="optparse.html"> optparse.coffee </a> <a class="source" href="repl.html"> repl.coffee </a> <a class="source" href="rewriter.html"> rewriter.coffee </a> <a class="source" href="scope.html"> scope.coffee </a> </div> </div> </div> <table cellpadding="0" cellspacing="0"> <thead> <tr> <th class="docs"> <h1> index.coffee </h1> </th> <th class="code"> </th> </tr> </thead> <tbody> <tr id="section-1"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-1">#</a> </div> <p>Loader for CoffeeScript as a Node.js library.</p> </td> <td class="code"> <div class="highlight"><pre><span class="p">(</span><span class="nx">exports</span><span class="p">[</span><span class="nx">key</span><span class="p">]</span><span class="o">:</span> <span class="nx">val</span><span class="p">)</span> <span class="k">for</span> <span class="nx">key</span><span class="p">,</span> <span class="nx">val</span> <span class="k">of</span> <span class="nx">require</span> <span class="s1">'./coffee-script'</span>
|
||||
|
||||
</pre></div> </td> </tr> </tbody> </table> </div> </body> </html>
|
||||
@@ -1,22 +1,18 @@
|
||||
<!DOCTYPE html> <html> <head> <title>lexer.coffee</title> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <link rel="stylesheet" media="all" href="docco.css" /> </head> <body> <div id="container"> <div id="background"></div> <div id="jump_to"> Jump To … <div id="jump_wrapper"> <div id="jump_page"> <a class="source" href="cake.html"> cake.coffee </a> <a class="source" href="coffee-script.html"> coffee-script.coffee </a> <a class="source" href="command.html"> command.coffee </a> <a class="source" href="grammar.html"> grammar.coffee </a> <a class="source" href="helpers.html"> helpers.coffee </a> <a class="source" href="lexer.html"> lexer.coffee </a> <a class="source" href="nodes.html"> nodes.coffee </a> <a class="source" href="optparse.html"> optparse.coffee </a> <a class="source" href="repl.html"> repl.coffee </a> <a class="source" href="rewriter.html"> rewriter.coffee </a> <a class="source" href="scope.html"> scope.coffee </a> </div> </div> </div> <table cellpadding="0" cellspacing="0"> <thead> <tr> <th class="docs"> <h1> lexer.coffee </h1> </th> <th class="code"> </th> </tr> </thead> <tbody> <tr id="section-1"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-1">#</a> </div> <p>The CoffeeScript Lexer. Uses a series of token-matching regexes to attempt
|
||||
<!DOCTYPE html> <html> <head> <title>lexer.coffee</title> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <link rel="stylesheet" media="all" href="docco.css" /> </head> <body> <div id="container"> <div id="background"></div> <div id="jump_to"> Jump To … <div id="jump_wrapper"> <div id="jump_page"> <a class="source" href="cake.html"> cake.coffee </a> <a class="source" href="coffee-script.html"> coffee-script.coffee </a> <a class="source" href="command.html"> command.coffee </a> <a class="source" href="grammar.html"> grammar.coffee </a> <a class="source" href="helpers.html"> helpers.coffee </a> <a class="source" href="index.html"> index.coffee </a> <a class="source" href="lexer.html"> lexer.coffee </a> <a class="source" href="nodes.html"> nodes.coffee </a> <a class="source" href="optparse.html"> optparse.coffee </a> <a class="source" href="repl.html"> repl.coffee </a> <a class="source" href="rewriter.html"> rewriter.coffee </a> <a class="source" href="scope.html"> scope.coffee </a> </div> </div> </div> <table cellpadding="0" cellspacing="0"> <thead> <tr> <th class="docs"> <h1> lexer.coffee </h1> </th> <th class="code"> </th> </tr> </thead> <tbody> <tr id="section-1"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-1">#</a> </div> <p>The CoffeeScript Lexer. Uses a series of token-matching regexes to attempt
|
||||
matches against the beginning of the source code. When a match is found,
|
||||
a token is produced, we consume the match, and start again. Tokens are in the
|
||||
form:</p>
|
||||
|
||||
<pre><code>[tag, value, line_number]
|
||||
<pre><code>[tag, value, lineNumber]
|
||||
</code></pre>
|
||||
|
||||
<p>Which is a format that can be fed directly into <a href="http://github.com/zaach/jison">Jison</a>.</p> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-2"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-2">#</a> </div> <p>Set up the Lexer for both Node.js and the browser, depending on where we are.</p> </td> <td class="code"> <div class="highlight"><pre><span class="k">if</span> <span class="nx">process</span><span class="o">?</span>
|
||||
<span class="nv">Rewriter: </span><span class="nx">require</span><span class="p">(</span><span class="s1">'./rewriter'</span><span class="p">).</span><span class="nx">Rewriter</span>
|
||||
<span class="nv">helpers: </span> <span class="nx">require</span><span class="p">(</span><span class="s1">'./helpers'</span><span class="p">).</span><span class="nx">helpers</span>
|
||||
<span class="p">{</span><span class="nx">Rewriter</span><span class="p">}</span><span class="o">:</span> <span class="nx">require</span><span class="p">(</span><span class="s1">'./rewriter'</span><span class="p">)</span>
|
||||
<span class="p">{</span><span class="nx">helpers</span><span class="p">}</span><span class="o">:</span> <span class="nx">require</span><span class="p">(</span><span class="s1">'./helpers'</span><span class="p">)</span>
|
||||
<span class="k">else</span>
|
||||
<span class="k">this</span><span class="p">.</span><span class="nv">exports: </span><span class="k">this</span>
|
||||
<span class="nv">Rewriter: </span> <span class="k">this</span><span class="p">.</span><span class="nx">Rewriter</span>
|
||||
<span class="nv">helpers: </span> <span class="k">this</span><span class="p">.</span><span class="nx">helpers</span></pre></div> </td> </tr> <tr id="section-3"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-3">#</a> </div> <p>Import the helpers we need.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">include: </span> <span class="nx">helpers</span><span class="p">.</span><span class="nx">include</span>
|
||||
<span class="nv">count: </span> <span class="nx">helpers</span><span class="p">.</span><span class="nx">count</span>
|
||||
<span class="nv">starts: </span> <span class="nx">helpers</span><span class="p">.</span><span class="nx">starts</span>
|
||||
<span class="nv">compact: </span> <span class="nx">helpers</span><span class="p">.</span><span class="nx">compact</span>
|
||||
<span class="nv">balanced_string: </span> <span class="nx">helpers</span><span class="p">.</span><span class="nx">balanced_string</span></pre></div> </td> </tr> <tr id="section-4"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-4">#</a> </div> <h2>The Lexer Class</h2> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-5"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-5">#</a> </div> <p>The Lexer class reads a stream of CoffeeScript and divvys it up into tagged
|
||||
<span class="nv">helpers: </span> <span class="k">this</span><span class="p">.</span><span class="nx">helpers</span></pre></div> </td> </tr> <tr id="section-3"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-3">#</a> </div> <p>Import the helpers we need.</p> </td> <td class="code"> <div class="highlight"><pre><span class="p">{</span><span class="nx">include</span><span class="p">,</span> <span class="nx">count</span><span class="p">,</span> <span class="nx">starts</span><span class="p">,</span> <span class="nx">compact</span><span class="p">}</span><span class="o">:</span> <span class="nx">helpers</span></pre></div> </td> </tr> <tr id="section-4"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-4">#</a> </div> <h2>The Lexer Class</h2> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-5"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-5">#</a> </div> <p>The Lexer class reads a stream of CoffeeScript and divvys it up into tagged
|
||||
tokens. Some potential ambiguity in the grammar has been avoided by
|
||||
pushing some extra smarts into the Lexer.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.Lexer: </span><span class="nx">class</span> <span class="nx">Lexer</span></pre></div> </td> </tr> <tr id="section-6"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-6">#</a> </div> <p><strong>tokenize</strong> is the Lexer's main method. Scan by attempting to match tokens
|
||||
one at a time, using a regular expression anchored at the start of the
|
||||
@@ -36,104 +32,110 @@ unless explicitly asked not to.</p> </td> <td class="cod
|
||||
<span class="vi">@i : </span><span class="mi">0</span> <span class="c1"># Current character position we're parsing.</span>
|
||||
<span class="vi">@line : </span><span class="nx">o</span><span class="p">.</span><span class="nx">line</span> <span class="o">or</span> <span class="mi">0</span> <span class="c1"># The current line.</span>
|
||||
<span class="vi">@indent : </span><span class="mi">0</span> <span class="c1"># The current indentation level.</span>
|
||||
<span class="vi">@outdebt : </span><span class="mi">0</span> <span class="c1"># The under-outdentation of the last outdent.</span>
|
||||
<span class="vi">@indents : </span><span class="p">[]</span> <span class="c1"># The stack of all current indentation levels.</span>
|
||||
<span class="vi">@tokens : </span><span class="p">[]</span> <span class="c1"># Stream of parsed tokens in the form ['TYPE', value, line]</span>
|
||||
<span class="k">while</span> <span class="nx">@i</span> <span class="o"><</span> <span class="nx">@code</span><span class="p">.</span><span class="nx">length</span>
|
||||
<span class="vi">@chunk: </span><span class="nx">@code</span><span class="p">.</span><span class="nx">slice</span> <span class="nx">@i</span>
|
||||
<span class="nx">@extract_next_token</span><span class="p">()</span>
|
||||
<span class="nx">@close_indentation</span><span class="p">()</span>
|
||||
<span class="nx">@extractNextToken</span><span class="p">()</span>
|
||||
<span class="nx">@closeIndentation</span><span class="p">()</span>
|
||||
<span class="k">return</span> <span class="nx">@tokens</span> <span class="k">if</span> <span class="nx">o</span><span class="p">.</span><span class="nx">rewrite</span> <span class="o">is</span> <span class="kc">off</span>
|
||||
<span class="p">(</span><span class="k">new</span> <span class="nx">Rewriter</span><span class="p">()).</span><span class="nx">rewrite</span> <span class="nx">@tokens</span></pre></div> </td> </tr> <tr id="section-7"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-7">#</a> </div> <p>At every position, run through this list of attempted matches,
|
||||
<span class="p">(</span><span class="k">new</span> <span class="nx">Rewriter</span><span class="p">).</span><span class="nx">rewrite</span> <span class="nx">@tokens</span></pre></div> </td> </tr> <tr id="section-7"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-7">#</a> </div> <p>At every position, run through this list of attempted matches,
|
||||
short-circuiting if any of them succeed. Their order determines precedence:
|
||||
<code>@literal_token</code> is the fallback catch-all.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">extract_next_token: </span><span class="o">-></span>
|
||||
<span class="k">return</span> <span class="k">if</span> <span class="nx">@extension_token</span><span class="p">()</span>
|
||||
<span class="k">return</span> <span class="k">if</span> <span class="nx">@identifier_token</span><span class="p">()</span>
|
||||
<span class="k">return</span> <span class="k">if</span> <span class="nx">@number_token</span><span class="p">()</span>
|
||||
<span class="k">return</span> <span class="k">if</span> <span class="nx">@heredoc_token</span><span class="p">()</span>
|
||||
<span class="k">return</span> <span class="k">if</span> <span class="nx">@regex_token</span><span class="p">()</span>
|
||||
<span class="k">return</span> <span class="k">if</span> <span class="nx">@comment_token</span><span class="p">()</span>
|
||||
<span class="k">return</span> <span class="k">if</span> <span class="nx">@line_token</span><span class="p">()</span>
|
||||
<span class="k">return</span> <span class="k">if</span> <span class="nx">@whitespace_token</span><span class="p">()</span>
|
||||
<span class="k">return</span> <span class="k">if</span> <span class="nx">@js_token</span><span class="p">()</span>
|
||||
<span class="k">return</span> <span class="k">if</span> <span class="nx">@string_token</span><span class="p">()</span>
|
||||
<span class="k">return</span> <span class="nx">@literal_token</span><span class="p">()</span></pre></div> </td> </tr> <tr id="section-8"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-8">#</a> </div> <h2>Tokenizers</h2> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-9"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-9">#</a> </div> <p>Language extensions get the highest priority, first chance to tag tokens
|
||||
as something else.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">extension_token: </span><span class="o">-></span>
|
||||
<span class="k">for</span> <span class="nx">extension</span> <span class="k">in</span> <span class="nx">Lexer</span><span class="p">.</span><span class="nx">extensions</span>
|
||||
<span class="k">return</span> <span class="kc">true</span> <span class="k">if</span> <span class="nx">extension</span><span class="p">.</span><span class="nx">call</span> <span class="k">this</span>
|
||||
<span class="kc">false</span></pre></div> </td> </tr> <tr id="section-10"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-10">#</a> </div> <p>Matches identifying literals: variables, keywords, method names, etc.
|
||||
<code>@literalToken</code> is the fallback catch-all.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">extractNextToken: </span><span class="o">-></span>
|
||||
<span class="k">return</span> <span class="k">if</span> <span class="nx">@identifierToken</span><span class="p">()</span>
|
||||
<span class="k">return</span> <span class="k">if</span> <span class="nx">@commentToken</span><span class="p">()</span>
|
||||
<span class="k">return</span> <span class="k">if</span> <span class="nx">@whitespaceToken</span><span class="p">()</span>
|
||||
<span class="k">return</span> <span class="k">if</span> <span class="nx">@lineToken</span><span class="p">()</span>
|
||||
<span class="k">return</span> <span class="k">if</span> <span class="nx">@heredocToken</span><span class="p">()</span>
|
||||
<span class="k">return</span> <span class="k">if</span> <span class="nx">@stringToken</span><span class="p">()</span>
|
||||
<span class="k">return</span> <span class="k">if</span> <span class="nx">@numberToken</span><span class="p">()</span>
|
||||
<span class="k">return</span> <span class="k">if</span> <span class="nx">@regexToken</span><span class="p">()</span>
|
||||
<span class="k">return</span> <span class="k">if</span> <span class="nx">@jsToken</span><span class="p">()</span>
|
||||
<span class="k">return</span> <span class="nx">@literalToken</span><span class="p">()</span></pre></div> </td> </tr> <tr id="section-8"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-8">#</a> </div> <h2>Tokenizers</h2> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-9"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-9">#</a> </div> <p>Matches identifying literals: variables, keywords, method names, etc.
|
||||
Check to ensure that JavaScript reserved words aren't being used as
|
||||
identifiers. Because CoffeeScript reserves a handful of keywords that are
|
||||
allowed in JavaScript, we're careful not to tag them as keywords when
|
||||
referenced as property names here, so you can still do <code>jQuery.is()</code> even
|
||||
though <code>is</code> means <code>===</code> otherwise.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">identifier_token: </span><span class="o">-></span>
|
||||
though <code>is</code> means <code>===</code> otherwise.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">identifierToken: </span><span class="o">-></span>
|
||||
<span class="k">return</span> <span class="kc">false</span> <span class="nx">unless</span> <span class="nv">id: </span><span class="nx">@match</span> <span class="nx">IDENTIFIER</span><span class="p">,</span> <span class="mi">1</span>
|
||||
<span class="nx">@name_access_type</span><span class="p">()</span>
|
||||
<span class="nv">accessed: </span><span class="nx">include</span> <span class="nx">ACCESSORS</span><span class="p">,</span> <span class="nx">@tag</span> <span class="mi">0</span>
|
||||
<span class="nv">tag: </span><span class="s1">'IDENTIFIER'</span>
|
||||
<span class="nv">tag: </span><span class="nx">id</span><span class="p">.</span><span class="nx">toUpperCase</span><span class="p">()</span> <span class="k">if</span> <span class="o">not</span> <span class="nx">accessed</span> <span class="o">and</span> <span class="nx">include</span><span class="p">(</span><span class="nx">KEYWORDS</span><span class="p">,</span> <span class="nx">id</span><span class="p">)</span>
|
||||
<span class="nx">@identifier_error</span> <span class="nx">id</span> <span class="k">if</span> <span class="nx">include</span> <span class="nx">RESERVED</span><span class="p">,</span> <span class="nx">id</span>
|
||||
<span class="nv">tag: </span><span class="s1">'LEADING_WHEN'</span> <span class="k">if</span> <span class="nx">tag</span> <span class="o">is</span> <span class="s1">'WHEN'</span> <span class="o">and</span> <span class="nx">include</span> <span class="nx">LINE_BREAK</span><span class="p">,</span> <span class="nx">@tag</span><span class="p">()</span>
|
||||
<span class="vi">@i: </span><span class="o">+</span> <span class="nx">id</span><span class="p">.</span><span class="nx">length</span>
|
||||
<span class="k">if</span> <span class="o">not</span> <span class="nx">accessed</span>
|
||||
<span class="nv">tag: id: </span><span class="nx">CONVERSIONS</span><span class="p">[</span><span class="nx">id</span><span class="p">]</span> <span class="k">if</span> <span class="nx">include</span> <span class="nx">COFFEE_ALIASES</span><span class="p">,</span> <span class="nx">id</span>
|
||||
<span class="k">return</span> <span class="nx">@tag_half_assignment</span> <span class="nx">tag</span> <span class="k">if</span> <span class="nx">@prev</span><span class="p">()</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="o">is</span> <span class="s1">'ASSIGN'</span> <span class="o">and</span> <span class="nx">include</span> <span class="nx">HALF_ASSIGNMENTS</span><span class="p">,</span> <span class="nx">tag</span>
|
||||
<span class="nv">forcedIdentifier: </span><span class="nx">@tagAccessor</span><span class="p">()</span> <span class="o">or</span> <span class="nx">@match</span> <span class="nx">ASSIGNED</span><span class="p">,</span> <span class="mi">1</span>
|
||||
<span class="nv">tag: </span><span class="s1">'IDENTIFIER'</span>
|
||||
<span class="nv">tag: </span><span class="nx">id</span><span class="p">.</span><span class="nx">toUpperCase</span><span class="p">()</span> <span class="k">if</span> <span class="nx">include</span><span class="p">(</span><span class="nx">JS_KEYWORDS</span><span class="p">,</span> <span class="nx">id</span><span class="p">)</span> <span class="o">or</span> <span class="p">(</span><span class="o">not</span> <span class="nx">forcedIdentifier</span> <span class="o">and</span> <span class="nx">include</span><span class="p">(</span><span class="nx">COFFEE_KEYWORDS</span><span class="p">,</span> <span class="nx">id</span><span class="p">))</span>
|
||||
<span class="nv">tag: </span><span class="s1">'LEADING_WHEN'</span> <span class="k">if</span> <span class="nx">tag</span> <span class="o">is</span> <span class="s1">'WHEN'</span> <span class="o">and</span> <span class="nx">include</span> <span class="nx">LINE_BREAK</span><span class="p">,</span> <span class="nx">@tag</span><span class="p">()</span>
|
||||
<span class="k">if</span> <span class="nx">include</span><span class="p">(</span><span class="nx">JS_FORBIDDEN</span><span class="p">,</span> <span class="nx">id</span><span class="p">)</span>
|
||||
<span class="k">if</span> <span class="nx">forcedIdentifier</span>
|
||||
<span class="nv">tag: </span><span class="s1">'STRING'</span>
|
||||
<span class="nv">id: </span> <span class="s2">"'$id'"</span>
|
||||
<span class="k">if</span> <span class="nx">forcedIdentifier</span> <span class="o">is</span> <span class="s1">'accessor'</span>
|
||||
<span class="nv">close_index: </span><span class="kc">true</span>
|
||||
<span class="nx">@tokens</span><span class="p">.</span><span class="nx">pop</span><span class="p">()</span> <span class="k">if</span> <span class="nx">@tag</span><span class="p">()</span> <span class="o">isnt</span> <span class="s1">'@'</span>
|
||||
<span class="nx">@token</span> <span class="s1">'INDEX_START'</span><span class="p">,</span> <span class="s1">'['</span>
|
||||
<span class="k">else</span> <span class="k">if</span> <span class="nx">include</span><span class="p">(</span><span class="nx">RESERVED</span><span class="p">,</span> <span class="nx">id</span><span class="p">)</span>
|
||||
<span class="nx">@identifierError</span> <span class="nx">id</span>
|
||||
<span class="nx">unless</span> <span class="nx">forcedIdentifier</span>
|
||||
<span class="nv">tag: id: </span><span class="nx">CONVERSIONS</span><span class="p">[</span><span class="nx">id</span><span class="p">]</span> <span class="k">if</span> <span class="nx">include</span> <span class="nx">COFFEE_ALIASES</span><span class="p">,</span> <span class="nx">id</span>
|
||||
<span class="k">return</span> <span class="nx">@tagHalfAssignment</span> <span class="nx">tag</span> <span class="k">if</span> <span class="nx">@prev</span><span class="p">()</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="o">is</span> <span class="s1">'ASSIGN'</span> <span class="o">and</span> <span class="nx">include</span> <span class="nx">HALF_ASSIGNMENTS</span><span class="p">,</span> <span class="nx">tag</span>
|
||||
<span class="nx">@token</span> <span class="nx">tag</span><span class="p">,</span> <span class="nx">id</span>
|
||||
<span class="kc">true</span></pre></div> </td> </tr> <tr id="section-11"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-11">#</a> </div> <p>Matches numbers, including decimals, hex, and exponential notation.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">number_token: </span><span class="o">-></span>
|
||||
<span class="nx">@token</span> <span class="s1">']'</span><span class="p">,</span> <span class="s1">']'</span> <span class="k">if</span> <span class="nx">close_index</span>
|
||||
<span class="kc">true</span></pre></div> </td> </tr> <tr id="section-10"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-10">#</a> </div> <p>Matches numbers, including decimals, hex, and exponential notation.
|
||||
Be careful not to interfere with ranges-in-progress.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">numberToken: </span><span class="o">-></span>
|
||||
<span class="k">return</span> <span class="kc">false</span> <span class="nx">unless</span> <span class="nv">number: </span><span class="nx">@match</span> <span class="nx">NUMBER</span><span class="p">,</span> <span class="mi">1</span>
|
||||
<span class="nx">@token</span> <span class="s1">'NUMBER'</span><span class="p">,</span> <span class="nx">number</span>
|
||||
<span class="k">return</span> <span class="kc">false</span> <span class="k">if</span> <span class="nx">@tag</span><span class="p">()</span> <span class="o">is</span> <span class="s1">'.'</span> <span class="o">and</span> <span class="nx">starts</span> <span class="nx">number</span><span class="p">,</span> <span class="s1">'.'</span>
|
||||
<span class="vi">@i: </span><span class="o">+</span> <span class="nx">number</span><span class="p">.</span><span class="nx">length</span>
|
||||
<span class="kc">true</span></pre></div> </td> </tr> <tr id="section-12"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-12">#</a> </div> <p>Matches strings, including multi-line strings. Ensures that quotation marks
|
||||
are balanced within the string's contents, and within nested interpolations.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">string_token: </span><span class="o">-></span>
|
||||
<span class="nx">@token</span> <span class="s1">'NUMBER'</span><span class="p">,</span> <span class="nx">number</span>
|
||||
<span class="kc">true</span></pre></div> </td> </tr> <tr id="section-11"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-11">#</a> </div> <p>Matches strings, including multi-line strings. Ensures that quotation marks
|
||||
are balanced within the string's contents, and within nested interpolations.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">stringToken: </span><span class="o">-></span>
|
||||
<span class="k">return</span> <span class="kc">false</span> <span class="nx">unless</span> <span class="nx">starts</span><span class="p">(</span><span class="nx">@chunk</span><span class="p">,</span> <span class="s1">'"'</span><span class="p">)</span> <span class="o">or</span> <span class="nx">starts</span><span class="p">(</span><span class="nx">@chunk</span><span class="p">,</span> <span class="s2">"'"</span><span class="p">)</span>
|
||||
<span class="k">return</span> <span class="kc">false</span> <span class="nx">unless</span> <span class="nv">string:</span>
|
||||
<span class="nx">@balanced_token</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="o">or</span>
|
||||
<span class="nx">@balanced_token</span> <span class="p">[</span><span class="s2">"'"</span><span class="p">,</span> <span class="s2">"'"</span><span class="p">]</span>
|
||||
<span class="nx">@interpolate_string</span> <span class="nx">string</span><span class="p">.</span><span class="nx">replace</span> <span class="nx">STRING_NEWLINES</span><span class="p">,</span> <span class="s2">" \\\n"</span>
|
||||
<span class="nx">@balancedToken</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="o">or</span>
|
||||
<span class="nx">@balancedToken</span> <span class="p">[</span><span class="s2">"'"</span><span class="p">,</span> <span class="s2">"'"</span><span class="p">]</span>
|
||||
<span class="nx">@interpolateString</span> <span class="nx">string</span><span class="p">.</span><span class="nx">replace</span> <span class="nx">STRING_NEWLINES</span><span class="p">,</span> <span class="s2">" \\\n"</span>
|
||||
<span class="vi">@line: </span><span class="o">+</span> <span class="nx">count</span> <span class="nx">string</span><span class="p">,</span> <span class="s2">"\n"</span>
|
||||
<span class="vi">@i: </span><span class="o">+</span> <span class="nx">string</span><span class="p">.</span><span class="nx">length</span>
|
||||
<span class="kc">true</span></pre></div> </td> </tr> <tr id="section-13"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-13">#</a> </div> <p>Matches heredocs, adjusting indentation to the correct level, as heredocs
|
||||
preserve whitespace, but ignore indentation to the left.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">heredoc_token: </span><span class="o">-></span>
|
||||
<span class="kc">true</span></pre></div> </td> </tr> <tr id="section-12"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-12">#</a> </div> <p>Matches heredocs, adjusting indentation to the correct level, as heredocs
|
||||
preserve whitespace, but ignore indentation to the left.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">heredocToken: </span><span class="o">-></span>
|
||||
<span class="k">return</span> <span class="kc">false</span> <span class="nx">unless</span> <span class="nv">match: </span><span class="nx">@chunk</span><span class="p">.</span><span class="nx">match</span><span class="p">(</span><span class="nx">HEREDOC</span><span class="p">)</span>
|
||||
<span class="nv">quote: </span><span class="nx">match</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="nx">substr</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span>
|
||||
<span class="nv">doc: </span><span class="nx">@sanitize_heredoc</span> <span class="nx">match</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="o">or</span> <span class="nx">match</span><span class="p">[</span><span class="mi">4</span><span class="p">],</span> <span class="nx">quote</span>
|
||||
<span class="nx">@interpolate_string</span> <span class="s2">"$quote$doc$quote"</span>
|
||||
<span class="nv">doc: </span><span class="nx">@sanitizeHeredoc</span> <span class="nx">match</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="o">or</span> <span class="nx">match</span><span class="p">[</span><span class="mi">4</span><span class="p">],</span> <span class="p">{</span><span class="nx">quote</span><span class="p">}</span>
|
||||
<span class="nx">@interpolateString</span> <span class="s2">"$quote$doc$quote"</span>
|
||||
<span class="vi">@line: </span><span class="o">+</span> <span class="nx">count</span> <span class="nx">match</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="s2">"\n"</span>
|
||||
<span class="vi">@i: </span><span class="o">+</span> <span class="nx">match</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="nx">length</span>
|
||||
<span class="kc">true</span></pre></div> </td> </tr> <tr id="section-14"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-14">#</a> </div> <p>Matches JavaScript interpolated directly into the source via backticks.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">js_token: </span><span class="o">-></span>
|
||||
<span class="kc">true</span></pre></div> </td> </tr> <tr id="section-13"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-13">#</a> </div> <p>Matches and conumes comments.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">commentToken: </span><span class="o">-></span>
|
||||
<span class="k">return</span> <span class="kc">false</span> <span class="nx">unless</span> <span class="nv">match: </span><span class="nx">@chunk</span><span class="p">.</span><span class="nx">match</span><span class="p">(</span><span class="nx">COMMENT</span><span class="p">)</span>
|
||||
<span class="vi">@line: </span><span class="o">+</span> <span class="nx">count</span> <span class="nx">match</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="s2">"\n"</span>
|
||||
<span class="vi">@i: </span><span class="o">+</span> <span class="nx">match</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="nx">length</span>
|
||||
<span class="k">if</span> <span class="nx">match</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span>
|
||||
<span class="nv">comment: </span><span class="nx">@sanitizeHeredoc</span> <span class="nx">match</span><span class="p">[</span><span class="mi">2</span><span class="p">],</span> <span class="p">{</span><span class="nv">herecomment: </span><span class="kc">true</span><span class="p">}</span>
|
||||
<span class="nx">@token</span> <span class="s1">'HERECOMMENT'</span><span class="p">,</span> <span class="nx">comment</span><span class="p">.</span><span class="nx">split</span> <span class="nx">MULTILINER</span>
|
||||
<span class="nx">@token</span> <span class="s1">'TERMINATOR'</span><span class="p">,</span> <span class="s1">'\n'</span>
|
||||
<span class="kc">true</span></pre></div> </td> </tr> <tr id="section-14"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-14">#</a> </div> <p>Matches JavaScript interpolated directly into the source via backticks.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">jsToken: </span><span class="o">-></span>
|
||||
<span class="k">return</span> <span class="kc">false</span> <span class="nx">unless</span> <span class="nx">starts</span> <span class="nx">@chunk</span><span class="p">,</span> <span class="s1">'`'</span>
|
||||
<span class="k">return</span> <span class="kc">false</span> <span class="nx">unless</span> <span class="nv">script: </span><span class="nx">@balanced_token</span> <span class="p">[</span><span class="s1">'`'</span><span class="p">,</span> <span class="s1">'`'</span><span class="p">]</span>
|
||||
<span class="k">return</span> <span class="kc">false</span> <span class="nx">unless</span> <span class="nv">script: </span><span class="nx">@balancedToken</span> <span class="p">[</span><span class="s1">'`'</span><span class="p">,</span> <span class="s1">'`'</span><span class="p">]</span>
|
||||
<span class="nx">@token</span> <span class="s1">'JS'</span><span class="p">,</span> <span class="nx">script</span><span class="p">.</span><span class="nx">replace</span> <span class="nx">JS_CLEANER</span><span class="p">,</span> <span class="s1">''</span>
|
||||
<span class="vi">@i: </span><span class="o">+</span> <span class="nx">script</span><span class="p">.</span><span class="nx">length</span>
|
||||
<span class="kc">true</span></pre></div> </td> </tr> <tr id="section-15"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-15">#</a> </div> <p>Matches regular expression literals. Lexing regular expressions is difficult
|
||||
to distinguish from division, so we borrow some basic heuristics from
|
||||
JavaScript and Ruby, borrow slash balancing from <code>@balanced_token</code>, and
|
||||
borrow interpolation from <code>@interpolate_string</code>.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">regex_token: </span><span class="o">-></span>
|
||||
JavaScript and Ruby, borrow slash balancing from <code>@balancedToken</code>, and
|
||||
borrow interpolation from <code>@interpolateString</code>.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">regexToken: </span><span class="o">-></span>
|
||||
<span class="k">return</span> <span class="kc">false</span> <span class="nx">unless</span> <span class="nx">@chunk</span><span class="p">.</span><span class="nx">match</span> <span class="nx">REGEX_START</span>
|
||||
<span class="k">return</span> <span class="kc">false</span> <span class="k">if</span> <span class="nx">include</span> <span class="nx">NOT_REGEX</span><span class="p">,</span> <span class="nx">@tag</span><span class="p">()</span>
|
||||
<span class="k">return</span> <span class="kc">false</span> <span class="nx">unless</span> <span class="nv">regex: </span><span class="nx">@balanced_token</span> <span class="p">[</span><span class="s1">'/'</span><span class="p">,</span> <span class="s1">'/'</span><span class="p">]</span>
|
||||
<span class="nv">regex: </span><span class="o">+</span> <span class="p">(</span><span class="nv">flags: </span><span class="nx">@chunk</span><span class="p">.</span><span class="nx">substr</span><span class="p">(</span><span class="nx">regex</span><span class="p">.</span><span class="nx">length</span><span class="p">).</span><span class="nx">match</span> <span class="nx">REGEX_FLAGS</span><span class="p">)</span>
|
||||
<span class="k">return</span> <span class="kc">false</span> <span class="nx">unless</span> <span class="nv">regex: </span><span class="nx">@balancedToken</span> <span class="p">[</span><span class="s1">'/'</span><span class="p">,</span> <span class="s1">'/'</span><span class="p">]</span>
|
||||
<span class="k">return</span> <span class="kc">false</span> <span class="nx">unless</span> <span class="nv">end: </span><span class="nx">@chunk</span><span class="p">.</span><span class="nx">substr</span><span class="p">(</span><span class="nx">regex</span><span class="p">.</span><span class="nx">length</span><span class="p">).</span><span class="nx">match</span> <span class="nx">REGEX_END</span>
|
||||
<span class="nv">regex: </span><span class="o">+</span> <span class="nv">flags: </span><span class="nx">end</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="k">if</span> <span class="nx">end</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span>
|
||||
<span class="k">if</span> <span class="nx">regex</span><span class="p">.</span><span class="nx">match</span> <span class="nx">REGEX_INTERPOLATION</span>
|
||||
<span class="nv">str: </span><span class="nx">regex</span><span class="p">.</span><span class="nx">substring</span><span class="p">(</span><span class="mi">1</span><span class="p">).</span><span class="nx">split</span><span class="p">(</span><span class="s1">'/'</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span>
|
||||
<span class="nv">str: </span><span class="nx">str</span><span class="p">.</span><span class="nx">replace</span> <span class="nx">REGEX_ESCAPE</span><span class="p">,</span> <span class="p">(</span><span class="nx">escaped</span><span class="p">)</span> <span class="o">-></span> <span class="s1">'\\'</span> <span class="o">+</span> <span class="nx">escaped</span>
|
||||
<span class="vi">@tokens: </span><span class="nx">@tokens</span><span class="p">.</span><span class="nx">concat</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">'NEW'</span><span class="p">,</span> <span class="s1">'new'</span><span class="p">],</span> <span class="p">[</span><span class="s1">'IDENTIFIER'</span><span class="p">,</span> <span class="s1">'RegExp'</span><span class="p">],</span> <span class="p">[</span><span class="s1">'CALL_START'</span><span class="p">,</span> <span class="s1">'('</span><span class="p">]]</span>
|
||||
<span class="nx">@interpolate_string</span> <span class="s2">"\"$str\""</span><span class="p">,</span> <span class="kc">yes</span>
|
||||
<span class="nx">@interpolateString</span> <span class="s2">"\"$str\""</span><span class="p">,</span> <span class="kc">yes</span>
|
||||
<span class="vi">@tokens: </span><span class="nx">@tokens</span><span class="p">.</span><span class="nx">concat</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">'STRING'</span><span class="p">,</span> <span class="s2">"\"$flags\""</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="k">else</span>
|
||||
<span class="nx">@token</span> <span class="s1">'REGEX'</span><span class="p">,</span> <span class="nx">regex</span>
|
||||
<span class="vi">@i: </span><span class="o">+</span> <span class="nx">regex</span><span class="p">.</span><span class="nx">length</span>
|
||||
<span class="kc">true</span></pre></div> </td> </tr> <tr id="section-16"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-16">#</a> </div> <p>Matches a token in which which the passed delimiter pairs must be correctly
|
||||
balanced (ie. strings, JS literals).</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">balanced_token: </span><span class="p">(</span><span class="nx">delimited</span><span class="p">...)</span> <span class="o">-></span>
|
||||
<span class="nx">balanced_string</span> <span class="nx">@chunk</span><span class="p">,</span> <span class="nx">delimited</span></pre></div> </td> </tr> <tr id="section-17"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-17">#</a> </div> <p>Matches and conumes comments. We pass through comments into JavaScript,
|
||||
so they're treated as real tokens, like any other part of the language.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">comment_token: </span><span class="o">-></span>
|
||||
<span class="k">return</span> <span class="kc">false</span> <span class="nx">unless</span> <span class="nv">comment: </span><span class="nx">@match</span> <span class="nx">COMMENT</span><span class="p">,</span> <span class="mi">1</span>
|
||||
<span class="vi">@line: </span><span class="o">+</span> <span class="p">(</span><span class="nx">comment</span><span class="p">.</span><span class="nx">match</span><span class="p">(</span><span class="nx">MULTILINER</span><span class="p">)</span> <span class="o">or</span> <span class="p">[]).</span><span class="nx">length</span>
|
||||
<span class="nv">lines: </span><span class="nx">compact</span> <span class="nx">comment</span><span class="p">.</span><span class="nx">replace</span><span class="p">(</span><span class="nx">COMMENT_CLEANER</span><span class="p">,</span> <span class="s1">''</span><span class="p">).</span><span class="nx">split</span> <span class="nx">MULTILINER</span>
|
||||
<span class="nv">i: </span><span class="nx">@tokens</span><span class="p">.</span><span class="nx">length</span> <span class="o">-</span> <span class="mi">1</span>
|
||||
<span class="k">if</span> <span class="nx">@unfinished</span><span class="p">()</span>
|
||||
<span class="nv">i: </span><span class="o">-</span> <span class="mi">1</span> <span class="k">while</span> <span class="nx">@tokens</span><span class="p">[</span><span class="nx">i</span><span class="p">]</span> <span class="o">and</span> <span class="o">not</span> <span class="nx">include</span> <span class="nx">LINE_BREAK</span><span class="p">,</span> <span class="nx">@tokens</span><span class="p">[</span><span class="nx">i</span><span class="p">][</span><span class="mi">0</span><span class="p">]</span>
|
||||
<span class="nx">@tokens</span><span class="p">.</span><span class="nx">splice</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="mi">0</span><span class="p">,</span> <span class="p">[</span><span class="s1">'COMMENT'</span><span class="p">,</span> <span class="nx">lines</span><span class="p">,</span> <span class="nx">@line</span><span class="p">],</span> <span class="p">[</span><span class="s1">'TERMINATOR'</span><span class="p">,</span> <span class="s1">'\n'</span><span class="p">,</span> <span class="nx">@line</span><span class="p">])</span>
|
||||
<span class="vi">@i: </span><span class="o">+</span> <span class="nx">comment</span><span class="p">.</span><span class="nx">length</span>
|
||||
<span class="kc">true</span></pre></div> </td> </tr> <tr id="section-18"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-18">#</a> </div> <p>Matches newlines, indents, and outdents, and determines which is which.
|
||||
balanced (ie. strings, JS literals).</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">balancedToken: </span><span class="p">(</span><span class="nx">delimited</span><span class="p">...)</span> <span class="o">-></span>
|
||||
<span class="nx">@balancedString</span> <span class="nx">@chunk</span><span class="p">,</span> <span class="nx">delimited</span></pre></div> </td> </tr> <tr id="section-17"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-17">#</a> </div> <p>Matches newlines, indents, and outdents, and determines which is which.
|
||||
If we can detect that the current line is continued onto the the next line,
|
||||
then the newline is suppressed:</p>
|
||||
|
||||
@@ -143,108 +145,149 @@ then the newline is suppressed:</p>
|
||||
</code></pre>
|
||||
|
||||
<p>Keeps track of the level of indentation, because a single outdent token
|
||||
can close multiple indents, so we need to know how far in we happen to be.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">line_token: </span><span class="o">-></span>
|
||||
can close multiple indents, so we need to know how far in we happen to be.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">lineToken: </span><span class="o">-></span>
|
||||
<span class="k">return</span> <span class="kc">false</span> <span class="nx">unless</span> <span class="nv">indent: </span><span class="nx">@match</span> <span class="nx">MULTI_DENT</span><span class="p">,</span> <span class="mi">1</span>
|
||||
<span class="vi">@line: </span><span class="o">+</span> <span class="nx">indent</span><span class="p">.</span><span class="nx">match</span><span class="p">(</span><span class="nx">MULTILINER</span><span class="p">).</span><span class="nx">length</span>
|
||||
<span class="vi">@line: </span><span class="o">+</span> <span class="nx">count</span> <span class="nx">indent</span><span class="p">,</span> <span class="s2">"\n"</span>
|
||||
<span class="vi">@i : </span><span class="o">+</span> <span class="nx">indent</span><span class="p">.</span><span class="nx">length</span>
|
||||
<span class="nv">prev: </span><span class="nx">@prev</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span>
|
||||
<span class="nv">size: </span><span class="nx">indent</span><span class="p">.</span><span class="nx">match</span><span class="p">(</span><span class="nx">LAST_DENTS</span><span class="p">).</span><span class="nx">reverse</span><span class="p">()[</span><span class="mi">0</span><span class="p">].</span><span class="nx">match</span><span class="p">(</span><span class="nx">LAST_DENT</span><span class="p">)[</span><span class="mi">1</span><span class="p">].</span><span class="nx">length</span>
|
||||
<span class="nv">next_character: </span><span class="nx">@chunk</span><span class="p">.</span><span class="nx">match</span><span class="p">(</span><span class="nx">MULTI_DENT</span><span class="p">)[</span><span class="mi">4</span><span class="p">]</span>
|
||||
<span class="nv">no_newlines: </span><span class="nx">next_character</span> <span class="o">is</span> <span class="s1">'.'</span> <span class="o">or</span> <span class="nx">@unfinished</span><span class="p">()</span>
|
||||
<span class="nv">nextCharacter: </span><span class="nx">@match</span> <span class="nx">NEXT_CHARACTER</span><span class="p">,</span> <span class="mi">1</span>
|
||||
<span class="nv">noNewlines: </span><span class="nx">nextCharacter</span> <span class="o">is</span> <span class="s1">'.'</span> <span class="o">or</span> <span class="nx">nextCharacter</span> <span class="o">is</span> <span class="s1">','</span> <span class="o">or</span> <span class="nx">@unfinished</span><span class="p">()</span>
|
||||
<span class="k">if</span> <span class="nx">size</span> <span class="o">is</span> <span class="nx">@indent</span>
|
||||
<span class="k">return</span> <span class="nx">@suppress_newlines</span><span class="p">()</span> <span class="k">if</span> <span class="nx">no_newlines</span>
|
||||
<span class="k">return</span> <span class="nx">@newline_token</span> <span class="nx">indent</span>
|
||||
<span class="k">return</span> <span class="nx">@suppressNewlines</span><span class="p">()</span> <span class="k">if</span> <span class="nx">noNewlines</span>
|
||||
<span class="k">return</span> <span class="nx">@newlineToken</span> <span class="nx">indent</span>
|
||||
<span class="k">else</span> <span class="k">if</span> <span class="nx">size</span> <span class="o">></span> <span class="nx">@indent</span>
|
||||
<span class="k">return</span> <span class="nx">@suppress_newlines</span><span class="p">()</span> <span class="k">if</span> <span class="nx">no_newlines</span>
|
||||
<span class="k">return</span> <span class="nx">@suppressNewlines</span><span class="p">()</span> <span class="k">if</span> <span class="nx">noNewlines</span>
|
||||
<span class="nv">diff: </span><span class="nx">size</span> <span class="o">-</span> <span class="nx">@indent</span>
|
||||
<span class="nx">@token</span> <span class="s1">'INDENT'</span><span class="p">,</span> <span class="nx">diff</span>
|
||||
<span class="nx">@indents</span><span class="p">.</span><span class="nx">push</span> <span class="nx">diff</span>
|
||||
<span class="k">else</span>
|
||||
<span class="nx">@outdent_token</span> <span class="nx">@indent</span> <span class="o">-</span> <span class="nx">size</span><span class="p">,</span> <span class="nx">no_newlines</span>
|
||||
<span class="nx">@outdentToken</span> <span class="nx">@indent</span> <span class="o">-</span> <span class="nx">size</span><span class="p">,</span> <span class="nx">noNewlines</span>
|
||||
<span class="vi">@indent: </span><span class="nx">size</span>
|
||||
<span class="kc">true</span></pre></div> </td> </tr> <tr id="section-19"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-19">#</a> </div> <p>Record an outdent token or multiple tokens, if we happen to be moving back
|
||||
inwards past several recorded indents.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">outdent_token: </span><span class="p">(</span><span class="nx">move_out</span><span class="p">,</span> <span class="nx">no_newlines</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="k">while</span> <span class="nx">move_out</span> <span class="o">></span> <span class="mi">0</span> <span class="o">and</span> <span class="nx">@indents</span><span class="p">.</span><span class="nx">length</span>
|
||||
<span class="nv">last_indent: </span><span class="nx">@indents</span><span class="p">.</span><span class="nx">pop</span><span class="p">()</span>
|
||||
<span class="nx">@token</span> <span class="s1">'OUTDENT'</span><span class="p">,</span> <span class="nx">last_indent</span>
|
||||
<span class="nv">move_out: </span><span class="o">-</span> <span class="nx">last_indent</span>
|
||||
<span class="nx">@token</span> <span class="s1">'TERMINATOR'</span><span class="p">,</span> <span class="s2">"\n"</span> <span class="nx">unless</span> <span class="nx">@tag</span><span class="p">()</span> <span class="o">is</span> <span class="s1">'TERMINATOR'</span> <span class="o">or</span> <span class="nx">no_newlines</span>
|
||||
<span class="kc">true</span></pre></div> </td> </tr> <tr id="section-20"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-20">#</a> </div> <p>Matches and consumes non-meaningful whitespace. Tag the previous token
|
||||
as being "spaced", because there are some cases where it makes a difference.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">whitespace_token: </span><span class="o">-></span>
|
||||
<span class="kc">true</span></pre></div> </td> </tr> <tr id="section-18"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-18">#</a> </div> <p>Record an outdent token or multiple tokens, if we happen to be moving back
|
||||
inwards past several recorded indents.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">outdentToken: </span><span class="p">(</span><span class="nx">moveOut</span><span class="p">,</span> <span class="nx">noNewlines</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="k">if</span> <span class="nx">moveOut</span> <span class="o">></span> <span class="o">-</span><span class="nx">@outdebt</span>
|
||||
<span class="k">while</span> <span class="nx">moveOut</span> <span class="o">></span> <span class="mi">0</span> <span class="o">and</span> <span class="nx">@indents</span><span class="p">.</span><span class="nx">length</span>
|
||||
<span class="nv">lastIndent: </span><span class="nx">@indents</span><span class="p">.</span><span class="nx">pop</span><span class="p">()</span>
|
||||
<span class="nx">@token</span> <span class="s1">'OUTDENT'</span><span class="p">,</span> <span class="nx">lastIndent</span>
|
||||
<span class="nv">moveOut: </span><span class="o">-</span> <span class="nx">lastIndent</span>
|
||||
<span class="k">else</span>
|
||||
<span class="vi">@outdebt: </span><span class="o">+</span> <span class="nx">moveOut</span>
|
||||
<span class="vi">@outdebt: </span><span class="nx">moveOut</span> <span class="nx">unless</span> <span class="nx">noNewlines</span>
|
||||
<span class="nx">@token</span> <span class="s1">'TERMINATOR'</span><span class="p">,</span> <span class="s2">"\n"</span> <span class="nx">unless</span> <span class="nx">@tag</span><span class="p">()</span> <span class="o">is</span> <span class="s1">'TERMINATOR'</span> <span class="o">or</span> <span class="nx">noNewlines</span>
|
||||
<span class="kc">true</span></pre></div> </td> </tr> <tr id="section-19"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-19">#</a> </div> <p>Matches and consumes non-meaningful whitespace. Tag the previous token
|
||||
as being "spaced", because there are some cases where it makes a difference.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">whitespaceToken: </span><span class="o">-></span>
|
||||
<span class="k">return</span> <span class="kc">false</span> <span class="nx">unless</span> <span class="nv">space: </span><span class="nx">@match</span> <span class="nx">WHITESPACE</span><span class="p">,</span> <span class="mi">1</span>
|
||||
<span class="nv">prev: </span><span class="nx">@prev</span><span class="p">()</span>
|
||||
<span class="nv">prev.spaced: </span><span class="kc">true</span> <span class="k">if</span> <span class="nx">prev</span>
|
||||
<span class="vi">@i: </span><span class="o">+</span> <span class="nx">space</span><span class="p">.</span><span class="nx">length</span>
|
||||
<span class="kc">true</span></pre></div> </td> </tr> <tr id="section-21"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-21">#</a> </div> <p>Generate a newline token. Consecutive newlines get merged together.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">newline_token: </span><span class="p">(</span><span class="nx">newlines</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="kc">true</span></pre></div> </td> </tr> <tr id="section-20"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-20">#</a> </div> <p>Generate a newline token. Consecutive newlines get merged together.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">newlineToken: </span><span class="p">(</span><span class="nx">newlines</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nx">@token</span> <span class="s1">'TERMINATOR'</span><span class="p">,</span> <span class="s2">"\n"</span> <span class="nx">unless</span> <span class="nx">@tag</span><span class="p">()</span> <span class="o">is</span> <span class="s1">'TERMINATOR'</span>
|
||||
<span class="kc">true</span></pre></div> </td> </tr> <tr id="section-22"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-22">#</a> </div> <p>Use a <code>\</code> at a line-ending to suppress the newline.
|
||||
The slash is removed here once its job is done.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">suppress_newlines: </span><span class="o">-></span>
|
||||
<span class="kc">true</span></pre></div> </td> </tr> <tr id="section-21"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-21">#</a> </div> <p>Use a <code>\</code> at a line-ending to suppress the newline.
|
||||
The slash is removed here once its job is done.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">suppressNewlines: </span><span class="o">-></span>
|
||||
<span class="nx">@tokens</span><span class="p">.</span><span class="nx">pop</span><span class="p">()</span> <span class="k">if</span> <span class="nx">@value</span><span class="p">()</span> <span class="o">is</span> <span class="s2">"\\"</span>
|
||||
<span class="kc">true</span></pre></div> </td> </tr> <tr id="section-23"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-23">#</a> </div> <p>We treat all other single characters as a token. Eg.: <code>( ) , . !</code>
|
||||
<span class="kc">true</span></pre></div> </td> </tr> <tr id="section-22"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-22">#</a> </div> <p>We treat all other single characters as a token. Eg.: <code>( ) , . !</code>
|
||||
Multi-character operators are also literal tokens, so that Jison can assign
|
||||
the proper order of operations. There are some symbols that we tag specially
|
||||
here. <code>;</code> and newlines are both treated as a <code>TERMINATOR</code>, we distinguish
|
||||
parentheses that indicate a method call from regular parentheses, and so on.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">literal_token: </span><span class="o">-></span>
|
||||
parentheses that indicate a method call from regular parentheses, and so on.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">literalToken: </span><span class="o">-></span>
|
||||
<span class="nv">match: </span><span class="nx">@chunk</span><span class="p">.</span><span class="nx">match</span> <span class="nx">OPERATOR</span>
|
||||
<span class="nv">value: </span><span class="nx">match</span> <span class="o">and</span> <span class="nx">match</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
|
||||
<span class="nv">space: </span><span class="nx">match</span> <span class="o">and</span> <span class="nx">match</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span>
|
||||
<span class="nx">@tag_parameters</span><span class="p">()</span> <span class="k">if</span> <span class="nx">value</span> <span class="o">and</span> <span class="nx">value</span><span class="p">.</span><span class="nx">match</span> <span class="nx">CODE</span>
|
||||
<span class="nx">@tagParameters</span><span class="p">()</span> <span class="k">if</span> <span class="nx">value</span> <span class="o">and</span> <span class="nx">value</span><span class="p">.</span><span class="nx">match</span> <span class="nx">CODE</span>
|
||||
<span class="nv">value: </span><span class="o">or</span> <span class="nx">@chunk</span><span class="p">.</span><span class="nx">substr</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span>
|
||||
<span class="nv">prev_spaced: </span><span class="nx">@prev</span><span class="p">()</span> <span class="o">and</span> <span class="nx">@prev</span><span class="p">().</span><span class="nx">spaced</span>
|
||||
<span class="nv">prevSpaced: </span><span class="nx">@prev</span><span class="p">()</span> <span class="o">and</span> <span class="nx">@prev</span><span class="p">().</span><span class="nx">spaced</span>
|
||||
<span class="nv">tag: </span><span class="nx">value</span>
|
||||
<span class="k">if</span> <span class="nx">value</span><span class="p">.</span><span class="nx">match</span> <span class="nx">ASSIGNMENT</span>
|
||||
<span class="nv">tag: </span><span class="s1">'ASSIGN'</span>
|
||||
<span class="nx">@assignment_error</span><span class="p">()</span> <span class="k">if</span> <span class="nx">include</span> <span class="nx">JS_FORBIDDEN</span><span class="p">,</span> <span class="nx">@value</span>
|
||||
<span class="nx">@assignmentError</span><span class="p">()</span> <span class="k">if</span> <span class="nx">include</span> <span class="nx">JS_FORBIDDEN</span><span class="p">,</span> <span class="nx">@value</span>
|
||||
<span class="k">else</span> <span class="k">if</span> <span class="nx">value</span> <span class="o">is</span> <span class="s1">';'</span>
|
||||
<span class="nv">tag: </span><span class="s1">'TERMINATOR'</span>
|
||||
<span class="k">else</span> <span class="k">if</span> <span class="nx">value</span> <span class="o">is</span> <span class="s1">'['</span> <span class="o">and</span> <span class="nx">@tag</span><span class="p">()</span> <span class="o">is</span> <span class="s1">'?'</span> <span class="o">and</span> <span class="o">not</span> <span class="nx">prev_spaced</span>
|
||||
<span class="nv">tag: </span><span class="s1">'SOAKED_INDEX_START'</span>
|
||||
<span class="vi">@soaked_index: </span><span class="kc">true</span>
|
||||
<span class="nx">@tokens</span><span class="p">.</span><span class="nx">pop</span><span class="p">()</span>
|
||||
<span class="k">else</span> <span class="k">if</span> <span class="nx">value</span> <span class="o">is</span> <span class="s1">']'</span> <span class="o">and</span> <span class="nx">@soaked_index</span>
|
||||
<span class="nv">tag: </span><span class="s1">'SOAKED_INDEX_END'</span>
|
||||
<span class="vi">@soaked_index: </span><span class="kc">false</span>
|
||||
<span class="k">else</span> <span class="k">if</span> <span class="nx">include</span><span class="p">(</span><span class="nx">CALLABLE</span><span class="p">,</span> <span class="nx">@tag</span><span class="p">())</span> <span class="o">and</span> <span class="o">not</span> <span class="nx">prev_spaced</span>
|
||||
<span class="nv">tag: </span><span class="s1">'CALL_START'</span> <span class="k">if</span> <span class="nx">value</span> <span class="o">is</span> <span class="s1">'('</span>
|
||||
<span class="nv">tag: </span><span class="s1">'INDEX_START'</span> <span class="k">if</span> <span class="nx">value</span> <span class="o">is</span> <span class="s1">'['</span>
|
||||
<span class="k">else</span> <span class="k">if</span> <span class="nx">value</span> <span class="o">is</span> <span class="s1">'?'</span> <span class="o">and</span> <span class="nx">prevSpaced</span>
|
||||
<span class="nv">tag: </span><span class="s1">'OP?'</span>
|
||||
<span class="k">else</span> <span class="k">if</span> <span class="nx">include</span><span class="p">(</span><span class="nx">CALLABLE</span><span class="p">,</span> <span class="nx">@tag</span><span class="p">())</span> <span class="o">and</span> <span class="o">not</span> <span class="nx">prevSpaced</span>
|
||||
<span class="k">if</span> <span class="nx">value</span> <span class="o">is</span> <span class="s1">'('</span>
|
||||
<span class="nv">tag: </span><span class="s1">'CALL_START'</span>
|
||||
<span class="k">else</span> <span class="k">if</span> <span class="nx">value</span> <span class="o">is</span> <span class="s1">'['</span>
|
||||
<span class="nv">tag: </span><span class="s1">'INDEX_START'</span>
|
||||
<span class="nx">@tag</span> <span class="mi">1</span><span class="p">,</span> <span class="s1">'INDEX_SOAK'</span> <span class="k">if</span> <span class="nx">@tag</span><span class="p">()</span> <span class="o">is</span> <span class="s1">'?'</span>
|
||||
<span class="nx">@tag</span> <span class="mi">1</span><span class="p">,</span> <span class="s1">'INDEX_PROTO'</span> <span class="k">if</span> <span class="nx">@tag</span><span class="p">()</span> <span class="o">is</span> <span class="s1">'::'</span>
|
||||
<span class="vi">@i: </span><span class="o">+</span> <span class="nx">value</span><span class="p">.</span><span class="nx">length</span>
|
||||
<span class="k">return</span> <span class="nx">@tag_half_assignment</span> <span class="nx">tag</span> <span class="k">if</span> <span class="nx">space</span> <span class="o">and</span> <span class="nx">prev_spaced</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="o">is</span> <span class="s1">'ASSIGN'</span> <span class="o">and</span> <span class="nx">include</span> <span class="nx">HALF_ASSIGNMENTS</span><span class="p">,</span> <span class="nx">tag</span>
|
||||
<span class="k">return</span> <span class="nx">@tagHalfAssignment</span> <span class="nx">tag</span> <span class="k">if</span> <span class="nx">space</span> <span class="o">and</span> <span class="nx">prevSpaced</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="o">is</span> <span class="s1">'ASSIGN'</span> <span class="o">and</span> <span class="nx">include</span> <span class="nx">HALF_ASSIGNMENTS</span><span class="p">,</span> <span class="nx">tag</span>
|
||||
<span class="nx">@token</span> <span class="nx">tag</span><span class="p">,</span> <span class="nx">value</span>
|
||||
<span class="kc">true</span></pre></div> </td> </tr> <tr id="section-24"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-24">#</a> </div> <h2>Token Manipulators</h2> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-25"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-25">#</a> </div> <p>As we consume a new <code>IDENTIFIER</code>, look at the previous token to determine
|
||||
if it's a special kind of accessor.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">name_access_type: </span><span class="o">-></span>
|
||||
<span class="nx">@tag</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="s1">'PROTOTYPE_ACCESS'</span><span class="p">)</span> <span class="k">if</span> <span class="nx">@value</span><span class="p">()</span> <span class="o">is</span> <span class="s1">'::'</span>
|
||||
<span class="k">if</span> <span class="nx">@value</span><span class="p">()</span> <span class="o">is</span> <span class="s1">'.'</span> <span class="o">and</span> <span class="o">not</span> <span class="p">(</span><span class="nx">@value</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span> <span class="o">is</span> <span class="s1">'.'</span><span class="p">)</span>
|
||||
<span class="kc">true</span></pre></div> </td> </tr> <tr id="section-23"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-23">#</a> </div> <h2>Token Manipulators</h2> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-24"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-24">#</a> </div> <p>As we consume a new <code>IDENTIFIER</code>, look at the previous token to determine
|
||||
if it's a special kind of accessor. Return <code>true</code> if any type of accessor
|
||||
is the previous token.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">tagAccessor: </span><span class="o">-></span>
|
||||
<span class="k">return</span> <span class="kc">false</span> <span class="k">if</span> <span class="p">(</span><span class="o">not</span> <span class="nv">prev: </span><span class="nx">@prev</span><span class="p">())</span> <span class="o">or</span> <span class="p">(</span><span class="nx">prev</span> <span class="o">and</span> <span class="nx">prev</span><span class="p">.</span><span class="nx">spaced</span><span class="p">)</span>
|
||||
<span class="nv">accessor: </span><span class="k">if</span> <span class="nx">prev</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">is</span> <span class="s1">'::'</span>
|
||||
<span class="nx">@tag</span> <span class="mi">1</span><span class="p">,</span> <span class="s1">'PROTOTYPE_ACCESS'</span>
|
||||
<span class="k">else</span> <span class="k">if</span> <span class="nx">prev</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">is</span> <span class="s1">'.'</span> <span class="o">and</span> <span class="o">not</span> <span class="p">(</span><span class="nx">@value</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span> <span class="o">is</span> <span class="s1">'.'</span><span class="p">)</span>
|
||||
<span class="k">if</span> <span class="nx">@tag</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span> <span class="o">is</span> <span class="s1">'?'</span>
|
||||
<span class="nx">@tag</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="s1">'SOAK_ACCESS'</span><span class="p">)</span>
|
||||
<span class="nx">@tokens</span><span class="p">.</span><span class="nx">splice</span><span class="p">(</span><span class="o">-</span><span class="mi">2</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
|
||||
<span class="k">else</span>
|
||||
<span class="nx">@tag</span> <span class="mi">1</span><span class="p">,</span> <span class="s1">'PROPERTY_ACCESS'</span></pre></div> </td> </tr> <tr id="section-26"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-26">#</a> </div> <p>Sanitize a heredoc by escaping internal double quotes and erasing all
|
||||
external indentation on the left-hand side.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">sanitize_heredoc: </span><span class="p">(</span><span class="nx">doc</span><span class="p">,</span> <span class="nx">quote</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nv">indent: </span><span class="p">(</span><span class="nx">doc</span><span class="p">.</span><span class="nx">match</span><span class="p">(</span><span class="nx">HEREDOC_INDENT</span><span class="p">)</span> <span class="o">or</span> <span class="p">[</span><span class="s1">''</span><span class="p">]).</span><span class="nx">sort</span><span class="p">()[</span><span class="mi">0</span><span class="p">]</span>
|
||||
<span class="nx">doc</span><span class="p">.</span><span class="nx">replace</span><span class="p">(</span><span class="k">new</span> <span class="nb">RegExp</span><span class="p">(</span><span class="s2">"^"</span> <span class="o">+</span><span class="nx">indent</span><span class="p">,</span> <span class="s1">'gm'</span><span class="p">),</span> <span class="s1">''</span><span class="p">)</span>
|
||||
<span class="p">.</span><span class="nx">replace</span><span class="p">(</span><span class="nx">MULTILINER</span><span class="p">,</span> <span class="s2">"\\n"</span><span class="p">)</span>
|
||||
<span class="p">.</span><span class="nx">replace</span><span class="p">(</span><span class="k">new</span> <span class="nb">RegExp</span><span class="p">(</span><span class="nx">quote</span><span class="p">,</span> <span class="s1">'g'</span><span class="p">),</span> <span class="s1">'\\"'</span><span class="p">)</span></pre></div> </td> </tr> <tr id="section-27"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-27">#</a> </div> <p>Tag a half assignment.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">tag_half_assignment: </span><span class="p">(</span><span class="nx">tag</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nx">@tag</span> <span class="mi">1</span><span class="p">,</span> <span class="s1">'PROPERTY_ACCESS'</span>
|
||||
<span class="k">else</span>
|
||||
<span class="nx">prev</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">is</span> <span class="s1">'@'</span>
|
||||
<span class="k">if</span> <span class="nx">accessor</span> <span class="k">then</span> <span class="s1">'accessor'</span> <span class="k">else</span> <span class="kc">false</span></pre></div> </td> </tr> <tr id="section-25"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-25">#</a> </div> <p>Sanitize a heredoc or herecomment by escaping internal double quotes and
|
||||
erasing all external indentation on the left-hand side.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">sanitizeHeredoc: </span><span class="p">(</span><span class="nx">doc</span><span class="p">,</span> <span class="nx">options</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="k">while</span> <span class="nv">match: </span><span class="nx">HEREDOC_INDENT</span><span class="p">.</span><span class="nx">exec</span> <span class="nx">doc</span>
|
||||
<span class="nv">attempt: </span><span class="k">if</span> <span class="nx">match</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span><span class="o">?</span> <span class="k">then</span> <span class="nx">match</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="k">else</span> <span class="nx">match</span><span class="p">[</span><span class="mi">3</span><span class="p">]</span>
|
||||
<span class="nv">indent: </span><span class="nx">attempt</span> <span class="k">if</span> <span class="o">not</span> <span class="nx">indent</span> <span class="o">or</span> <span class="nx">attempt</span><span class="p">.</span><span class="nx">length</span> <span class="o"><</span> <span class="nx">indent</span><span class="p">.</span><span class="nx">length</span>
|
||||
<span class="nv">doc: </span><span class="nx">doc</span><span class="p">.</span><span class="nx">replace</span><span class="p">(</span><span class="k">new</span> <span class="nb">RegExp</span><span class="p">(</span><span class="s2">"^"</span> <span class="o">+</span><span class="nx">indent</span><span class="p">,</span> <span class="s1">'gm'</span><span class="p">),</span> <span class="s1">''</span><span class="p">)</span>
|
||||
<span class="k">return</span> <span class="nx">doc</span> <span class="k">if</span> <span class="nx">options</span><span class="p">.</span><span class="nx">herecomment</span>
|
||||
<span class="nx">doc</span><span class="p">.</span><span class="nx">replace</span><span class="p">(</span><span class="nx">MULTILINER</span><span class="p">,</span> <span class="s2">"\\n"</span><span class="p">)</span>
|
||||
<span class="p">.</span><span class="nx">replace</span><span class="p">(</span><span class="k">new</span> <span class="nb">RegExp</span><span class="p">(</span><span class="nx">options</span><span class="p">.</span><span class="nx">quote</span><span class="p">,</span> <span class="s1">'g'</span><span class="p">),</span> <span class="s2">"\\$options.quote"</span><span class="p">)</span></pre></div> </td> </tr> <tr id="section-26"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-26">#</a> </div> <p>Tag a half assignment.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">tagHalfAssignment: </span><span class="p">(</span><span class="nx">tag</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nv">tag: </span> <span class="s1">'?'</span> <span class="k">if</span> <span class="nx">tag</span> <span class="o">is</span> <span class="s1">'OP?'</span>
|
||||
<span class="nv">last: </span><span class="nx">@tokens</span><span class="p">.</span><span class="nx">pop</span><span class="p">()</span>
|
||||
<span class="nx">@tokens</span><span class="p">.</span><span class="nx">push</span> <span class="p">[</span><span class="s2">"$tag="</span><span class="p">,</span> <span class="s2">"$tag="</span><span class="p">,</span> <span class="nx">last</span><span class="p">[</span><span class="mi">2</span><span class="p">]]</span>
|
||||
<span class="kc">true</span></pre></div> </td> </tr> <tr id="section-28"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-28">#</a> </div> <p>A source of ambiguity in our grammar used to be parameter lists in function
|
||||
<span class="kc">true</span></pre></div> </td> </tr> <tr id="section-27"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-27">#</a> </div> <p>A source of ambiguity in our grammar used to be parameter lists in function
|
||||
definitions versus argument lists in function calls. Walk backwards, tagging
|
||||
parameters specially in order to make things easier for the parser.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">tag_parameters: </span><span class="o">-></span>
|
||||
parameters specially in order to make things easier for the parser.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">tagParameters: </span><span class="o">-></span>
|
||||
<span class="k">return</span> <span class="k">if</span> <span class="nx">@tag</span><span class="p">()</span> <span class="o">isnt</span> <span class="s1">')'</span>
|
||||
<span class="nv">i: </span><span class="mi">0</span>
|
||||
<span class="k">while</span> <span class="kc">true</span>
|
||||
<span class="nx">loop</span>
|
||||
<span class="nv">i: </span><span class="o">+</span> <span class="mi">1</span>
|
||||
<span class="nv">tok: </span><span class="nx">@prev</span> <span class="nx">i</span>
|
||||
<span class="k">return</span> <span class="k">if</span> <span class="o">not</span> <span class="nx">tok</span>
|
||||
<span class="k">switch</span> <span class="nx">tok</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
|
||||
<span class="k">when</span> <span class="s1">'IDENTIFIER'</span> <span class="k">then</span> <span class="nx">tok</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">:</span> <span class="s1">'PARAM'</span>
|
||||
<span class="k">when</span> <span class="s1">')'</span> <span class="k">then</span> <span class="nx">tok</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">:</span> <span class="s1">'PARAM_END'</span>
|
||||
<span class="k">when</span> <span class="s1">'('</span> <span class="k">then</span> <span class="k">return</span> <span class="nx">tok</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">:</span> <span class="s1">'PARAM_START'</span>
|
||||
<span class="kc">true</span></pre></div> </td> </tr> <tr id="section-29"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-29">#</a> </div> <p>Close up all remaining open blocks at the end of the file.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">close_indentation: </span><span class="o">-></span>
|
||||
<span class="nx">@outdent_token</span> <span class="nx">@indent</span></pre></div> </td> </tr> <tr id="section-30"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-30">#</a> </div> <p>The error for when you try to use a forbidden word in JavaScript as
|
||||
an identifier.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">identifier_error: </span><span class="p">(</span><span class="nx">word</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="s2">"SyntaxError: Reserved word \"$word\" on line ${@line + 1}"</span></pre></div> </td> </tr> <tr id="section-31"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-31">#</a> </div> <p>The error for when you try to assign to a reserved word in JavaScript,
|
||||
like "function" or "default".</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">assignment_error: </span><span class="o">-></span>
|
||||
<span class="k">throw</span> <span class="k">new</span> <span class="nb">Error</span> <span class="s2">"SyntaxError: Reserved word \"${@value()}\" on line ${@line + 1} can't be assigned"</span></pre></div> </td> </tr> <tr id="section-32"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-32">#</a> </div> <p>Expand variables and expressions inside double-quoted strings using
|
||||
<span class="k">when</span> <span class="s1">'IDENTIFIER'</span> <span class="k">then</span> <span class="nx">tok</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">:</span> <span class="s1">'PARAM'</span>
|
||||
<span class="k">when</span> <span class="s1">')'</span> <span class="k">then</span> <span class="nx">tok</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">:</span> <span class="s1">'PARAM_END'</span>
|
||||
<span class="k">when</span> <span class="s1">'('</span><span class="p">,</span> <span class="s1">'CALL_START'</span> <span class="k">then</span> <span class="k">return</span> <span class="nx">tok</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">:</span> <span class="s1">'PARAM_START'</span>
|
||||
<span class="kc">true</span></pre></div> </td> </tr> <tr id="section-28"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-28">#</a> </div> <p>Close up all remaining open blocks at the end of the file.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">closeIndentation: </span><span class="o">-></span>
|
||||
<span class="nx">@outdentToken</span> <span class="nx">@indent</span></pre></div> </td> </tr> <tr id="section-29"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-29">#</a> </div> <p>The error for when you try to use a forbidden word in JavaScript as
|
||||
an identifier.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">identifierError: </span><span class="p">(</span><span class="nx">word</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="s2">"SyntaxError: Reserved word \"$word\" on line ${@line + 1}"</span></pre></div> </td> </tr> <tr id="section-30"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-30">#</a> </div> <p>The error for when you try to assign to a reserved word in JavaScript,
|
||||
like "function" or "default".</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">assignmentError: </span><span class="o">-></span>
|
||||
<span class="k">throw</span> <span class="k">new</span> <span class="nb">Error</span> <span class="s2">"SyntaxError: Reserved word \"${@value()}\" on line ${@line + 1} can't be assigned"</span></pre></div> </td> </tr> <tr id="section-31"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-31">#</a> </div> <p>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
|
||||
interpolations within strings, ad infinitum.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">balancedString: </span><span class="p">(</span><span class="nx">str</span><span class="p">,</span> <span class="nx">delimited</span><span class="p">,</span> <span class="nx">options</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nv">options: </span><span class="o">or</span> <span class="p">{}</span>
|
||||
<span class="nv">slash: </span><span class="nx">delimited</span><span class="p">[</span><span class="mi">0</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="nv">levels: </span><span class="p">[]</span>
|
||||
<span class="nv">i: </span><span class="mi">0</span>
|
||||
<span class="k">while</span> <span class="nx">i</span> <span class="o"><</span> <span class="nx">str</span><span class="p">.</span><span class="nx">length</span>
|
||||
<span class="k">if</span> <span class="nx">levels</span><span class="p">.</span><span class="nx">length</span> <span class="o">and</span> <span class="nx">starts</span> <span class="nx">str</span><span class="p">,</span> <span class="s1">'\\'</span><span class="p">,</span> <span class="nx">i</span>
|
||||
<span class="nv">i: </span><span class="o">+</span> <span class="mi">1</span>
|
||||
<span class="k">else</span>
|
||||
<span class="k">for</span> <span class="nx">pair</span> <span class="k">in</span> <span class="nx">delimited</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="o">:</span> <span class="nx">pair</span>
|
||||
<span class="k">if</span> <span class="nx">levels</span><span class="p">.</span><span class="nx">length</span> <span class="o">and</span> <span class="nx">starts</span><span class="p">(</span><span class="nx">str</span><span class="p">,</span> <span class="nx">close</span><span class="p">,</span> <span class="nx">i</span><span class="p">)</span> <span class="o">and</span> <span class="nx">levels</span><span class="p">[</span><span class="nx">levels</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="nx">pair</span>
|
||||
<span class="nx">levels</span><span class="p">.</span><span class="nx">pop</span><span class="p">()</span>
|
||||
<span class="nv">i: </span><span class="o">+</span> <span class="nx">close</span><span class="p">.</span><span class="nx">length</span> <span class="o">-</span> <span class="mi">1</span>
|
||||
<span class="nv">i: </span><span class="o">+</span> <span class="mi">1</span> <span class="nx">unless</span> <span class="nx">levels</span><span class="p">.</span><span class="nx">length</span>
|
||||
<span class="k">break</span>
|
||||
<span class="k">else</span> <span class="k">if</span> <span class="nx">starts</span> <span class="nx">str</span><span class="p">,</span> <span class="nx">open</span><span class="p">,</span> <span class="nx">i</span>
|
||||
<span class="nx">levels</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="nx">pair</span><span class="p">)</span>
|
||||
<span class="nv">i: </span><span class="o">+</span> <span class="nx">open</span><span class="p">.</span><span class="nx">length</span> <span class="o">-</span> <span class="mi">1</span>
|
||||
<span class="k">break</span>
|
||||
<span class="k">break</span> <span class="k">if</span> <span class="o">not</span> <span class="nx">levels</span><span class="p">.</span><span class="nx">length</span> <span class="o">or</span> <span class="nx">slash</span> <span class="o">and</span> <span class="nx">starts</span> <span class="nx">str</span><span class="p">,</span> <span class="s1">'\n'</span><span class="p">,</span> <span class="nx">i</span>
|
||||
<span class="nv">i: </span><span class="o">+</span> <span class="mi">1</span>
|
||||
<span class="k">if</span> <span class="nx">levels</span><span class="p">.</span><span class="nx">length</span>
|
||||
<span class="k">return</span> <span class="kc">false</span> <span class="k">if</span> <span class="nx">slash</span>
|
||||
<span class="k">throw</span> <span class="k">new</span> <span class="nb">Error</span> <span class="s2">"SyntaxError: Unterminated ${levels.pop()[0]} starting on line ${@line + 1}"</span>
|
||||
<span class="k">if</span> <span class="o">not</span> <span class="nx">i</span> <span class="k">then</span> <span class="kc">false</span> <span class="k">else</span> <span class="nx">str</span><span class="p">.</span><span class="nx">substring</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="nx">i</span><span class="p">)</span></pre></div> </td> </tr> <tr id="section-32"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-32">#</a> </div> <p>Expand variables and expressions inside double-quoted strings using
|
||||
<a href="http://wiki.ecmascript.org/doku.php?id=strawman:string_interpolation">ECMA Harmony's interpolation syntax</a>
|
||||
for substitution of bare variables as well as arbitrary expressions.</p>
|
||||
|
||||
@@ -254,11 +297,11 @@ for substitution of bare variables as well as arbitrary expressions.</p>
|
||||
|
||||
<p>If it encounters an interpolation, this method will recursively create a
|
||||
new Lexer, tokenize the interpolated contents, and merge them into the
|
||||
token stream.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">interpolate_string: </span><span class="p">(</span><span class="nx">str</span><span class="p">,</span> <span class="nx">escape_quotes</span><span class="p">)</span> <span class="o">-></span>
|
||||
token stream.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">interpolateString: </span><span class="p">(</span><span class="nx">str</span><span class="p">,</span> <span class="nx">escapeQuotes</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="k">if</span> <span class="nx">str</span><span class="p">.</span><span class="nx">length</span> <span class="o"><</span> <span class="mi">3</span> <span class="o">or</span> <span class="o">not</span> <span class="nx">starts</span> <span class="nx">str</span><span class="p">,</span> <span class="s1">'"'</span>
|
||||
<span class="nx">@token</span> <span class="s1">'STRING'</span><span class="p">,</span> <span class="nx">str</span>
|
||||
<span class="k">else</span>
|
||||
<span class="nv">lexer: </span> <span class="k">new</span> <span class="nx">Lexer</span><span class="p">()</span>
|
||||
<span class="nv">lexer: </span> <span class="k">new</span> <span class="nx">Lexer</span>
|
||||
<span class="nv">tokens: </span> <span class="p">[]</span>
|
||||
<span class="nv">quote: </span> <span class="nx">str</span><span class="p">.</span><span class="nx">substring</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span>
|
||||
<span class="p">[</span><span class="nx">i</span><span class="p">,</span> <span class="nx">pi</span><span class="p">]</span><span class="o">:</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">]</span>
|
||||
@@ -272,11 +315,13 @@ token stream.</p> </td> <td class="code">
|
||||
<span class="nx">tokens</span><span class="p">.</span><span class="nx">push</span> <span class="p">[</span><span class="s1">'IDENTIFIER'</span><span class="p">,</span> <span class="nx">interp</span><span class="p">]</span>
|
||||
<span class="nv">i: </span><span class="o">+</span> <span class="nx">group</span><span class="p">.</span><span class="nx">length</span> <span class="o">-</span> <span class="mi">1</span>
|
||||
<span class="nv">pi: </span><span class="nx">i</span> <span class="o">+</span> <span class="mi">1</span>
|
||||
<span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="nv">expr: </span><span class="nx">balanced_string</span> <span class="nx">str</span><span class="p">.</span><span class="nx">substring</span><span class="p">(</span><span class="nx">i</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="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="nv">expr: </span><span class="nx">@balancedString</span> <span class="nx">str</span><span class="p">.</span><span class="nx">substring</span><span class="p">(</span><span class="nx">i</span><span class="p">),</span> <span class="p">[[</span><span class="s1">'${'</span><span class="p">,</span> <span class="s1">'}'</span><span class="p">]])</span>
|
||||
<span class="nx">tokens</span><span class="p">.</span><span class="nx">push</span> <span class="p">[</span><span class="s1">'STRING'</span><span class="p">,</span> <span class="s2">"$quote${ str.substring(pi, i) }$quote"</span><span class="p">]</span> <span class="k">if</span> <span class="nx">pi</span> <span class="o"><</span> <span class="nx">i</span>
|
||||
<span class="nv">inner: </span><span class="nx">expr</span><span class="p">.</span><span class="nx">substring</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="nx">expr</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="k">if</span> <span class="nx">inner</span><span class="p">.</span><span class="nx">length</span>
|
||||
<span class="nv">nested: </span><span class="nx">lexer</span><span class="p">.</span><span class="nx">tokenize</span> <span class="s2">"($inner)"</span><span class="p">,</span> <span class="p">{</span><span class="nv">rewrite: </span><span class="kc">no</span><span class="p">,</span> <span class="nv">line: </span><span class="nx">@line</span><span class="p">}</span>
|
||||
<span class="nv">inner: </span><span class="nx">inner</span><span class="p">.</span><span class="nx">replace</span> <span class="k">new</span> <span class="nb">RegExp</span><span class="p">(</span><span class="s1">'\\\\'</span> <span class="o">+</span> <span class="nx">quote</span><span class="p">,</span> <span class="s1">'g'</span><span class="p">),</span> <span class="nx">quote</span>
|
||||
<span class="nv">nested: </span><span class="nx">lexer</span><span class="p">.</span><span class="nx">tokenize</span> <span class="s2">"($inner)"</span><span class="p">,</span> <span class="p">{</span><span class="nv">line: </span><span class="nx">@line</span><span class="p">}</span>
|
||||
<span class="p">(</span><span class="nx">tok</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">:</span> <span class="s1">')'</span><span class="p">)</span> <span class="k">for</span> <span class="nx">tok</span><span class="p">,</span> <span class="nx">idx</span> <span class="k">in</span> <span class="nx">nested</span> <span class="k">when</span> <span class="nx">tok</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">is</span> <span class="s1">'CALL_END'</span>
|
||||
<span class="nx">nested</span><span class="p">.</span><span class="nx">pop</span><span class="p">()</span>
|
||||
<span class="nx">tokens</span><span class="p">.</span><span class="nx">push</span> <span class="p">[</span><span class="s1">'TOKENS'</span><span class="p">,</span> <span class="nx">nested</span><span class="p">]</span>
|
||||
<span class="k">else</span>
|
||||
@@ -286,20 +331,23 @@ token stream.</p> </td> <td class="code">
|
||||
<span class="nv">i: </span><span class="o">+</span> <span class="mi">1</span>
|
||||
<span class="nx">tokens</span><span class="p">.</span><span class="nx">push</span> <span class="p">[</span><span class="s1">'STRING'</span><span class="p">,</span> <span class="s2">"$quote${ str.substring(pi, i) }$quote"</span><span class="p">]</span> <span class="k">if</span> <span class="nx">pi</span> <span class="o"><</span> <span class="nx">i</span> <span class="o">and</span> <span class="nx">pi</span> <span class="o"><</span> <span class="nx">str</span><span class="p">.</span><span class="nx">length</span> <span class="o">-</span> <span class="mi">1</span>
|
||||
<span class="nx">tokens</span><span class="p">.</span><span class="nx">unshift</span> <span class="p">[</span><span class="s1">'STRING'</span><span class="p">,</span> <span class="s1">'""'</span><span class="p">]</span> <span class="nx">unless</span> <span class="nx">tokens</span><span class="p">[</span><span class="mi">0</span><span class="p">][</span><span class="mi">0</span><span class="p">]</span> <span class="o">is</span> <span class="s1">'STRING'</span>
|
||||
<span class="nv">interpolated: </span><span class="nx">tokens</span><span class="p">.</span><span class="nx">length</span> <span class="o">></span> <span class="mi">1</span>
|
||||
<span class="nx">@token</span> <span class="s1">'('</span><span class="p">,</span> <span class="s1">'('</span> <span class="k">if</span> <span class="nx">interpolated</span>
|
||||
<span class="k">for</span> <span class="nx">token</span><span class="p">,</span> <span class="nx">i</span> <span class="k">in</span> <span class="nx">tokens</span>
|
||||
<span class="p">[</span><span class="nx">tag</span><span class="p">,</span> <span class="nx">value</span><span class="p">]</span><span class="o">:</span> <span class="nx">token</span>
|
||||
<span class="k">if</span> <span class="nx">tag</span> <span class="o">is</span> <span class="s1">'TOKENS'</span>
|
||||
<span class="vi">@tokens: </span><span class="nx">@tokens</span><span class="p">.</span><span class="nx">concat</span> <span class="nx">value</span>
|
||||
<span class="k">else</span> <span class="k">if</span> <span class="nx">tag</span> <span class="o">is</span> <span class="s1">'STRING'</span> <span class="o">and</span> <span class="nx">escape_quotes</span>
|
||||
<span class="k">else</span> <span class="k">if</span> <span class="nx">tag</span> <span class="o">is</span> <span class="s1">'STRING'</span> <span class="o">and</span> <span class="nx">escapeQuotes</span>
|
||||
<span class="nv">escaped: </span><span class="nx">value</span><span class="p">.</span><span class="nx">substring</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="nx">value</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="nx">replace</span><span class="p">(</span><span class="sr">/"/g</span><span class="p">,</span> <span class="s1">'\\"'</span><span class="p">)</span>
|
||||
<span class="nx">@token</span> <span class="nx">tag</span><span class="p">,</span> <span class="s2">"\"$escaped\""</span>
|
||||
<span class="k">else</span>
|
||||
<span class="nx">@token</span> <span class="nx">tag</span><span class="p">,</span> <span class="nx">value</span>
|
||||
<span class="nx">@token</span> <span class="s1">'+'</span><span class="p">,</span> <span class="s1">'+'</span> <span class="k">if</span> <span class="nx">i</span> <span class="o"><</span> <span class="nx">tokens</span><span class="p">.</span><span class="nx">length</span> <span class="o">-</span> <span class="mi">1</span>
|
||||
<span class="nx">@token</span> <span class="s1">')'</span><span class="p">,</span> <span class="s1">')'</span> <span class="k">if</span> <span class="nx">interpolated</span>
|
||||
<span class="nx">tokens</span></pre></div> </td> </tr> <tr id="section-33"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-33">#</a> </div> <h2>Helpers</h2> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-34"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-34">#</a> </div> <p>Add a token to the results, taking note of the line number.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">token: </span><span class="p">(</span><span class="nx">tag</span><span class="p">,</span> <span class="nx">value</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nx">@tokens</span><span class="p">.</span><span class="nx">push</span> <span class="p">[</span><span class="nx">tag</span><span class="p">,</span> <span class="nx">value</span><span class="p">,</span> <span class="nx">@line</span><span class="p">]</span></pre></div> </td> </tr> <tr id="section-35"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-35">#</a> </div> <p>Peek at a tag in the current token stream.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">tag: </span><span class="p">(</span><span class="nx">index</span><span class="p">,</span> <span class="nx">tag</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nx">@tokens</span><span class="p">.</span><span class="nx">push</span> <span class="p">[</span><span class="nx">tag</span><span class="p">,</span> <span class="nx">value</span><span class="p">,</span> <span class="nx">@line</span><span class="p">]</span></pre></div> </td> </tr> <tr id="section-35"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-35">#</a> </div> <p>Peek at a tag in the current token stream.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">tag: </span><span class="p">(</span><span class="nx">index</span><span class="p">,</span> <span class="nx">newTag</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="k">return</span> <span class="nx">unless</span> <span class="nv">tok: </span><span class="nx">@prev</span> <span class="nx">index</span>
|
||||
<span class="k">return</span> <span class="nx">tok</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">:</span> <span class="nx">tag</span> <span class="k">if</span> <span class="nx">tag</span><span class="o">?</span>
|
||||
<span class="k">return</span> <span class="nx">tok</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">:</span> <span class="nx">newTag</span> <span class="k">if</span> <span class="nx">newTag</span><span class="o">?</span>
|
||||
<span class="nx">tok</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span></pre></div> </td> </tr> <tr id="section-36"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-36">#</a> </div> <p>Peek at a value in the current token stream.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">value: </span><span class="p">(</span><span class="nx">index</span><span class="p">,</span> <span class="nx">val</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="k">return</span> <span class="nx">unless</span> <span class="nv">tok: </span><span class="nx">@prev</span> <span class="nx">index</span>
|
||||
<span class="k">return</span> <span class="nx">tok</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span><span class="o">:</span> <span class="nx">val</span> <span class="k">if</span> <span class="nx">val</span><span class="o">?</span>
|
||||
@@ -310,7 +358,7 @@ match if successful, and <code>false</code> otherwise.</p> </td>
|
||||
<span class="k">if</span> <span class="nx">m</span> <span class="k">then</span> <span class="nx">m</span><span class="p">[</span><span class="nx">index</span><span class="p">]</span> <span class="k">else</span> <span class="kc">false</span></pre></div> </td> </tr> <tr id="section-39"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-39">#</a> </div> <p>Are we in the midst of an unfinished expression?</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">unfinished: </span><span class="o">-></span>
|
||||
<span class="nv">prev: </span><span class="nx">@prev</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span>
|
||||
<span class="nx">@value</span><span class="p">()</span> <span class="o">and</span> <span class="nx">@value</span><span class="p">().</span><span class="nx">match</span> <span class="o">and</span> <span class="nx">@value</span><span class="p">().</span><span class="nx">match</span><span class="p">(</span><span class="nx">NO_NEWLINE</span><span class="p">)</span> <span class="o">and</span>
|
||||
<span class="nx">prev</span> <span class="o">and</span> <span class="p">(</span><span class="nx">prev</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">isnt</span> <span class="s1">'.'</span><span class="p">)</span> <span class="o">and</span> <span class="o">not</span> <span class="nx">@value</span><span class="p">().</span><span class="nx">match</span><span class="p">(</span><span class="nx">CODE</span><span class="p">)</span></pre></div> </td> </tr> <tr id="section-40"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-40">#</a> </div> <h2>Lexer Properties</h2> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-41"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-41">#</a> </div> <p>There are no exensions to the core lexer by default.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="vi">@extensions: </span><span class="p">[]</span></pre></div> </td> </tr> <tr id="section-42"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-42">#</a> </div> <h2>Constants</h2> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-43"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-43">#</a> </div> <p>Keywords that CoffeeScript shares in common with JavaScript.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">JS_KEYWORDS: </span><span class="p">[</span>
|
||||
<span class="nx">prev</span> <span class="o">and</span> <span class="p">(</span><span class="nx">prev</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">isnt</span> <span class="s1">'.'</span><span class="p">)</span> <span class="o">and</span> <span class="o">not</span> <span class="nx">@value</span><span class="p">().</span><span class="nx">match</span><span class="p">(</span><span class="nx">CODE</span><span class="p">)</span></pre></div> </td> </tr> <tr id="section-40"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-40">#</a> </div> <h2>Constants</h2> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-41"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-41">#</a> </div> <p>Keywords that CoffeeScript shares in common with JavaScript.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">JS_KEYWORDS: </span><span class="p">[</span>
|
||||
<span class="s2">"if"</span><span class="p">,</span> <span class="s2">"else"</span><span class="p">,</span>
|
||||
<span class="s2">"true"</span><span class="p">,</span> <span class="s2">"false"</span><span class="p">,</span>
|
||||
<span class="s2">"new"</span><span class="p">,</span> <span class="s2">"return"</span><span class="p">,</span>
|
||||
@@ -320,51 +368,50 @@ match if successful, and <code>false</code> otherwise.</p> </td>
|
||||
<span class="s2">"delete"</span><span class="p">,</span> <span class="s2">"instanceof"</span><span class="p">,</span> <span class="s2">"typeof"</span><span class="p">,</span>
|
||||
<span class="s2">"switch"</span><span class="p">,</span> <span class="s2">"super"</span><span class="p">,</span> <span class="s2">"extends"</span><span class="p">,</span> <span class="s2">"class"</span><span class="p">,</span>
|
||||
<span class="s2">"this"</span><span class="p">,</span> <span class="s2">"null"</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-44"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-44">#</a> </div> <p>CoffeeScript-only keywords, which we're more relaxed about allowing. They can't
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-42"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-42">#</a> </div> <p>CoffeeScript-only keywords, which we're more relaxed about allowing. They can't
|
||||
be used standalone, but you can reference them as an attached property.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">COFFEE_ALIASES: </span> <span class="p">[</span><span class="s2">"and"</span><span class="p">,</span> <span class="s2">"or"</span><span class="p">,</span> <span class="s2">"is"</span><span class="p">,</span> <span class="s2">"isnt"</span><span class="p">,</span> <span class="s2">"not"</span><span class="p">]</span>
|
||||
<span class="nv">COFFEE_KEYWORDS: </span><span class="nx">COFFEE_ALIASES</span><span class="p">.</span><span class="nx">concat</span> <span class="p">[</span>
|
||||
<span class="s2">"then"</span><span class="p">,</span> <span class="s2">"unless"</span><span class="p">,</span>
|
||||
<span class="s2">"then"</span><span class="p">,</span> <span class="s2">"unless"</span><span class="p">,</span> <span class="s2">"until"</span><span class="p">,</span> <span class="s2">"loop"</span><span class="p">,</span>
|
||||
<span class="s2">"yes"</span><span class="p">,</span> <span class="s2">"no"</span><span class="p">,</span> <span class="s2">"on"</span><span class="p">,</span> <span class="s2">"off"</span><span class="p">,</span>
|
||||
<span class="s2">"of"</span><span class="p">,</span> <span class="s2">"by"</span><span class="p">,</span> <span class="s2">"where"</span><span class="p">,</span> <span class="s2">"when"</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-45"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-45">#</a> </div> <p>The combined list of keywords is the superset that gets passed verbatim to
|
||||
the parser.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">KEYWORDS: </span><span class="nx">JS_KEYWORDS</span><span class="p">.</span><span class="nx">concat</span> <span class="nx">COFFEE_KEYWORDS</span></pre></div> </td> </tr> <tr id="section-46"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-46">#</a> </div> <p>The list of keywords that are reserved by JavaScript, but not used, or are
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-43"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-43">#</a> </div> <p>The list of keywords that are reserved by JavaScript, but not used, or are
|
||||
used by CoffeeScript internally. We throw an error when these are encountered,
|
||||
to avoid having a JavaScript error at runtime.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">RESERVED: </span><span class="p">[</span>
|
||||
<span class="s2">"case"</span><span class="p">,</span> <span class="s2">"default"</span><span class="p">,</span> <span class="s2">"do"</span><span class="p">,</span> <span class="s2">"function"</span><span class="p">,</span> <span class="s2">"var"</span><span class="p">,</span> <span class="s2">"void"</span><span class="p">,</span> <span class="s2">"with"</span>
|
||||
<span class="s2">"const"</span><span class="p">,</span> <span class="s2">"let"</span><span class="p">,</span> <span class="s2">"debugger"</span><span class="p">,</span> <span class="s2">"enum"</span><span class="p">,</span> <span class="s2">"export"</span><span class="p">,</span> <span class="s2">"import"</span><span class="p">,</span> <span class="s2">"native"</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-47"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-47">#</a> </div> <p>The superset of both JavaScript keywords and reserved words, none of which may
|
||||
be used as identifiers or properties.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">JS_FORBIDDEN: </span><span class="nx">JS_KEYWORDS</span><span class="p">.</span><span class="nx">concat</span> <span class="nx">RESERVED</span></pre></div> </td> </tr> <tr id="section-48"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-48">#</a> </div> <p>Token matching regexes.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">IDENTIFIER : </span><span class="sr">/^([a-zA-Z\$_](\w|\$)*)/</span>
|
||||
<span class="nv">NUMBER : </span><span class="sr">/^(\b((0(x|X)[0-9a-fA-F]+)|([0-9]+(\.[0-9]+)?(e[+\-]?[0-9]+)?)))\b/i</span>
|
||||
<span class="s2">"const"</span><span class="p">,</span> <span class="s2">"let"</span><span class="p">,</span> <span class="s2">"enum"</span><span class="p">,</span> <span class="s2">"export"</span><span class="p">,</span> <span class="s2">"import"</span><span class="p">,</span> <span class="s2">"native"</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-44"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-44">#</a> </div> <p>The superset of both JavaScript keywords and reserved words, none of which may
|
||||
be used as identifiers or properties.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">JS_FORBIDDEN: </span><span class="nx">JS_KEYWORDS</span><span class="p">.</span><span class="nx">concat</span> <span class="nx">RESERVED</span></pre></div> </td> </tr> <tr id="section-45"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-45">#</a> </div> <p>Token matching regexes.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">IDENTIFIER : </span><span class="sr">/^([a-zA-Z\$_](\w|\$)*)/</span>
|
||||
<span class="nv">NUMBER : </span><span class="sr">/^(((\b0(x|X)[0-9a-fA-F]+)|((\b[0-9]+(\.[0-9]+)?|\.[0-9]+)(e[+\-]?[0-9]+)?)))\b/i</span>
|
||||
<span class="nv">HEREDOC : </span><span class="sr">/^("{6}|'{6}|"{3}\n?([\s\S]*?)\n?([ \t]*)"{3}|'{3}\n?([\s\S]*?)\n?([ \t]*)'{3})/</span>
|
||||
<span class="nv">INTERPOLATION : </span><span class="sr">/^\$([a-zA-Z_@]\w*(\.\w+)*)/</span>
|
||||
<span class="nv">OPERATOR : </span><span class="sr">/^([+\*&|\/\-%=<>:!?]+)([ \t]*)/</span>
|
||||
<span class="nv">OPERATOR : </span><span class="sr">/^(-[\-=>]?|\+[+=]?|[*&|\/%=<>:!?]+)([ \t]*)/</span>
|
||||
<span class="nv">WHITESPACE : </span><span class="sr">/^([ \t]+)/</span>
|
||||
<span class="nv">COMMENT : </span><span class="sr">/^(((\n?[ \t]*)?#[^\n]*)+)/</span>
|
||||
<span class="nv">COMMENT : </span><span class="sr">/^(\s*#{3}(?!#)[ \t]*\n+([\s\S]*?)[ \t]*\n+[ \t]*#{3}|(\s*#(?!##[^#])[^\n]*)+)/</span>
|
||||
<span class="nv">CODE : </span><span class="sr">/^((-|=)>)/</span>
|
||||
<span class="nv">MULTI_DENT : </span><span class="sr">/^((\n([ \t]*))+)(\.)?/</span>
|
||||
<span class="nv">LAST_DENTS : </span><span class="sr">/\n([ \t]*)/g</span>
|
||||
<span class="nv">LAST_DENT : </span><span class="sr">/\n([ \t]*)/</span>
|
||||
<span class="nv">ASSIGNMENT : </span><span class="sr">/^(:|=)$/</span></pre></div> </td> </tr> <tr id="section-49"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-49">#</a> </div> <p>Regex-matching-regexes.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">REGEX_START : </span><span class="sr">/^\/[^\/ ]/</span>
|
||||
<span class="nv">ASSIGNMENT : </span><span class="sr">/^[:=]$/</span></pre></div> </td> </tr> <tr id="section-46"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-46">#</a> </div> <p>Regex-matching-regexes.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">REGEX_START : </span><span class="sr">/^\/[^\/ ]/</span>
|
||||
<span class="nv">REGEX_INTERPOLATION: </span><span class="sr">/([^\\]\$[a-zA-Z_@]|[^\\]\$\{.*[^\\]\})/</span>
|
||||
<span class="nv">REGEX_FLAGS : </span><span class="sr">/^[imgy]{0,4}/</span>
|
||||
<span class="nv">REGEX_ESCAPE : </span><span class="sr">/\\[^\$]/g</span></pre></div> </td> </tr> <tr id="section-50"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-50">#</a> </div> <p>Token cleaning regexes.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">JS_CLEANER : </span><span class="sr">/(^`|`$)/g</span>
|
||||
<span class="nv">REGEX_END : </span><span class="sr">/^(([imgy]{1,4})\b|\W|$)/</span>
|
||||
<span class="nv">REGEX_ESCAPE : </span><span class="sr">/\\[^\$]/g</span></pre></div> </td> </tr> <tr id="section-47"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-47">#</a> </div> <p>Token cleaning regexes.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">JS_CLEANER : </span><span class="sr">/(^`|`$)/g</span>
|
||||
<span class="nv">MULTILINER : </span><span class="sr">/\n/g</span>
|
||||
<span class="nv">STRING_NEWLINES : </span><span class="sr">/\n[ \t]*/g</span>
|
||||
<span class="nv">COMMENT_CLEANER : </span><span class="sr">/(^[ \t]*#|\n[ \t]*$)/mg</span>
|
||||
<span class="nv">NO_NEWLINE : </span><span class="sr">/^([+\*&|\/\-%=<>:!.\\][<>=&|]*|and|or|is|isnt|not|delete|typeof|instanceof)$/</span>
|
||||
<span class="nv">HEREDOC_INDENT : </span><span class="sr">/^[ \t]+/mg</span></pre></div> </td> </tr> <tr id="section-51"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-51">#</a> </div> <p>Tokens which a regular expression will never immediately follow, but which
|
||||
<span class="nv">HEREDOC_INDENT : </span><span class="sr">/(\n+([ \t]*)|^([ \t]+))/g</span>
|
||||
<span class="nv">ASSIGNED : </span><span class="sr">/^([a-zA-Z\$_]\w*[ \t]*?[:=][^=])/</span>
|
||||
<span class="nv">NEXT_CHARACTER : </span><span class="sr">/^\s*(\S)/</span></pre></div> </td> </tr> <tr id="section-48"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-48">#</a> </div> <p>Tokens which a regular expression will never immediately follow, but which
|
||||
a division operator might.</p>
|
||||
|
||||
<p>See: <a href='http://www.mozilla.org/js/language/js20-2002-04/rationale/syntax.html#regular-expressions'>http://www.mozilla.org/js/language/js20-2002-04/rationale/syntax.html#regular-expressions</a></p>
|
||||
<p>See: http://www.mozilla.org/js/language/js20-2002-04/rationale/syntax.html#regular-expressions</p>
|
||||
|
||||
<p>Our list is shorter, due to sans-parentheses method calls.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">NOT_REGEX: </span><span class="p">[</span>
|
||||
<span class="s1">'NUMBER'</span><span class="p">,</span> <span class="s1">'REGEX'</span><span class="p">,</span> <span class="s1">'++'</span><span class="p">,</span> <span class="s1">'--'</span><span class="p">,</span> <span class="s1">'FALSE'</span><span class="p">,</span> <span class="s1">'NULL'</span><span class="p">,</span> <span class="s1">'TRUE'</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-52"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-52">#</a> </div> <p>Tokens which could legitimately be invoked or indexed. A opening
|
||||
<span class="s1">'NUMBER'</span><span class="p">,</span> <span class="s1">'REGEX'</span><span class="p">,</span> <span class="s1">'++'</span><span class="p">,</span> <span class="s1">'--'</span><span class="p">,</span> <span class="s1">'FALSE'</span><span class="p">,</span> <span class="s1">'NULL'</span><span class="p">,</span> <span class="s1">'TRUE'</span><span class="p">,</span> <span class="s1">']'</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-49"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-49">#</a> </div> <p>Tokens which could legitimately be invoked or indexed. A opening
|
||||
parentheses or bracket following these tokens will be recorded as the start
|
||||
of a function invocation or indexing operation.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">CALLABLE: </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">']'</span><span class="p">,</span> <span class="s1">'}'</span><span class="p">,</span> <span class="s1">'STRING'</span><span class="p">,</span> <span class="s1">'@'</span><span class="p">,</span> <span class="s1">'THIS'</span><span class="p">]</span></pre></div> </td> </tr> <tr id="section-53"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-53">#</a> </div> <p>Tokens that indicate an access -- keywords immediately following will be
|
||||
treated as identifiers.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">ACCESSORS: </span><span class="p">[</span><span class="s1">'PROPERTY_ACCESS'</span><span class="p">,</span> <span class="s1">'PROTOTYPE_ACCESS'</span><span class="p">,</span> <span class="s1">'SOAK_ACCESS'</span><span class="p">,</span> <span class="s1">'@'</span><span class="p">]</span></pre></div> </td> </tr> <tr id="section-54"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-54">#</a> </div> <p>Tokens that, when immediately preceding a <code>WHEN</code>, indicate that the <code>WHEN</code>
|
||||
of a function invocation or indexing operation.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">CALLABLE: </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">']'</span><span class="p">,</span> <span class="s1">'}'</span><span class="p">,</span> <span class="s1">'STRING'</span><span class="p">,</span> <span class="s1">'@'</span><span class="p">,</span> <span class="s1">'THIS'</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-50"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-50">#</a> </div> <p>Tokens that, when immediately preceding a <code>WHEN</code>, indicate that the <code>WHEN</code>
|
||||
occurs at the start of a line. We disambiguate these from trailing whens to
|
||||
avoid an ambiguity in the grammar.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">LINE_BREAK: </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="s1">'TERMINATOR'</span><span class="p">]</span></pre></div> </td> </tr> <tr id="section-55"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-55">#</a> </div> <p>Half-assignments...</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">HALF_ASSIGNMENTS: </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="s1">'?'</span><span class="p">]</span></pre></div> </td> </tr> <tr id="section-56"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-56">#</a> </div> <p>Conversions from CoffeeScript operators into JavaScript ones.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">CONVERSIONS: </span><span class="p">{</span>
|
||||
avoid an ambiguity in the grammar.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">LINE_BREAK: </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="s1">'TERMINATOR'</span><span class="p">]</span></pre></div> </td> </tr> <tr id="section-51"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-51">#</a> </div> <p>Half-assignments...</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">HALF_ASSIGNMENTS: </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="s1">'?'</span><span class="p">,</span> <span class="s1">'OP?'</span><span class="p">]</span></pre></div> </td> </tr> <tr id="section-52"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-52">#</a> </div> <p>Conversions from CoffeeScript operators into JavaScript ones.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">CONVERSIONS: </span><span class="p">{</span>
|
||||
<span class="s1">'and'</span><span class="o">:</span> <span class="s1">'&&'</span>
|
||||
<span class="s1">'or'</span><span class="o">:</span> <span class="s1">'||'</span>
|
||||
<span class="s1">'is'</span><span class="o">:</span> <span class="s1">'=='</span>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,60 +1,65 @@
|
||||
<!DOCTYPE html> <html> <head> <title>optparse.coffee</title> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <link rel="stylesheet" media="all" href="docco.css" /> </head> <body> <div id="container"> <div id="background"></div> <div id="jump_to"> Jump To … <div id="jump_wrapper"> <div id="jump_page"> <a class="source" href="cake.html"> cake.coffee </a> <a class="source" href="coffee-script.html"> coffee-script.coffee </a> <a class="source" href="command.html"> command.coffee </a> <a class="source" href="grammar.html"> grammar.coffee </a> <a class="source" href="helpers.html"> helpers.coffee </a> <a class="source" href="lexer.html"> lexer.coffee </a> <a class="source" href="nodes.html"> nodes.coffee </a> <a class="source" href="optparse.html"> optparse.coffee </a> <a class="source" href="repl.html"> repl.coffee </a> <a class="source" href="rewriter.html"> rewriter.coffee </a> <a class="source" href="scope.html"> scope.coffee </a> </div> </div> </div> <table cellpadding="0" cellspacing="0"> <thead> <tr> <th class="docs"> <h1> optparse.coffee </h1> </th> <th class="code"> </th> </tr> </thead> <tbody> <tr id="section-1"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-1">#</a> </div> <p>A simple <strong>OptionParser</strong> class to parse option flags from the command-line.
|
||||
<!DOCTYPE html> <html> <head> <title>optparse.coffee</title> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <link rel="stylesheet" media="all" href="docco.css" /> </head> <body> <div id="container"> <div id="background"></div> <div id="jump_to"> Jump To … <div id="jump_wrapper"> <div id="jump_page"> <a class="source" href="cake.html"> cake.coffee </a> <a class="source" href="coffee-script.html"> coffee-script.coffee </a> <a class="source" href="command.html"> command.coffee </a> <a class="source" href="grammar.html"> grammar.coffee </a> <a class="source" href="helpers.html"> helpers.coffee </a> <a class="source" href="index.html"> index.coffee </a> <a class="source" href="lexer.html"> lexer.coffee </a> <a class="source" href="nodes.html"> nodes.coffee </a> <a class="source" href="optparse.html"> optparse.coffee </a> <a class="source" href="repl.html"> repl.coffee </a> <a class="source" href="rewriter.html"> rewriter.coffee </a> <a class="source" href="scope.html"> scope.coffee </a> </div> </div> </div> <table cellpadding="0" cellspacing="0"> <thead> <tr> <th class="docs"> <h1> optparse.coffee </h1> </th> <th class="code"> </th> </tr> </thead> <tbody> <tr id="section-1"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-1">#</a> </div> <p>A simple <strong>OptionParser</strong> class to parse option flags from the command-line.
|
||||
Use it like so:</p>
|
||||
|
||||
<pre><code>parser: new OptionParser switches, help_banner
|
||||
<pre><code>parser: new OptionParser switches, helpBanner
|
||||
options: parser.parse process.argv
|
||||
</code></pre> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.OptionParser: </span><span class="nx">class</span> <span class="nx">OptionParser</span></pre></div> </td> </tr> <tr id="section-2"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-2">#</a> </div> <p>Initialize with a list of valid options, in the form:</p>
|
||||
</code></pre>
|
||||
|
||||
<p>The first non-option is considered to be the start of the file (and file
|
||||
option) list, and all subsequent arguments are left unparsed.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.OptionParser: </span><span class="nx">class</span> <span class="nx">OptionParser</span></pre></div> </td> </tr> <tr id="section-2"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-2">#</a> </div> <p>Initialize with a list of valid options, in the form:</p>
|
||||
|
||||
<pre><code>[short-flag, long-flag, description]
|
||||
</code></pre>
|
||||
|
||||
<p>Along with an an optional banner for the usage help.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">constructor: </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">@banner: </span> <span class="nx">banner</span>
|
||||
<span class="vi">@rules: </span> <span class="nx">build_rules</span><span class="p">(</span><span class="nx">rules</span><span class="p">)</span></pre></div> </td> </tr> <tr id="section-3"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-3">#</a> </div> <p>Parse the list of arguments, populating an <code>options</code> object with all of the
|
||||
<span class="vi">@rules: </span> <span class="nx">buildRules</span><span class="p">(</span><span class="nx">rules</span><span class="p">)</span></pre></div> </td> </tr> <tr id="section-3"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-3">#</a> </div> <p>Parse the list of arguments, populating an <code>options</code> object with all of the
|
||||
specified options, and returning it. <code>options.arguments</code> will be an array
|
||||
containing the remaning non-option arguments. This is a simpler API than
|
||||
many option parsers that allow you to attach callback actions for every
|
||||
flag. Instead, you're responsible for interpreting the options object.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">parse: </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="p">{</span><span class="nv">arguments: </span><span class="p">[]}</span>
|
||||
<span class="nv">args: </span><span class="nx">normalize_arguments</span> <span class="nx">args</span>
|
||||
<span class="k">while</span> <span class="p">(</span><span class="nv">arg: </span><span class="nx">args</span><span class="p">.</span><span class="nx">shift</span><span class="p">())</span>
|
||||
<span class="nv">is_option: </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">matched_rule: </span><span class="kc">no</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="nv">isOption: </span><span class="o">!!</span><span class="p">(</span><span class="nx">arg</span><span class="p">.</span><span class="nx">match</span><span class="p">(</span><span class="nx">LONG_FLAG</span><span class="p">)</span> <span class="o">or</span> <span class="nx">arg</span><span class="p">.</span><span class="nx">match</span><span class="p">(</span><span class="nx">SHORT_FLAG</span><span class="p">))</span>
|
||||
<span class="nv">matchedRule: </span><span class="kc">no</span>
|
||||
<span class="k">for</span> <span class="nx">rule</span> <span class="k">in</span> <span class="nx">@rules</span>
|
||||
<span class="k">if</span> <span class="nx">rule</span><span class="p">.</span><span class="nx">short_flag</span> <span class="o">is</span> <span class="nx">arg</span> <span class="o">or</span> <span class="nx">rule</span><span class="p">.</span><span class="nx">long_flag</span> <span class="o">is</span> <span class="nx">arg</span>
|
||||
<span class="nx">options</span><span class="p">[</span><span class="nx">rule</span><span class="p">.</span><span class="nx">name</span><span class="p">]</span><span class="o">:</span> <span class="k">if</span> <span class="nx">rule</span><span class="p">.</span><span class="nx">has_argument</span> <span class="k">then</span> <span class="nx">args</span><span class="p">.</span><span class="nx">shift</span><span class="p">()</span> <span class="k">else</span> <span class="kc">true</span>
|
||||
<span class="nv">matched_rule: </span><span class="kc">yes</span>
|
||||
<span class="k">if</span> <span class="nx">rule</span><span class="p">.</span><span class="nx">shortFlag</span> <span class="o">is</span> <span class="nx">arg</span> <span class="o">or</span> <span class="nx">rule</span><span class="p">.</span><span class="nx">longFlag</span> <span class="o">is</span> <span class="nx">arg</span>
|
||||
<span class="nx">options</span><span class="p">[</span><span class="nx">rule</span><span class="p">.</span><span class="nx">name</span><span class="p">]</span><span class="o">:</span> <span class="k">if</span> <span class="nx">rule</span><span class="p">.</span><span class="nx">hasArgument</span> <span class="k">then</span> <span class="nx">args</span><span class="p">[</span><span class="nv">i: </span><span class="o">+</span> <span class="mi">1</span><span class="p">]</span> <span class="k">else</span> <span class="kc">true</span>
|
||||
<span class="nv">matchedRule: </span><span class="kc">yes</span>
|
||||
<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">is_option</span> <span class="o">and</span> <span class="o">not</span> <span class="nx">matched_rule</span>
|
||||
<span class="nx">options</span><span class="p">.</span><span class="nx">arguments</span><span class="p">.</span><span class="nx">push</span> <span class="nx">arg</span> <span class="nx">unless</span> <span class="nx">is_option</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">i</span><span class="p">...</span><span class="nx">args</span><span class="p">.</span><span class="nx">length</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="octowrap"> <a class="octothorpe" 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="nv">help: </span><span class="o">-></span>
|
||||
<span class="nv">lines: </span><span class="p">[</span><span class="s1">'Available options:'</span><span class="p">]</span>
|
||||
<span class="nx">lines</span><span class="p">.</span><span class="nx">unshift</span> <span class="s2">"$@banner\n"</span> <span class="k">if</span> <span class="nx">@banner</span>
|
||||
<span class="k">for</span> <span class="nx">rule</span> <span class="k">in</span> <span class="nx">@rules</span>
|
||||
<span class="nv">spaces: </span> <span class="mi">15</span> <span class="o">-</span> <span class="nx">rule</span><span class="p">.</span><span class="nx">long_flag</span><span class="p">.</span><span class="nx">length</span>
|
||||
<span class="nv">spaces: </span> <span class="mi">15</span> <span class="o">-</span> <span class="nx">rule</span><span class="p">.</span><span class="nx">longFlag</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="p">(</span><span class="s1">' '</span> <span class="k">for</span> <span class="nx">i</span> <span class="k">in</span> <span class="p">[</span><span class="mi">0</span><span class="p">..</span><span class="nx">spaces</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">let_part: </span><span class="k">if</span> <span class="nx">rule</span><span class="p">.</span><span class="nx">short_flag</span> <span class="k">then</span> <span class="nx">rule</span><span class="p">.</span><span class="nx">short_flag</span> <span class="o">+</span> <span class="s1">', '</span> <span class="k">else</span> <span class="s1">' '</span>
|
||||
<span class="nx">lines</span><span class="p">.</span><span class="nx">push</span> <span class="s2">" $let_part${rule.long_flag}$spaces${rule.description}"</span>
|
||||
<span class="nv">letPart: </span><span class="k">if</span> <span class="nx">rule</span><span class="p">.</span><span class="nx">shortFlag</span> <span class="k">then</span> <span class="nx">rule</span><span class="p">.</span><span class="nx">shortFlag</span> <span class="o">+</span> <span class="s1">', '</span> <span class="k">else</span> <span class="s1">' '</span>
|
||||
<span class="nx">lines</span><span class="p">.</span><span class="nx">push</span> <span class="s2">" $letPart$rule.longFlag$spaces$rule.description"</span>
|
||||
<span class="s2">"\n${ lines.join('\n') }\n"</span></pre></div> </td> </tr> <tr id="section-5"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-5">#</a> </div> <h2>Helpers</h2> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-6"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-6">#</a> </div> <p>Regex matchers for option flags.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">LONG_FLAG: </span> <span class="sr">/^(--\w[\w\-]+)/</span>
|
||||
<span class="nv">SHORT_FLAG: </span><span class="sr">/^(-\w)/</span>
|
||||
<span class="nv">MULTI_FLAG: </span><span class="sr">/^-(\w{2,})/</span>
|
||||
<span class="nv">OPTIONAL: </span> <span class="sr">/\[(.+)\]/</span></pre></div> </td> </tr> <tr id="section-7"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-7">#</a> </div> <p>Build and return the list of option rules. If the optional <em>short-flag</em> is
|
||||
unspecified, leave it out by padding with <code>null</code>.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">build_rules: </span><span class="p">(</span><span class="nx">rules</span><span class="p">)</span> <span class="o">-></span>
|
||||
unspecified, leave it out by padding with <code>null</code>.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">buildRules: </span><span class="p">(</span><span class="nx">rules</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="k">for</span> <span class="nx">tuple</span> <span class="k">in</span> <span class="nx">rules</span>
|
||||
<span class="nx">tuple</span><span class="p">.</span><span class="nx">unshift</span> <span class="kc">null</span> <span class="k">if</span> <span class="nx">tuple</span><span class="p">.</span><span class="nx">length</span> <span class="o"><</span> <span class="mi">3</span>
|
||||
<span class="nx">build_rule</span> <span class="nx">tuple</span><span class="p">...</span></pre></div> </td> </tr> <tr id="section-8"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-8">#</a> </div> <p>Build a rule from a <code>-o</code> short flag, a <code>--output [DIR]</code> long flag, and the
|
||||
description of what the option does.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">build_rule: </span><span class="p">(</span><span class="nx">short_flag</span><span class="p">,</span> <span class="nx">long_flag</span><span class="p">,</span> <span class="nx">description</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nv">match: </span> <span class="nx">long_flag</span><span class="p">.</span><span class="nx">match</span><span class="p">(</span><span class="nx">OPTIONAL</span><span class="p">)</span>
|
||||
<span class="nv">long_flag: </span> <span class="nx">long_flag</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="mi">1</span><span class="p">]</span>
|
||||
<span class="nx">buildRule</span> <span class="nx">tuple</span><span class="p">...</span></pre></div> </td> </tr> <tr id="section-8"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-8">#</a> </div> <p>Build a rule from a <code>-o</code> short flag, a <code>--output [DIR]</code> long flag, and the
|
||||
description of what the option does.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">buildRule: </span><span class="p">(</span><span class="nx">shortFlag</span><span class="p">,</span> <span class="nx">longFlag</span><span class="p">,</span> <span class="nx">description</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nv">match: </span> <span class="nx">longFlag</span><span class="p">.</span><span class="nx">match</span><span class="p">(</span><span class="nx">OPTIONAL</span><span class="p">)</span>
|
||||
<span class="nv">longFlag: </span> <span class="nx">longFlag</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="mi">1</span><span class="p">]</span>
|
||||
<span class="p">{</span>
|
||||
<span class="nv">name: </span> <span class="nx">long_flag</span><span class="p">.</span><span class="nx">substr</span> <span class="mi">2</span>
|
||||
<span class="nv">short_flag: </span> <span class="nx">short_flag</span>
|
||||
<span class="nv">long_flag: </span> <span class="nx">long_flag</span>
|
||||
<span class="nv">name: </span> <span class="nx">longFlag</span><span class="p">.</span><span class="nx">substr</span> <span class="mi">2</span>
|
||||
<span class="nv">shortFlag: </span> <span class="nx">shortFlag</span>
|
||||
<span class="nv">longFlag: </span> <span class="nx">longFlag</span>
|
||||
<span class="nv">description: </span> <span class="nx">description</span>
|
||||
<span class="nv">has_argument: </span><span class="o">!!</span><span class="p">(</span><span class="nx">match</span> <span class="o">and</span> <span class="nx">match</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span>
|
||||
<span class="nv">hasArgument: </span><span class="o">!!</span><span class="p">(</span><span class="nx">match</span> <span class="o">and</span> <span class="nx">match</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span>
|
||||
<span class="p">}</span></pre></div> </td> </tr> <tr id="section-9"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-9">#</a> </div> <p>Normalize arguments by expanding merged flags into multiple flags. This allows
|
||||
you to have <code>-wl</code> be the same as <code>--watch --lint</code>.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">normalize_arguments: </span><span class="p">(</span><span class="nx">args</span><span class="p">)</span> <span class="o">-></span>
|
||||
you to have <code>-wl</code> be the same as <code>--watch --lint</code>.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">normalizeArguments: </span><span class="p">(</span><span class="nx">args</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nv">args: </span><span class="nx">args</span><span class="p">.</span><span class="nx">slice</span> <span class="mi">0</span>
|
||||
<span class="nv">result: </span><span class="p">[]</span>
|
||||
<span class="k">for</span> <span class="nx">arg</span> <span class="k">in</span> <span class="nx">args</span>
|
||||
|
||||
@@ -1,21 +1,25 @@
|
||||
<!DOCTYPE html> <html> <head> <title>repl.coffee</title> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <link rel="stylesheet" media="all" href="docco.css" /> </head> <body> <div id="container"> <div id="background"></div> <div id="jump_to"> Jump To … <div id="jump_wrapper"> <div id="jump_page"> <a class="source" href="cake.html"> cake.coffee </a> <a class="source" href="coffee-script.html"> coffee-script.coffee </a> <a class="source" href="command.html"> command.coffee </a> <a class="source" href="grammar.html"> grammar.coffee </a> <a class="source" href="helpers.html"> helpers.coffee </a> <a class="source" href="lexer.html"> lexer.coffee </a> <a class="source" href="nodes.html"> nodes.coffee </a> <a class="source" href="optparse.html"> optparse.coffee </a> <a class="source" href="repl.html"> repl.coffee </a> <a class="source" href="rewriter.html"> rewriter.coffee </a> <a class="source" href="scope.html"> scope.coffee </a> </div> </div> </div> <table cellpadding="0" cellspacing="0"> <thead> <tr> <th class="docs"> <h1> repl.coffee </h1> </th> <th class="code"> </th> </tr> </thead> <tbody> <tr id="section-1"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-1">#</a> </div> <p>A very simple Read-Eval-Print-Loop. Compiles one line at a time to JavaScript
|
||||
<!DOCTYPE html> <html> <head> <title>repl.coffee</title> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <link rel="stylesheet" media="all" href="docco.css" /> </head> <body> <div id="container"> <div id="background"></div> <div id="jump_to"> Jump To … <div id="jump_wrapper"> <div id="jump_page"> <a class="source" href="cake.html"> cake.coffee </a> <a class="source" href="coffee-script.html"> coffee-script.coffee </a> <a class="source" href="command.html"> command.coffee </a> <a class="source" href="grammar.html"> grammar.coffee </a> <a class="source" href="helpers.html"> helpers.coffee </a> <a class="source" href="index.html"> index.coffee </a> <a class="source" href="lexer.html"> lexer.coffee </a> <a class="source" href="nodes.html"> nodes.coffee </a> <a class="source" href="optparse.html"> optparse.coffee </a> <a class="source" href="repl.html"> repl.coffee </a> <a class="source" href="rewriter.html"> rewriter.coffee </a> <a class="source" href="scope.html"> scope.coffee </a> </div> </div> </div> <table cellpadding="0" cellspacing="0"> <thead> <tr> <th class="docs"> <h1> repl.coffee </h1> </th> <th class="code"> </th> </tr> </thead> <tbody> <tr id="section-1"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-1">#</a> </div> <p>A very simple Read-Eval-Print-Loop. Compiles one line at a time to JavaScript
|
||||
and evaluates it. Good for simple tests, or poking around the <strong>Node.js</strong> API.
|
||||
Using it looks like this:</p>
|
||||
|
||||
<pre><code>coffee> puts "$num bottles of beer" for num in [99..1]
|
||||
</code></pre> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-2"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-2">#</a> </div> <p>Require the <strong>coffee-script</strong> module to get access to the compiler.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">CoffeeScript: </span><span class="nx">require</span> <span class="s1">'./coffee-script'</span>
|
||||
<span class="nv">helpers: </span> <span class="nx">require</span><span class="p">(</span><span class="s1">'./helpers'</span><span class="p">).</span><span class="nx">helpers</span></pre></div> </td> </tr> <tr id="section-3"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-3">#</a> </div> <p>Our prompt.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">prompt: </span><span class="s1">'coffee> '</span></pre></div> </td> </tr> <tr id="section-4"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-4">#</a> </div> <p>Quick alias for quitting the REPL.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nx">helpers</span><span class="p">.</span><span class="nx">extend</span> <span class="nx">global</span><span class="p">,</span> <span class="p">{</span>
|
||||
<span class="nv">helpers: </span> <span class="nx">require</span><span class="p">(</span><span class="s1">'./helpers'</span><span class="p">).</span><span class="nx">helpers</span>
|
||||
<span class="nv">readline: </span> <span class="nx">require</span> <span class="s1">'readline'</span></pre></div> </td> </tr> <tr id="section-3"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-3">#</a> </div> <p>Start by opening up <strong>stdio</strong>.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">stdio: </span><span class="nx">process</span><span class="p">.</span><span class="nx">openStdin</span><span class="p">()</span></pre></div> </td> </tr> <tr id="section-4"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-4">#</a> </div> <p>Quick alias for quitting the REPL.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nx">helpers</span><span class="p">.</span><span class="nx">extend</span> <span class="nx">global</span><span class="p">,</span> <span class="p">{</span>
|
||||
<span class="nv">quit: </span><span class="o">-></span> <span class="nx">process</span><span class="p">.</span><span class="nx">exit</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
|
||||
<span class="p">}</span></pre></div> </td> </tr> <tr id="section-5"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-5">#</a> </div> <p>The main REPL function. <strong>run</strong> is called every time a line of code is entered.
|
||||
Attempt to evaluate the command. If there's an exception, print it out instead
|
||||
of exiting.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">run: </span><span class="p">(</span><span class="nx">code</span><span class="p">)</span> <span class="o">-></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">try</span>
|
||||
<span class="nv">val: </span><span class="nx">CoffeeScript</span><span class="p">.</span><span class="nx">run</span> <span class="nx">code</span><span class="p">,</span> <span class="p">{</span><span class="nv">no_wrap: </span><span class="kc">true</span><span class="p">,</span> <span class="nv">globals: </span><span class="kc">true</span><span class="p">,</span> <span class="nv">source: </span><span class="s1">'repl'</span><span class="p">}</span>
|
||||
<span class="nx">p</span> <span class="nx">val</span> <span class="k">if</span> <span class="nx">val</span> <span class="o">isnt</span> <span class="kc">undefined</span>
|
||||
<span class="nv">val: </span><span class="nx">CoffeeScript</span><span class="p">.</span><span class="nx">run</span> <span class="nx">buffer</span><span class="p">.</span><span class="nx">toString</span><span class="p">(),</span> <span class="p">{</span><span class="nv">noWrap: </span><span class="kc">true</span><span class="p">,</span> <span class="nv">globals: </span><span class="kc">true</span><span class="p">,</span> <span class="nv">source: </span><span class="s1">'repl'</span><span class="p">}</span>
|
||||
<span class="nx">puts</span> <span class="nx">inspect</span> <span class="nx">val</span> <span class="k">if</span> <span class="nx">val</span> <span class="o">isnt</span> <span class="kc">undefined</span>
|
||||
<span class="k">catch</span> <span class="nx">err</span>
|
||||
<span class="nx">puts</span> <span class="nx">err</span><span class="p">.</span><span class="nx">stack</span> <span class="o">or</span> <span class="nx">err</span><span class="p">.</span><span class="nx">toString</span><span class="p">()</span>
|
||||
<span class="nx">print</span> <span class="nx">prompt</span></pre></div> </td> </tr> <tr id="section-6"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-6">#</a> </div> <p>Start up the REPL by opening <strong>stdio</strong> and listening for input.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nx">process</span><span class="p">.</span><span class="nx">stdio</span><span class="p">.</span><span class="nx">addListener</span> <span class="s1">'data'</span><span class="p">,</span> <span class="nx">run</span>
|
||||
<span class="nx">process</span><span class="p">.</span><span class="nx">stdio</span><span class="p">.</span><span class="nx">open</span><span class="p">()</span>
|
||||
<span class="nx">print</span> <span class="nx">prompt</span>
|
||||
<span class="nx">repl</span><span class="p">.</span><span class="nx">prompt</span><span class="p">()</span></pre></div> </td> </tr> <tr id="section-6"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-6">#</a> </div> <p>Create the REPL by listening to <strong>stdin</strong>.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">repl: </span><span class="nx">readline</span><span class="p">.</span><span class="nx">createInterface</span> <span class="nx">stdio</span>
|
||||
<span class="nx">repl</span><span class="p">.</span><span class="nx">setPrompt</span> <span class="s1">'coffee> '</span>
|
||||
<span class="nx">stdio</span><span class="p">.</span><span class="nx">addListener</span> <span class="s1">'data'</span><span class="p">,</span> <span class="p">(</span><span class="nx">buffer</span><span class="p">)</span> <span class="o">-></span> <span class="nx">repl</span><span class="p">.</span><span class="nx">write</span> <span class="nx">buffer</span>
|
||||
<span class="nx">repl</span><span class="p">.</span><span class="nx">addListener</span> <span class="s1">'close'</span><span class="p">,</span> <span class="o">-></span> <span class="nx">stdio</span><span class="p">.</span><span class="nx">destroy</span><span class="p">()</span>
|
||||
<span class="nx">repl</span><span class="p">.</span><span class="nx">addListener</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">prompt</span><span class="p">()</span>
|
||||
|
||||
</pre></div> </td> </tr> </tbody> </table> </div> </body> </html>
|
||||
@@ -1,63 +1,68 @@
|
||||
<!DOCTYPE html> <html> <head> <title>rewriter.coffee</title> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <link rel="stylesheet" media="all" href="docco.css" /> </head> <body> <div id="container"> <div id="background"></div> <div id="jump_to"> Jump To … <div id="jump_wrapper"> <div id="jump_page"> <a class="source" href="cake.html"> cake.coffee </a> <a class="source" href="coffee-script.html"> coffee-script.coffee </a> <a class="source" href="command.html"> command.coffee </a> <a class="source" href="grammar.html"> grammar.coffee </a> <a class="source" href="helpers.html"> helpers.coffee </a> <a class="source" href="lexer.html"> lexer.coffee </a> <a class="source" href="nodes.html"> nodes.coffee </a> <a class="source" href="optparse.html"> optparse.coffee </a> <a class="source" href="repl.html"> repl.coffee </a> <a class="source" href="rewriter.html"> rewriter.coffee </a> <a class="source" href="scope.html"> scope.coffee </a> </div> </div> </div> <table cellpadding="0" cellspacing="0"> <thead> <tr> <th class="docs"> <h1> rewriter.coffee </h1> </th> <th class="code"> </th> </tr> </thead> <tbody> <tr id="section-1"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-1">#</a> </div> <p>The CoffeeScript language has a good deal of optional syntax, implicit syntax,
|
||||
<!DOCTYPE html> <html> <head> <title>rewriter.coffee</title> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <link rel="stylesheet" media="all" href="docco.css" /> </head> <body> <div id="container"> <div id="background"></div> <div id="jump_to"> Jump To … <div id="jump_wrapper"> <div id="jump_page"> <a class="source" href="cake.html"> cake.coffee </a> <a class="source" href="coffee-script.html"> coffee-script.coffee </a> <a class="source" href="command.html"> command.coffee </a> <a class="source" href="grammar.html"> grammar.coffee </a> <a class="source" href="helpers.html"> helpers.coffee </a> <a class="source" href="index.html"> index.coffee </a> <a class="source" href="lexer.html"> lexer.coffee </a> <a class="source" href="nodes.html"> nodes.coffee </a> <a class="source" href="optparse.html"> optparse.coffee </a> <a class="source" href="repl.html"> repl.coffee </a> <a class="source" href="rewriter.html"> rewriter.coffee </a> <a class="source" href="scope.html"> scope.coffee </a> </div> </div> </div> <table cellpadding="0" cellspacing="0"> <thead> <tr> <th class="docs"> <h1> rewriter.coffee </h1> </th> <th class="code"> </th> </tr> </thead> <tbody> <tr id="section-1"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-1">#</a> </div> <p>The CoffeeScript language has a good deal of optional syntax, implicit syntax,
|
||||
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="octowrap"> <a class="octothorpe" href="#section-2">#</a> </div> <p>Set up exported variables for both Node.js and the browser.</p> </td> <td class="code"> <div class="highlight"><pre><span class="k">if</span> <span class="nx">process</span><span class="o">?</span>
|
||||
<span class="nv">helpers: </span><span class="nx">require</span><span class="p">(</span><span class="s1">'./helpers'</span><span class="p">).</span><span class="nx">helpers</span>
|
||||
<span class="p">{</span><span class="nx">helpers</span><span class="p">}</span><span class="o">:</span> <span class="nx">require</span><span class="p">(</span><span class="s1">'./helpers'</span><span class="p">)</span>
|
||||
<span class="k">else</span>
|
||||
<span class="k">this</span><span class="p">.</span><span class="nv">exports: </span><span class="k">this</span>
|
||||
<span class="nv">helpers: </span> <span class="k">this</span><span class="p">.</span><span class="nx">helpers</span></pre></div> </td> </tr> <tr id="section-3"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-3">#</a> </div> <p>Import the helpers we need.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">include: </span><span class="nx">helpers</span><span class="p">.</span><span class="nx">include</span></pre></div> </td> </tr> <tr id="section-4"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-4">#</a> </div> <p>The <strong>Rewriter</strong> class is used by the <a href="lexer.html">Lexer</a>, directly against
|
||||
<span class="nv">helpers: </span> <span class="k">this</span><span class="p">.</span><span class="nx">helpers</span></pre></div> </td> </tr> <tr id="section-3"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-3">#</a> </div> <p>Import the helpers we need.</p> </td> <td class="code"> <div class="highlight"><pre><span class="p">{</span><span class="nx">include</span><span class="p">}</span><span class="o">:</span> <span class="nx">helpers</span></pre></div> </td> </tr> <tr id="section-4"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-4">#</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="nv">exports.Rewriter: </span><span class="nx">class</span> <span class="nx">Rewriter</span></pre></div> </td> </tr> <tr id="section-5"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-5">#</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
|
||||
stream, with a big ol' efficient switch, but it's much nicer to work with
|
||||
like this. The order of these passes matters -- indentation must be
|
||||
corrected before implicit parentheses can be wrapped around blocks of code.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">rewrite: </span><span class="p">(</span><span class="nx">tokens</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="vi">@tokens: </span><span class="nx">tokens</span>
|
||||
<span class="nx">@adjust_comments</span><span class="p">()</span>
|
||||
<span class="nx">@remove_leading_newlines</span><span class="p">()</span>
|
||||
<span class="nx">@remove_mid_expression_newlines</span><span class="p">()</span>
|
||||
<span class="nx">@close_open_calls_and_indexes</span><span class="p">()</span>
|
||||
<span class="nx">@add_implicit_indentation</span><span class="p">()</span>
|
||||
<span class="nx">@add_implicit_parentheses</span><span class="p">()</span>
|
||||
<span class="nx">@ensure_balance</span> <span class="nx">BALANCED_PAIRS</span>
|
||||
<span class="nx">@rewrite_closing_parens</span><span class="p">()</span>
|
||||
<span class="nx">@adjustComments</span><span class="p">()</span>
|
||||
<span class="nx">@removeLeadingNewlines</span><span class="p">()</span>
|
||||
<span class="nx">@removeMidExpressionNewlines</span><span class="p">()</span>
|
||||
<span class="nx">@closeOpenCallsAndIndexes</span><span class="p">()</span>
|
||||
<span class="nx">@addImplicitIndentation</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-6"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-6">#</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
|
||||
as tokens are inserted and removed, and the stream changes length under
|
||||
our feet.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">scan_tokens: </span><span class="p">(</span><span class="nx">block</span><span class="p">)</span> <span class="o">-></span>
|
||||
our feet.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">scanTokens: </span><span class="p">(</span><span class="nx">block</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nv">i: </span><span class="mi">0</span>
|
||||
<span class="k">while</span> <span class="kc">true</span>
|
||||
<span class="nx">loop</span>
|
||||
<span class="k">break</span> <span class="nx">unless</span> <span class="nx">@tokens</span><span class="p">[</span><span class="nx">i</span><span class="p">]</span>
|
||||
<span class="nv">move: </span><span class="nx">block</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">@tokens</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="nx">i</span> <span class="o">+</span> <span class="mi">1</span><span class="p">],</span> <span class="nx">i</span>
|
||||
<span class="nv">i: </span><span class="o">+</span> <span class="nx">move</span>
|
||||
<span class="kc">true</span></pre></div> </td> </tr> <tr id="section-7"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-7">#</a> </div> <p>Massage newlines and indentations so that comments don't have to be
|
||||
correctly indented, or appear on a line of their own.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">adjust_comments: </span><span class="o">-></span>
|
||||
<span class="nx">@scan_tokens</span> <span class="p">(</span><span class="nx">prev</span><span class="p">,</span> <span class="nx">token</span><span class="p">,</span> <span class="nx">post</span><span class="p">,</span> <span class="nx">i</span><span class="p">)</span> <span class="o">=></span>
|
||||
<span class="k">return</span> <span class="mi">1</span> <span class="nx">unless</span> <span class="nx">token</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">is</span> <span class="s1">'COMMENT'</span>
|
||||
<span class="nv">after: </span> <span class="nx">@tokens</span><span class="p">[</span><span class="nx">i</span> <span class="o">+</span> <span class="mi">2</span><span class="p">]</span>
|
||||
correctly indented, or appear on a line of their own.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">adjustComments: </span><span class="o">-></span>
|
||||
<span class="nx">@scanTokens</span> <span class="p">(</span><span class="nx">prev</span><span class="p">,</span> <span class="nx">token</span><span class="p">,</span> <span class="nx">post</span><span class="p">,</span> <span class="nx">i</span><span class="p">)</span> <span class="o">=></span>
|
||||
<span class="k">return</span> <span class="mi">1</span> <span class="nx">unless</span> <span class="nx">token</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">is</span> <span class="s1">'HERECOMMENT'</span>
|
||||
<span class="p">[</span><span class="nx">before</span><span class="p">,</span> <span class="nx">after</span><span class="p">]</span><span class="o">:</span> <span class="p">[</span><span class="nx">@tokens</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="nx">@tokens</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="k">if</span> <span class="nx">after</span> <span class="o">and</span> <span class="nx">after</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">is</span> <span class="s1">'INDENT'</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">2</span><span class="p">,</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">0</span><span class="p">,</span> <span class="nx">after</span>
|
||||
<span class="k">return</span> <span class="mi">1</span>
|
||||
<span class="k">else</span> <span class="k">if</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="o">isnt</span> <span class="s1">'TERMINATOR'</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="o">isnt</span> <span class="s1">'INDENT'</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="o">isnt</span> <span class="s1">'OUTDENT'</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">'TERMINATOR'</span><span class="p">,</span> <span class="s2">"\n"</span><span class="p">,</span> <span class="nx">prev</span><span class="p">[</span><span class="mi">2</span><span class="p">]]</span>
|
||||
<span class="k">if</span> <span class="nx">before</span> <span class="o">and</span> <span class="nx">before</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="o">and</span> <span class="nx">post</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="o">is</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">'TERMINATOR'</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">2</span><span class="p">,</span> <span class="mi">1</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">after</span>
|
||||
<span class="k">else</span> <span class="k">if</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="o">not</span> <span class="k">in</span> <span class="p">[</span><span class="s1">'TERMINATOR'</span><span class="p">,</span> <span class="s1">'INDENT'</span><span class="p">,</span> <span class="s1">'OUTDENT'</span><span class="p">]</span>
|
||||
<span class="k">if</span> <span class="nx">post</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">'TERMINATOR'</span> <span class="o">and</span> <span class="nx">after</span> <span class="o">and</span> <span class="nx">after</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="nx">@tokens</span><span class="p">.</span><span class="nx">splice</span><span class="p">(</span><span class="nx">i</span> <span class="o">+</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="nx">@tokens</span><span class="p">.</span><span class="nx">splice</span><span class="p">(</span><span class="nx">i</span><span class="p">,</span> <span class="mi">2</span><span class="p">)...)</span>
|
||||
<span class="nx">@tokens</span><span class="p">.</span><span class="nx">splice</span><span class="p">(</span><span class="nx">i</span> <span class="o">+</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="p">[</span><span class="s1">'TERMINATOR'</span><span class="p">,</span> <span class="s2">"\n"</span><span class="p">,</span> <span class="nx">prev</span><span class="p">[</span><span class="mi">2</span><span class="p">]])</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="p">[</span><span class="s1">'TERMINATOR'</span><span class="p">,</span> <span class="s2">"\n"</span><span class="p">,</span> <span class="nx">prev</span><span class="p">[</span><span class="mi">2</span><span class="p">]]</span>
|
||||
<span class="k">return</span> <span class="mi">2</span>
|
||||
<span class="k">else</span>
|
||||
<span class="k">return</span> <span class="mi">1</span></pre></div> </td> </tr> <tr id="section-8"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-8">#</a> </div> <p>Leading newlines would introduce an ambiguity in the grammar, so we
|
||||
dispatch them here.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">remove_leading_newlines: </span><span class="o">-></span>
|
||||
<span class="k">return</span> <span class="mi">1</span></pre></div> </td> </tr> <tr id="section-8"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-8">#</a> </div> <p>Leading newlines would introduce an ambiguity in the grammar, so we
|
||||
dispatch them here.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">removeLeadingNewlines: </span><span class="o">-></span>
|
||||
<span class="nx">@tokens</span><span class="p">.</span><span class="nx">shift</span><span class="p">()</span> <span class="k">while</span> <span class="nx">@tokens</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">and</span> <span class="nx">@tokens</span><span class="p">[</span><span class="mi">0</span><span class="p">][</span><span class="mi">0</span><span class="p">]</span> <span class="o">is</span> <span class="s1">'TERMINATOR'</span></pre></div> </td> </tr> <tr id="section-9"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-9">#</a> </div> <p>Some blocks occur in the middle of expressions -- when we're expecting
|
||||
this, remove their trailing newlines.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">remove_mid_expression_newlines: </span><span class="o">-></span>
|
||||
<span class="nx">@scan_tokens</span> <span class="p">(</span><span class="nx">prev</span><span class="p">,</span> <span class="nx">token</span><span class="p">,</span> <span class="nx">post</span><span class="p">,</span> <span class="nx">i</span><span class="p">)</span> <span class="o">=></span>
|
||||
this, remove their trailing newlines.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">removeMidExpressionNewlines: </span><span class="o">-></span>
|
||||
<span class="nx">@scanTokens</span> <span class="p">(</span><span class="nx">prev</span><span class="p">,</span> <span class="nx">token</span><span class="p">,</span> <span class="nx">post</span><span class="p">,</span> <span class="nx">i</span><span class="p">)</span> <span class="o">=></span>
|
||||
<span class="k">return</span> <span class="mi">1</span> <span class="nx">unless</span> <span class="nx">post</span> <span class="o">and</span> <span class="nx">include</span><span class="p">(</span><span class="nx">EXPRESSION_CLOSE</span><span class="p">,</span> <span class="nx">post</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span> <span class="o">and</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">'TERMINATOR'</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></pre></div> </td> </tr> <tr id="section-10"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-10">#</a> </div> <p>The lexer has tagged the opening parenthesis of a method call, and the
|
||||
opening bracket of an indexing operation. Match them with their paired
|
||||
close.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">close_open_calls_and_indexes: </span><span class="o">-></span>
|
||||
close.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">closeOpenCallsAndIndexes: </span><span class="o">-></span>
|
||||
<span class="nv">parens: </span> <span class="p">[</span><span class="mi">0</span><span class="p">]</span>
|
||||
<span class="nv">brackets: </span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
|
||||
<span class="nx">@scan_tokens</span> <span class="p">(</span><span class="nx">prev</span><span class="p">,</span> <span class="nx">token</span><span class="p">,</span> <span class="nx">post</span><span class="p">,</span> <span class="nx">i</span><span class="p">)</span> <span class="o">=></span>
|
||||
<span class="nx">@scanTokens</span> <span class="p">(</span><span class="nx">prev</span><span class="p">,</span> <span class="nx">token</span><span class="p">,</span> <span class="nx">post</span><span class="p">,</span> <span class="nx">i</span><span class="p">)</span> <span class="o">=></span>
|
||||
<span class="k">switch</span> <span class="nx">token</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
|
||||
<span class="k">when</span> <span class="s1">'CALL_START'</span> <span class="k">then</span> <span class="nx">parens</span><span class="p">.</span><span class="nx">push</span> <span class="mi">0</span>
|
||||
<span class="k">when</span> <span class="s1">'INDEX_START'</span> <span class="k">then</span> <span class="nx">brackets</span><span class="p">.</span><span class="nx">push</span> <span class="mi">0</span>
|
||||
@@ -77,62 +82,71 @@ close.</p> </td> <td class="code"> <div cl
|
||||
<span class="nx">brackets</span><span class="p">[</span><span class="nx">brackets</span><span class="p">.</span><span class="nx">length</span> <span class="o">-</span> <span class="mi">1</span><span class="p">]</span><span class="o">:</span> <span class="o">-</span> <span class="mi">1</span>
|
||||
<span class="k">return</span> <span class="mi">1</span></pre></div> </td> </tr> <tr id="section-11"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-11">#</a> </div> <p>Methods may be optionally called without parentheses, for simple cases.
|
||||
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="nv">add_implicit_parentheses: </span><span class="o">-></span>
|
||||
deal with them.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">addImplicitParentheses: </span><span class="o">-></span>
|
||||
<span class="nv">stack: </span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
|
||||
<span class="nv">calls: </span> <span class="mi">0</span>
|
||||
<span class="nv">parens: </span><span class="mi">0</span>
|
||||
<span class="nv">start_parens: </span><span class="mi">0</span>
|
||||
<span class="nx">@scan_tokens</span> <span class="p">(</span><span class="nx">prev</span><span class="p">,</span> <span class="nx">token</span><span class="p">,</span> <span class="nx">post</span><span class="p">,</span> <span class="nx">i</span><span class="p">)</span> <span class="o">=></span>
|
||||
<span class="nv">closeCalls: </span><span class="p">(</span><span class="nx">i</span><span class="p">)</span> <span class="o">=></span>
|
||||
<span class="k">for</span> <span class="nx">tmp</span> <span class="k">in</span> <span class="p">[</span><span class="mi">0</span><span class="p">...</span><span class="nx">stack</span><span class="p">[</span><span class="nx">stack</span><span class="p">.</span><span class="nx">length</span> <span class="o">-</span> <span class="mi">1</span><span class="p">]]</span>
|
||||
<span class="nx">@tokens</span><span class="p">.</span><span class="nx">splice</span><span class="p">(</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">@tokens</span><span class="p">[</span><span class="nx">i</span><span class="p">][</span><span class="mi">2</span><span class="p">]])</span>
|
||||
<span class="nv">size: </span><span class="nx">stack</span><span class="p">[</span><span class="nx">stack</span><span class="p">.</span><span class="nx">length</span> <span class="o">-</span> <span class="mi">1</span><span class="p">]</span> <span class="o">+</span> <span class="mi">1</span>
|
||||
<span class="nx">stack</span><span class="p">[</span><span class="nx">stack</span><span class="p">.</span><span class="nx">length</span> <span class="o">-</span> <span class="mi">1</span><span class="p">]</span><span class="o">:</span> <span class="mi">0</span>
|
||||
<span class="nx">size</span>
|
||||
<span class="nx">@scanTokens</span> <span class="p">(</span><span class="nx">prev</span><span class="p">,</span> <span class="nx">token</span><span class="p">,</span> <span class="nx">post</span><span class="p">,</span> <span class="nx">i</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="k">switch</span> <span class="nx">tag</span>
|
||||
<span class="k">when</span> <span class="s1">'CALL_START'</span> <span class="k">then</span> <span class="nv">calls: </span><span class="o">+</span> <span class="mi">1</span>
|
||||
<span class="k">when</span> <span class="s1">'CALL_END'</span> <span class="k">then</span> <span class="nv">calls: </span><span class="o">-</span> <span class="mi">1</span>
|
||||
<span class="k">when</span> <span class="s1">'('</span> <span class="k">then</span> <span class="nv">parens: </span><span class="o">+</span> <span class="mi">1</span>
|
||||
<span class="k">when</span> <span class="s1">')'</span> <span class="k">then</span> <span class="nv">parens: </span><span class="o">-</span> <span class="mi">1</span>
|
||||
<span class="k">when</span> <span class="s1">'INDENT'</span> <span class="k">then</span> <span class="nx">stack</span><span class="p">.</span><span class="nx">push</span> <span class="mi">0</span>
|
||||
<span class="k">when</span> <span class="s1">'OUTDENT'</span>
|
||||
<span class="nv">last: </span><span class="nx">stack</span><span class="p">.</span><span class="nx">pop</span><span class="p">()</span>
|
||||
<span class="nx">stack</span><span class="p">[</span><span class="nx">stack</span><span class="p">.</span><span class="nx">length</span> <span class="o">-</span> <span class="mi">1</span><span class="p">]</span><span class="o">:</span> <span class="o">+</span> <span class="nx">last</span>
|
||||
<span class="nx">stack</span><span class="p">[</span><span class="nx">stack</span><span class="p">.</span><span class="nx">length</span> <span class="o">-</span> <span class="mi">2</span><span class="p">]</span><span class="o">:</span> <span class="o">+</span> <span class="nx">stack</span><span class="p">.</span><span class="nx">pop</span><span class="p">()</span> <span class="k">if</span> <span class="nx">tag</span> <span class="o">is</span> <span class="s1">'OUTDENT'</span>
|
||||
<span class="nv">open: </span><span class="nx">stack</span><span class="p">[</span><span class="nx">stack</span><span class="p">.</span><span class="nx">length</span> <span class="o">-</span> <span class="mi">1</span><span class="p">]</span> <span class="o">></span> <span class="mi">0</span>
|
||||
<span class="k">if</span> <span class="o">!</span><span class="nx">post</span><span class="o">?</span> <span class="o">or</span> <span class="p">(</span><span class="nx">start_parens</span> <span class="o">></span> <span class="nx">parens</span><span class="p">)</span> <span class="o">or</span> <span class="p">(</span><span class="nx">parens</span> <span class="o">is</span> <span class="mi">0</span> <span class="o">and</span> <span class="nx">include</span> <span class="nx">IMPLICIT_END</span><span class="p">,</span> <span class="nx">tag</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="s1">'INDENT'</span> <span class="o">and</span> <span class="nx">prev</span> <span class="o">and</span> <span class="nx">include</span> <span class="nx">IMPLICIT_BLOCK</span><span class="p">,</span> <span class="nx">prev</span><span class="p">[</span><span class="mi">0</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="s1">'OUTDENT'</span> <span class="o">and</span> <span class="nx">token</span><span class="p">.</span><span class="nx">generated</span>
|
||||
<span class="k">if</span> <span class="nx">open</span> <span class="o">or</span> <span class="nx">tag</span> <span class="o">is</span> <span class="s1">'INDENT'</span>
|
||||
<span class="nv">idx: </span><span class="k">if</span> <span class="nx">tag</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="nv">stack_pointer: </span><span class="k">if</span> <span class="nx">tag</span> <span class="o">is</span> <span class="s1">'INDENT'</span> <span class="k">then</span> <span class="mi">2</span> <span class="k">else</span> <span class="mi">1</span>
|
||||
<span class="k">for</span> <span class="nx">tmp</span> <span class="k">in</span> <span class="p">[</span><span class="mi">0</span><span class="p">...</span><span class="nx">stack</span><span class="p">[</span><span class="nx">stack</span><span class="p">.</span><span class="nx">length</span> <span class="o">-</span> <span class="nx">stack_pointer</span><span class="p">]]</span>
|
||||
<span class="nx">@tokens</span><span class="p">.</span><span class="nx">splice</span><span class="p">(</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">size: </span><span class="nx">stack</span><span class="p">[</span><span class="nx">stack</span><span class="p">.</span><span class="nx">length</span> <span class="o">-</span> <span class="nx">stack_pointer</span><span class="p">]</span> <span class="o">+</span> <span class="mi">1</span>
|
||||
<span class="nx">stack</span><span class="p">[</span><span class="nx">stack</span><span class="p">.</span><span class="nx">length</span> <span class="o">-</span> <span class="nx">stack_pointer</span><span class="p">]</span><span class="o">:</span> <span class="mi">0</span>
|
||||
<span class="k">if</span> <span class="nx">prev</span> <span class="o">and</span> <span class="nx">prev</span><span class="p">.</span><span class="nx">spaced</span> <span class="o">and</span> <span class="nx">include</span><span class="p">(</span><span class="nx">IMPLICIT_FUNC</span><span class="p">,</span> <span class="nx">prev</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span> <span class="o">and</span> <span class="nx">include</span><span class="p">(</span><span class="nx">IMPLICIT_CALL</span><span class="p">,</span> <span class="nx">tag</span><span class="p">)</span> <span class="o">and</span>
|
||||
<span class="o">not</span> <span class="p">(</span><span class="nx">tag</span> <span class="o">is</span> <span class="s1">'!'</span> <span class="o">and</span> <span class="p">(</span><span class="nx">post</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="k">in</span> <span class="p">[</span><span class="s1">'IN'</span><span class="p">,</span> <span class="s1">'OF'</span><span class="p">]))</span>
|
||||
<span class="nx">@tokens</span><span class="p">.</span><span class="nx">splice</span> <span class="nx">i</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="p">[</span><span class="s1">'CALL_START'</span><span class="p">,</span> <span class="s1">'('</span><span class="p">,</span> <span class="nx">token</span><span class="p">[</span><span class="mi">2</span><span class="p">]]</span>
|
||||
<span class="nx">stack</span><span class="p">[</span><span class="nx">stack</span><span class="p">.</span><span class="nx">length</span> <span class="o">-</span> <span class="mi">1</span><span class="p">]</span><span class="o">:</span> <span class="o">+</span> <span class="mi">1</span>
|
||||
<span class="nx">stack</span><span class="p">.</span><span class="nx">push</span> <span class="mi">0</span> <span class="k">if</span> <span class="nx">include</span><span class="p">(</span><span class="nx">EXPRESSION_START</span><span class="p">,</span> <span class="nx">tag</span><span class="p">)</span>
|
||||
<span class="k">return</span> <span class="mi">2</span>
|
||||
<span class="k">if</span> <span class="nx">include</span><span class="p">(</span><span class="nx">EXPRESSION_START</span><span class="p">,</span> <span class="nx">tag</span><span class="p">)</span>
|
||||
<span class="k">if</span> <span class="nx">tag</span> <span class="o">is</span> <span class="s1">'INDENT'</span> <span class="o">and</span> <span class="o">!</span><span class="nx">token</span><span class="p">.</span><span class="nx">generated</span> <span class="o">and</span> <span class="nx">open</span> <span class="o">and</span> <span class="o">not</span> <span class="p">(</span><span class="nx">prev</span> <span class="o">and</span> <span class="nx">include</span><span class="p">(</span><span class="nx">IMPLICIT_BLOCK</span><span class="p">,</span> <span class="nx">prev</span><span class="p">[</span><span class="mi">0</span><span class="p">]))</span>
|
||||
<span class="nv">size: </span><span class="nx">closeCalls</span><span class="p">(</span><span class="nx">i</span><span class="p">)</span>
|
||||
<span class="nx">stack</span><span class="p">.</span><span class="nx">push</span> <span class="mi">0</span>
|
||||
<span class="k">return</span> <span class="nx">size</span>
|
||||
<span class="k">return</span> <span class="mi">1</span> <span class="nx">unless</span> <span class="nx">prev</span> <span class="o">and</span> <span class="nx">include</span><span class="p">(</span><span class="nx">IMPLICIT_FUNC</span><span class="p">,</span> <span class="nx">prev</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span> <span class="o">and</span> <span class="nx">include</span><span class="p">(</span><span class="nx">IMPLICIT_CALL</span><span class="p">,</span> <span class="nx">tag</span><span class="p">)</span>
|
||||
<span class="nv">calls: </span><span class="mi">0</span>
|
||||
<span class="nv">start_parens: </span><span class="k">if</span> <span class="nx">tag</span> <span class="o">is</span> <span class="s1">'('</span> <span class="k">then</span> <span class="nx">parens</span> <span class="o">-</span> <span class="mi">1</span> <span class="k">else</span> <span class="nx">parens</span>
|
||||
<span class="nx">@tokens</span><span class="p">.</span><span class="nx">splice</span> <span class="nx">i</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="p">[</span><span class="s1">'CALL_START'</span><span class="p">,</span> <span class="s1">'('</span><span class="p">,</span> <span class="nx">token</span><span class="p">[</span><span class="mi">2</span><span class="p">]]</span>
|
||||
<span class="nx">stack</span><span class="p">[</span><span class="nx">stack</span><span class="p">.</span><span class="nx">length</span> <span class="o">-</span> <span class="mi">1</span><span class="p">]</span><span class="o">:</span> <span class="o">+</span> <span class="mi">1</span>
|
||||
<span class="k">return</span> <span class="mi">2</span></pre></div> </td> </tr> <tr id="section-12"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-12">#</a> </div> <p>Because our grammar is LALR(1), it can't handle some single-line
|
||||
<span class="nx">stack</span><span class="p">.</span><span class="nx">push</span> <span class="mi">0</span>
|
||||
<span class="k">return</span> <span class="mi">1</span>
|
||||
<span class="k">if</span> <span class="nx">open</span> <span class="o">and</span> <span class="o">!</span><span class="nx">token</span><span class="p">.</span><span class="nx">generated</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="o">isnt</span> <span class="s1">','</span> <span class="o">and</span> <span class="p">(</span><span class="o">!</span><span class="nx">post</span> <span class="o">or</span> <span class="nx">include</span><span class="p">(</span><span class="nx">IMPLICIT_END</span><span class="p">,</span> <span class="nx">tag</span><span class="p">))</span>
|
||||
<span class="nv">j: </span><span class="mi">1</span><span class="p">;</span> <span class="nx">j</span><span class="o">++</span> <span class="k">while</span> <span class="p">(</span><span class="nv">nx: </span><span class="nx">@tokens</span><span class="p">[</span><span class="nx">i</span> <span class="o">+</span> <span class="nx">j</span><span class="p">])</span><span class="o">?</span> <span class="o">and</span> <span class="nx">include</span><span class="p">(</span><span class="nx">IMPLICIT_END</span><span class="p">,</span> <span class="nx">nx</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span>
|
||||
<span class="k">if</span> <span class="nx">nx</span><span class="o">?</span> <span class="o">and</span> <span class="nx">nx</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="nx">@tokens</span><span class="p">.</span><span class="nx">splice</span><span class="p">(</span><span class="nx">i</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span> <span class="k">if</span> <span class="nx">tag</span> <span class="o">is</span> <span class="s1">'TERMINATOR'</span>
|
||||
<span class="k">else</span>
|
||||
<span class="nv">size: </span><span class="nx">closeCalls</span><span class="p">(</span><span class="nx">i</span><span class="p">)</span>
|
||||
<span class="nx">stack</span><span class="p">.</span><span class="nx">pop</span><span class="p">()</span> <span class="k">if</span> <span class="nx">tag</span> <span class="o">isnt</span> <span class="s1">'OUTDENT'</span> <span class="o">and</span> <span class="nx">include</span> <span class="nx">EXPRESSION_END</span><span class="p">,</span> <span class="nx">tag</span>
|
||||
<span class="k">return</span> <span class="nx">size</span>
|
||||
<span class="k">if</span> <span class="nx">tag</span> <span class="o">isnt</span> <span class="s1">'OUTDENT'</span> <span class="o">and</span> <span class="nx">include</span> <span class="nx">EXPRESSION_END</span><span class="p">,</span> <span class="nx">tag</span>
|
||||
<span class="nx">stack</span><span class="p">[</span><span class="nx">stack</span><span class="p">.</span><span class="nx">length</span> <span class="o">-</span> <span class="mi">2</span><span class="p">]</span><span class="o">:</span> <span class="o">+</span> <span class="nx">stack</span><span class="p">.</span><span class="nx">pop</span><span class="p">()</span>
|
||||
<span class="k">return</span> <span class="mi">1</span>
|
||||
<span class="k">return</span> <span class="mi">1</span></pre></div> </td> </tr> <tr id="section-12"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-12">#</a> </div> <p>Because our grammar is LALR(1), it can't handle some single-line
|
||||
expressions that lack ending delimiters. The <strong>Rewriter</strong> adds the implicit
|
||||
blocks, so it doesn't need to. ')' can close a single-line block,
|
||||
but we need to make sure it's balanced.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">add_implicit_indentation: </span><span class="o">-></span>
|
||||
<span class="nx">@scan_tokens</span> <span class="p">(</span><span class="nx">prev</span><span class="p">,</span> <span class="nx">token</span><span class="p">,</span> <span class="nx">post</span><span class="p">,</span> <span class="nx">i</span><span class="p">)</span> <span class="o">=></span>
|
||||
but we need to make sure it's balanced.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">addImplicitIndentation: </span><span class="o">-></span>
|
||||
<span class="nx">@scanTokens</span> <span class="p">(</span><span class="nx">prev</span><span class="p">,</span> <span class="nx">token</span><span class="p">,</span> <span class="nx">post</span><span class="p">,</span> <span class="nx">i</span><span class="p">)</span> <span class="o">=></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">'ELSE'</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="o">isnt</span> <span class="s1">'OUTDENT'</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">@indentation</span><span class="p">(</span><span class="nx">token</span><span class="p">)...</span>
|
||||
<span class="k">return</span> <span class="mi">2</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">'CATCH'</span> <span class="o">and</span> <span class="nx">@tokens</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="mi">0</span><span class="p">]</span> <span class="o">is</span> <span class="s1">'TERMINATOR'</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">2</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="nx">@indentation</span><span class="p">(</span><span class="nx">token</span><span class="p">)...</span>
|
||||
<span class="k">return</span> <span class="mi">4</span>
|
||||
<span class="k">return</span> <span class="mi">1</span> <span class="nx">unless</span> <span class="nx">include</span><span class="p">(</span><span class="nx">SINGLE_LINERS</span><span class="p">,</span> <span class="nx">token</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span> <span class="o">and</span>
|
||||
<span class="nx">post</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="o">and</span>
|
||||
<span class="o">not</span> <span class="p">(</span><span class="nx">token</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">is</span> <span class="s1">'ELSE'</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">'IF'</span><span class="p">)</span>
|
||||
<span class="nv">starter: </span><span class="nx">token</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
|
||||
<span class="nx">@tokens</span><span class="p">.</span><span class="nx">splice</span> <span class="nx">i</span> <span class="o">+</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</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="nx">indent</span><span class="p">,</span> <span class="nx">outdent</span><span class="p">]</span><span class="o">:</span> <span class="nx">@indentation</span> <span class="nx">token</span>
|
||||
<span class="nv">indent.generated: outdent.generated: </span><span class="kc">true</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">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="nx">indent</span>
|
||||
<span class="nv">idx: </span><span class="nx">i</span> <span class="o">+</span> <span class="mi">1</span>
|
||||
<span class="nv">parens: </span><span class="mi">0</span>
|
||||
<span class="k">while</span> <span class="kc">true</span>
|
||||
<span class="nx">loop</span>
|
||||
<span class="nv">idx: </span><span class="o">+</span> <span class="mi">1</span>
|
||||
<span class="nv">tok: </span><span class="nx">@tokens</span><span class="p">[</span><span class="nx">idx</span><span class="p">]</span>
|
||||
<span class="nv">pre: </span><span class="nx">@tokens</span><span class="p">[</span><span class="nx">idx</span> <span class="o">-</span> <span class="mi">1</span><span class="p">]</span>
|
||||
<span class="k">if</span> <span class="p">(</span><span class="o">not</span> <span class="nx">tok</span> <span class="o">or</span>
|
||||
<span class="p">(</span><span class="nx">include</span><span class="p">(</span><span class="nx">SINGLE_CLOSERS</span><span class="p">,</span> <span class="nx">tok</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span> <span class="o">and</span> <span class="nx">tok</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="o">or</span>
|
||||
<span class="p">(</span><span class="nx">include</span><span class="p">(</span><span class="nx">SINGLE_CLOSERS</span><span class="p">,</span> <span class="nx">tok</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span> <span class="o">and</span> <span class="nx">tok</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="o">and</span> <span class="nx">parens</span> <span class="o">is</span> <span class="mi">0</span><span class="p">)</span> <span class="o">or</span>
|
||||
<span class="p">(</span><span class="nx">tok</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">parens</span> <span class="o">is</span> <span class="mi">0</span><span class="p">))</span> <span class="o">and</span>
|
||||
<span class="o">not</span> <span class="p">(</span><span class="nx">starter</span> <span class="o">is</span> <span class="s1">'ELSE'</span> <span class="o">and</span> <span class="nx">tok</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">is</span> <span class="s1">'ELSE'</span><span class="p">)</span>
|
||||
<span class="o">not</span> <span class="p">(</span><span class="nx">tok</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">is</span> <span class="s1">'ELSE'</span> <span class="o">and</span> <span class="nx">starter</span> <span class="o">not</span> <span class="k">in</span> <span class="p">[</span><span class="s1">'IF'</span><span class="p">,</span> <span class="s1">'THEN'</span><span class="p">])</span>
|
||||
<span class="nv">insertion: </span><span class="k">if</span> <span class="nx">pre</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">is</span> <span class="s2">","</span> <span class="k">then</span> <span class="nx">idx</span> <span class="o">-</span> <span class="mi">1</span> <span class="k">else</span> <span class="nx">idx</span>
|
||||
<span class="nv">outdent: </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>
|
||||
<span class="nv">outdent.generated: </span><span class="kc">true</span>
|
||||
<span class="nx">@tokens</span><span class="p">.</span><span class="nx">splice</span> <span class="nx">insertion</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="nx">outdent</span>
|
||||
<span class="k">break</span>
|
||||
<span class="nv">parens: </span><span class="o">+</span> <span class="mi">1</span> <span class="k">if</span> <span class="nx">tok</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">is</span> <span class="s1">'('</span>
|
||||
@@ -140,15 +154,15 @@ but we need to make sure it's balanced.</p> </td> <td cl
|
||||
<span class="k">return</span> <span class="mi">1</span> <span class="nx">unless</span> <span class="nx">token</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">is</span> <span class="s1">'THEN'</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></pre></div> </td> </tr> <tr id="section-13"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-13">#</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="nv">ensure_balance: </span><span class="p">(</span><span class="nx">pairs</span><span class="p">)</span> <span class="o">-></span>
|
||||
the course of the token stream.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">ensureBalance: </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">open_line: </span><span class="p">{}</span>
|
||||
<span class="nx">@scan_tokens</span> <span class="p">(</span><span class="nx">prev</span><span class="p">,</span> <span class="nx">token</span><span class="p">,</span> <span class="nx">post</span><span class="p">,</span> <span class="nx">i</span><span class="p">)</span> <span class="o">=></span>
|
||||
<span class="nv">openLine: </span><span class="p">{}</span>
|
||||
<span class="nx">@scanTokens</span> <span class="p">(</span><span class="nx">prev</span><span class="p">,</span> <span class="nx">token</span><span class="p">,</span> <span class="nx">post</span><span class="p">,</span> <span class="nx">i</span><span class="p">)</span> <span class="o">=></span>
|
||||
<span class="k">for</span> <span class="nx">pair</span> <span class="k">in</span> <span class="nx">pairs</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="o">:</span> <span class="nx">pair</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">or</span> <span class="mi">0</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="nx">open</span>
|
||||
<span class="nx">open_line</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="mi">0</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="mi">0</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">+</span> <span class="mi">1</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">-</span> <span class="mi">1</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="nx">close</span>
|
||||
<span class="k">throw</span> <span class="k">new</span> <span class="nb">Error</span><span class="p">(</span><span class="s2">"too many ${token[1]} on line ${token[2] + 1}"</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="mi">0</span>
|
||||
@@ -156,7 +170,7 @@ the course of the token stream.</p> </td> <td class="cod
|
||||
<span class="nv">unclosed: </span><span class="nx">key</span> <span class="k">for</span> <span class="nx">key</span><span class="p">,</span> <span class="nx">value</span> <span class="k">of</span> <span class="nx">levels</span> <span class="k">when</span> <span class="nx">value</span> <span class="o">></span> <span class="mi">0</span>
|
||||
<span class="k">if</span> <span class="nx">unclosed</span><span class="p">.</span><span class="nx">length</span>
|
||||
<span class="nv">open: </span><span class="nx">unclosed</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
|
||||
<span class="nv">line: </span><span class="nx">open_line</span><span class="p">[</span><span class="nx">open</span><span class="p">]</span> <span class="o">+</span> <span class="mi">1</span>
|
||||
<span class="nv">line: </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="mi">1</span>
|
||||
<span class="k">throw</span> <span class="k">new</span> <span class="nb">Error</span> <span class="s2">"unclosed $open on line $line"</span></pre></div> </td> </tr> <tr id="section-14"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-14">#</a> </div> <p>We'd like to support syntax like this:</p>
|
||||
|
||||
<pre><code>el.click((event) ->
|
||||
@@ -173,11 +187,13 @@ to the stack. If you see an <code>EXPRESSION_END</code>, pop the stack and repla
|
||||
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>
|
||||
</ol> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">rewrite_closing_parens: </span><span class="o">-></span>
|
||||
<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="nv">rewriteClosingParens: </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="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="p">)</span> <span class="k">for</span> <span class="nx">key</span><span class="p">,</span> <span class="nx">val</span> <span class="k">of</span> <span class="nx">INVERSES</span>
|
||||
<span class="nx">@scan_tokens</span> <span class="p">(</span><span class="nx">prev</span><span class="p">,</span> <span class="nx">token</span><span class="p">,</span> <span class="nx">post</span><span class="p">,</span> <span class="nx">i</span><span class="p">)</span> <span class="o">=></span>
|
||||
<span class="nx">@scanTokens</span> <span class="p">(</span><span class="nx">prev</span><span class="p">,</span> <span class="nx">token</span><span class="p">,</span> <span class="nx">post</span><span class="p">,</span> <span class="nx">i</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">inv: </span><span class="nx">INVERSES</span><span class="p">[</span><span class="nx">token</span><span class="p">[</span><span class="mi">0</span><span class="p">]]</span>
|
||||
<span class="k">if</span> <span class="nx">include</span> <span class="nx">EXPRESSION_START</span><span class="p">,</span> <span class="nx">tag</span>
|
||||
@@ -191,23 +207,28 @@ up balanced in the end.</li>
|
||||
<span class="k">else</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="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">INVERSES</span><span class="p">[</span><span class="nx">mtag</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="o">+</span> <span class="mi">1</span>
|
||||
<span class="nv">val: </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">INVERSES</span><span class="p">[</span><span class="nx">mtag</span><span class="p">]</span>
|
||||
<span class="nx">@tokens</span><span class="p">.</span><span class="nx">splice</span> <span class="nx">i</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="p">[</span><span class="nx">INVERSES</span><span class="p">[</span><span class="nx">mtag</span><span class="p">],</span> <span class="nx">val</span><span class="p">]</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">@tokens</span><span class="p">[</span><span class="nx">i</span> <span class="o">+</span> <span class="mi">2</span><span class="p">]</span><span class="o">?</span><span class="p">[</span><span class="mi">0</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="p">(</span><span class="nx">match</span><span class="p">)</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="k">return</span> <span class="mi">1</span>
|
||||
<span class="k">else</span>
|
||||
<span class="k">return</span> <span class="mi">1</span></pre></div> </td> </tr> <tr id="section-15"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-15">#</a> </div> <h2>Constants</h2> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-16"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-16">#</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="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> <span class="p">[</span><span class="s1">'INDENT'</span><span class="p">,</span> <span class="s1">'OUTDENT'</span><span class="p">],</span>
|
||||
<span class="p">[</span><span class="s1">'PARAM_START'</span><span class="p">,</span> <span class="s1">'PARAM_END'</span><span class="p">],</span> <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">'INDEX_START'</span><span class="p">,</span> <span class="s1">'INDEX_END'</span><span class="p">],</span> <span class="p">[</span><span class="s1">'SOAKED_INDEX_START'</span><span class="p">,</span> <span class="s1">'SOAKED_INDEX_END'</span><span class="p">]]</span></pre></div> </td> </tr> <tr id="section-17"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-17">#</a> </div> <p>The inverse mappings of <code>BALANCED_PAIRS</code> we're trying to fix up, so we can
|
||||
<span class="k">return</span> <span class="mi">1</span></pre></div> </td> </tr> <tr id="section-15"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-15">#</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="nv">indentation: </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-16"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" 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="octowrap"> <a class="octothorpe" 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="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> <span class="p">[</span><span class="s1">'INDENT'</span><span class="p">,</span> <span class="s1">'OUTDENT'</span><span class="p">],</span>
|
||||
<span class="p">[</span><span class="s1">'PARAM_START'</span><span class="p">,</span> <span class="s1">'PARAM_END'</span><span class="p">],</span> <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">'INDEX_START'</span><span class="p">,</span> <span class="s1">'INDEX_END'</span><span class="p">]]</span></pre></div> </td> </tr> <tr id="section-18"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" 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">INVERSES: </span><span class="p">{}</span>
|
||||
<span class="k">for</span> <span class="nx">pair</span> <span class="k">in</span> <span class="nx">BALANCED_PAIRS</span>
|
||||
<span class="nx">INVERSES</span><span class="p">[</span><span class="nx">pair</span><span class="p">[</span><span class="mi">0</span><span class="p">]]</span><span class="o">:</span> <span class="nx">pair</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
|
||||
<span class="nx">INVERSES</span><span class="p">[</span><span class="nx">pair</span><span class="p">[</span><span class="mi">1</span><span class="p">]]</span><span class="o">:</span> <span class="nx">pair</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="octowrap"> <a class="octothorpe" href="#section-18">#</a> </div> <p>The tokens that signal the start of a balanced pair.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">EXPRESSION_START: </span><span class="nx">pair</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="k">for</span> <span class="nx">pair</span> <span class="k">in</span> <span class="nx">BALANCED_PAIRS</span></pre></div> </td> </tr> <tr id="section-19"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-19">#</a> </div> <p>The tokens that signal the end of a balanced pair.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">EXPRESSION_END: </span> <span class="nx">pair</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="k">for</span> <span class="nx">pair</span> <span class="k">in</span> <span class="nx">BALANCED_PAIRS</span></pre></div> </td> </tr> <tr id="section-20"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" 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="octowrap"> <a class="octothorpe" 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></pre></div> </td> </tr> <tr id="section-22"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" 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">'TRY'</span><span class="p">,</span> <span class="s1">'DELETE'</span><span class="p">,</span> <span class="s1">'TYPEOF'</span><span class="p">,</span> <span class="s1">'SWITCH'</span><span class="p">,</span> <span class="s1">'EXTENSION'</span><span class="p">,</span>
|
||||
<span class="s1">'TRUE'</span><span class="p">,</span> <span class="s1">'FALSE'</span><span class="p">,</span> <span class="s1">'YES'</span><span class="p">,</span> <span class="s1">'NO'</span><span class="p">,</span> <span class="s1">'ON'</span><span class="p">,</span> <span class="s1">'OFF'</span><span class="p">,</span> <span class="s1">'!'</span><span class="p">,</span> <span class="s1">'!!'</span><span class="p">,</span> <span class="s1">'NOT'</span><span class="p">,</span>
|
||||
<span class="nx">INVERSES</span><span class="p">[</span><span class="nx">pair</span><span class="p">[</span><span class="mi">1</span><span class="p">]]</span><span class="o">:</span> <span class="nx">pair</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span></pre></div> </td> </tr> <tr id="section-19"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-19">#</a> </div> <p>The tokens that signal the start of a balanced pair.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">EXPRESSION_START: </span><span class="nx">pair</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="k">for</span> <span class="nx">pair</span> <span class="k">in</span> <span class="nx">BALANCED_PAIRS</span></pre></div> </td> </tr> <tr id="section-20"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-20">#</a> </div> <p>The tokens that signal the end of a balanced pair.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">EXPRESSION_END: </span> <span class="nx">pair</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="k">for</span> <span class="nx">pair</span> <span class="k">in</span> <span class="nx">BALANCED_PAIRS</span></pre></div> </td> </tr> <tr id="section-21"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-21">#</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-22"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-22">#</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></pre></div> </td> </tr> <tr id="section-23"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-23">#</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">'TRY'</span><span class="p">,</span> <span class="s1">'DELETE'</span><span class="p">,</span> <span class="s1">'TYPEOF'</span><span class="p">,</span> <span class="s1">'SWITCH'</span><span class="p">,</span>
|
||||
<span class="s1">'TRUE'</span><span class="p">,</span> <span class="s1">'FALSE'</span><span class="p">,</span> <span class="s1">'YES'</span><span class="p">,</span> <span class="s1">'NO'</span><span class="p">,</span> <span class="s1">'ON'</span><span class="p">,</span> <span class="s1">'OFF'</span><span class="p">,</span> <span class="s1">'!'</span><span class="p">,</span> <span class="s1">'!!'</span><span class="p">,</span>
|
||||
<span class="s1">'THIS'</span><span class="p">,</span> <span class="s1">'NULL'</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></pre></div> </td> </tr> <tr id="section-23"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" 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="octowrap"> <a class="octothorpe" 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">'IF'</span><span class="p">,</span> <span class="s1">'UNLESS'</span><span class="p">,</span> <span class="s1">'FOR'</span><span class="p">,</span> <span class="s1">'WHILE'</span><span class="p">,</span> <span class="s1">'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> <tr id="section-25"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-25">#</a> </div> <p>Single-line flavors of block expressions that have unclosed endings.
|
||||
<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></pre></div> </td> </tr> <tr id="section-24"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-24">#</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-25"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-25">#</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">'IF'</span><span class="p">,</span> <span class="s1">'UNLESS'</span><span class="p">,</span> <span class="s1">'FOR'</span><span class="p">,</span> <span class="s1">'WHILE'</span><span class="p">,</span> <span class="s1">'UNTIL'</span><span class="p">,</span> <span class="s1">'LOOP'</span><span class="p">,</span> <span class="s1">'TERMINATOR'</span><span class="p">,</span> <span class="s1">'INDENT'</span><span class="p">].</span><span class="nx">concat</span> <span class="nx">EXPRESSION_END</span></pre></div> </td> </tr> <tr id="section-26"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-26">#</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="s2">"->"</span><span class="p">,</span> <span class="s2">"=>"</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>
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<!DOCTYPE html> <html> <head> <title>scope.coffee</title> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <link rel="stylesheet" media="all" href="docco.css" /> </head> <body> <div id="container"> <div id="background"></div> <div id="jump_to"> Jump To … <div id="jump_wrapper"> <div id="jump_page"> <a class="source" href="cake.html"> cake.coffee </a> <a class="source" href="coffee-script.html"> coffee-script.coffee </a> <a class="source" href="command.html"> command.coffee </a> <a class="source" href="grammar.html"> grammar.coffee </a> <a class="source" href="helpers.html"> helpers.coffee </a> <a class="source" href="lexer.html"> lexer.coffee </a> <a class="source" href="nodes.html"> nodes.coffee </a> <a class="source" href="optparse.html"> optparse.coffee </a> <a class="source" href="repl.html"> repl.coffee </a> <a class="source" href="rewriter.html"> rewriter.coffee </a> <a class="source" href="scope.html"> scope.coffee </a> </div> </div> </div> <table cellpadding="0" cellspacing="0"> <thead> <tr> <th class="docs"> <h1> scope.coffee </h1> </th> <th class="code"> </th> </tr> </thead> <tbody> <tr id="section-1"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-1">#</a> </div> <p>The <strong>Scope</strong> class regulates lexical scoping within CoffeeScript. As you
|
||||
<!DOCTYPE html> <html> <head> <title>scope.coffee</title> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <link rel="stylesheet" media="all" href="docco.css" /> </head> <body> <div id="container"> <div id="background"></div> <div id="jump_to"> Jump To … <div id="jump_wrapper"> <div id="jump_page"> <a class="source" href="cake.html"> cake.coffee </a> <a class="source" href="coffee-script.html"> coffee-script.coffee </a> <a class="source" href="command.html"> command.coffee </a> <a class="source" href="grammar.html"> grammar.coffee </a> <a class="source" href="helpers.html"> helpers.coffee </a> <a class="source" href="index.html"> index.coffee </a> <a class="source" href="lexer.html"> lexer.coffee </a> <a class="source" href="nodes.html"> nodes.coffee </a> <a class="source" href="optparse.html"> optparse.coffee </a> <a class="source" href="repl.html"> repl.coffee </a> <a class="source" href="rewriter.html"> rewriter.coffee </a> <a class="source" href="scope.html"> scope.coffee </a> </div> </div> </div> <table cellpadding="0" cellspacing="0"> <thead> <tr> <th class="docs"> <h1> scope.coffee </h1> </th> <th class="code"> </th> </tr> </thead> <tbody> <tr id="section-1"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-1">#</a> </div> <p>The <strong>Scope</strong> class regulates lexical scoping within CoffeeScript. As you
|
||||
generate code, you create a tree of scopes in the same shape as the nested
|
||||
function bodies. Each scope knows about the variables declared within it,
|
||||
and has a reference to its parent enclosing scope. In this way, we know which
|
||||
@@ -12,10 +12,10 @@ it wraps.</p> </td> <td class="code"> <div
|
||||
<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="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="vi">@variables: </span><span class="p">{}</span>
|
||||
<span class="k">if</span> <span class="nx">@parent</span>
|
||||
<span class="vi">@temp_var: </span><span class="nx">@parent</span><span class="p">.</span><span class="nx">temp_var</span>
|
||||
<span class="vi">@tempVar: </span><span class="nx">@parent</span><span class="p">.</span><span class="nx">tempVar</span>
|
||||
<span class="k">else</span>
|
||||
<span class="nv">Scope.root: </span><span class="k">this</span>
|
||||
<span class="vi">@temp_var: </span><span class="s1">'_a'</span></pre></div> </td> </tr> <tr id="section-5"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-5">#</a> </div> <p>Look up a variable name in lexical scope, and declare it if it does not
|
||||
<span class="vi">@tempVar: </span><span class="s1">'_a'</span></pre></div> </td> </tr> <tr id="section-5"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-5">#</a> </div> <p>Look up a variable name in lexical scope, and declare it if it does not
|
||||
already exist.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">find: </span><span class="p">(</span><span class="nx">name</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="k">return</span> <span class="kc">true</span> <span class="k">if</span> <span class="nx">@check</span> <span class="nx">name</span>
|
||||
<span class="nx">@variables</span><span class="p">[</span><span class="nx">name</span><span class="p">]</span><span class="o">:</span> <span class="s1">'var'</span>
|
||||
@@ -25,24 +25,24 @@ already exist.</p> </td> <td class="code">
|
||||
<span class="k">return</span> <span class="kc">false</span></pre></div> </td> </tr> <tr id="section-7"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-7">#</a> </div> <p>Reserve a variable name as originating from a function parameter for this
|
||||
scope. No <code>var</code> required for internal references.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">parameter: </span><span class="p">(</span><span class="nx">name</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nx">@variables</span><span class="p">[</span><span class="nx">name</span><span class="p">]</span><span class="o">:</span> <span class="s1">'param'</span></pre></div> </td> </tr> <tr id="section-8"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-8">#</a> </div> <p>Just check to see if a variable has already been declared, without reserving.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">check: </span><span class="p">(</span><span class="nx">name</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="k">return</span> <span class="kc">true</span> <span class="k">if</span> <span class="nx">@variables</span><span class="p">[</span><span class="nx">name</span><span class="p">]</span>
|
||||
<span class="k">return</span> <span class="kc">true</span> <span class="k">if</span> <span class="nx">@variables</span><span class="p">.</span><span class="nx">hasOwnProperty</span> <span class="nx">name</span>
|
||||
<span class="o">!!</span><span class="p">(</span><span class="nx">@parent</span> <span class="o">and</span> <span class="nx">@parent</span><span class="p">.</span><span class="nx">check</span><span class="p">(</span><span class="nx">name</span><span class="p">))</span></pre></div> </td> </tr> <tr id="section-9"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-9">#</a> </div> <p>If we need to store an intermediate result, find an available name for a
|
||||
compiler-generated variable. <code>_a</code>, <code>_b</code>, and so on...</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">free_variable: </span><span class="o">-></span>
|
||||
<span class="k">while</span> <span class="nx">@check</span> <span class="nx">@temp_var</span>
|
||||
<span class="nv">ordinal: </span><span class="mi">1</span> <span class="o">+</span> <span class="nb">parseInt</span> <span class="nx">@temp_var</span><span class="p">.</span><span class="nx">substr</span><span class="p">(</span><span class="mi">1</span><span class="p">),</span> <span class="mi">36</span>
|
||||
<span class="vi">@temp_var: </span><span class="s1">'_'</span> <span class="o">+</span> <span class="nx">ordinal</span><span class="p">.</span><span class="nx">toString</span><span class="p">(</span><span class="mi">36</span><span class="p">).</span><span class="nx">replace</span><span class="p">(</span><span class="sr">/\d/g</span><span class="p">,</span> <span class="s1">'a'</span><span class="p">)</span>
|
||||
<span class="nx">@variables</span><span class="p">[</span><span class="nx">@temp_var</span><span class="p">]</span><span class="o">:</span> <span class="s1">'var'</span>
|
||||
<span class="nx">@temp_var</span></pre></div> </td> </tr> <tr id="section-10"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-10">#</a> </div> <p>Ensure that an assignment is made at the top of this scope
|
||||
compiler-generated variable. <code>_a</code>, <code>_b</code>, and so on...</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">freeVariable: </span><span class="o">-></span>
|
||||
<span class="k">while</span> <span class="nx">@check</span> <span class="nx">@tempVar</span>
|
||||
<span class="nv">ordinal: </span><span class="mi">1</span> <span class="o">+</span> <span class="nb">parseInt</span> <span class="nx">@tempVar</span><span class="p">.</span><span class="nx">substr</span><span class="p">(</span><span class="mi">1</span><span class="p">),</span> <span class="mi">36</span>
|
||||
<span class="vi">@tempVar: </span><span class="s1">'_'</span> <span class="o">+</span> <span class="nx">ordinal</span><span class="p">.</span><span class="nx">toString</span><span class="p">(</span><span class="mi">36</span><span class="p">).</span><span class="nx">replace</span><span class="p">(</span><span class="sr">/\d/g</span><span class="p">,</span> <span class="s1">'a'</span><span class="p">)</span>
|
||||
<span class="nx">@variables</span><span class="p">[</span><span class="nx">@tempVar</span><span class="p">]</span><span class="o">:</span> <span class="s1">'var'</span>
|
||||
<span class="nx">@tempVar</span></pre></div> </td> </tr> <tr id="section-10"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-10">#</a> </div> <p>Ensure that an assignment is made at the top of this scope
|
||||
(or at the top-level scope, if requested).</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">assign: </span><span class="p">(</span><span class="nx">name</span><span class="p">,</span> <span class="nx">value</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nx">@variables</span><span class="p">[</span><span class="nx">name</span><span class="p">]</span><span class="o">:</span> <span class="p">{</span><span class="nv">value: </span><span class="nx">value</span><span class="p">,</span> <span class="nv">assigned: </span><span class="kc">true</span><span class="p">}</span></pre></div> </td> </tr> <tr id="section-11"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-11">#</a> </div> <p>Does this scope reference any variables that need to be declared in the
|
||||
given function body?</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">has_declarations: </span><span class="p">(</span><span class="nx">body</span><span class="p">)</span> <span class="o">-></span>
|
||||
given function body?</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">hasDeclarations: </span><span class="p">(</span><span class="nx">body</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nx">body</span> <span class="o">is</span> <span class="nx">@expressions</span> <span class="o">and</span> <span class="nx">@any</span> <span class="p">(</span><span class="nx">k</span><span class="p">,</span> <span class="nx">val</span><span class="p">)</span> <span class="o">-></span> <span class="nx">val</span> <span class="o">is</span> <span class="s1">'var'</span></pre></div> </td> </tr> <tr id="section-12"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-12">#</a> </div> <p>Does this scope reference any assignments that need to be declared at the
|
||||
top of the given function body?</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">has_assignments: </span><span class="p">(</span><span class="nx">body</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nx">body</span> <span class="o">is</span> <span class="nx">@expressions</span> <span class="o">and</span> <span class="nx">@any</span> <span class="p">(</span><span class="nx">k</span><span class="p">,</span> <span class="nx">val</span><span class="p">)</span> <span class="o">-></span> <span class="nx">val</span><span class="p">.</span><span class="nx">assigned</span></pre></div> </td> </tr> <tr id="section-13"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-13">#</a> </div> <p>Return the list of variables first declared in this scope.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">declared_variables: </span><span class="o">-></span>
|
||||
top of the given function body?</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">hasAssignments: </span><span class="p">(</span><span class="nx">body</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nx">body</span> <span class="o">is</span> <span class="nx">@expressions</span> <span class="o">and</span> <span class="nx">@any</span> <span class="p">(</span><span class="nx">k</span><span class="p">,</span> <span class="nx">val</span><span class="p">)</span> <span class="o">-></span> <span class="nx">val</span><span class="p">.</span><span class="nx">assigned</span></pre></div> </td> </tr> <tr id="section-13"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-13">#</a> </div> <p>Return the list of variables first declared in this scope.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">declaredVariables: </span><span class="o">-></span>
|
||||
<span class="p">(</span><span class="nx">key</span> <span class="k">for</span> <span class="nx">key</span><span class="p">,</span> <span class="nx">val</span> <span class="k">of</span> <span class="nx">@variables</span> <span class="k">when</span> <span class="nx">val</span> <span class="o">is</span> <span class="s1">'var'</span><span class="p">).</span><span class="nx">sort</span><span class="p">()</span></pre></div> </td> </tr> <tr id="section-14"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-14">#</a> </div> <p>Return the list of assignments that are supposed to be made at the top
|
||||
of this scope.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">assigned_variables: </span><span class="o">-></span>
|
||||
<span class="s2">"$key = ${val.value}"</span> <span class="k">for</span> <span class="nx">key</span><span class="p">,</span> <span class="nx">val</span> <span class="k">of</span> <span class="nx">@variables</span> <span class="k">when</span> <span class="nx">val</span><span class="p">.</span><span class="nx">assigned</span></pre></div> </td> </tr> <tr id="section-15"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-15">#</a> </div> <p>Compile the JavaScript for all of the variable declarations in this scope.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">compiled_declarations: </span><span class="o">-></span>
|
||||
<span class="nx">@declared_variables</span><span class="p">().</span><span class="nx">join</span> <span class="s1">', '</span></pre></div> </td> </tr> <tr id="section-16"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-16">#</a> </div> <p>Compile the JavaScript for all of the variable assignments in this scope.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">compiled_assignments: </span><span class="o">-></span>
|
||||
<span class="nx">@assigned_variables</span><span class="p">().</span><span class="nx">join</span> <span class="s1">', '</span>
|
||||
of this scope.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">assignedVariables: </span><span class="o">-></span>
|
||||
<span class="s2">"$key = $val.value"</span> <span class="k">for</span> <span class="nx">key</span><span class="p">,</span> <span class="nx">val</span> <span class="k">of</span> <span class="nx">@variables</span> <span class="k">when</span> <span class="nx">val</span><span class="p">.</span><span class="nx">assigned</span></pre></div> </td> </tr> <tr id="section-15"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-15">#</a> </div> <p>Compile the JavaScript for all of the variable declarations in this scope.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">compiledDeclarations: </span><span class="o">-></span>
|
||||
<span class="nx">@declaredVariables</span><span class="p">().</span><span class="nx">join</span> <span class="s1">', '</span></pre></div> </td> </tr> <tr id="section-16"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-16">#</a> </div> <p>Compile the JavaScript for all of the variable assignments in this scope.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">compiledAssignments: </span><span class="o">-></span>
|
||||
<span class="nx">@assignedVariables</span><span class="p">().</span><span class="nx">join</span> <span class="s1">', '</span>
|
||||
|
||||
</pre></div> </td> </tr> </tbody> </table> </div> </body> </html>
|
||||
@@ -7,7 +7,7 @@ Portions of Underscore are inspired by or borrowed from
|
||||
<a href="http://osteele.com">Functional</a>, and John Resig's
|
||||
<a href="http://ejohn.com">Micro-Templating</a>.
|
||||
For all details and documentation:
|
||||
<a href='http://documentcloud.github.com/underscore/'>http://documentcloud.github.com/underscore/</a></p> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-3"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-3">#</a> </div> <h2>Baseline setup</h2> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-4"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-4">#</a> </div> <p>Establish the root object, <code>window</code> in the browser, or <code>global</code> on the server.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">root: </span><span class="k">this</span></pre></div> </td> </tr> <tr id="section-5"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-5">#</a> </div> <p>Save the previous value of the <code>_</code> variable.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">previousUnderscore: </span><span class="nx">root</span><span class="p">.</span><span class="nx">_</span></pre></div> </td> </tr> <tr id="section-6"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-6">#</a> </div> <p>Establish the object that gets thrown to break out of a loop iteration.
|
||||
http://documentcloud.github.com/underscore/</p> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-3"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-3">#</a> </div> <h2>Baseline setup</h2> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-4"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-4">#</a> </div> <p>Establish the root object, <code>window</code> in the browser, or <code>global</code> on the server.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">root: </span><span class="k">this</span></pre></div> </td> </tr> <tr id="section-5"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-5">#</a> </div> <p>Save the previous value of the <code>_</code> variable.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">previousUnderscore: </span><span class="nx">root</span><span class="p">.</span><span class="nx">_</span></pre></div> </td> </tr> <tr id="section-6"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-6">#</a> </div> <p>Establish the object that gets thrown to break out of a loop iteration.
|
||||
<code>StopIteration</code> is SOP on Mozilla.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">breaker: </span><span class="k">if</span> <span class="k">typeof</span><span class="p">(</span><span class="nx">StopIteration</span><span class="p">)</span> <span class="o">is</span> <span class="s1">'undefined'</span> <span class="k">then</span> <span class="s1">'__break__'</span> <span class="k">else</span> <span class="nx">StopIteration</span></pre></div> </td> </tr> <tr id="section-7"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-7">#</a> </div> <p>Helper function to escape <strong>RegExp</strong> contents, because JS doesn't have one.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">escapeRegExp: </span><span class="p">(</span><span class="nx">string</span><span class="p">)</span> <span class="o">-></span> <span class="nx">string</span><span class="p">.</span><span class="nx">replace</span><span class="p">(</span><span class="sr">/([.*+?^${}()|[\]\/\\])/g</span><span class="p">,</span> <span class="s1">'\\$1'</span><span class="p">)</span></pre></div> </td> </tr> <tr id="section-8"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-8">#</a> </div> <p>Save bytes in the minified (but not gzipped) version:</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">ArrayProto: </span> <span class="nb">Array</span><span class="p">.</span><span class="nx">prototype</span>
|
||||
<span class="nv">ObjProto: </span> <span class="nb">Object</span><span class="p">.</span><span class="nx">prototype</span></pre></div> </td> </tr> <tr id="section-9"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-9">#</a> </div> <p>Create quick reference variables for speed access to core prototypes.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">slice: </span> <span class="nx">ArrayProto</span><span class="p">.</span><span class="nx">slice</span>
|
||||
<span class="nv">unshift: </span> <span class="nx">ArrayProto</span><span class="p">.</span><span class="nx">unshift</span>
|
||||
@@ -172,7 +172,7 @@ if possible.</p> </td> <td class="code"> <
|
||||
<span class="k">return</span> <span class="p">[]</span> <span class="k">if</span> <span class="nx">len</span> <span class="o"><=</span> <span class="mi">0</span>
|
||||
<span class="nv">range: </span> <span class="k">new</span> <span class="nb">Array</span> <span class="nx">len</span>
|
||||
<span class="nv">idx: </span> <span class="mi">0</span>
|
||||
<span class="k">while</span> <span class="kc">true</span>
|
||||
<span class="nx">loop</span>
|
||||
<span class="k">return</span> <span class="nx">range</span> <span class="k">if</span> <span class="p">(</span><span class="k">if</span> <span class="nx">step</span> <span class="o">></span> <span class="mi">0</span> <span class="k">then</span> <span class="nx">i</span> <span class="o">-</span> <span class="nx">stop</span> <span class="k">else</span> <span class="nx">stop</span> <span class="o">-</span> <span class="nx">i</span><span class="p">)</span> <span class="o">>=</span> <span class="mi">0</span>
|
||||
<span class="nx">range</span><span class="p">[</span><span class="nx">idx</span><span class="p">]</span><span class="o">:</span> <span class="nx">i</span>
|
||||
<span class="nx">idx</span><span class="o">++</span>
|
||||
|
||||
@@ -46,7 +46,7 @@
|
||||
<a href="#conditionals">Conditionals, Ternaries, and Conditional Assignment</a>
|
||||
<a href="#aliases">Aliases</a>
|
||||
<a href="#splats">Splats...</a>
|
||||
<a href="#while">While Loops</a>
|
||||
<a href="#while">While, Until, and Loop</a>
|
||||
<a href="#comprehensions">Comprehensions (Arrays, Objects, and Ranges)</a>
|
||||
<a href="#slice_splice">Array Slicing and Splicing with Ranges</a>
|
||||
<a href="#expressions">Everything is an Expression</a>
|
||||
@@ -63,6 +63,7 @@
|
||||
<a href="#cake">Cake, and Cakefiles</a>
|
||||
<a href="#scripts">"text/coffeescript" Script Tags</a>
|
||||
<a href="#resources">Resources</a>
|
||||
<a href="#webchat">Web Chat (IRC)</a>
|
||||
<a href="#change_log">Change Log</a>
|
||||
</div>
|
||||
</div>
|
||||
@@ -123,13 +124,12 @@ alert reverse '.eeffoC yrT'</textarea></div>
|
||||
it compiles into clean JavaScript (the good parts) that can use existing
|
||||
JavaScript libraries seamlessly, and passes through
|
||||
<a href="http://www.jslint.com/">JSLint</a> without warnings. The compiled
|
||||
output is quite readable — pretty-printed, with comments
|
||||
preserved intact.
|
||||
output is pretty-printed and quite readable.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<b>Latest Version:</b>
|
||||
<a href="http://github.com/jashkenas/coffee-script/tarball/0.6.0">0.6.0</a>
|
||||
<a href="http://github.com/jashkenas/coffee-script/tarball/0.7.2">0.7.2</a>
|
||||
</p>
|
||||
|
||||
<h2>
|
||||
@@ -139,7 +139,7 @@ alert reverse '.eeffoC yrT'</textarea></div>
|
||||
|
||||
<p><i>CoffeeScript on the left, compiled JavaScript output on the right.</i></p>
|
||||
|
||||
<%= code_for('overview', 'cubed_list') %>
|
||||
<%= code_for('overview', 'cubes') %>
|
||||
|
||||
<p>
|
||||
For a longer CoffeeScript example, check out
|
||||
@@ -171,11 +171,11 @@ alert reverse '.eeffoC yrT'</textarea></div>
|
||||
|
||||
<p>
|
||||
To install, first make sure you have a working copy of the latest tagged version of
|
||||
<a href="http://nodejs.org/">Node.js</a>, currently <b>0.1.33</b> or higher.
|
||||
<a href="http://nodejs.org/">Node.js</a>, currently <b>0.1.90</b> or higher.
|
||||
Then clone the CoffeeScript
|
||||
<a href="http://github.com/jashkenas/coffee-script">source repository</a>
|
||||
from GitHub, or download the latest
|
||||
release: <a href="http://github.com/jashkenas/coffee-script/tarball/0.6.0">0.6.0</a>.
|
||||
release: <a href="http://github.com/jashkenas/coffee-script/tarball/0.7.2">0.7.2</a>.
|
||||
To install the CoffeeScript compiler system-wide
|
||||
under <tt>/usr/local</tt>, open the directory and run:
|
||||
</p>
|
||||
@@ -184,7 +184,16 @@ alert reverse '.eeffoC yrT'</textarea></div>
|
||||
sudo bin/cake install</pre>
|
||||
|
||||
<p>
|
||||
This provides the <tt>coffee</tt> command, which will execute CoffeeScripts
|
||||
Alternatively, if you already have the
|
||||
<a href="http://npmjs.org/">Node Package Manager</a> installed,
|
||||
you can use that to grab the latest CoffeeScript:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
sudo npm install coffee-script</pre>
|
||||
|
||||
<p>
|
||||
Both of these provide the <tt>coffee</tt> command, which will execute CoffeeScripts
|
||||
under Node.js by default, but is also used to compile CoffeeScript
|
||||
<tt>.coffee</tt> files into JavaScript, or to run an an interactive REPL.
|
||||
When compiling to JavaScript, <tt>coffee</tt> writes the output
|
||||
@@ -331,7 +340,8 @@ coffee --print app/scripts/*.coffee > concatenation.js</pre>
|
||||
|
||||
<p>
|
||||
You don't need to use parentheses to invoke a function if you're passing
|
||||
arguments:<br /><tt>print "coffee"</tt>
|
||||
arguments:<br /><tt>print "coffee"</tt>. Implicit parentheses wrap forwards
|
||||
to the end of the line, or block expression.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
@@ -344,8 +354,7 @@ coffee --print app/scripts/*.coffee > concatenation.js</pre>
|
||||
<span id="functions" class="bookmark"></span>
|
||||
<b class="header">Functions and Invocation</b>
|
||||
Functions are defined by a list of parameters, an arrow, and the
|
||||
function body. The empty function looks like this: <tt>-></tt> All
|
||||
functions in CoffeeScript are named by default, for easier debugging.
|
||||
function body. The empty function looks like this: <tt>-></tt>
|
||||
</p>
|
||||
<%= code_for('functions', 'cube(5)') %>
|
||||
<p>
|
||||
@@ -378,6 +387,12 @@ coffee --print app/scripts/*.coffee > concatenation.js</pre>
|
||||
and match the two styles.
|
||||
</p>
|
||||
<%= code_for('objects_and_arrays', 'song.join(",")') %>
|
||||
<p>
|
||||
In JavaScript, you can't use reserved words, like <tt>class</tt>, as properties
|
||||
of an object, without quoting them as strings. CoffeeScript notices and quotes
|
||||
them for you, so you don't have to worry about it (say, when using jQuery).
|
||||
</p>
|
||||
<%= code_for('objects_reserved') %>
|
||||
|
||||
<p>
|
||||
<span id="lexical_scope" class="bookmark"></span>
|
||||
@@ -386,7 +401,7 @@ coffee --print app/scripts/*.coffee > concatenation.js</pre>
|
||||
are properly declared within lexical scope — you never need to write
|
||||
<tt>var</tt> yourself.
|
||||
</p>
|
||||
<%= code_for('scope', 'new_num') %>
|
||||
<%= code_for('scope', 'inner') %>
|
||||
<p>
|
||||
Notice how the all of the variable declarations have been pushed up to
|
||||
the top of the closest scope, the first time they appear.
|
||||
@@ -432,7 +447,7 @@ coffee --print app/scripts/*.coffee > concatenation.js</pre>
|
||||
<%= code_for('conditionals') %>
|
||||
<p>
|
||||
You can assign a variable to a half-expression to perform an operation
|
||||
like Ruby's <tt>||=</tt>, which only assigns a value to a variable
|
||||
like Ruby's <tt>||=</tt>, which only assigns a value to a variable
|
||||
if the variable's current value is falsy.
|
||||
</p>
|
||||
|
||||
@@ -468,6 +483,10 @@ coffee --print app/scripts/*.coffee > concatenation.js</pre>
|
||||
<p>
|
||||
As a shortcut for <tt>this.property</tt>, you can use <tt>@property</tt>.
|
||||
</p>
|
||||
<p>
|
||||
You can use <tt>in</tt> to test for array presence, and <tt>of</tt> to
|
||||
test for JavaScript object-key presence.
|
||||
</p>
|
||||
<%= code_for('aliases') %>
|
||||
|
||||
<p>
|
||||
@@ -482,7 +501,7 @@ coffee --print app/scripts/*.coffee > concatenation.js</pre>
|
||||
|
||||
<p>
|
||||
<span id="while" class="bookmark"></span>
|
||||
<b class="header">While Loops</b>
|
||||
<b class="header">While, Until, and Loop</b>
|
||||
The only low-level loop that CoffeeScript provides is the <b>while</b> loop. The
|
||||
main difference from JavaScript is that the <b>while</b> loop can be used
|
||||
as an expression, returning an array containing the result of each iteration
|
||||
@@ -490,8 +509,10 @@ coffee --print app/scripts/*.coffee > concatenation.js</pre>
|
||||
</p>
|
||||
<%= code_for('while', 'lyrics.join("\n")') %>
|
||||
<p>
|
||||
For readability, the <b>until</b> keyword is equivalent to <tt>while not</tt>,
|
||||
and the <b>loop</b> keyword is equivalent to <tt>while true</tt>.
|
||||
Other JavaScript loops, such as <b>for</b> loops and <b>do-while</b> loops
|
||||
can be mimicked by variations on <b>while</b>, but the hope is that you
|
||||
can be mimicked by variations on <b>loop</b>, but the hope is that you
|
||||
won't need to do that with CoffeeScript, either because you're using
|
||||
<b>each</b> (<b>forEach</b>) style iterators, or...
|
||||
</p>
|
||||
@@ -510,8 +531,7 @@ coffee --print app/scripts/*.coffee > concatenation.js</pre>
|
||||
<p>
|
||||
If you know the start and end of your loop, or would like to step through
|
||||
in fixed-size increments, you can use a range to specify the start and
|
||||
end of your comprehension. (The long line-breaking "for" definitions in
|
||||
the compiled JS below allow ranges to count downwards, as well as upwards).
|
||||
end of your comprehension.
|
||||
</p>
|
||||
<%= code_for('range_comprehensions', 'countdown') %>
|
||||
<p>
|
||||
@@ -531,7 +551,7 @@ coffee --print app/scripts/*.coffee > concatenation.js</pre>
|
||||
the slice, and the second is the index of the last one. Three dots signify
|
||||
a range that excludes the end.
|
||||
</p>
|
||||
<%= code_for('slices', 'numbers_copy') %>
|
||||
<%= code_for('slices', 'copy') %>
|
||||
<p>
|
||||
The same syntax can be used with assignment to replace a segment of an
|
||||
array with new values (to splice it).
|
||||
@@ -654,7 +674,7 @@ coffee --print app/scripts/*.coffee > concatenation.js</pre>
|
||||
on the right to the variables on the left. In the simplest case, it can be
|
||||
used for parallel assignment:
|
||||
</p>
|
||||
<%= code_for('parallel_assignment', 'bait') %>
|
||||
<%= code_for('parallel_assignment', 'theBait') %>
|
||||
<p>
|
||||
But it's also helpful for dealing with functions that return multiple
|
||||
values.
|
||||
@@ -664,7 +684,7 @@ coffee --print app/scripts/*.coffee > concatenation.js</pre>
|
||||
Pattern matching can be used with any depth of array and object nesting,
|
||||
to help pull out deeply nested properties.
|
||||
</p>
|
||||
<%= code_for('object_extraction', 'poet + " — " + street') %>
|
||||
<%= code_for('object_extraction', 'name + " — " + street') %>
|
||||
<p>
|
||||
Pattern matching can even be combined with splats.
|
||||
</p>
|
||||
@@ -694,15 +714,6 @@ coffee --print app/scripts/*.coffee > concatenation.js</pre>
|
||||
have referred to the undefined "customer" property of the DOM element,
|
||||
and trying to call <tt>purchase()</tt> on it would have raised an exception.
|
||||
</p>
|
||||
<p>
|
||||
If you have more custom needs for function binding, CoffeeScript includes
|
||||
the <tt><-</tt> bind operator, which works the same as ECMAScript 5
|
||||
and Prototype.js's <tt>Function#bind</tt>. The first argument is the <tt>this</tt>
|
||||
value, and the remainder are curried arguments. In the example below,
|
||||
we curry a jQuery request for a URL, and then execute the bound function
|
||||
with the missing callback argument.
|
||||
</p>
|
||||
<%= code_for('binding', true) %>
|
||||
|
||||
<p>
|
||||
<span id="embedded" class="bookmark"></span>
|
||||
@@ -768,7 +779,7 @@ coffee --print app/scripts/*.coffee > concatenation.js</pre>
|
||||
<b class="header">Multiline Strings and Heredocs</b>
|
||||
Multiline strings are allowed in CoffeeScript.
|
||||
</p>
|
||||
<%= code_for('strings', 'moby_dick') %>
|
||||
<%= code_for('strings', 'mobyDick') %>
|
||||
<p>
|
||||
Heredocs can be used to hold formatted or indentation-sensitive text
|
||||
(or, if you just don't feel like escaping quotes and apostrophes). The
|
||||
@@ -857,6 +868,11 @@ coffee --print app/scripts/*.coffee > concatenation.js</pre>
|
||||
IRC client of your choice, or on
|
||||
<a href="http://webchat.freenode.net/">webchat.freenode.net</a>.
|
||||
</li>
|
||||
<li>
|
||||
<b>yeungda</b>'s <a href="http://github.com/yeungda/jcoffeescript">JCoffeeScript</a>
|
||||
— A Java Library that uses Rhino to compile CoffeeScript, allowing
|
||||
compilation within Java projects or on systems that Node.js doesn't support.
|
||||
</li>
|
||||
<li>
|
||||
<b>defunkt</b>'s <a href="http://github.com/defunkt/coffee-mode">CoffeeScript Major Mode</a>
|
||||
— a Emacs major mode that provides syntax highlighting, indentation
|
||||
@@ -871,6 +887,14 @@ coffee --print app/scripts/*.coffee > concatenation.js</pre>
|
||||
<b>kchmck</b>'s <a href="http://github.com/kchmck/vim-coffee-script">Vim CoffeeScript</a>
|
||||
— which adds Vim syntax highlighting and indentation support.
|
||||
</li>
|
||||
<li>
|
||||
<b>wavded</b>'s <a href="http://github.com/wavded/gedit-coffeescript">gedit-coffeescript</a>
|
||||
— a CoffeeScript syntax highlighter for the gedit text editor.
|
||||
</li>
|
||||
<li>
|
||||
<b>yeungda</b>'s <a href="http://yeungda.github.com/coffeescript-idea/">coffeescript-idea</a>
|
||||
— a plugin for IntelliJ IDEA and RubyMine providing syntax highlighting.
|
||||
</li>
|
||||
<li>
|
||||
<b>mattly</b>'s <a href="http://github.com/mattly/rack-coffee">rack-coffee</a>
|
||||
— a small Rack middleware for serving CoffeeScript files as
|
||||
@@ -881,17 +905,98 @@ coffee --print app/scripts/*.coffee > concatenation.js</pre>
|
||||
— a plugin that serves and bundles CoffeeScript from within your
|
||||
Rails application.
|
||||
</li>
|
||||
<li>
|
||||
<b>dsc</b>'s <a href="http://github.com/dsc/coffeecup">CoffeeCup</a>
|
||||
— A Python WSGI middleware that compiles CoffeeScript to JavaScript
|
||||
on-demand during development.
|
||||
</li>
|
||||
<li>
|
||||
<b>sutto</b>'s <a href="http://github.com/Sutto/barista">Barista</a>
|
||||
— a BistroCar alternative that integrates well with
|
||||
<a href="http://documentcloud.github.com/jammit">Jammit</a> and Rails 3.
|
||||
</li>
|
||||
<li>
|
||||
<b>inem</b> and <b>gerad</b>'s <a href="http://github.com/gerad/coffee-haml-filter">coffee-haml-filter</a>
|
||||
— a custom filter for rendering CoffeeScript inline within
|
||||
<a href="http://haml-lang.com/">HAML</a> templates.
|
||||
</li>
|
||||
<li>
|
||||
<b>jashkenas</b>'s <a href="http://jashkenas.github.com/docco/">Docco</a>
|
||||
— A quick-and-dirty literate-programming-style documentation generator
|
||||
for CoffeeScript. Used to produce the annotated source.
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h2>
|
||||
<span id="webchat" class="bookmark"></span>
|
||||
Web Chat (IRC)
|
||||
</h2>
|
||||
|
||||
<p>
|
||||
Quick help and advice can usually be found in the CoffeeScript IRC room.
|
||||
Join <tt>#coffeescript</tt> on <tt>irc.freenode.net</tt>, or click the
|
||||
button below to open a webchat session on this page.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<button id="open_webchat">click to open #coffeescript</button>
|
||||
</p>
|
||||
|
||||
<h2>
|
||||
<span id="change_log" class="bookmark"></span>
|
||||
Change Log
|
||||
</h2>
|
||||
|
||||
<p>
|
||||
<b class="header" style="margin-top: 20px;">0.7.1</b>
|
||||
Block-style comments are now passed through and printed as JavaScript block
|
||||
comments -- making them useful for licenses and copyright headers. Better
|
||||
support for running coffee scripts standalone via hashbangs.
|
||||
Improved syntax errors for tokens that are not in the grammar.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<b class="header" style="margin-top: 20px;">0.7.0</b>
|
||||
Official CoffeeScript variable style is now camelCase, as in JavaScript.
|
||||
Reserved words are now allowed as object keys, and will be quoted for you.
|
||||
Range comprehensions now generate cleaner code, but you have to specify <tt>by -1</tt>
|
||||
if you'd like to iterate downward. Reporting of syntax errors is greatly
|
||||
improved from the previous release. Running <tt>coffee</tt> with no arguments
|
||||
now launches the REPL, with Readline support. The <tt><-</tt> bind operator
|
||||
has been removed from CoffeeScript. The <tt>loop</tt> keyword was added,
|
||||
which is equivalent to a <tt>while true</tt> loop. Comprehensions that contain
|
||||
closures will now close over their variables, like the semantics of a <tt>forEach</tt>.
|
||||
You can now use bound function in class definitions (bound to the instance).
|
||||
For consistency, <tt>a in b</tt> is now an array presence check, and <tt>a of b</tt>
|
||||
is an object-key check. Comments are no longer passed through to the generated
|
||||
JavaScript.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<b class="header" style="margin-top: 20px;">0.6.2</b>
|
||||
The <tt>coffee</tt> command will now preserve directory structure when
|
||||
compiling a directory full of scripts. Fixed two omissions that were preventing
|
||||
the CoffeeScript compiler from running live within Internet Explorer.
|
||||
There's now a syntax for block comments, similar in spirit to CoffeeScript's heredocs.
|
||||
ECMA Harmony DRY-style pattern matching is now supported, where the name
|
||||
of the property is the same as the name of the value: <tt>{name, length}: func</tt>.
|
||||
Pattern matching is now allowed within comprehension variables. <tt>unless</tt>
|
||||
is now allowed in block form. <tt>until</tt> loops were added, as the inverse
|
||||
of <tt>while</tt> loops. <tt>switch</tt> statements are now allowed without
|
||||
switch object clauses. Compatible
|
||||
with Node.js <b>v0.1.95</b>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<b class="header" style="margin-top: 20px;">0.6.1</b>
|
||||
Upgraded CoffeeScript for compatibility with the new Node.js <b>v0.1.90</b>
|
||||
series.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<b class="header" style="margin-top: 20px;">0.6.0</b>
|
||||
Trailing commas are now allowed, a-la Python. Static
|
||||
properties may be assigned directly within class definitions,
|
||||
Trailing commas are now allowed, a-la Python. Static
|
||||
properties may be assigned directly within class definitions,
|
||||
using <tt>@property</tt> notation.
|
||||
</p>
|
||||
|
||||
@@ -1118,7 +1223,7 @@ coffee --print app/scripts/*.coffee > concatenation.js</pre>
|
||||
source: $('#repl_source').val()
|
||||
window.compiled_js: ''
|
||||
try
|
||||
window.compiled_js: CoffeeScript.compile source, {no_wrap: true}
|
||||
window.compiled_js: CoffeeScript.compile source, {noWrap: true}
|
||||
$('#repl_results').text window.compiled_js
|
||||
$('#error').hide();
|
||||
catch error
|
||||
@@ -1159,6 +1264,9 @@ coffee --print app/scripts/*.coffee > concatenation.js</pre>
|
||||
$('.navigation .minimize').click ->
|
||||
document.body.className: 'minimized'
|
||||
|
||||
$('#open_webchat').click ->
|
||||
$(this).replaceWith $('<iframe src="http://webchat.freenode.net/?channels=coffeescript" width="625" height="400"></iframe>')
|
||||
|
||||
compile_source()
|
||||
|
||||
</script>
|
||||
|
||||
@@ -1,14 +1,17 @@
|
||||
(function(){
|
||||
var volume;
|
||||
var volume, winner;
|
||||
if (ignition === true) {
|
||||
launch();
|
||||
}
|
||||
if (band !== spinal_tap) {
|
||||
if (band !== SpinalTap) {
|
||||
volume = 10;
|
||||
}
|
||||
if (!(answer === false)) {
|
||||
let_the_wild_rumpus_begin();
|
||||
letTheWildRumpusBegin();
|
||||
}
|
||||
car.speed < limit ? accelerate() : null;
|
||||
if (47 === pick || 92 === pick || 13 === pick) {
|
||||
winner = true;
|
||||
}
|
||||
car.speed < speed_limit ? accelerate() : null;
|
||||
print("My name is " + this.name);
|
||||
})();
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
(function(){
|
||||
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, food, lunch, roid, roid2;
|
||||
// Eat lunch.
|
||||
lunch = (function() {
|
||||
_a = []; _c = ['toast', 'cheese', 'wine'];
|
||||
for (_b = 0, _d = _c.length; _b < _d; _b++) {
|
||||
@@ -8,8 +7,7 @@
|
||||
_a.push(eat(food));
|
||||
}
|
||||
return _a;
|
||||
}).call(this);
|
||||
// Naive collision detection.
|
||||
})();
|
||||
_f = asteroids;
|
||||
for (_e = 0, _g = _f.length; _e < _g; _e++) {
|
||||
roid = _f[_e];
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
(function(){
|
||||
var get_source, url;
|
||||
var __slice = Array.prototype.slice, __bind = function(func, obj, args) {
|
||||
return function() {
|
||||
return func.apply(obj || {}, args ? args.concat(__slice.call(arguments, 0)) : arguments);
|
||||
};
|
||||
};
|
||||
url = "documentation/coffee/binding.coffee";
|
||||
get_source = __bind(jQuery.get, jQuery, [url]);
|
||||
get_source(function(response) {
|
||||
return alert(response);
|
||||
});
|
||||
})();
|
||||
@@ -1,12 +1,14 @@
|
||||
(function(){
|
||||
task('test', 'run each of the unit tests', function() {
|
||||
var _a, _b, _c, _d, test;
|
||||
_a = []; _c = test_files;
|
||||
var _a, _b, _c, _d;
|
||||
_a = []; _c = files;
|
||||
for (_b = 0, _d = _c.length; _b < _d; _b++) {
|
||||
test = _c[_b];
|
||||
_a.push(fs.readFile(test, function(err, code) {
|
||||
return eval(coffee.compile(code));
|
||||
}));
|
||||
(function() {
|
||||
var test = _c[_b];
|
||||
return _a.push(fs.readFile(test, function(err, code) {
|
||||
return eval(coffee.compile(code));
|
||||
}));
|
||||
})();
|
||||
}
|
||||
return _a;
|
||||
});
|
||||
|
||||
@@ -7,28 +7,31 @@
|
||||
child.prototype = new ctor();
|
||||
child.prototype.constructor = child;
|
||||
};
|
||||
Animal = function Animal() { };
|
||||
Animal.prototype.move = function move(meters) {
|
||||
Animal = function() { };
|
||||
Animal.prototype.move = function(meters) {
|
||||
return alert(this.name + " moved " + meters + "m.");
|
||||
};
|
||||
Snake = function Snake(name) {
|
||||
|
||||
Snake = function(name) {
|
||||
this.name = name;
|
||||
return this;
|
||||
};
|
||||
__extends(Snake, Animal);
|
||||
Snake.prototype.move = function move() {
|
||||
Snake.prototype.move = function() {
|
||||
alert("Slithering...");
|
||||
return Snake.__superClass__.move.call(this, 5);
|
||||
};
|
||||
Horse = function Horse(name) {
|
||||
|
||||
Horse = function(name) {
|
||||
this.name = name;
|
||||
return this;
|
||||
};
|
||||
__extends(Horse, Animal);
|
||||
Horse.prototype.move = function move() {
|
||||
Horse.prototype.move = function() {
|
||||
alert("Galloping...");
|
||||
return Horse.__superClass__.move.call(this, 45);
|
||||
};
|
||||
|
||||
sam = new Snake("Sammy the Python");
|
||||
tom = new Horse("Tommy the Palomino");
|
||||
sam.move();
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
(function(){
|
||||
var date, expensive, mood;
|
||||
var date, mood, options;
|
||||
if (singing) {
|
||||
mood = greatly_improved;
|
||||
mood = greatlyImproved;
|
||||
}
|
||||
if (happy && knows_it) {
|
||||
claps_hands();
|
||||
cha_cha_cha();
|
||||
if (happy && knowsIt) {
|
||||
clapsHands();
|
||||
chaChaCha();
|
||||
}
|
||||
date = friday ? sue : jill;
|
||||
expensive = expensive || do_the_math();
|
||||
options = options || defaultOptions;
|
||||
})();
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
(function(){
|
||||
var eldest, grade;
|
||||
grade = function grade(student) {
|
||||
if (student.excellent_work) {
|
||||
grade = function(student) {
|
||||
if (student.excellentWork) {
|
||||
return "A+";
|
||||
} else if (student.okay_stuff) {
|
||||
if (student.tried_hard) {
|
||||
} else if (student.okayStuff) {
|
||||
if (student.triedHard) {
|
||||
return "B";
|
||||
} else {
|
||||
return "B-";
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
(function(){
|
||||
var _a, _b, globals, name;
|
||||
var __hasProp = Object.prototype.hasOwnProperty;
|
||||
// The first ten global properties.
|
||||
globals = (function() {
|
||||
_a = []; _b = window;
|
||||
for (name in _b) { if (__hasProp.call(_b, name)) {
|
||||
_a.push(name);
|
||||
}}
|
||||
return _a;
|
||||
}).call(this).slice(0, 10);
|
||||
})().slice(0, 10);
|
||||
})();
|
||||
|
||||
@@ -5,5 +5,5 @@
|
||||
} catch (error) {
|
||||
return "And the error is ... " + error;
|
||||
}
|
||||
}).call(this));
|
||||
})());
|
||||
})();
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
(function(){
|
||||
var Account;
|
||||
var __slice = Array.prototype.slice, __bind = function(func, obj, args) {
|
||||
return function() {
|
||||
return func.apply(obj || {}, args ? args.concat(__slice.call(arguments, 0)) : arguments);
|
||||
};
|
||||
};
|
||||
Account = function Account(customer, cart) {
|
||||
Account = function(customer, cart) {
|
||||
this.customer = customer;
|
||||
this.cart = cart;
|
||||
return $('.shopping_cart').bind('click', __bind(function(event) {
|
||||
return $('.shopping_cart').bind('click', (function(__this) {
|
||||
var __func = function(event) {
|
||||
return this.customer.purchase(this.cart);
|
||||
}, this));
|
||||
};
|
||||
return (function() {
|
||||
return __func.apply(__this, arguments);
|
||||
});
|
||||
})(this));
|
||||
};
|
||||
})();
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
(function(){
|
||||
var cube, square;
|
||||
square = function square(x) {
|
||||
square = function(x) {
|
||||
return x * x;
|
||||
};
|
||||
cube = function cube(x) {
|
||||
cube = function(x) {
|
||||
return square(x) * x;
|
||||
};
|
||||
})();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
(function(){
|
||||
var author, quote;
|
||||
author = "Wittgenstein";
|
||||
quote = "A picture is a fact. -- " + author;
|
||||
quote = ("A picture is a fact. -- " + author);
|
||||
})();
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
(function(){
|
||||
var dates, sentence, sep;
|
||||
sentence = "" + (22 / 7) + " is a decent approximation of π";
|
||||
sentence = ("" + (22 / 7) + " is a decent approximation of π");
|
||||
sep = "[.\\/\\- ]";
|
||||
dates = (new RegExp("\\d+" + sep + "\\d+" + sep + "\\d+", "g"));
|
||||
dates = (new RegExp(("\\d+" + sep + "\\d+" + sep + "\\d+"), "g"));
|
||||
})();
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
(function(){
|
||||
var _a, city, forecast, temp, weather_report;
|
||||
weather_report = function weather_report(location) {
|
||||
// Make an Ajax request to fetch the weather...
|
||||
var _a, city, forecast, temp, weatherReport;
|
||||
weatherReport = function(location) {
|
||||
return [location, 72, "Mostly Sunny"];
|
||||
};
|
||||
_a = weather_report("Berkeley, CA");
|
||||
_a = weatherReport("Berkeley, CA");
|
||||
city = _a[0];
|
||||
temp = _a[1];
|
||||
forecast = _a[2];
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
(function(){
|
||||
var _a, _b, age, ages, child, years_old;
|
||||
var _a, _b, age, ages, child, yearsOld;
|
||||
var __hasProp = Object.prototype.hasOwnProperty;
|
||||
years_old = {
|
||||
yearsOld = {
|
||||
max: 10,
|
||||
ida: 9,
|
||||
tim: 11
|
||||
};
|
||||
ages = (function() {
|
||||
_a = []; _b = years_old;
|
||||
_a = []; _b = yearsOld;
|
||||
for (child in _b) { if (__hasProp.call(_b, child)) {
|
||||
age = _b[child];
|
||||
_a.push(child + " is " + age);
|
||||
}}
|
||||
return _a;
|
||||
}).call(this);
|
||||
})();
|
||||
})();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
(function(){
|
||||
var _a, _b, _c, city, futurists, poet, street;
|
||||
var _a, _b, _c, city, futurists, name, street;
|
||||
futurists = {
|
||||
sculptor: "Umberto Boccioni",
|
||||
painter: "Vladimir Burliuk",
|
||||
@@ -10,7 +10,7 @@
|
||||
};
|
||||
_a = futurists;
|
||||
_b = _a.poet;
|
||||
poet = _b.name;
|
||||
name = _b.name;
|
||||
_c = _b.address;
|
||||
street = _c[0];
|
||||
city = _c[1];
|
||||
|
||||
5
documentation/js/objects_reserved.js
Normal file
5
documentation/js/objects_reserved.js
Normal file
@@ -0,0 +1,5 @@
|
||||
(function(){
|
||||
$('.account').css({
|
||||
'class': 'active'
|
||||
});
|
||||
})();
|
||||
@@ -1,44 +1,37 @@
|
||||
(function(){
|
||||
var _a, _b, _c, _d, cubed_list, list, math, num, number, opposite_day, race, square;
|
||||
var _a, _b, _c, _d, cubes, list, math, num, number, opposite, race, square;
|
||||
var __slice = Array.prototype.slice;
|
||||
// Assignment:
|
||||
number = 42;
|
||||
opposite_day = true;
|
||||
// Conditions:
|
||||
if (opposite_day) {
|
||||
opposite = true;
|
||||
if (opposite) {
|
||||
number = -42;
|
||||
}
|
||||
// Functions:
|
||||
square = function square(x) {
|
||||
square = function(x) {
|
||||
return x * x;
|
||||
};
|
||||
// Arrays:
|
||||
list = [1, 2, 3, 4, 5];
|
||||
// Objects:
|
||||
math = {
|
||||
root: Math.sqrt,
|
||||
square: square,
|
||||
cube: function cube(x) {
|
||||
cube: function(x) {
|
||||
return x * square(x);
|
||||
}
|
||||
};
|
||||
// Splats:
|
||||
race = function race(winner) {
|
||||
race = function(winner) {
|
||||
var runners;
|
||||
runners = __slice.call(arguments, 1, arguments.length - 0);
|
||||
var _a = arguments.length, _b = _a >= 2;
|
||||
runners = __slice.call(arguments, 1, _a - 0);
|
||||
return print(winner, runners);
|
||||
};
|
||||
// Existence:
|
||||
if ((typeof elvis !== "undefined" && elvis !== null)) {
|
||||
if (typeof elvis !== "undefined" && elvis !== null) {
|
||||
alert("I knew it!");
|
||||
}
|
||||
// Array comprehensions:
|
||||
cubed_list = (function() {
|
||||
cubes = (function() {
|
||||
_a = []; _c = list;
|
||||
for (_b = 0, _d = _c.length; _b < _d; _b++) {
|
||||
num = _c[_b];
|
||||
_a.push(math.cube(num));
|
||||
}
|
||||
return _a;
|
||||
}).call(this);
|
||||
})();
|
||||
})();
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
(function(){
|
||||
var _a, and_switch, bait;
|
||||
bait = 1000;
|
||||
and_switch = 0;
|
||||
_a = [and_switch, bait];
|
||||
bait = _a[0];
|
||||
and_switch = _a[1];
|
||||
var _a, theBait, theSwitch;
|
||||
theBait = 1000;
|
||||
theSwitch = 0;
|
||||
_a = [theSwitch, theBait];
|
||||
theBait = _a[0];
|
||||
theSwitch = _a[1];
|
||||
})();
|
||||
|
||||
2
documentation/js/prototypes.js
vendored
2
documentation/js/prototypes.js
vendored
@@ -1,5 +1,5 @@
|
||||
(function(){
|
||||
String.prototype.dasherize = function dasherize() {
|
||||
String.prototype.dasherize = function() {
|
||||
return this.replace(/_/g, "-");
|
||||
};
|
||||
})();
|
||||
|
||||
@@ -1,21 +1,22 @@
|
||||
(function(){
|
||||
var _a, _b, _c, _d, countdown, egg_delivery, num;
|
||||
var _a, countdown, deliverEggs, num;
|
||||
countdown = (function() {
|
||||
_a = []; _c = 10; _d = 1;
|
||||
for (_b = 0, num = _c; (_c <= _d ? num <= _d : num >= _d); (_c <= _d ? num += 1 : num -= 1), _b++) {
|
||||
_a = [];
|
||||
for (num = 10; num >= 1; num += -1) {
|
||||
_a.push(num);
|
||||
}
|
||||
return _a;
|
||||
}).call(this);
|
||||
egg_delivery = function egg_delivery() {
|
||||
var _e, _f, _g, _h, dozen_eggs, i;
|
||||
_e = []; _g = 0; _h = eggs.length;
|
||||
for (_f = 0, i = _g; (_g <= _h ? i < _h : i > _h); (_g <= _h ? i += 12 : i -= 12), _f++) {
|
||||
_e.push((function() {
|
||||
dozen_eggs = eggs.slice(i, i + 12);
|
||||
return deliver(new egg_carton(dozen));
|
||||
}).call(this));
|
||||
})();
|
||||
deliverEggs = function() {
|
||||
var _b, _c, dozen, i;
|
||||
_b = []; (_c = eggs.length);
|
||||
|
||||
for (i = 0; i < _c; i += 12) {
|
||||
_b.push((function() {
|
||||
dozen = eggs.slice(i, i + 12);
|
||||
return deliver(new eggCarton(dozen));
|
||||
})());
|
||||
}
|
||||
return _e;
|
||||
return _b;
|
||||
};
|
||||
})();
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
(function(){
|
||||
var change_numbers, new_num, num;
|
||||
num = 1;
|
||||
change_numbers = function change_numbers() {
|
||||
var new_num;
|
||||
new_num = -1;
|
||||
num = 10;
|
||||
return num;
|
||||
var changeNumbers, inner, outer;
|
||||
outer = 1;
|
||||
changeNumbers = function() {
|
||||
var inner;
|
||||
inner = -1;
|
||||
outer = 10;
|
||||
return outer;
|
||||
};
|
||||
new_num = change_numbers();
|
||||
inner = changeNumbers();
|
||||
})();
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
(function(){
|
||||
var numbers, numbers_copy, three_to_six;
|
||||
var copy, numbers, threeToSix;
|
||||
numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
|
||||
three_to_six = numbers.slice(3, 6 + 1);
|
||||
numbers_copy = numbers.slice(0, numbers.length);
|
||||
threeToSix = numbers.slice(3, 6 + 1);
|
||||
copy = numbers.slice(0, numbers.length);
|
||||
})();
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
(function(){
|
||||
var _a;
|
||||
(_a = lottery.draw_winner()) == undefined ? undefined : _a.address == undefined ? undefined : _a.address.zipcode;
|
||||
typeof (_a = (lottery.drawWinner())) === "undefined" || _a == undefined ? undefined : _a.address == undefined ? undefined : _a.address.zipcode;
|
||||
})();
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
(function(){
|
||||
var award_medals, contenders, gold, silver, the_field;
|
||||
var awardMedals, contenders, gold, rest, silver;
|
||||
var __slice = Array.prototype.slice;
|
||||
gold = (silver = (the_field = "unknown"));
|
||||
award_medals = function award_medals(first, second) {
|
||||
var rest;
|
||||
rest = __slice.call(arguments, 2, arguments.length - 0);
|
||||
gold = (silver = (rest = "unknown"));
|
||||
awardMedals = function(first, second) {
|
||||
var _a = arguments.length, _b = _a >= 3;
|
||||
rest = __slice.call(arguments, 2, _a - 0);
|
||||
gold = first;
|
||||
silver = second;
|
||||
the_field = rest;
|
||||
return the_field;
|
||||
rest = rest;
|
||||
return rest;
|
||||
};
|
||||
contenders = ["Michael Phelps", "Liu Xiang", "Yao Ming", "Allyson Felix", "Shawn Johnson", "Roman Sebrle", "Guo Jingjing", "Tyson Gay", "Asafa Powell", "Usain Bolt"];
|
||||
award_medals.apply(this, contenders);
|
||||
awardMedals.apply(this, contenders);
|
||||
alert("Gold: " + gold);
|
||||
alert("Silver: " + silver);
|
||||
alert("The Field: " + the_field);
|
||||
alert("The Field: " + rest);
|
||||
})();
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
(function(){
|
||||
var moby_dick;
|
||||
moby_dick = "Call me Ishmael. Some years ago -- \
|
||||
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 \
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
(function(){
|
||||
if (day === "Mon") {
|
||||
go_to_work();
|
||||
goToWork();
|
||||
} else if (day === "Tue") {
|
||||
go_to_the_park();
|
||||
goToThePark();
|
||||
} else if (day === "Thu") {
|
||||
go_ice_fishing();
|
||||
goIceFishing();
|
||||
} else if (day === "Fri" || day === "Sat") {
|
||||
if (day === bingo_day) {
|
||||
go_to_bingo();
|
||||
go_dancing();
|
||||
if (day === bingoDay) {
|
||||
goToBingo();
|
||||
goDancing();
|
||||
}
|
||||
} else if (day === "Sun") {
|
||||
go_to_church();
|
||||
goToChurch();
|
||||
} else {
|
||||
go_to_work();
|
||||
goToWork();
|
||||
}
|
||||
})();
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
(function(){
|
||||
try {
|
||||
all_hell_breaks_loose();
|
||||
cats_and_dogs_living_together();
|
||||
allHellBreaksLoose();
|
||||
catsAndDogsLivingTogether();
|
||||
} catch (error) {
|
||||
print(error);
|
||||
} finally {
|
||||
clean_up();
|
||||
cleanUp();
|
||||
}
|
||||
})();
|
||||
|
||||
@@ -1,15 +1,13 @@
|
||||
(function(){
|
||||
var _a, lyrics, num;
|
||||
// Econ 101
|
||||
if (this.studying_economics) {
|
||||
if (this.studyingEconomics) {
|
||||
while (supply > demand) {
|
||||
buy();
|
||||
}
|
||||
while (supply < demand) {
|
||||
while (!(supply > demand)) {
|
||||
sell();
|
||||
}
|
||||
}
|
||||
// Nursery Rhyme
|
||||
num = 6;
|
||||
lyrics = (function() {
|
||||
_a = [];
|
||||
@@ -18,5 +16,5 @@
|
||||
One fell out and bumped his head.");
|
||||
}
|
||||
return _a;
|
||||
}).call(this);
|
||||
})();
|
||||
})();
|
||||
|
||||
@@ -21,7 +21,7 @@ match_here: (regexp, text) ->
|
||||
|
||||
# Search for a kleene star match at the beginning of the text.
|
||||
match_star: (c, regexp, text) ->
|
||||
while true
|
||||
loop
|
||||
return true if match_here(regexp, text)
|
||||
return false unless text and (text[0] is c or c is '.')
|
||||
text: text.slice(1)
|
||||
|
||||
@@ -33,7 +33,7 @@ File.open: (path, mode, block) ->
|
||||
|
||||
# Write.
|
||||
write: (location, data) ->
|
||||
path = new Pathname location
|
||||
path: new Pathname location
|
||||
raise "Location does not exist" unless path.exists()
|
||||
|
||||
File.open path, 'w', (file) ->
|
||||
|
||||
@@ -19,7 +19,7 @@ spaced_out_multiline_object: {
|
||||
pi: 3.14159
|
||||
list: [1, 2, 3, 4]
|
||||
regex: /match[ing](every|thing|\/)/gi
|
||||
three: new Idea()
|
||||
three: new Idea
|
||||
|
||||
inner_obj: {
|
||||
freedom: -> _.freedom()
|
||||
@@ -94,7 +94,7 @@ while demand > supply
|
||||
|
||||
while supply > demand then buy()
|
||||
|
||||
while true
|
||||
loop
|
||||
break if broken
|
||||
continue if continuing
|
||||
|
||||
|
||||
@@ -90,14 +90,14 @@ class LinkedList
|
||||
|
||||
|
||||
# Tests.
|
||||
list: new LinkedList()
|
||||
list: new LinkedList
|
||||
|
||||
list.add("Hi")
|
||||
puts(list.size() is 1)
|
||||
puts(list.item(0) is "Hi")
|
||||
puts(list.item(1) is null)
|
||||
|
||||
list: new LinkedList()
|
||||
list: new LinkedList
|
||||
list.add("zero").add("one").add("two")
|
||||
puts(list.size() is 3)
|
||||
puts(list.item(2) is "two")
|
||||
|
||||
@@ -14,8 +14,7 @@ print(add(2, 4))
|
||||
|
||||
# loop: 'quaff' print.
|
||||
|
||||
while true
|
||||
print('quaff')
|
||||
loop print 'quaff'
|
||||
|
||||
|
||||
# ('cheese', 'bread', 'mayo') at (1) print
|
||||
@@ -61,7 +60,7 @@ class Person
|
||||
# p = Person ()
|
||||
# p /name string print
|
||||
|
||||
p: new Person()
|
||||
p: new Person
|
||||
print p.name
|
||||
|
||||
|
||||
@@ -189,9 +188,9 @@ HomePage::get: (url) ->
|
||||
# b /right = BTree ()
|
||||
|
||||
BTree: ->
|
||||
b: new BTree()
|
||||
b.left: new BTree()
|
||||
b.right: new BTree()
|
||||
b: new BTree
|
||||
b.left: new BTree
|
||||
b.right: new BTree
|
||||
|
||||
|
||||
# BTree = class: /left, /right.
|
||||
@@ -201,6 +200,6 @@ b.right: new BTree()
|
||||
# 'left path found!' print.
|
||||
|
||||
BTree: ->
|
||||
b: new BTree()
|
||||
b: new BTree
|
||||
|
||||
print('left path found!') if b.left?
|
||||
|
||||
@@ -346,7 +346,7 @@
|
||||
return [] if len <= 0
|
||||
range: new Array len
|
||||
idx: 0
|
||||
while true
|
||||
loop
|
||||
return range if (if step > 0 then i - stop else stop - i) >= 0
|
||||
range[idx]: i
|
||||
idx++
|
||||
|
||||
@@ -6,7 +6,7 @@ http: require 'http'
|
||||
server: http.createServer (req, res) ->
|
||||
res.writeHeader 200, {'Content-Type': 'text/plain'}
|
||||
res.write 'Hello, World!'
|
||||
res.close()
|
||||
res.end()
|
||||
|
||||
server.listen 3000
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
762
index.html
762
index.html
File diff suppressed because it is too large
Load Diff
61
lib/cake.js
61
lib/cake.js
@@ -1,28 +1,23 @@
|
||||
(function(){
|
||||
var CoffeeScript, fs, helpers, no_such_task, oparse, options, optparse, path, print_tasks, switches, tasks;
|
||||
var CoffeeScript, fs, helpers, missingTask, oparse, options, optparse, path, printTasks, switches, tasks;
|
||||
var __hasProp = Object.prototype.hasOwnProperty;
|
||||
// `cake` is a simplified version of [Make](http://www.gnu.org/software/make/)
|
||||
// ([Rake](http://rake.rubyforge.org/), [Jake](http://github.com/280north/jake))
|
||||
// for CoffeeScript. You define tasks with names and descriptions in a Cakefile,
|
||||
// and can call them from the command line, or invoke them from other tasks.
|
||||
// Running `cake` with no arguments will print out a list of all the tasks in the
|
||||
// current directory's Cakefile.
|
||||
// External dependencies.
|
||||
fs = require('fs');
|
||||
path = require('path');
|
||||
helpers = require('./helpers').helpers;
|
||||
optparse = require('./optparse');
|
||||
CoffeeScript = require('./coffee-script');
|
||||
// Keep track of the list of defined tasks, the accepted options, and so on.
|
||||
tasks = {};
|
||||
options = {};
|
||||
switches = [];
|
||||
oparse = null;
|
||||
// Mixin the top-level Cake functions for Cakefiles to use directly.
|
||||
helpers.extend(global, {
|
||||
// Define a Cake task with a short name, a sentence description,
|
||||
// and the function to run as the action itself.
|
||||
task: function task(name, description, action) {
|
||||
task: function(name, description, action) {
|
||||
var _a;
|
||||
if (!(action)) {
|
||||
_a = [description, action];
|
||||
action = _a[0];
|
||||
description = _a[1];
|
||||
}
|
||||
tasks[name] = {
|
||||
name: name,
|
||||
description: description,
|
||||
@@ -30,36 +25,29 @@
|
||||
};
|
||||
return tasks[name];
|
||||
},
|
||||
// Define an option that the Cakefile accepts. The parsed options hash,
|
||||
// containing all of the command-line options passed, will be made available
|
||||
// as the first argument to the action.
|
||||
option: function option(letter, flag, description) {
|
||||
option: function(letter, flag, description) {
|
||||
return switches.push([letter, flag, description]);
|
||||
},
|
||||
// Invoke another task in the current Cakefile.
|
||||
invoke: function invoke(name) {
|
||||
invoke: function(name) {
|
||||
if (!(tasks[name])) {
|
||||
no_such_task(name);
|
||||
missingTask(name);
|
||||
}
|
||||
return 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.
|
||||
exports.run = function run() {
|
||||
exports.run = function() {
|
||||
return path.exists('Cakefile', function(exists) {
|
||||
var _a, _b, _c, _d, arg, args;
|
||||
if (!(exists)) {
|
||||
throw new Error("Cakefile not found in " + (process.cwd()));
|
||||
throw new Error(("Cakefile not found in " + (process.cwd())));
|
||||
}
|
||||
args = process.argv.slice(2, process.argv.length);
|
||||
CoffeeScript.run(fs.readFileSync('Cakefile'), {
|
||||
CoffeeScript.run(fs.readFileSync('Cakefile').toString(), {
|
||||
source: 'Cakefile'
|
||||
});
|
||||
oparse = new optparse.OptionParser(switches);
|
||||
if (!(args.length)) {
|
||||
return print_tasks();
|
||||
return printTasks();
|
||||
}
|
||||
options = oparse.parse(args);
|
||||
_a = []; _c = options.arguments;
|
||||
@@ -70,30 +58,29 @@
|
||||
return _a;
|
||||
});
|
||||
};
|
||||
// Display the list of Cake tasks in a format similar to `rake -T`
|
||||
print_tasks = function print_tasks() {
|
||||
var _a, _b, _c, _d, _e, i, name, spaces, task;
|
||||
printTasks = function() {
|
||||
var _a, _b, desc, i, name, spaces, task;
|
||||
puts('');
|
||||
_a = tasks;
|
||||
for (name in _a) { if (__hasProp.call(_a, name)) {
|
||||
task = _a[name];
|
||||
spaces = 20 - name.length;
|
||||
spaces = spaces > 0 ? (function() {
|
||||
_b = []; _d = 0; _e = spaces;
|
||||
for (_c = 0, i = _d; (_d <= _e ? i <= _e : i >= _e); (_d <= _e ? i += 1 : i -= 1), _c++) {
|
||||
_b = [];
|
||||
for (i = 0; i <= spaces; i += 1) {
|
||||
_b.push(' ');
|
||||
}
|
||||
return _b;
|
||||
}).call(this).join('') : '';
|
||||
puts("cake " + name + spaces + " # " + (task.description));
|
||||
})().join('') : '';
|
||||
desc = task.description ? ("# " + task.description) : '';
|
||||
puts("cake " + name + spaces + " " + desc);
|
||||
}}
|
||||
if (switches.length) {
|
||||
return puts(oparse.help());
|
||||
}
|
||||
};
|
||||
// Print an error and exit when attempting to all an undefined task.
|
||||
no_such_task = function no_such_task(task) {
|
||||
process.stdio.writeError("No such task: \"" + task + "\"\n");
|
||||
missingTask = function(task) {
|
||||
puts("No such task: \"" + task + "\"");
|
||||
return process.exit(1);
|
||||
};
|
||||
})();
|
||||
|
||||
@@ -1,13 +1,6 @@
|
||||
(function(){
|
||||
var Lexer, compile, helpers, lexer, parser, path, process_scripts;
|
||||
// CoffeeScript can be used both on the server, as a command-line compiler based
|
||||
// on Node.js/V8, or to run CoffeeScripts directly in the browser. This module
|
||||
// contains the main entry functions for tokenzing, parsing, and compiling source
|
||||
// CoffeeScript into JavaScript.
|
||||
// If included on a webpage, it will automatically sniff out, compile, and
|
||||
// execute all scripts present in `text/coffeescript` tags.
|
||||
// Set up dependencies correctly for both the server and the browser.
|
||||
if ((typeof process !== "undefined" && process !== null)) {
|
||||
var Lexer, compile, helpers, lexer, parser, path, processScripts;
|
||||
if (typeof process !== "undefined" && process !== null) {
|
||||
path = require('path');
|
||||
Lexer = require('./lexer').Lexer;
|
||||
parser = require('./parser').parser;
|
||||
@@ -22,53 +15,33 @@
|
||||
parser = this.parser;
|
||||
helpers = this.helpers;
|
||||
}
|
||||
// The current CoffeeScript version number.
|
||||
exports.VERSION = '0.6.0';
|
||||
// Instantiate a Lexer for our use here.
|
||||
exports.VERSION = '0.7.2';
|
||||
lexer = new Lexer();
|
||||
// Compile a string of CoffeeScript code to JavaScript, using the Coffee/Jison
|
||||
// compiler.
|
||||
exports.compile = (compile = function compile(code, options) {
|
||||
exports.compile = (compile = function(code, options) {
|
||||
options = options || {};
|
||||
try {
|
||||
return (parser.parse(lexer.tokenize(code))).compile(options);
|
||||
} catch (err) {
|
||||
if (options.source) {
|
||||
err.message = "In " + (options.source) + ", " + (err.message);
|
||||
err.message = ("In " + options.source + ", " + err.message);
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
});
|
||||
// Tokenize a string of CoffeeScript code, and return the array of tokens.
|
||||
exports.tokens = function tokens(code) {
|
||||
exports.tokens = function(code) {
|
||||
return lexer.tokenize(code);
|
||||
};
|
||||
// Tokenize and parse a string of CoffeeScript code, and return the AST. You can
|
||||
// then compile it by calling `.compile()` on the root, or traverse it by using
|
||||
// `.traverse()` with a callback.
|
||||
exports.nodes = function nodes(code) {
|
||||
exports.nodes = function(code) {
|
||||
return parser.parse(lexer.tokenize(code));
|
||||
};
|
||||
// Compile and execute a string of CoffeeScript (on the server), correctly
|
||||
// setting `__filename`, `__dirname`, and relative `require()`.
|
||||
exports.run = (function(code, options) {
|
||||
var __dirname, __filename;
|
||||
module.filename = (__filename = options.source);
|
||||
__dirname = path.dirname(__filename);
|
||||
return eval(exports.compile(code, options));
|
||||
});
|
||||
// Extend CoffeeScript with a custom language extension. It should hook in to
|
||||
// the **Lexer** (as a peer of any of the lexer's tokenizing methods), and
|
||||
// push a token on to the stack that contains a **Node** as the value (as a
|
||||
// peer of the nodes in [nodes.coffee](nodes.html)).
|
||||
exports.extend = function extend(func) {
|
||||
return Lexer.extensions.push(func);
|
||||
};
|
||||
// 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".
|
||||
parser.lexer = {
|
||||
lex: function lex() {
|
||||
lex: function() {
|
||||
var token;
|
||||
token = this.tokens[this.pos] || [""];
|
||||
this.pos += 1;
|
||||
@@ -76,24 +49,17 @@
|
||||
this.yytext = token[1];
|
||||
return token[0];
|
||||
},
|
||||
setInput: function setInput(tokens) {
|
||||
setInput: function(tokens) {
|
||||
this.tokens = tokens;
|
||||
this.pos = 0;
|
||||
return this.pos;
|
||||
},
|
||||
upcomingInput: function upcomingInput() {
|
||||
upcomingInput: function() {
|
||||
return "";
|
||||
},
|
||||
showPosition: function showPosition() {
|
||||
return this.pos;
|
||||
}
|
||||
};
|
||||
// Activate CoffeeScript in the browser by having it compile and evaluate
|
||||
// all script tags with a content-type of `text/coffeescript`. This happens
|
||||
// on page load. Unfortunately, the text contents of remote scripts cannot be
|
||||
// accessed from the browser, so only inline script tags will work.
|
||||
if ((typeof document !== "undefined" && document !== null) && document.getElementsByTagName) {
|
||||
process_scripts = function process_scripts() {
|
||||
processScripts = function() {
|
||||
var _a, _b, _c, _d, tag;
|
||||
_a = []; _c = document.getElementsByTagName('script');
|
||||
for (_b = 0, _d = _c.length; _b < _d; _b++) {
|
||||
@@ -103,9 +69,9 @@
|
||||
return _a;
|
||||
};
|
||||
if (window.addEventListener) {
|
||||
window.addEventListener('load', process_scripts, false);
|
||||
window.addEventListener('load', processScripts, false);
|
||||
} else if (window.attachEvent) {
|
||||
window.attachEvent('onload', process_scripts);
|
||||
window.attachEvent('onload', processScripts);
|
||||
}
|
||||
}
|
||||
})();
|
||||
|
||||
277
lib/command.js
277
lib/command.js
@@ -1,29 +1,20 @@
|
||||
(function(){
|
||||
var BANNER, CoffeeScript, SWITCHES, compile_options, compile_script, compile_scripts, compile_stdio, fs, lint, option_parser, options, optparse, parse_options, path, print_tokens, sources, usage, version, watch_scripts, write_js;
|
||||
// The `coffee` utility. Handles command-line compilation of CoffeeScript
|
||||
// into various forms: saved into `.js` files or printed to stdout, piped to
|
||||
// [JSLint](http://javascriptlint.com/) or recompiled every time the source is
|
||||
// saved, printed as a token stream or as the syntax tree, or launch an
|
||||
// interactive REPL.
|
||||
// External dependencies.
|
||||
var BANNER, CoffeeScript, SWITCHES, _a, compileOptions, compileScript, compileScripts, compileStdio, exec, fs, lint, optionParser, options, optparse, parseOptions, path, printTokens, sources, spawn, usage, version, watch, writeJs;
|
||||
fs = require('fs');
|
||||
path = require('path');
|
||||
optparse = require('./optparse');
|
||||
CoffeeScript = require('./coffee-script');
|
||||
// The help banner that is printed when `coffee` is called without arguments.
|
||||
_a = require('child_process');
|
||||
spawn = _a.spawn;
|
||||
exec = _a.exec;
|
||||
BANNER = 'coffee compiles CoffeeScript source files into JavaScript.\n\nUsage:\n coffee path/to/script.coffee';
|
||||
// The list of all the valid option flags that `coffee` knows how to handle.
|
||||
SWITCHES = [['-c', '--compile', 'compile to JavaScript and save as .js files'], ['-i', '--interactive', 'run an interactive CoffeeScript REPL'], ['-o', '--output [DIR]', 'set the directory for compiled JavaScript'], ['-w', '--watch', 'watch scripts for changes, and recompile'], ['-p', '--print', 'print the compiled JavaScript to stdout'], ['-l', '--lint', 'pipe the compiled JavaScript through JSLint'], ['-s', '--stdio', 'listen for and compile scripts over stdio'], ['-e', '--eval', 'compile a string from the command line'], ['--no-wrap', 'compile without the top-level function wrapper'], ['-t', '--tokens', 'print the tokens that the lexer produces'], ['-n', '--nodes', 'print the parse tree that Jison produces'], ['-v', '--version', 'display CoffeeScript version'], ['-h', '--help', 'display this help message']];
|
||||
// Top-level objects shared by all the functions.
|
||||
options = {};
|
||||
sources = [];
|
||||
option_parser = null;
|
||||
// Run `coffee` by parsing passed options and determining what action to take.
|
||||
// Many flags cause us to divert before compiling anything. Flags passed after
|
||||
// `--` will be passed verbatim to your script as arguments in `process.argv`
|
||||
exports.run = function run() {
|
||||
optionParser = null;
|
||||
exports.run = function() {
|
||||
var flags, separator;
|
||||
parse_options();
|
||||
parseOptions();
|
||||
if (options.help) {
|
||||
return usage();
|
||||
}
|
||||
@@ -34,13 +25,13 @@
|
||||
return require('./repl');
|
||||
}
|
||||
if (options.stdio) {
|
||||
return compile_stdio();
|
||||
return compileStdio();
|
||||
}
|
||||
if (options.eval) {
|
||||
return compile_script('console', sources[0]);
|
||||
return compileScript('console', sources[0]);
|
||||
}
|
||||
if (!(sources.length)) {
|
||||
return usage();
|
||||
return require('./repl');
|
||||
}
|
||||
separator = sources.indexOf('--');
|
||||
flags = [];
|
||||
@@ -48,180 +39,178 @@
|
||||
flags = sources.slice((separator + 1), sources.length);
|
||||
sources = sources.slice(0, separator);
|
||||
}
|
||||
if (options.run) {
|
||||
flags = sources.slice(1, sources.length + 1).concat(flags);
|
||||
sources = [sources[0]];
|
||||
}
|
||||
process.ARGV = (process.argv = flags);
|
||||
if (options.watch) {
|
||||
watch_scripts();
|
||||
}
|
||||
return compile_scripts();
|
||||
return compileScripts();
|
||||
};
|
||||
// Asynchronously read in each CoffeeScript in a list of source files and
|
||||
// compile them.
|
||||
compile_scripts = function compile_scripts() {
|
||||
var _a, _b, _c, _d, compile, source;
|
||||
compile = function compile(source) {
|
||||
return path.exists(source, function(exists) {
|
||||
if (!(exists)) {
|
||||
throw new Error("File not found: " + source);
|
||||
}
|
||||
return fs.readFile(source, function(err, code) {
|
||||
return compile_script(source, code);
|
||||
});
|
||||
});
|
||||
};
|
||||
_a = []; _c = sources;
|
||||
for (_b = 0, _d = _c.length; _b < _d; _b++) {
|
||||
source = _c[_b];
|
||||
_a.push(compile(source));
|
||||
compileScripts = function() {
|
||||
var _b, _c, _d, _e;
|
||||
_b = []; _d = sources;
|
||||
for (_c = 0, _e = _d.length; _c < _e; _c++) {
|
||||
(function() {
|
||||
var base, compile;
|
||||
var source = _d[_c];
|
||||
return _b.push((function() {
|
||||
base = source;
|
||||
compile = function(source, topLevel) {
|
||||
return path.exists(source, function(exists) {
|
||||
if (!(exists)) {
|
||||
throw new Error("File not found: " + source);
|
||||
}
|
||||
return fs.stat(source, function(err, stats) {
|
||||
if (stats.isDirectory()) {
|
||||
return fs.readdir(source, function(err, files) {
|
||||
var _f, _g, _h, _i, file;
|
||||
_f = []; _h = files;
|
||||
for (_g = 0, _i = _h.length; _g < _i; _g++) {
|
||||
file = _h[_g];
|
||||
_f.push(compile(path.join(source, file)));
|
||||
}
|
||||
return _f;
|
||||
});
|
||||
} else if (topLevel || path.extname(source) === '.coffee') {
|
||||
fs.readFile(source, function(err, code) {
|
||||
return compileScript(source, code.toString(), base);
|
||||
});
|
||||
if (options.watch) {
|
||||
return watch(source, base);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
return compile(source, true);
|
||||
})());
|
||||
})();
|
||||
}
|
||||
return _a;
|
||||
return _b;
|
||||
};
|
||||
// Compile a single source script, containing the given code, according to the
|
||||
// requested options. Both compile_scripts and watch_scripts share this method
|
||||
// in common. If evaluating the script directly sets `__filename`, `__dirname`
|
||||
// and `module.filename` to be correct relative to the script's path.
|
||||
compile_script = function compile_script(source, code) {
|
||||
var code_opts, js, o;
|
||||
compileScript = function(source, code, base) {
|
||||
var codeOpts, js, o;
|
||||
o = options;
|
||||
code_opts = compile_options(source);
|
||||
codeOpts = compileOptions(source);
|
||||
try {
|
||||
if (o.tokens) {
|
||||
return print_tokens(CoffeeScript.tokens(code));
|
||||
return printTokens(CoffeeScript.tokens(code));
|
||||
} else if (o.nodes) {
|
||||
return puts(CoffeeScript.nodes(code).toString());
|
||||
} else if (o.run) {
|
||||
return CoffeeScript.run(code, code_opts);
|
||||
return CoffeeScript.run(code, codeOpts);
|
||||
} else {
|
||||
js = CoffeeScript.compile(code, code_opts);
|
||||
js = CoffeeScript.compile(code, codeOpts);
|
||||
if (o.print) {
|
||||
return process.stdio.write(js);
|
||||
return print(js);
|
||||
} else if (o.compile) {
|
||||
return write_js(source, js);
|
||||
return writeJs(source, js, base);
|
||||
} else if (o.lint) {
|
||||
return lint(js);
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
if (o.watch) {
|
||||
return puts(err.message);
|
||||
} else {
|
||||
throw err;
|
||||
if (!(o.watch)) {
|
||||
error(err.stack) && process.exit(1);
|
||||
}
|
||||
return puts(err.message);
|
||||
}
|
||||
};
|
||||
// Attach the appropriate listeners to compile scripts incoming over **stdin**,
|
||||
// and write them back to **stdout**.
|
||||
compile_stdio = function compile_stdio() {
|
||||
var code;
|
||||
compileStdio = function() {
|
||||
var code, stdin;
|
||||
code = '';
|
||||
process.stdio.open();
|
||||
process.stdio.addListener('data', function(string) {
|
||||
if (string) {
|
||||
return code += string;
|
||||
stdin = process.openStdin();
|
||||
stdin.addListener('data', function(buffer) {
|
||||
if (buffer) {
|
||||
return code += buffer.toString();
|
||||
}
|
||||
});
|
||||
return process.stdio.addListener('close', function() {
|
||||
return compile_script('stdio', code);
|
||||
return stdin.addListener('end', function() {
|
||||
return compileScript('stdio', code);
|
||||
});
|
||||
};
|
||||
// Watch a list of source CoffeeScript files using `fs.watchFile`, recompiling
|
||||
// them every time the files are updated. May be used in combination with other
|
||||
// options, such as `--lint` or `--print`.
|
||||
watch_scripts = function watch_scripts() {
|
||||
var _a, _b, _c, _d, source, watch;
|
||||
watch = function watch(source) {
|
||||
return fs.watchFile(source, {
|
||||
persistent: true,
|
||||
interval: 500
|
||||
}, function(curr, prev) {
|
||||
if (curr.mtime.getTime() === prev.mtime.getTime()) {
|
||||
return null;
|
||||
watch = function(source, base) {
|
||||
return fs.watchFile(source, {
|
||||
persistent: true,
|
||||
interval: 500
|
||||
}, function(curr, prev) {
|
||||
if (curr.mtime.getTime() === prev.mtime.getTime()) {
|
||||
return null;
|
||||
}
|
||||
return fs.readFile(source, function(err, code) {
|
||||
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';
|
||||
srcDir = path.dirname(source);
|
||||
baseDir = srcDir.substring(base.length);
|
||||
dir = options.output ? path.join(options.output, baseDir) : srcDir;
|
||||
jsPath = path.join(dir, filename);
|
||||
compile = function() {
|
||||
return fs.writeFile(jsPath, js, function(err) {
|
||||
if (options.compile && options.watch) {
|
||||
return puts("Compiled " + source);
|
||||
}
|
||||
return fs.readFile(source, function(err, code) {
|
||||
return compile_script(source, code);
|
||||
});
|
||||
});
|
||||
};
|
||||
_a = []; _c = sources;
|
||||
for (_b = 0, _d = _c.length; _b < _d; _b++) {
|
||||
source = _c[_b];
|
||||
_a.push(watch(source));
|
||||
}
|
||||
return _a;
|
||||
};
|
||||
// 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
|
||||
// directory can be customized with `--output`.
|
||||
write_js = function write_js(source, js) {
|
||||
var dir, filename, js_path;
|
||||
filename = path.basename(source, path.extname(source)) + '.js';
|
||||
dir = options.output || path.dirname(source);
|
||||
js_path = path.join(dir, filename);
|
||||
return fs.writeFile(js_path, js);
|
||||
};
|
||||
// Pipe compiled JS through JSLint (requires a working `jsl` command), printing
|
||||
// any errors or warnings that arise.
|
||||
lint = function lint(js) {
|
||||
var jsl;
|
||||
jsl = process.createChildProcess('jsl', ['-nologo', '-stdin']);
|
||||
jsl.addListener('output', function(result) {
|
||||
if (result) {
|
||||
return puts(result.replace(/\n/g, ''));
|
||||
}
|
||||
return path.exists(dir, function(exists) {
|
||||
return exists ? compile() : exec(("mkdir -p " + dir), compile);
|
||||
});
|
||||
jsl.addListener('error', function(result) {
|
||||
if (result) {
|
||||
return puts(result);
|
||||
}
|
||||
});
|
||||
jsl.write(js);
|
||||
return jsl.close();
|
||||
};
|
||||
// Pretty-print a stream of tokens.
|
||||
print_tokens = function print_tokens(tokens) {
|
||||
var _a, _b, _c, _d, _e, strings, tag, token, value;
|
||||
lint = function(js) {
|
||||
var jsl, printIt;
|
||||
printIt = function(buffer) {
|
||||
return print(buffer.toString());
|
||||
};
|
||||
jsl = spawn('jsl', ['-nologo', '-stdin']);
|
||||
jsl.stdout.addListener('data', printIt);
|
||||
jsl.stderr.addListener('data', printIt);
|
||||
jsl.stdin.write(js);
|
||||
return jsl.stdin.end();
|
||||
};
|
||||
printTokens = function(tokens) {
|
||||
var _b, _c, _d, _e, _f, strings, tag, token, value;
|
||||
strings = (function() {
|
||||
_a = []; _c = tokens;
|
||||
for (_b = 0, _d = _c.length; _b < _d; _b++) {
|
||||
token = _c[_b];
|
||||
_a.push((function() {
|
||||
_e = [token[0], token[1].toString().replace(/\n/, '\\n')];
|
||||
tag = _e[0];
|
||||
value = _e[1];
|
||||
_b = []; _d = tokens;
|
||||
for (_c = 0, _e = _d.length; _c < _e; _c++) {
|
||||
token = _d[_c];
|
||||
_b.push((function() {
|
||||
_f = [token[0], token[1].toString().replace(/\n/, '\\n')];
|
||||
tag = _f[0];
|
||||
value = _f[1];
|
||||
return "[" + tag + " " + value + "]";
|
||||
}).call(this));
|
||||
})());
|
||||
}
|
||||
return _a;
|
||||
}).call(this);
|
||||
return _b;
|
||||
})();
|
||||
return puts(strings.join(' '));
|
||||
};
|
||||
// Use the [OptionParser module](optparse.html) to extract all options from
|
||||
// `process.argv` that are specified in `SWITCHES`.
|
||||
parse_options = function parse_options() {
|
||||
parseOptions = function() {
|
||||
var o;
|
||||
option_parser = new optparse.OptionParser(SWITCHES, BANNER);
|
||||
o = (options = option_parser.parse(process.argv));
|
||||
optionParser = new optparse.OptionParser(SWITCHES, BANNER);
|
||||
o = (options = optionParser.parse(process.argv.slice(2, process.argv.length)));
|
||||
options.run = !(o.compile || o.print || o.lint);
|
||||
options.print = !!(o.print || (o.eval || o.stdio && o.compile));
|
||||
sources = options.arguments.slice(2, options.arguments.length);
|
||||
sources = options.arguments;
|
||||
return sources;
|
||||
};
|
||||
// The compile-time options to pass to the CoffeeScript compiler.
|
||||
compile_options = function compile_options(source) {
|
||||
compileOptions = function(source) {
|
||||
var o;
|
||||
o = {
|
||||
source: source
|
||||
};
|
||||
o['no_wrap'] = options['no-wrap'];
|
||||
o.noWrap = options['no-wrap'];
|
||||
return o;
|
||||
};
|
||||
// Print the `--help` usage message and exit.
|
||||
usage = function usage() {
|
||||
puts(option_parser.help());
|
||||
usage = function() {
|
||||
puts(optionParser.help());
|
||||
return process.exit(0);
|
||||
};
|
||||
// Print the `--version` message and exit.
|
||||
version = function version() {
|
||||
puts("CoffeeScript version " + (CoffeeScript.VERSION));
|
||||
version = function() {
|
||||
puts("CoffeeScript version " + CoffeeScript.VERSION);
|
||||
return process.exit(0);
|
||||
};
|
||||
})();
|
||||
|
||||
537
lib/grammar.js
537
lib/grammar.js
@@ -1,77 +1,42 @@
|
||||
(function(){
|
||||
var Parser, _a, _b, _c, _d, _e, _f, _g, _h, alt, alternatives, grammar, name, o, operators, token, tokens, unwrap;
|
||||
var __hasProp = Object.prototype.hasOwnProperty;
|
||||
// The CoffeeScript parser is generated by [Jison](http://github.com/zaach/jison)
|
||||
// from this grammar file. Jison is a bottom-up parser generator, similar in
|
||||
// style to [Bison](http://www.gnu.org/software/bison), implemented in JavaScript.
|
||||
// It can recognize [LALR(1), LR(0), SLR(1), and LR(1)](http://en.wikipedia.org/wiki/LR_grammar)
|
||||
// type grammars. To create the Jison parser, we list the pattern to match
|
||||
// on the left-hand side, and the action to take (usually the creation of syntax
|
||||
// tree nodes) on the right. As the parser runs, it
|
||||
// shifts tokens from our token stream, from left to right, and
|
||||
// [attempts to match](http://en.wikipedia.org/wiki/Bottom-up_parsing)
|
||||
// the token sequence against the rules below. When a match can be made, it
|
||||
// reduces into the [nonterminal](http://en.wikipedia.org/wiki/Terminal_and_nonterminal_symbols)
|
||||
// (the enclosing name at the top), and we proceed from there.
|
||||
// If you run the `cake build:parser` command, Jison constructs a parse table
|
||||
// from our rules and saves it into `lib/parser.js`.
|
||||
// The only dependency is on the **Jison.Parser**.
|
||||
Parser = require('jison').Parser;
|
||||
// Jison DSL
|
||||
// ---------
|
||||
// Since we're going to be wrapped in a function by Jison in any case, if our
|
||||
// action immediately returns a value, we can optimize by removing the function
|
||||
// wrapper and just returning the value directly.
|
||||
unwrap = /function\s*\(\)\s*\{\s*return\s*([\s\S]*);\s*\}/;
|
||||
// Our handy DSL for Jison grammar generation, thanks to
|
||||
// [Tim Caswell](http://github.com/creationix). For every rule in the grammar,
|
||||
// we pass the pattern-defining string, the action to run, and extra options,
|
||||
// optionally. If no action is specified, we simply pass the value of the
|
||||
// previous nonterminal.
|
||||
o = function o(pattern_string, action, options) {
|
||||
o = function(patternString, action, options) {
|
||||
var match;
|
||||
if (!(action)) {
|
||||
return [pattern_string, '$$ = $1;', options];
|
||||
return [patternString, '$$ = $1;', options];
|
||||
}
|
||||
action = (match = (action + '').match(unwrap)) ? match[1] : "(" + action + "())";
|
||||
return [pattern_string, "$$ = " + action + ";", options];
|
||||
action = (match = (action + '').match(unwrap)) ? match[1] : ("(" + action + "())");
|
||||
return [patternString, ("$$ = " + action + ";"), options];
|
||||
};
|
||||
// Grammatical Rules
|
||||
// -----------------
|
||||
// In all of the rules that follow, you'll see the name of the nonterminal as
|
||||
// the key to a list of alternative matches. With each match's action, the
|
||||
// dollar-sign variables are provided by Jison as references to the value of
|
||||
// their numeric position, so in this rule:
|
||||
// "Expression UNLESS Expression"
|
||||
// `$1` would be the value of the first `Expression`, `$2` would be the token
|
||||
// for the `UNLESS` terminal, and `$3` would be the value of the second
|
||||
// `Expression`.
|
||||
grammar = {
|
||||
// The **Root** is the top-level node in the syntax tree. Since we parse bottom-up,
|
||||
// all parsing must end here.
|
||||
Root: [o("", function() {
|
||||
Root: [
|
||||
o("", function() {
|
||||
return new Expressions();
|
||||
}), o("TERMINATOR", function() {
|
||||
return new Expressions();
|
||||
}), o("Expressions"), o("Block TERMINATOR")
|
||||
}), o("Body"), o("Block TERMINATOR")
|
||||
],
|
||||
// Any list of expressions or method body, seperated by line breaks or
|
||||
// semicolons.
|
||||
Expressions: [o("Expression", function() {
|
||||
Body: [
|
||||
o("Line", function() {
|
||||
return Expressions.wrap([$1]);
|
||||
}), o("Expressions TERMINATOR Expression", function() {
|
||||
}), o("Body TERMINATOR Line", function() {
|
||||
return $1.push($3);
|
||||
}), o("Expressions TERMINATOR")
|
||||
}), o("Body TERMINATOR")
|
||||
],
|
||||
// All the different types of expressions in our language. The basic unit of
|
||||
// CoffeeScript is the **Expression** -- you'll notice that there is no
|
||||
// "statement" nonterminal. Expressions serve as the building blocks
|
||||
// of many other rules, making them somewhat circular.
|
||||
Expression: [o("Value"), o("Call"), o("Curry"), o("Code"), o("Operation"), o("Assign"), o("If"), o("Try"), o("Throw"), o("Return"), o("While"), o("For"), o("Switch"), o("Extends"), o("Class"), o("Splat"), o("Existence"), o("Comment"), o("Extension")],
|
||||
// A an indented block of expressions. Note that the [Rewriter](rewriter.html)
|
||||
// will convert some postfix forms into blocks for us, by adjusting the
|
||||
// token stream.
|
||||
Block: [o("INDENT Expressions OUTDENT", function() {
|
||||
Line: [o("Expression"), o("Statement")],
|
||||
Statement: [
|
||||
o("Return"), o("Throw"), o("BREAK", function() {
|
||||
return new LiteralNode($1);
|
||||
}), o("CONTINUE", function() {
|
||||
return new LiteralNode($1);
|
||||
})
|
||||
],
|
||||
Expression: [o("Value"), o("Call"), o("Code"), o("Operation"), o("Assign"), o("If"), o("Try"), o("While"), o("For"), o("Switch"), o("Extends"), o("Class"), o("Splat"), o("Existence"), o("Comment")],
|
||||
Block: [
|
||||
o("INDENT Body OUTDENT", function() {
|
||||
return $2;
|
||||
}), o("INDENT OUTDENT", function() {
|
||||
return new Expressions();
|
||||
@@ -79,29 +44,23 @@
|
||||
return Expressions.wrap([$2]);
|
||||
})
|
||||
],
|
||||
// A literal identifier, a variable name or property.
|
||||
Identifier: [o("IDENTIFIER", function() {
|
||||
return new LiteralNode(yytext);
|
||||
Identifier: [
|
||||
o("IDENTIFIER", function() {
|
||||
return new LiteralNode($1);
|
||||
})
|
||||
],
|
||||
// Alphanumerics are separated from the other **Literal** matchers because
|
||||
// they can also serve as keys in object literals.
|
||||
AlphaNumeric: [o("NUMBER", function() {
|
||||
return new LiteralNode(yytext);
|
||||
AlphaNumeric: [
|
||||
o("NUMBER", function() {
|
||||
return new LiteralNode($1);
|
||||
}), o("STRING", function() {
|
||||
return new LiteralNode(yytext);
|
||||
return new LiteralNode($1);
|
||||
})
|
||||
],
|
||||
// All of our immediate values. These can (in general), be passed straight
|
||||
// through and printed to JavaScript.
|
||||
Literal: [o("AlphaNumeric"), o("JS", function() {
|
||||
return new LiteralNode(yytext);
|
||||
Literal: [
|
||||
o("AlphaNumeric"), o("JS", function() {
|
||||
return new LiteralNode($1);
|
||||
}), o("REGEX", function() {
|
||||
return new LiteralNode(yytext);
|
||||
}), o("BREAK", function() {
|
||||
return new LiteralNode(yytext);
|
||||
}), o("CONTINUE", function() {
|
||||
return new LiteralNode(yytext);
|
||||
return new LiteralNode($1);
|
||||
}), o("TRUE", function() {
|
||||
return new LiteralNode(true);
|
||||
}), o("FALSE", function() {
|
||||
@@ -116,57 +75,54 @@
|
||||
return new LiteralNode(false);
|
||||
})
|
||||
],
|
||||
// Assignment of a variable, property, or index to a value.
|
||||
Assign: [o("Assignable ASSIGN Expression", function() {
|
||||
Assign: [
|
||||
o("Assignable ASSIGN Expression", function() {
|
||||
return new AssignNode($1, $3);
|
||||
})
|
||||
],
|
||||
// Assignment when it happens within an object literal. The difference from
|
||||
// the ordinary **Assign** is that these allow numbers and strings as keys.
|
||||
AssignObj: [o("Identifier ASSIGN Expression", function() {
|
||||
AssignObj: [
|
||||
o("Identifier", function() {
|
||||
return new ValueNode($1);
|
||||
}), o("AlphaNumeric"), o("Identifier ASSIGN Expression", function() {
|
||||
return new AssignNode(new ValueNode($1), $3, 'object');
|
||||
}), o("AlphaNumeric ASSIGN Expression", function() {
|
||||
return new AssignNode(new ValueNode($1), $3, 'object');
|
||||
}), o("Comment")
|
||||
],
|
||||
// A return statement from a function body.
|
||||
Return: [o("RETURN Expression", function() {
|
||||
Return: [
|
||||
o("RETURN Expression", function() {
|
||||
return new ReturnNode($2);
|
||||
}), o("RETURN", function() {
|
||||
return new ReturnNode(new ValueNode(new LiteralNode('null')));
|
||||
})
|
||||
],
|
||||
// A comment. Because CoffeeScript passes comments through to JavaScript, we
|
||||
// have to parse comments like any other construct, and identify all of the
|
||||
// positions in which they can occur in the grammar.
|
||||
Comment: [o("COMMENT", function() {
|
||||
return new CommentNode(yytext);
|
||||
Comment: [
|
||||
o("HERECOMMENT", function() {
|
||||
return new CommentNode($1);
|
||||
})
|
||||
],
|
||||
// [The existential operator](http://jashkenas.github.com/coffee-script/#existence).
|
||||
Existence: [o("Expression ?", function() {
|
||||
Existence: [
|
||||
o("Expression ?", function() {
|
||||
return new ExistenceNode($1);
|
||||
})
|
||||
],
|
||||
// The **Code** node is the function literal. It's defined by an indented block
|
||||
// of **Expressions** preceded by a function arrow, with an optional parameter
|
||||
// list.
|
||||
Code: [o("PARAM_START ParamList PARAM_END FuncGlyph Block", function() {
|
||||
Code: [
|
||||
o("PARAM_START ParamList PARAM_END FuncGlyph Block", function() {
|
||||
return new CodeNode($2, $5, $4);
|
||||
}), o("FuncGlyph Block", function() {
|
||||
return new CodeNode([], $2, $1);
|
||||
})
|
||||
],
|
||||
// CoffeeScript has two different symbols for functions. `->` is for ordinary
|
||||
// functions, and `=>` is for functions bound to the current value of *this*.
|
||||
FuncGlyph: [o("->", function() {
|
||||
FuncGlyph: [
|
||||
o("->", function() {
|
||||
return 'func';
|
||||
}), o("=>", function() {
|
||||
return 'boundfunc';
|
||||
})
|
||||
],
|
||||
// The list of parameters that a function accepts can be of any length.
|
||||
ParamList: [o("", function() {
|
||||
OptComma: [o(''), o(',')],
|
||||
ParamList: [
|
||||
o("", function() {
|
||||
return [];
|
||||
}), o("Param", function() {
|
||||
return [$1];
|
||||
@@ -174,21 +130,20 @@
|
||||
return $1.concat([$3]);
|
||||
})
|
||||
],
|
||||
// A single parameter in a function definition can be ordinary, or a splat
|
||||
// that hoovers up the remaining arguments.
|
||||
Param: [o("PARAM", function() {
|
||||
return new LiteralNode(yytext);
|
||||
Param: [
|
||||
o("PARAM", function() {
|
||||
return new LiteralNode($1);
|
||||
}), o("Param . . .", function() {
|
||||
return new SplatNode($1);
|
||||
})
|
||||
],
|
||||
// A splat that occurs outside of a parameter list.
|
||||
Splat: [o("Expression . . .", function() {
|
||||
Splat: [
|
||||
o("Expression . . .", function() {
|
||||
return new SplatNode($1);
|
||||
})
|
||||
],
|
||||
// Variables and properties that can be assigned to.
|
||||
SimpleAssignable: [o("Identifier", function() {
|
||||
SimpleAssignable: [
|
||||
o("Identifier", function() {
|
||||
return new ValueNode($1);
|
||||
}), o("Value Accessor", function() {
|
||||
return $1.push($2);
|
||||
@@ -196,16 +151,15 @@
|
||||
return new ValueNode($1, [$2]);
|
||||
}), o("ThisProperty")
|
||||
],
|
||||
// Everything that can be assigned to.
|
||||
Assignable: [o("SimpleAssignable"), o("Array", function() {
|
||||
Assignable: [
|
||||
o("SimpleAssignable"), o("Array", function() {
|
||||
return new ValueNode($1);
|
||||
}), o("Object", function() {
|
||||
return new ValueNode($1);
|
||||
})
|
||||
],
|
||||
// The types of things that can be treated as values -- assigned to, invoked
|
||||
// as functions, indexed into, named as a class, etc.
|
||||
Value: [o("Assignable"), o("Literal", function() {
|
||||
Value: [
|
||||
o("Assignable"), o("Literal", function() {
|
||||
return new ValueNode($1);
|
||||
}), o("Parenthetical", function() {
|
||||
return new ValueNode($1);
|
||||
@@ -215,9 +169,8 @@
|
||||
return new ValueNode(new LiteralNode('null'));
|
||||
})
|
||||
],
|
||||
// The general group of accessors into an object, by property, by prototype
|
||||
// or by array index or slice.
|
||||
Accessor: [o("PROPERTY_ACCESS Identifier", function() {
|
||||
Accessor: [
|
||||
o("PROPERTY_ACCESS Identifier", function() {
|
||||
return new AccessorNode($2);
|
||||
}), o("PROTOTYPE_ACCESS Identifier", function() {
|
||||
return new AccessorNode($2, 'prototype');
|
||||
@@ -229,48 +182,37 @@
|
||||
return new SliceNode($1);
|
||||
})
|
||||
],
|
||||
// Indexing into an object or array using bracket notation.
|
||||
Index: [o("INDEX_START Expression INDEX_END", function() {
|
||||
Index: [
|
||||
o("INDEX_START Expression INDEX_END", function() {
|
||||
return new IndexNode($2);
|
||||
}), o("SOAKED_INDEX_START Expression SOAKED_INDEX_END", function() {
|
||||
return new IndexNode($2, 'soak');
|
||||
}), o("INDEX_SOAK Index", function() {
|
||||
$2.soakNode = true;
|
||||
return $2;
|
||||
}), o("INDEX_PROTO Index", function() {
|
||||
$2.proto = true;
|
||||
return $2;
|
||||
})
|
||||
],
|
||||
// In CoffeeScript, an object literal is simply a list of assignments.
|
||||
Object: [o("{ AssignList }", function() {
|
||||
return new ObjectNode($2);
|
||||
}), o("{ IndentedAssignList }", function() {
|
||||
return new ObjectNode($2);
|
||||
}), o("{ AssignList , }", function() {
|
||||
return new ObjectNode($2);
|
||||
}), o("{ IndentedAssignList , }", function() {
|
||||
Object: [
|
||||
o("{ AssignList OptComma }", function() {
|
||||
return new ObjectNode($2);
|
||||
})
|
||||
],
|
||||
// Assignment of properties within an object literal can be separated by
|
||||
// comma, as in JavaScript, or simply by newline.
|
||||
AssignList: [o("", function() {
|
||||
AssignList: [
|
||||
o("", function() {
|
||||
return [];
|
||||
}), o("AssignObj", function() {
|
||||
return [$1];
|
||||
}), o("AssignList , AssignObj", function() {
|
||||
return $1.concat([$3]);
|
||||
}), o("AssignList TERMINATOR AssignObj", function() {
|
||||
return $1.concat([$3]);
|
||||
}), o("AssignList , TERMINATOR AssignObj", function() {
|
||||
}), o("AssignList OptComma TERMINATOR AssignObj", function() {
|
||||
return $1.concat([$4]);
|
||||
}), o("AssignList OptComma INDENT AssignList OptComma OUTDENT", function() {
|
||||
return $1.concat($4);
|
||||
})
|
||||
],
|
||||
// An **AssignList** within a block indentation.
|
||||
IndentedAssignList: [o("INDENT AssignList OUTDENT", function() {
|
||||
return $2;
|
||||
}), o("INDENT AssignList , OUTDENT", function() {
|
||||
return $2;
|
||||
})
|
||||
],
|
||||
// Class definitions have optional bodies of prototype property assignments,
|
||||
// and optional references to the superclass.
|
||||
Class: [o("CLASS SimpleAssignable", function() {
|
||||
Class: [
|
||||
o("CLASS SimpleAssignable", function() {
|
||||
return new ClassNode($2);
|
||||
}), o("CLASS SimpleAssignable EXTENDS Value", function() {
|
||||
return new ClassNode($2, $4);
|
||||
@@ -280,15 +222,15 @@
|
||||
return new ClassNode($2, $4, $6);
|
||||
})
|
||||
],
|
||||
// Assignments that can happen directly inside a class declaration.
|
||||
ClassAssign: [o("AssignObj", function() {
|
||||
ClassAssign: [
|
||||
o("AssignObj", function() {
|
||||
return $1;
|
||||
}), o("ThisProperty ASSIGN Expression", function() {
|
||||
return new AssignNode(new ValueNode($1), $3, 'this');
|
||||
})
|
||||
],
|
||||
// A list of assignments to a class.
|
||||
ClassBody: [o("", function() {
|
||||
ClassBody: [
|
||||
o("", function() {
|
||||
return [];
|
||||
}), o("ClassAssign", function() {
|
||||
return [$1];
|
||||
@@ -296,109 +238,86 @@
|
||||
return $1.concat($3);
|
||||
})
|
||||
],
|
||||
// The three flavors of function call: normal, object instantiation with `new`,
|
||||
// and calling `super()`
|
||||
Call: [o("Invocation"), o("NEW Invocation", function() {
|
||||
return $2.new_instance();
|
||||
}), o("Super")
|
||||
],
|
||||
// Binds a function call to a context and/or arguments.
|
||||
Curry: [o("Value <- Arguments", function() {
|
||||
return new CurryNode($1, $3);
|
||||
Call: [
|
||||
o("Invocation"), o("Super"), o("NEW Invocation", function() {
|
||||
return $2.newInstance();
|
||||
}), o("NEW Value", function() {
|
||||
return (new CallNode($2, [])).newInstance();
|
||||
})
|
||||
],
|
||||
// Extending an object by setting its prototype chain to reference a parent
|
||||
// object.
|
||||
Extends: [o("SimpleAssignable EXTENDS Value", function() {
|
||||
Extends: [
|
||||
o("SimpleAssignable EXTENDS Value", function() {
|
||||
return new ExtendsNode($1, $3);
|
||||
})
|
||||
],
|
||||
// Ordinary function invocation, or a chained series of calls.
|
||||
Invocation: [o("Value Arguments", function() {
|
||||
Invocation: [
|
||||
o("Value Arguments", function() {
|
||||
return new CallNode($1, $2);
|
||||
}), o("Invocation Arguments", function() {
|
||||
return new CallNode($1, $2);
|
||||
})
|
||||
],
|
||||
// The list of arguments to a function call.
|
||||
Arguments: [o("CALL_START ArgList CALL_END", function() {
|
||||
return $2;
|
||||
}), o("CALL_START ArgList , CALL_END", function() {
|
||||
Arguments: [
|
||||
o("CALL_START ArgList OptComma CALL_END", function() {
|
||||
return $2;
|
||||
})
|
||||
],
|
||||
// Calling super.
|
||||
Super: [o("SUPER CALL_START ArgList CALL_END", function() {
|
||||
return new CallNode('super', $3);
|
||||
}), o("SUPER CALL_START ArgList , CALL_END", function() {
|
||||
return new CallNode('super', $3);
|
||||
Super: [
|
||||
o("SUPER Arguments", function() {
|
||||
return new CallNode('super', $2);
|
||||
})
|
||||
],
|
||||
// A reference to the *this* current object.
|
||||
This: [o("THIS", function() {
|
||||
This: [
|
||||
o("THIS", function() {
|
||||
return new ValueNode(new LiteralNode('this'));
|
||||
}), o("@", function() {
|
||||
return new ValueNode(new LiteralNode('this'));
|
||||
})
|
||||
],
|
||||
// A reference to a property on *this*.
|
||||
ThisProperty: [o("@ Identifier", function() {
|
||||
ThisProperty: [
|
||||
o("@ Identifier", function() {
|
||||
return new ValueNode(new LiteralNode('this'), [new AccessorNode($2)]);
|
||||
})
|
||||
],
|
||||
// The CoffeeScript range literal.
|
||||
Range: [o("[ Expression . . Expression ]", function() {
|
||||
Range: [
|
||||
o("[ Expression . . Expression ]", function() {
|
||||
return new RangeNode($2, $5);
|
||||
}), o("[ Expression . . . Expression ]", function() {
|
||||
return new RangeNode($2, $6, true);
|
||||
})
|
||||
],
|
||||
// The slice literal.
|
||||
Slice: [o("INDEX_START Expression . . Expression INDEX_END", function() {
|
||||
Slice: [
|
||||
o("INDEX_START Expression . . Expression INDEX_END", function() {
|
||||
return new RangeNode($2, $5);
|
||||
}), o("INDEX_START Expression . . . Expression INDEX_END", function() {
|
||||
return new RangeNode($2, $6, true);
|
||||
})
|
||||
],
|
||||
// The array literal.
|
||||
Array: [o("[ ArgList ]", function() {
|
||||
return new ArrayNode($2);
|
||||
}), o("[ ArgList , ]", function() {
|
||||
Array: [
|
||||
o("[ ArgList OptComma ]", function() {
|
||||
return new ArrayNode($2);
|
||||
})
|
||||
],
|
||||
// The **ArgList** 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.
|
||||
ArgList: [o("", function() {
|
||||
ArgList: [
|
||||
o("", function() {
|
||||
return [];
|
||||
}), o("Expression", function() {
|
||||
return [$1];
|
||||
}), o("INDENT Expression", function() {
|
||||
return [$2];
|
||||
}), o("ArgList , Expression", function() {
|
||||
return $1.concat([$3]);
|
||||
}), o("ArgList TERMINATOR Expression", function() {
|
||||
return $1.concat([$3]);
|
||||
}), o("ArgList , TERMINATOR Expression", function() {
|
||||
}), o("ArgList OptComma TERMINATOR Expression", function() {
|
||||
return $1.concat([$4]);
|
||||
}), o("ArgList , INDENT Expression", function() {
|
||||
return $1.concat([$4]);
|
||||
}), o("ArgList OUTDENT"), o("ArgList , OUTDENT")
|
||||
],
|
||||
// Just simple, comma-separated, required arguments (no fancy syntax). We need
|
||||
// this to be separate from the **ArgList** for use in **Switch** blocks, where
|
||||
// having the newlines wouldn't make sense.
|
||||
SimpleArgs: [o("Expression"), o("SimpleArgs , Expression", function() {
|
||||
if ($1 instanceof Array) {
|
||||
return $1.concat([$3]);
|
||||
} else {
|
||||
return [$1].concat([$3]);
|
||||
}
|
||||
}), o("ArgList OptComma INDENT ArgList OptComma OUTDENT", function() {
|
||||
return $1.concat($4);
|
||||
})
|
||||
],
|
||||
// The variants of *try/catch/finally* exception handling blocks.
|
||||
Try: [o("TRY Block Catch", function() {
|
||||
SimpleArgs: [
|
||||
o("Expression"), o("SimpleArgs , Expression", function() {
|
||||
return $1 instanceof Array ? $1.concat([$3]) : [$1].concat([$3]);
|
||||
})
|
||||
],
|
||||
Try: [
|
||||
o("TRY Block Catch", function() {
|
||||
return new TryNode($2, $3[0], $3[1]);
|
||||
}), o("TRY Block FINALLY Block", function() {
|
||||
return new TryNode($2, null, null, $4);
|
||||
@@ -406,69 +325,82 @@
|
||||
return new TryNode($2, $3[0], $3[1], $5);
|
||||
})
|
||||
],
|
||||
// A catch clause names its error and runs a block of code.
|
||||
Catch: [o("CATCH Identifier Block", function() {
|
||||
Catch: [
|
||||
o("CATCH Identifier Block", function() {
|
||||
return [$2, $3];
|
||||
})
|
||||
],
|
||||
// Throw an exception object.
|
||||
Throw: [o("THROW Expression", function() {
|
||||
Throw: [
|
||||
o("THROW Expression", function() {
|
||||
return new ThrowNode($2);
|
||||
})
|
||||
],
|
||||
// Parenthetical expressions. Note that the **Parenthetical** is a **Value**,
|
||||
// not an **Expression**, 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.
|
||||
Parenthetical: [o("( Expression )", function() {
|
||||
Parenthetical: [
|
||||
o("( Line )", function() {
|
||||
return new ParentheticalNode($2);
|
||||
})
|
||||
],
|
||||
// A language extension to CoffeeScript from the outside. We simply pass
|
||||
// it through unaltered.
|
||||
Extension: [o("EXTENSION", function() {
|
||||
return yytext;
|
||||
})
|
||||
],
|
||||
// The condition portion of a while loop.
|
||||
WhileSource: [o("WHILE Expression", function() {
|
||||
WhileSource: [
|
||||
o("WHILE Expression", function() {
|
||||
return new WhileNode($2);
|
||||
}), o("WHILE Expression WHEN Expression", function() {
|
||||
return new WhileNode($2, {
|
||||
filter: $4
|
||||
guard: $4
|
||||
});
|
||||
}), o("UNTIL Expression", function() {
|
||||
return new WhileNode($2, {
|
||||
invert: true
|
||||
});
|
||||
}), o("UNTIL Expression WHEN Expression", function() {
|
||||
return new WhileNode($2, {
|
||||
invert: true,
|
||||
guard: $4
|
||||
});
|
||||
})
|
||||
],
|
||||
// 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.
|
||||
While: [o("WhileSource Block", function() {
|
||||
return $1.add_body($2);
|
||||
While: [
|
||||
o("WhileSource Block", function() {
|
||||
return $1.addBody($2);
|
||||
}), o("Statement WhileSource", function() {
|
||||
return $2.addBody(Expressions.wrap([$1]));
|
||||
}), o("Expression WhileSource", function() {
|
||||
return $2.add_body(Expressions.wrap([$1]));
|
||||
return $2.addBody(Expressions.wrap([$1]));
|
||||
}), o("Loop", function() {
|
||||
return $1;
|
||||
})
|
||||
],
|
||||
// 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.
|
||||
For: [o("Expression FOR ForVariables ForSource", function() {
|
||||
Loop: [
|
||||
o("LOOP Block", function() {
|
||||
return new WhileNode(new LiteralNode('true')).addBody($2);
|
||||
}), o("LOOP Expression", function() {
|
||||
return new WhileNode(new LiteralNode('true')).addBody(Expressions.wrap([$2]));
|
||||
})
|
||||
],
|
||||
For: [
|
||||
o("Statement FOR ForVariables ForSource", function() {
|
||||
return new ForNode($1, $4, $3[0], $3[1]);
|
||||
}), o("Expression FOR ForVariables ForSource", function() {
|
||||
return new ForNode($1, $4, $3[0], $3[1]);
|
||||
}), o("FOR ForVariables ForSource Block", function() {
|
||||
return new ForNode($4, $3, $2[0], $2[1]);
|
||||
})
|
||||
],
|
||||
// An array or range comprehension has variables for the current element and
|
||||
// (optional) reference to the current index. Or, *key, value*, in the case
|
||||
// of object comprehensions.
|
||||
ForVariables: [o("Identifier", function() {
|
||||
ForValue: [
|
||||
o("Identifier"), o("Array", function() {
|
||||
return new ValueNode($1);
|
||||
}), o("Object", function() {
|
||||
return new ValueNode($1);
|
||||
})
|
||||
],
|
||||
ForVariables: [
|
||||
o("ForValue", function() {
|
||||
return [$1];
|
||||
}), o("Identifier , Identifier", function() {
|
||||
}), o("ForValue , ForValue", function() {
|
||||
return [$1, $3];
|
||||
})
|
||||
],
|
||||
// The source of a comprehension is an array or object with an optional filter
|
||||
// clause. If it's an array comprehension, you can also choose to step through
|
||||
// in fixed-size increments.
|
||||
ForSource: [o("IN Expression", function() {
|
||||
ForSource: [
|
||||
o("IN Expression", function() {
|
||||
return {
|
||||
source: $2
|
||||
};
|
||||
@@ -480,12 +412,12 @@
|
||||
}), o("IN Expression WHEN Expression", function() {
|
||||
return {
|
||||
source: $2,
|
||||
filter: $4
|
||||
guard: $4
|
||||
};
|
||||
}), o("OF Expression WHEN Expression", function() {
|
||||
return {
|
||||
source: $2,
|
||||
filter: $4,
|
||||
guard: $4,
|
||||
object: true
|
||||
};
|
||||
}), o("IN Expression BY Expression", function() {
|
||||
@@ -496,84 +428,80 @@
|
||||
}), o("IN Expression WHEN Expression BY Expression", function() {
|
||||
return {
|
||||
source: $2,
|
||||
filter: $4,
|
||||
guard: $4,
|
||||
step: $6
|
||||
};
|
||||
}), o("IN Expression BY Expression WHEN Expression", function() {
|
||||
return {
|
||||
source: $2,
|
||||
step: $4,
|
||||
filter: $6
|
||||
guard: $6
|
||||
};
|
||||
})
|
||||
],
|
||||
// The CoffeeScript switch/when/else block replaces the JavaScript
|
||||
// switch/case/default by compiling into an if-else chain.
|
||||
Switch: [o("SWITCH Expression INDENT Whens OUTDENT", function() {
|
||||
return $4.rewrite_condition($2);
|
||||
Switch: [
|
||||
o("SWITCH Expression INDENT Whens OUTDENT", function() {
|
||||
return $4.switchesOver($2);
|
||||
}), o("SWITCH Expression INDENT Whens ELSE Block OUTDENT", function() {
|
||||
return $4.rewrite_condition($2).add_else($6, true);
|
||||
return $4.switchesOver($2).addElse($6, true);
|
||||
}), o("SWITCH INDENT Whens OUTDENT", function() {
|
||||
return $3;
|
||||
}), o("SWITCH INDENT Whens ELSE Block OUTDENT", function() {
|
||||
return $3.addElse($5, true);
|
||||
})
|
||||
],
|
||||
// The inner list of whens is left recursive. At code-generation time, the
|
||||
// IfNode will rewrite them into a proper chain.
|
||||
Whens: [o("When"), o("Whens When", function() {
|
||||
return $1.push($2);
|
||||
Whens: [
|
||||
o("When"), o("Whens When", function() {
|
||||
return $1.addElse($2);
|
||||
})
|
||||
],
|
||||
// An individual **When** clause, with action.
|
||||
When: [o("LEADING_WHEN SimpleArgs Block", function() {
|
||||
return new IfNode($2, $3, null, {
|
||||
When: [
|
||||
o("LEADING_WHEN SimpleArgs Block", function() {
|
||||
return new IfNode($2, $3, {
|
||||
statement: true
|
||||
});
|
||||
}), o("LEADING_WHEN SimpleArgs Block TERMINATOR", function() {
|
||||
return new IfNode($2, $3, null, {
|
||||
return new IfNode($2, $3, {
|
||||
statement: true
|
||||
});
|
||||
}), o("Comment TERMINATOR When", function() {
|
||||
$3.comment = $1;
|
||||
return $3;
|
||||
})
|
||||
],
|
||||
// The most basic form of *if* is a condition and an action. The following
|
||||
// if-related rules are broken up along these lines in order to avoid
|
||||
// ambiguity.
|
||||
IfStart: [o("IF Expression Block", function() {
|
||||
IfBlock: [
|
||||
o("IF Expression Block", function() {
|
||||
return new IfNode($2, $3);
|
||||
}), o("IfStart ElsIf", function() {
|
||||
return $1.add_else($2);
|
||||
}), o("UNLESS Expression Block", function() {
|
||||
return new IfNode($2, $3, {
|
||||
invert: true
|
||||
});
|
||||
}), o("IfBlock ELSE IF Expression Block", function() {
|
||||
return $1.addElse((new IfNode($4, $5)).forceStatement());
|
||||
}), o("IfBlock ELSE Block", function() {
|
||||
return $1.addElse($3);
|
||||
})
|
||||
],
|
||||
// An **IfStart** can optionally be followed by an else block.
|
||||
IfBlock: [o("IfStart"), o("IfStart ELSE Block", function() {
|
||||
return $1.add_else($3);
|
||||
})
|
||||
],
|
||||
// An *else if* continuation of the *if* expression.
|
||||
ElsIf: [o("ELSE IF Expression Block", function() {
|
||||
return (new IfNode($3, $4)).force_statement();
|
||||
})
|
||||
],
|
||||
// The full complement of *if* expressions, including postfix one-liner
|
||||
// *if* and *unless*.
|
||||
If: [o("IfBlock"), o("Expression IF Expression", function() {
|
||||
return new IfNode($3, Expressions.wrap([$1]), null, {
|
||||
If: [
|
||||
o("IfBlock"), o("Statement IF Expression", function() {
|
||||
return new IfNode($3, Expressions.wrap([$1]), {
|
||||
statement: true
|
||||
});
|
||||
}), o("Expression IF Expression", function() {
|
||||
return new IfNode($3, Expressions.wrap([$1]), {
|
||||
statement: true
|
||||
});
|
||||
}), o("Statement UNLESS Expression", function() {
|
||||
return new IfNode($3, Expressions.wrap([$1]), {
|
||||
statement: true,
|
||||
invert: true
|
||||
});
|
||||
}), o("Expression UNLESS Expression", function() {
|
||||
return new IfNode($3, Expressions.wrap([$1]), null, {
|
||||
return new IfNode($3, Expressions.wrap([$1]), {
|
||||
statement: true,
|
||||
invert: true
|
||||
});
|
||||
})
|
||||
],
|
||||
// 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 *Operand OpSymbol Operand*
|
||||
// -type rule, but in order to make the precedence binding possible, separate
|
||||
// rules are necessary.
|
||||
Operation: [o("! Expression", function() {
|
||||
Operation: [
|
||||
o("! Expression", function() {
|
||||
return new OpNode('!', $2);
|
||||
}), o("!! Expression", function() {
|
||||
return new OpNode('!!', $2);
|
||||
@@ -637,7 +565,7 @@
|
||||
return new OpNode('&&', $1, $3);
|
||||
}), o("Expression || Expression", function() {
|
||||
return new OpNode('||', $1, $3);
|
||||
}), o("Expression ? Expression", function() {
|
||||
}), o("Expression OP? Expression", function() {
|
||||
return new OpNode('?', $1, $3);
|
||||
}), o("Expression -= Expression", function() {
|
||||
return new OpNode('-=', $1, $3);
|
||||
@@ -658,24 +586,17 @@
|
||||
}), o("Expression INSTANCEOF Expression", function() {
|
||||
return new OpNode('instanceof', $1, $3);
|
||||
}), o("Expression IN Expression", function() {
|
||||
return new InNode($1, $3);
|
||||
}), o("Expression OF Expression", function() {
|
||||
return new OpNode('in', $1, $3);
|
||||
}), o("Expression ! IN Expression", function() {
|
||||
return new OpNode('!', new InNode($1, $4));
|
||||
}), o("Expression ! OF Expression", function() {
|
||||
return new OpNode('!', new ParentheticalNode(new OpNode('in', $1, $4)));
|
||||
})
|
||||
]
|
||||
};
|
||||
// Precedence
|
||||
// ----------
|
||||
// Operators at the top of this list have higher precedence than the ones lower
|
||||
// down. Following these rules is what makes `2 + 3 * 4` parse as:
|
||||
// 2 + (3 * 4)
|
||||
// And not:
|
||||
// (2 + 3) * 4
|
||||
operators = [["left", '?'], ["nonassoc", 'UMINUS', 'UPLUS', '!', '!!', '~', '++', '--'], ["left", '*', '/', '%'], ["left", '+', '-'], ["left", '<<', '>>', '>>>'], ["left", '&', '|', '^'], ["left", '<=', '<', '>', '>='], ["right", 'DELETE', 'INSTANCEOF', 'TYPEOF'], ["left", '==', '!='], ["left", '&&', '||'], ["right", '-=', '+=', '/=', '*=', '%=', '||=', '&&=', '?='], ["left", '.'], ["right", 'INDENT'], ["left", 'OUTDENT'], ["right", 'WHEN', 'LEADING_WHEN', 'IN', 'OF', 'BY', 'THROW'], ["right", 'FOR', 'NEW', 'SUPER', 'CLASS'], ["left", 'EXTENDS'], ["right", 'ASSIGN', 'RETURN'], ["right", '->', '=>', '<-', 'UNLESS', 'IF', 'ELSE', 'WHILE']];
|
||||
// Wrapping Up
|
||||
// -----------
|
||||
// Finally, now what 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".
|
||||
operators = [["left", '?'], ["nonassoc", 'UMINUS', 'UPLUS', '!', '!!', '~', '++', '--'], ["left", '*', '/', '%'], ["left", '+', '-'], ["left", '<<', '>>', '>>>'], ["left", '&', '|', '^'], ["left", '<=', '<', '>', '>='], ["right", 'DELETE', 'INSTANCEOF', 'TYPEOF'], ["left", '==', '!='], ["left", '&&', '||', 'OP?'], ["right", '-=', '+=', '/=', '*=', '%=', '||=', '&&=', '?='], ["left", '.'], ["right", 'INDENT'], ["left", 'OUTDENT'], ["right", 'WHEN', 'LEADING_WHEN', 'IN', 'OF', 'BY', 'THROW'], ["right", 'FOR', 'WHILE', 'UNTIL', 'LOOP', 'NEW', 'SUPER', 'CLASS'], ["left", 'EXTENDS'], ["right", 'ASSIGN', 'RETURN'], ["right", '->', '=>', 'UNLESS', 'IF', 'ELSE']];
|
||||
tokens = [];
|
||||
_a = grammar;
|
||||
for (name in _a) { if (__hasProp.call(_a, name)) {
|
||||
@@ -693,18 +614,14 @@
|
||||
}
|
||||
}
|
||||
if (name === 'Root') {
|
||||
alt[1] = "return " + (alt[1]);
|
||||
alt[1] = ("return " + (alt[1]));
|
||||
}
|
||||
return alt;
|
||||
}).call(this));
|
||||
})());
|
||||
}
|
||||
return _b;
|
||||
}).call(this);
|
||||
})();
|
||||
}}
|
||||
// Initialize the **Parser** with our list of terminal **tokens**, our **grammar**
|
||||
// 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 [Yacc](http://dinosaur.compilertools.net/yacc/index.html)).
|
||||
exports.parser = new Parser({
|
||||
tokens: tokens.join(' '),
|
||||
bnf: grammar,
|
||||
|
||||
110
lib/helpers.js
110
lib/helpers.js
@@ -1,24 +1,31 @@
|
||||
(function(){
|
||||
var balanced_string, compact, count, del, extend, flatten, helpers, include, merge, starts;
|
||||
var compact, count, del, extend, flatten, helpers, include, indexOf, merge, starts;
|
||||
var __hasProp = Object.prototype.hasOwnProperty;
|
||||
// This file contains the common helper functions that we'd like to share among
|
||||
// the **Lexer**, **Rewriter**, and the **Nodes**. Merge objects, flatten
|
||||
// arrays, count characters, that sort of thing.
|
||||
// Set up exported variables for both **Node.js** and the browser.
|
||||
if (!((typeof process !== "undefined" && process !== null))) {
|
||||
if (!(typeof process !== "undefined" && process !== null)) {
|
||||
this.exports = this;
|
||||
}
|
||||
helpers = (exports.helpers = {});
|
||||
// Does a list include a value?
|
||||
helpers.include = (include = function include(list, value) {
|
||||
return list.indexOf(value) >= 0;
|
||||
helpers.indexOf = (indexOf = function(array, item, from) {
|
||||
var _a, _b, index, other;
|
||||
if (array.indexOf) {
|
||||
return array.indexOf(item, from);
|
||||
}
|
||||
_a = array;
|
||||
for (index = 0, _b = _a.length; index < _b; index++) {
|
||||
other = _a[index];
|
||||
if (other === item && (!from || (from <= index))) {
|
||||
return index;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
});
|
||||
// Peek at the beginning of a given string to see if it matches a sequence.
|
||||
helpers.starts = (starts = function starts(string, literal, start) {
|
||||
helpers.include = (include = function(list, value) {
|
||||
return indexOf(list, value) >= 0;
|
||||
});
|
||||
helpers.starts = (starts = function(string, literal, start) {
|
||||
return string.substring(start, (start || 0) + literal.length) === literal;
|
||||
});
|
||||
// Trim out all falsy values from an array.
|
||||
helpers.compact = (compact = function compact(array) {
|
||||
helpers.compact = (compact = function(array) {
|
||||
var _a, _b, _c, _d, item;
|
||||
_a = []; _c = array;
|
||||
for (_b = 0, _d = _c.length; _b < _d; _b++) {
|
||||
@@ -27,21 +34,17 @@
|
||||
}
|
||||
return _a;
|
||||
});
|
||||
// Count the number of occurences of a character in a string.
|
||||
helpers.count = (count = function count(string, letter) {
|
||||
helpers.count = (count = function(string, letter) {
|
||||
var num, pos;
|
||||
num = 0;
|
||||
pos = string.indexOf(letter);
|
||||
pos = indexOf(string, letter);
|
||||
while (pos !== -1) {
|
||||
num += 1;
|
||||
pos = string.indexOf(letter, pos + 1);
|
||||
pos = indexOf(string, letter, pos + 1);
|
||||
}
|
||||
return num;
|
||||
});
|
||||
// Merge objects, returning a fresh copy with attributes from both sides.
|
||||
// Used every time `BaseNode#compile` is called, to allow properties in the
|
||||
// options hash to propagate down the tree without polluting other branches.
|
||||
helpers.merge = (merge = function merge(options, overrides) {
|
||||
helpers.merge = (merge = function(options, overrides) {
|
||||
var _a, _b, fresh, key, val;
|
||||
fresh = {};
|
||||
_a = options;
|
||||
@@ -58,20 +61,16 @@
|
||||
}
|
||||
return fresh;
|
||||
});
|
||||
// Extend a source object with the properties of another object (shallow copy).
|
||||
// We use this to simulate Node's deprecated `process.mixin`
|
||||
helpers.extend = (extend = function extend(object, properties) {
|
||||
helpers.extend = (extend = function(object, properties) {
|
||||
var _a, _b, key, val;
|
||||
_a = []; _b = properties;
|
||||
for (key in _b) { if (__hasProp.call(_b, key)) {
|
||||
val = _b[key];
|
||||
_a.push((object[key] = val));
|
||||
_a.push(object[key] = val);
|
||||
}}
|
||||
return _a;
|
||||
});
|
||||
// Return a completely flattened version of an array. Handy for getting a
|
||||
// list of `children` from the nodes.
|
||||
helpers.flatten = (flatten = function flatten(array) {
|
||||
helpers.flatten = (flatten = function(array) {
|
||||
var _a, _b, _c, item, memo;
|
||||
memo = [];
|
||||
_b = array;
|
||||
@@ -81,63 +80,10 @@
|
||||
}
|
||||
return memo;
|
||||
});
|
||||
// Delete a key from an object, returning the value. Useful when a node is
|
||||
// looking for a particular method in an options hash.
|
||||
helpers.del = (del = function del(obj, key) {
|
||||
helpers.del = (del = function(obj, key) {
|
||||
var val;
|
||||
val = obj[key];
|
||||
delete obj[key];
|
||||
return val;
|
||||
});
|
||||
// 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
|
||||
// interpolations within strings, ad infinitum.
|
||||
helpers.balanced_string = (balanced_string = function balanced_string(str, delimited, options) {
|
||||
var _a, _b, _c, _d, close, i, levels, open, pair, slash;
|
||||
options = options || {};
|
||||
slash = delimited[0][0] === '/';
|
||||
levels = [];
|
||||
i = 0;
|
||||
while (i < str.length) {
|
||||
if (levels.length && starts(str, '\\', i)) {
|
||||
i += 1;
|
||||
} else {
|
||||
_b = delimited;
|
||||
for (_a = 0, _c = _b.length; _a < _c; _a++) {
|
||||
pair = _b[_a];
|
||||
_d = pair;
|
||||
open = _d[0];
|
||||
close = _d[1];
|
||||
if (levels.length && starts(str, close, i) && levels[levels.length - 1] === pair) {
|
||||
levels.pop();
|
||||
i += close.length - 1;
|
||||
if (!(levels.length)) {
|
||||
i += 1;
|
||||
}
|
||||
break;
|
||||
} else if (starts(str, open, i)) {
|
||||
levels.push(pair);
|
||||
i += open.length - 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!levels.length || slash && starts(str, '\n', i)) {
|
||||
break;
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
if (levels.length) {
|
||||
if (slash) {
|
||||
return false;
|
||||
}
|
||||
throw new Error("SyntaxError: Unterminated " + (levels.pop()[0]) + " starting on line " + (this.line + 1));
|
||||
}
|
||||
if (!i) {
|
||||
return false;
|
||||
} else {
|
||||
return str.substring(0, i);
|
||||
}
|
||||
});
|
||||
})();
|
||||
|
||||
9
lib/index.js
Normal file
9
lib/index.js
Normal file
@@ -0,0 +1,9 @@
|
||||
(function(){
|
||||
var _a, key, val;
|
||||
var __hasProp = Object.prototype.hasOwnProperty;
|
||||
_a = require('./coffee-script');
|
||||
for (key in _a) { if (__hasProp.call(_a, key)) {
|
||||
val = _a[key];
|
||||
(exports[key] = val);
|
||||
}}
|
||||
})();
|
||||
635
lib/lexer.js
635
lib/lexer.js
@@ -1,318 +1,270 @@
|
||||
(function(){
|
||||
var ACCESSORS, ASSIGNMENT, CALLABLE, CODE, COFFEE_ALIASES, COFFEE_KEYWORDS, COMMENT, COMMENT_CLEANER, CONVERSIONS, HALF_ASSIGNMENTS, HEREDOC, HEREDOC_INDENT, IDENTIFIER, INTERPOLATION, JS_CLEANER, JS_FORBIDDEN, JS_KEYWORDS, KEYWORDS, LAST_DENT, LAST_DENTS, LINE_BREAK, Lexer, MULTILINER, MULTI_DENT, NOT_REGEX, NO_NEWLINE, NUMBER, OPERATOR, REGEX_ESCAPE, REGEX_FLAGS, REGEX_INTERPOLATION, REGEX_START, RESERVED, Rewriter, STRING_NEWLINES, WHITESPACE, balanced_string, compact, count, helpers, include, starts;
|
||||
var ASSIGNED, ASSIGNMENT, CALLABLE, CODE, COFFEE_ALIASES, COFFEE_KEYWORDS, COMMENT, CONVERSIONS, HALF_ASSIGNMENTS, HEREDOC, HEREDOC_INDENT, IDENTIFIER, INTERPOLATION, JS_CLEANER, JS_FORBIDDEN, JS_KEYWORDS, LAST_DENT, LAST_DENTS, LINE_BREAK, Lexer, MULTILINER, MULTI_DENT, NEXT_CHARACTER, NOT_REGEX, NO_NEWLINE, NUMBER, OPERATOR, REGEX_END, REGEX_ESCAPE, REGEX_INTERPOLATION, REGEX_START, RESERVED, Rewriter, STRING_NEWLINES, WHITESPACE, _a, _b, _c, compact, count, helpers, include, starts;
|
||||
var __slice = Array.prototype.slice;
|
||||
// The CoffeeScript Lexer. Uses a series of token-matching regexes to attempt
|
||||
// matches against the beginning of the source code. When a match is found,
|
||||
// a token is produced, we consume the match, and start again. Tokens are in the
|
||||
// form:
|
||||
// [tag, value, line_number]
|
||||
// Which is a format that can be fed directly into [Jison](http://github.com/zaach/jison).
|
||||
// Set up the Lexer for both Node.js and the browser, depending on where we are.
|
||||
if ((typeof process !== "undefined" && process !== null)) {
|
||||
Rewriter = require('./rewriter').Rewriter;
|
||||
helpers = require('./helpers').helpers;
|
||||
if (typeof process !== "undefined" && process !== null) {
|
||||
_a = require('./rewriter');
|
||||
Rewriter = _a.Rewriter;
|
||||
_b = require('./helpers');
|
||||
helpers = _b.helpers;
|
||||
} else {
|
||||
this.exports = this;
|
||||
Rewriter = this.Rewriter;
|
||||
helpers = this.helpers;
|
||||
}
|
||||
// Import the helpers we need.
|
||||
include = helpers.include;
|
||||
count = helpers.count;
|
||||
starts = helpers.starts;
|
||||
compact = helpers.compact;
|
||||
balanced_string = helpers.balanced_string;
|
||||
// The Lexer Class
|
||||
// ---------------
|
||||
// The Lexer class reads a stream of CoffeeScript and divvys it up into tagged
|
||||
// tokens. Some potential ambiguity in the grammar has been avoided by
|
||||
// pushing some extra smarts into the Lexer.
|
||||
_c = helpers;
|
||||
include = _c.include;
|
||||
count = _c.count;
|
||||
starts = _c.starts;
|
||||
compact = _c.compact;
|
||||
exports.Lexer = (function() {
|
||||
Lexer = function Lexer() { };
|
||||
// **tokenize** is the Lexer's main method. Scan by attempting to match tokens
|
||||
// one at a time, using a regular expression anchored at the start of the
|
||||
// remaining code, or a custom recursive token-matching method
|
||||
// (for interpolations). When the next token has been recorded, we move forward
|
||||
// within the code past the token, and begin again.
|
||||
// Each tokenizing method is responsible for incrementing `@i` by the number of
|
||||
// characters it has consumed. `@i` can be thought of as our finger on the page
|
||||
// of source.
|
||||
// Before returning the token stream, run it through the [Rewriter](rewriter.html)
|
||||
// unless explicitly asked not to.
|
||||
Lexer.prototype.tokenize = function tokenize(code, options) {
|
||||
Lexer = function() { };
|
||||
Lexer.prototype.tokenize = function(code, options) {
|
||||
var o;
|
||||
code = code.replace(/(\r|\s+$)/g, '');
|
||||
o = options || {};
|
||||
this.code = code;
|
||||
// The remainder of the source code.
|
||||
this.i = 0;
|
||||
// Current character position we're parsing.
|
||||
this.line = o.line || 0;
|
||||
// The current line.
|
||||
this.indent = 0;
|
||||
// The current indentation level.
|
||||
this.outdebt = 0;
|
||||
this.indents = [];
|
||||
// The stack of all current indentation levels.
|
||||
this.tokens = [];
|
||||
// Stream of parsed tokens in the form ['TYPE', value, line]
|
||||
while (this.i < this.code.length) {
|
||||
this.chunk = this.code.slice(this.i);
|
||||
this.extract_next_token();
|
||||
this.extractNextToken();
|
||||
}
|
||||
this.close_indentation();
|
||||
this.closeIndentation();
|
||||
if (o.rewrite === false) {
|
||||
return this.tokens;
|
||||
}
|
||||
return (new Rewriter()).rewrite(this.tokens);
|
||||
};
|
||||
// At every position, run through this list of attempted matches,
|
||||
// short-circuiting if any of them succeed. Their order determines precedence:
|
||||
// `@literal_token` is the fallback catch-all.
|
||||
Lexer.prototype.extract_next_token = function extract_next_token() {
|
||||
if (this.extension_token()) {
|
||||
Lexer.prototype.extractNextToken = function() {
|
||||
if (this.identifierToken()) {
|
||||
return null;
|
||||
}
|
||||
if (this.identifier_token()) {
|
||||
if (this.commentToken()) {
|
||||
return null;
|
||||
}
|
||||
if (this.number_token()) {
|
||||
if (this.whitespaceToken()) {
|
||||
return null;
|
||||
}
|
||||
if (this.heredoc_token()) {
|
||||
if (this.lineToken()) {
|
||||
return null;
|
||||
}
|
||||
if (this.regex_token()) {
|
||||
if (this.heredocToken()) {
|
||||
return null;
|
||||
}
|
||||
if (this.comment_token()) {
|
||||
if (this.stringToken()) {
|
||||
return null;
|
||||
}
|
||||
if (this.line_token()) {
|
||||
if (this.numberToken()) {
|
||||
return null;
|
||||
}
|
||||
if (this.whitespace_token()) {
|
||||
if (this.regexToken()) {
|
||||
return null;
|
||||
}
|
||||
if (this.js_token()) {
|
||||
if (this.jsToken()) {
|
||||
return null;
|
||||
}
|
||||
if (this.string_token()) {
|
||||
return null;
|
||||
}
|
||||
return this.literal_token();
|
||||
return this.literalToken();
|
||||
};
|
||||
// Tokenizers
|
||||
// ----------
|
||||
// Language extensions get the highest priority, first chance to tag tokens
|
||||
// as something else.
|
||||
Lexer.prototype.extension_token = function extension_token() {
|
||||
var _a, _b, _c, extension;
|
||||
_b = Lexer.extensions;
|
||||
for (_a = 0, _c = _b.length; _a < _c; _a++) {
|
||||
extension = _b[_a];
|
||||
if (extension.call(this)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
// Matches identifying literals: variables, keywords, method names, etc.
|
||||
// Check to ensure that JavaScript reserved words aren't being used as
|
||||
// identifiers. Because CoffeeScript reserves a handful of keywords that are
|
||||
// allowed in JavaScript, we're careful not to tag them as keywords when
|
||||
// referenced as property names here, so you can still do `jQuery.is()` even
|
||||
// though `is` means `===` otherwise.
|
||||
Lexer.prototype.identifier_token = function identifier_token() {
|
||||
var accessed, id, tag;
|
||||
Lexer.prototype.identifierToken = function() {
|
||||
var close_index, forcedIdentifier, id, tag;
|
||||
if (!(id = this.match(IDENTIFIER, 1))) {
|
||||
return false;
|
||||
}
|
||||
this.name_access_type();
|
||||
accessed = include(ACCESSORS, this.tag(0));
|
||||
this.i += id.length;
|
||||
forcedIdentifier = this.tagAccessor() || this.match(ASSIGNED, 1);
|
||||
tag = 'IDENTIFIER';
|
||||
if (!accessed && include(KEYWORDS, id)) {
|
||||
if (include(JS_KEYWORDS, id) || (!forcedIdentifier && include(COFFEE_KEYWORDS, id))) {
|
||||
tag = id.toUpperCase();
|
||||
}
|
||||
if (include(RESERVED, id)) {
|
||||
this.identifier_error(id);
|
||||
}
|
||||
if (tag === 'WHEN' && include(LINE_BREAK, this.tag())) {
|
||||
tag = 'LEADING_WHEN';
|
||||
}
|
||||
this.i += id.length;
|
||||
if (!accessed) {
|
||||
if (include(JS_FORBIDDEN, id)) {
|
||||
if (forcedIdentifier) {
|
||||
tag = 'STRING';
|
||||
id = ("'" + id + "'");
|
||||
if (forcedIdentifier === 'accessor') {
|
||||
close_index = true;
|
||||
if (this.tag() !== '@') {
|
||||
this.tokens.pop();
|
||||
}
|
||||
this.token('INDEX_START', '[');
|
||||
}
|
||||
} else if (include(RESERVED, id)) {
|
||||
this.identifierError(id);
|
||||
}
|
||||
}
|
||||
if (!(forcedIdentifier)) {
|
||||
if (include(COFFEE_ALIASES, id)) {
|
||||
tag = (id = CONVERSIONS[id]);
|
||||
}
|
||||
if (this.prev() && this.prev()[0] === 'ASSIGN' && include(HALF_ASSIGNMENTS, tag)) {
|
||||
return this.tag_half_assignment(tag);
|
||||
return this.tagHalfAssignment(tag);
|
||||
}
|
||||
}
|
||||
this.token(tag, id);
|
||||
if (close_index) {
|
||||
this.token(']', ']');
|
||||
}
|
||||
return true;
|
||||
};
|
||||
// Matches numbers, including decimals, hex, and exponential notation.
|
||||
Lexer.prototype.number_token = function number_token() {
|
||||
Lexer.prototype.numberToken = function() {
|
||||
var number;
|
||||
if (!(number = this.match(NUMBER, 1))) {
|
||||
return false;
|
||||
}
|
||||
this.token('NUMBER', number);
|
||||
if (this.tag() === '.' && starts(number, '.')) {
|
||||
return false;
|
||||
}
|
||||
this.i += number.length;
|
||||
this.token('NUMBER', number);
|
||||
return true;
|
||||
};
|
||||
// Matches strings, including multi-line strings. Ensures that quotation marks
|
||||
// are balanced within the string's contents, and within nested interpolations.
|
||||
Lexer.prototype.string_token = function string_token() {
|
||||
Lexer.prototype.stringToken = function() {
|
||||
var string;
|
||||
if (!(starts(this.chunk, '"') || starts(this.chunk, "'"))) {
|
||||
return false;
|
||||
}
|
||||
if (!(string = this.balanced_token(['"', '"'], ['${', '}']) || this.balanced_token(["'", "'"]))) {
|
||||
if (!(string = this.balancedToken(['"', '"'], ['${', '}']) || this.balancedToken(["'", "'"]))) {
|
||||
return false;
|
||||
}
|
||||
this.interpolate_string(string.replace(STRING_NEWLINES, " \\\n"));
|
||||
this.interpolateString(string.replace(STRING_NEWLINES, " \\\n"));
|
||||
this.line += count(string, "\n");
|
||||
this.i += string.length;
|
||||
return true;
|
||||
};
|
||||
// Matches heredocs, adjusting indentation to the correct level, as heredocs
|
||||
// preserve whitespace, but ignore indentation to the left.
|
||||
Lexer.prototype.heredoc_token = function heredoc_token() {
|
||||
Lexer.prototype.heredocToken = function() {
|
||||
var doc, match, quote;
|
||||
if (!(match = this.chunk.match(HEREDOC))) {
|
||||
return false;
|
||||
}
|
||||
quote = match[1].substr(0, 1);
|
||||
doc = this.sanitize_heredoc(match[2] || match[4], quote);
|
||||
this.interpolate_string("" + quote + doc + quote);
|
||||
doc = this.sanitizeHeredoc(match[2] || match[4], {
|
||||
quote: quote
|
||||
});
|
||||
this.interpolateString("" + quote + doc + quote);
|
||||
this.line += count(match[1], "\n");
|
||||
this.i += match[1].length;
|
||||
return true;
|
||||
};
|
||||
// Matches JavaScript interpolated directly into the source via backticks.
|
||||
Lexer.prototype.js_token = function js_token() {
|
||||
Lexer.prototype.commentToken = function() {
|
||||
var comment, match;
|
||||
if (!(match = this.chunk.match(COMMENT))) {
|
||||
return false;
|
||||
}
|
||||
this.line += count(match[1], "\n");
|
||||
this.i += match[1].length;
|
||||
if (match[2]) {
|
||||
comment = this.sanitizeHeredoc(match[2], {
|
||||
herecomment: true
|
||||
});
|
||||
this.token('HERECOMMENT', comment.split(MULTILINER));
|
||||
this.token('TERMINATOR', '\n');
|
||||
}
|
||||
return true;
|
||||
};
|
||||
Lexer.prototype.jsToken = function() {
|
||||
var script;
|
||||
if (!(starts(this.chunk, '`'))) {
|
||||
return false;
|
||||
}
|
||||
if (!(script = this.balanced_token(['`', '`']))) {
|
||||
if (!(script = this.balancedToken(['`', '`']))) {
|
||||
return false;
|
||||
}
|
||||
this.token('JS', script.replace(JS_CLEANER, ''));
|
||||
this.i += script.length;
|
||||
return true;
|
||||
};
|
||||
// Matches regular expression literals. Lexing regular expressions is difficult
|
||||
// to distinguish from division, so we borrow some basic heuristics from
|
||||
// JavaScript and Ruby, borrow slash balancing from `@balanced_token`, and
|
||||
// borrow interpolation from `@interpolate_string`.
|
||||
Lexer.prototype.regex_token = function regex_token() {
|
||||
var flags, regex, str;
|
||||
Lexer.prototype.regexToken = function() {
|
||||
var end, flags, regex, str;
|
||||
if (!(this.chunk.match(REGEX_START))) {
|
||||
return false;
|
||||
}
|
||||
if (include(NOT_REGEX, this.tag())) {
|
||||
return false;
|
||||
}
|
||||
if (!(regex = this.balanced_token(['/', '/']))) {
|
||||
if (!(regex = this.balancedToken(['/', '/']))) {
|
||||
return false;
|
||||
}
|
||||
regex += (flags = this.chunk.substr(regex.length).match(REGEX_FLAGS));
|
||||
if (!(end = this.chunk.substr(regex.length).match(REGEX_END))) {
|
||||
return false;
|
||||
}
|
||||
if (end[2]) {
|
||||
regex += (flags = end[2]);
|
||||
}
|
||||
if (regex.match(REGEX_INTERPOLATION)) {
|
||||
str = regex.substring(1).split('/')[0];
|
||||
str = str.replace(REGEX_ESCAPE, function(escaped) {
|
||||
return '\\' + escaped;
|
||||
});
|
||||
this.tokens = this.tokens.concat([['(', '('], ['NEW', 'new'], ['IDENTIFIER', 'RegExp'], ['CALL_START', '(']]);
|
||||
this.interpolate_string("\"" + str + "\"", true);
|
||||
this.tokens = this.tokens.concat([[',', ','], ['STRING', "\"" + flags + "\""], [')', ')'], [')', ')']]);
|
||||
this.interpolateString(("\"" + str + "\""), true);
|
||||
this.tokens = this.tokens.concat([[',', ','], ['STRING', ("\"" + flags + "\"")], [')', ')'], [')', ')']]);
|
||||
} else {
|
||||
this.token('REGEX', regex);
|
||||
}
|
||||
this.i += regex.length;
|
||||
return true;
|
||||
};
|
||||
// Matches a token in which which the passed delimiter pairs must be correctly
|
||||
// balanced (ie. strings, JS literals).
|
||||
Lexer.prototype.balanced_token = function balanced_token() {
|
||||
Lexer.prototype.balancedToken = function() {
|
||||
var delimited;
|
||||
delimited = __slice.call(arguments, 0, arguments.length - 0);
|
||||
return balanced_string(this.chunk, delimited);
|
||||
var _d = arguments.length, _e = _d >= 1;
|
||||
delimited = __slice.call(arguments, 0, _d - 0);
|
||||
return this.balancedString(this.chunk, delimited);
|
||||
};
|
||||
// Matches and conumes comments. We pass through comments into JavaScript,
|
||||
// so they're treated as real tokens, like any other part of the language.
|
||||
Lexer.prototype.comment_token = function comment_token() {
|
||||
var comment, i, lines;
|
||||
if (!(comment = this.match(COMMENT, 1))) {
|
||||
return false;
|
||||
}
|
||||
this.line += (comment.match(MULTILINER) || []).length;
|
||||
lines = compact(comment.replace(COMMENT_CLEANER, '').split(MULTILINER));
|
||||
i = this.tokens.length - 1;
|
||||
if (this.unfinished()) {
|
||||
while (this.tokens[i] && !include(LINE_BREAK, this.tokens[i][0])) {
|
||||
i -= 1;
|
||||
}
|
||||
}
|
||||
this.tokens.splice(i + 1, 0, ['COMMENT', lines, this.line], ['TERMINATOR', '\n', this.line]);
|
||||
this.i += comment.length;
|
||||
return true;
|
||||
};
|
||||
// Matches newlines, indents, and outdents, and determines which is which.
|
||||
// If we can detect that the current line is continued onto the the next line,
|
||||
// then the newline is suppressed:
|
||||
// elements
|
||||
// .each( ... )
|
||||
// .map( ... )
|
||||
// Keeps track of the level of indentation, because a single outdent token
|
||||
// can close multiple indents, so we need to know how far in we happen to be.
|
||||
Lexer.prototype.line_token = function line_token() {
|
||||
var diff, indent, next_character, no_newlines, prev, size;
|
||||
Lexer.prototype.lineToken = function() {
|
||||
var diff, indent, nextCharacter, noNewlines, prev, size;
|
||||
if (!(indent = this.match(MULTI_DENT, 1))) {
|
||||
return false;
|
||||
}
|
||||
this.line += indent.match(MULTILINER).length;
|
||||
this.line += count(indent, "\n");
|
||||
this.i += indent.length;
|
||||
prev = this.prev(2);
|
||||
size = indent.match(LAST_DENTS).reverse()[0].match(LAST_DENT)[1].length;
|
||||
next_character = this.chunk.match(MULTI_DENT)[4];
|
||||
no_newlines = next_character === '.' || this.unfinished();
|
||||
nextCharacter = this.match(NEXT_CHARACTER, 1);
|
||||
noNewlines = nextCharacter === '.' || nextCharacter === ',' || this.unfinished();
|
||||
if (size === this.indent) {
|
||||
if (no_newlines) {
|
||||
return this.suppress_newlines();
|
||||
if (noNewlines) {
|
||||
return this.suppressNewlines();
|
||||
}
|
||||
return this.newline_token(indent);
|
||||
return this.newlineToken(indent);
|
||||
} else if (size > this.indent) {
|
||||
if (no_newlines) {
|
||||
return this.suppress_newlines();
|
||||
if (noNewlines) {
|
||||
return this.suppressNewlines();
|
||||
}
|
||||
diff = size - this.indent;
|
||||
this.token('INDENT', diff);
|
||||
this.indents.push(diff);
|
||||
} else {
|
||||
this.outdent_token(this.indent - size, no_newlines);
|
||||
this.outdentToken(this.indent - size, noNewlines);
|
||||
}
|
||||
this.indent = size;
|
||||
return true;
|
||||
};
|
||||
// Record an outdent token or multiple tokens, if we happen to be moving back
|
||||
// inwards past several recorded indents.
|
||||
Lexer.prototype.outdent_token = function outdent_token(move_out, no_newlines) {
|
||||
var last_indent;
|
||||
while (move_out > 0 && this.indents.length) {
|
||||
last_indent = this.indents.pop();
|
||||
this.token('OUTDENT', last_indent);
|
||||
move_out -= last_indent;
|
||||
Lexer.prototype.outdentToken = function(moveOut, noNewlines) {
|
||||
var lastIndent;
|
||||
if (moveOut > -this.outdebt) {
|
||||
while (moveOut > 0 && this.indents.length) {
|
||||
lastIndent = this.indents.pop();
|
||||
this.token('OUTDENT', lastIndent);
|
||||
moveOut -= lastIndent;
|
||||
}
|
||||
} else {
|
||||
this.outdebt += moveOut;
|
||||
}
|
||||
if (!(this.tag() === 'TERMINATOR' || no_newlines)) {
|
||||
if (!(noNewlines)) {
|
||||
this.outdebt = moveOut;
|
||||
}
|
||||
if (!(this.tag() === 'TERMINATOR' || noNewlines)) {
|
||||
this.token('TERMINATOR', "\n");
|
||||
}
|
||||
return true;
|
||||
};
|
||||
// Matches and consumes non-meaningful whitespace. Tag the previous token
|
||||
// as being "spaced", because there are some cases where it makes a difference.
|
||||
Lexer.prototype.whitespace_token = function whitespace_token() {
|
||||
Lexer.prototype.whitespaceToken = function() {
|
||||
var prev, space;
|
||||
if (!(space = this.match(WHITESPACE, 1))) {
|
||||
return false;
|
||||
@@ -324,102 +276,104 @@
|
||||
this.i += space.length;
|
||||
return true;
|
||||
};
|
||||
// Generate a newline token. Consecutive newlines get merged together.
|
||||
Lexer.prototype.newline_token = function newline_token(newlines) {
|
||||
Lexer.prototype.newlineToken = function(newlines) {
|
||||
if (!(this.tag() === 'TERMINATOR')) {
|
||||
this.token('TERMINATOR', "\n");
|
||||
}
|
||||
return true;
|
||||
};
|
||||
// Use a `\` at a line-ending to suppress the newline.
|
||||
// The slash is removed here once its job is done.
|
||||
Lexer.prototype.suppress_newlines = function suppress_newlines() {
|
||||
Lexer.prototype.suppressNewlines = function() {
|
||||
if (this.value() === "\\") {
|
||||
this.tokens.pop();
|
||||
}
|
||||
return true;
|
||||
};
|
||||
// We treat all other single characters as a token. Eg.: `( ) , . !`
|
||||
// Multi-character operators are also literal tokens, so that Jison can assign
|
||||
// the proper order of operations. There are some symbols that we tag specially
|
||||
// here. `;` and newlines are both treated as a `TERMINATOR`, we distinguish
|
||||
// parentheses that indicate a method call from regular parentheses, and so on.
|
||||
Lexer.prototype.literal_token = function literal_token() {
|
||||
var match, prev_spaced, space, tag, value;
|
||||
Lexer.prototype.literalToken = function() {
|
||||
var match, prevSpaced, space, tag, value;
|
||||
match = this.chunk.match(OPERATOR);
|
||||
value = match && match[1];
|
||||
space = match && match[2];
|
||||
if (value && value.match(CODE)) {
|
||||
this.tag_parameters();
|
||||
this.tagParameters();
|
||||
}
|
||||
value = value || this.chunk.substr(0, 1);
|
||||
prev_spaced = this.prev() && this.prev().spaced;
|
||||
prevSpaced = this.prev() && this.prev().spaced;
|
||||
tag = value;
|
||||
if (value.match(ASSIGNMENT)) {
|
||||
tag = 'ASSIGN';
|
||||
if (include(JS_FORBIDDEN, this.value)) {
|
||||
this.assignment_error();
|
||||
this.assignmentError();
|
||||
}
|
||||
} else if (value === ';') {
|
||||
tag = 'TERMINATOR';
|
||||
} else if (value === '[' && this.tag() === '?' && !prev_spaced) {
|
||||
tag = 'SOAKED_INDEX_START';
|
||||
this.soaked_index = true;
|
||||
this.tokens.pop();
|
||||
} else if (value === ']' && this.soaked_index) {
|
||||
tag = 'SOAKED_INDEX_END';
|
||||
this.soaked_index = false;
|
||||
} else if (include(CALLABLE, this.tag()) && !prev_spaced) {
|
||||
} else if (value === '?' && prevSpaced) {
|
||||
tag = 'OP?';
|
||||
} else if (include(CALLABLE, this.tag()) && !prevSpaced) {
|
||||
if (value === '(') {
|
||||
tag = 'CALL_START';
|
||||
}
|
||||
if (value === '[') {
|
||||
} else if (value === '[') {
|
||||
tag = 'INDEX_START';
|
||||
if (this.tag() === '?') {
|
||||
this.tag(1, 'INDEX_SOAK');
|
||||
}
|
||||
if (this.tag() === '::') {
|
||||
this.tag(1, 'INDEX_PROTO');
|
||||
}
|
||||
}
|
||||
}
|
||||
this.i += value.length;
|
||||
if (space && prev_spaced && this.prev()[0] === 'ASSIGN' && include(HALF_ASSIGNMENTS, tag)) {
|
||||
return this.tag_half_assignment(tag);
|
||||
if (space && prevSpaced && this.prev()[0] === 'ASSIGN' && include(HALF_ASSIGNMENTS, tag)) {
|
||||
return this.tagHalfAssignment(tag);
|
||||
}
|
||||
this.token(tag, value);
|
||||
return true;
|
||||
};
|
||||
// Token Manipulators
|
||||
// ------------------
|
||||
// As we consume a new `IDENTIFIER`, look at the previous token to determine
|
||||
// if it's a special kind of accessor.
|
||||
Lexer.prototype.name_access_type = function name_access_type() {
|
||||
if (this.value() === '::') {
|
||||
this.tag(1, 'PROTOTYPE_ACCESS');
|
||||
Lexer.prototype.tagAccessor = function() {
|
||||
var accessor, prev;
|
||||
if ((!(prev = this.prev())) || (prev && prev.spaced)) {
|
||||
return false;
|
||||
}
|
||||
if (this.value() === '.' && !(this.value(2) === '.')) {
|
||||
if (this.tag(2) === '?') {
|
||||
this.tag(1, 'SOAK_ACCESS');
|
||||
return this.tokens.splice(-2, 1);
|
||||
accessor = (function() {
|
||||
if (prev[1] === '::') {
|
||||
return this.tag(1, 'PROTOTYPE_ACCESS');
|
||||
} else if (prev[1] === '.' && !(this.value(2) === '.')) {
|
||||
if (this.tag(2) === '?') {
|
||||
this.tag(1, 'SOAK_ACCESS');
|
||||
return this.tokens.splice(-2, 1);
|
||||
} else {
|
||||
return this.tag(1, 'PROPERTY_ACCESS');
|
||||
}
|
||||
} else {
|
||||
return this.tag(1, 'PROPERTY_ACCESS');
|
||||
return prev[0] === '@';
|
||||
}
|
||||
}).call(this);
|
||||
return accessor ? 'accessor' : false;
|
||||
};
|
||||
Lexer.prototype.sanitizeHeredoc = function(doc, options) {
|
||||
var _d, attempt, indent, match;
|
||||
while (match = HEREDOC_INDENT.exec(doc)) {
|
||||
attempt = (typeof (_d = match[2]) !== "undefined" && _d !== null) ? match[2] : match[3];
|
||||
if (!indent || attempt.length < indent.length) {
|
||||
indent = attempt;
|
||||
}
|
||||
}
|
||||
doc = doc.replace(new RegExp("^" + indent, 'gm'), '');
|
||||
if (options.herecomment) {
|
||||
return doc;
|
||||
}
|
||||
return doc.replace(MULTILINER, "\\n").replace(new RegExp(options.quote, 'g'), ("\\" + options.quote));
|
||||
};
|
||||
// Sanitize a heredoc by escaping internal double quotes and erasing all
|
||||
// external indentation on the left-hand side.
|
||||
Lexer.prototype.sanitize_heredoc = function sanitize_heredoc(doc, quote) {
|
||||
var indent;
|
||||
indent = (doc.match(HEREDOC_INDENT) || ['']).sort()[0];
|
||||
return doc.replace(new RegExp("^" + indent, 'gm'), '').replace(MULTILINER, "\\n").replace(new RegExp(quote, 'g'), '\\"');
|
||||
};
|
||||
// Tag a half assignment.
|
||||
Lexer.prototype.tag_half_assignment = function tag_half_assignment(tag) {
|
||||
Lexer.prototype.tagHalfAssignment = function(tag) {
|
||||
var last;
|
||||
if (tag === 'OP?') {
|
||||
tag = '?';
|
||||
}
|
||||
last = this.tokens.pop();
|
||||
this.tokens.push(["" + tag + "=", "" + tag + "=", last[2]]);
|
||||
this.tokens.push([("" + tag + "="), ("" + tag + "="), last[2]]);
|
||||
return true;
|
||||
};
|
||||
// A source of ambiguity in our grammar used to be parameter lists in function
|
||||
// definitions versus argument lists in function calls. Walk backwards, tagging
|
||||
// parameters specially in order to make things easier for the parser.
|
||||
Lexer.prototype.tag_parameters = function tag_parameters() {
|
||||
var _a, i, tok;
|
||||
Lexer.prototype.tagParameters = function() {
|
||||
var _d, i, tok;
|
||||
if (this.tag() !== ')') {
|
||||
return null;
|
||||
}
|
||||
@@ -430,80 +384,115 @@
|
||||
if (!tok) {
|
||||
return null;
|
||||
}
|
||||
if ((_a = tok[0]) === 'IDENTIFIER') {
|
||||
if ((_d = tok[0]) === 'IDENTIFIER') {
|
||||
tok[0] = 'PARAM';
|
||||
} else if (_a === ')') {
|
||||
} else if (_d === ')') {
|
||||
tok[0] = 'PARAM_END';
|
||||
} else if (_a === '(') {
|
||||
} else if (_d === '(' || _d === 'CALL_START') {
|
||||
tok[0] = 'PARAM_START';
|
||||
return tok[0];
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
// Close up all remaining open blocks at the end of the file.
|
||||
Lexer.prototype.close_indentation = function close_indentation() {
|
||||
return this.outdent_token(this.indent);
|
||||
Lexer.prototype.closeIndentation = function() {
|
||||
return this.outdentToken(this.indent);
|
||||
};
|
||||
// The error for when you try to use a forbidden word in JavaScript as
|
||||
// an identifier.
|
||||
Lexer.prototype.identifier_error = function identifier_error(word) {
|
||||
throw new Error("SyntaxError: Reserved word \"" + word + "\" on line " + (this.line + 1));
|
||||
Lexer.prototype.identifierError = function(word) {
|
||||
throw new Error(("SyntaxError: Reserved word \"" + word + "\" on line " + (this.line + 1)));
|
||||
};
|
||||
// The error for when you try to assign to a reserved word in JavaScript,
|
||||
// like "function" or "default".
|
||||
Lexer.prototype.assignment_error = function assignment_error() {
|
||||
throw new Error("SyntaxError: Reserved word \"" + (this.value()) + "\" on line " + (this.line + 1) + " can't be assigned");
|
||||
Lexer.prototype.assignmentError = function() {
|
||||
throw new Error(("SyntaxError: Reserved word \"" + (this.value()) + "\" on line " + (this.line + 1) + " can't be assigned"));
|
||||
};
|
||||
// Expand variables and expressions inside double-quoted strings using
|
||||
// [ECMA Harmony's interpolation syntax](http://wiki.ecmascript.org/doku.php?id=strawman:string_interpolation)
|
||||
// for substitution of bare variables as well as arbitrary expressions.
|
||||
// "Hello $name."
|
||||
// "Hello ${name.capitalize()}."
|
||||
// If it encounters an interpolation, this method will recursively create a
|
||||
// new Lexer, tokenize the interpolated contents, and merge them into the
|
||||
// token stream.
|
||||
Lexer.prototype.interpolate_string = function interpolate_string(str, escape_quotes) {
|
||||
var _a, _b, _c, _d, _e, escaped, expr, group, i, inner, interp, lexer, match, nested, pi, quote, tag, token, tokens, value;
|
||||
Lexer.prototype.balancedString = function(str, delimited, options) {
|
||||
var _d, _e, _f, _g, close, i, levels, open, pair, slash;
|
||||
options = options || {};
|
||||
slash = delimited[0][0] === '/';
|
||||
levels = [];
|
||||
i = 0;
|
||||
while (i < str.length) {
|
||||
if (levels.length && starts(str, '\\', i)) {
|
||||
i += 1;
|
||||
} else {
|
||||
_e = delimited;
|
||||
for (_d = 0, _f = _e.length; _d < _f; _d++) {
|
||||
pair = _e[_d];
|
||||
_g = pair;
|
||||
open = _g[0];
|
||||
close = _g[1];
|
||||
if (levels.length && starts(str, close, i) && levels[levels.length - 1] === pair) {
|
||||
levels.pop();
|
||||
i += close.length - 1;
|
||||
if (!(levels.length)) {
|
||||
i += 1;
|
||||
}
|
||||
break;
|
||||
} else if (starts(str, open, i)) {
|
||||
levels.push(pair);
|
||||
i += open.length - 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!levels.length || slash && starts(str, '\n', i)) {
|
||||
break;
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
if (levels.length) {
|
||||
if (slash) {
|
||||
return false;
|
||||
}
|
||||
throw new Error(("SyntaxError: Unterminated " + (levels.pop()[0]) + " starting on line " + (this.line + 1)));
|
||||
}
|
||||
return !i ? false : str.substring(0, i);
|
||||
};
|
||||
Lexer.prototype.interpolateString = function(str, escapeQuotes) {
|
||||
var _d, _e, _f, _g, _h, _i, _j, escaped, expr, group, i, idx, inner, interp, interpolated, lexer, match, nested, pi, quote, tag, tok, token, tokens, value;
|
||||
if (str.length < 3 || !starts(str, '"')) {
|
||||
return this.token('STRING', str);
|
||||
} else {
|
||||
lexer = new Lexer();
|
||||
tokens = [];
|
||||
quote = str.substring(0, 1);
|
||||
_a = [1, 1];
|
||||
i = _a[0];
|
||||
pi = _a[1];
|
||||
_d = [1, 1];
|
||||
i = _d[0];
|
||||
pi = _d[1];
|
||||
while (i < str.length - 1) {
|
||||
if (starts(str, '\\', i)) {
|
||||
i += 1;
|
||||
} else if ((match = str.substring(i).match(INTERPOLATION))) {
|
||||
_b = match;
|
||||
group = _b[0];
|
||||
interp = _b[1];
|
||||
_e = match;
|
||||
group = _e[0];
|
||||
interp = _e[1];
|
||||
if (starts(interp, '@')) {
|
||||
interp = "this." + (interp.substring(1));
|
||||
interp = ("this." + (interp.substring(1)));
|
||||
}
|
||||
if (pi < i) {
|
||||
tokens.push(['STRING', "" + quote + (str.substring(pi, i)) + quote]);
|
||||
tokens.push(['STRING', ("" + quote + (str.substring(pi, i)) + quote)]);
|
||||
}
|
||||
tokens.push(['IDENTIFIER', interp]);
|
||||
i += group.length - 1;
|
||||
pi = i + 1;
|
||||
} else if ((expr = balanced_string(str.substring(i), [['${', '}']]))) {
|
||||
} else if ((expr = this.balancedString(str.substring(i), [['${', '}']]))) {
|
||||
if (pi < i) {
|
||||
tokens.push(['STRING', "" + quote + (str.substring(pi, i)) + quote]);
|
||||
tokens.push(['STRING', ("" + quote + (str.substring(pi, i)) + quote)]);
|
||||
}
|
||||
inner = expr.substring(2, expr.length - 1);
|
||||
if (inner.length) {
|
||||
nested = lexer.tokenize("(" + inner + ")", {
|
||||
rewrite: false,
|
||||
inner = inner.replace(new RegExp('\\\\' + quote, 'g'), quote);
|
||||
nested = lexer.tokenize(("(" + inner + ")"), {
|
||||
line: this.line
|
||||
});
|
||||
_f = nested;
|
||||
for (idx = 0, _g = _f.length; idx < _g; idx++) {
|
||||
tok = _f[idx];
|
||||
tok[0] === 'CALL_END' ? (tok[0] = ')') : null;
|
||||
}
|
||||
nested.pop();
|
||||
tokens.push(['TOKENS', nested]);
|
||||
} else {
|
||||
tokens.push(['STRING', "" + quote + quote]);
|
||||
tokens.push(['STRING', ("" + quote + quote)]);
|
||||
}
|
||||
i += expr.length - 1;
|
||||
pi = i + 1;
|
||||
@@ -511,22 +500,26 @@
|
||||
i += 1;
|
||||
}
|
||||
if (pi < i && pi < str.length - 1) {
|
||||
tokens.push(['STRING', "" + quote + (str.substring(pi, i)) + quote]);
|
||||
tokens.push(['STRING', ("" + quote + (str.substring(pi, i)) + quote)]);
|
||||
}
|
||||
if (!(tokens[0][0] === 'STRING')) {
|
||||
tokens.unshift(['STRING', '""']);
|
||||
}
|
||||
_c = tokens;
|
||||
for (i = 0, _d = _c.length; i < _d; i++) {
|
||||
token = _c[i];
|
||||
_e = token;
|
||||
tag = _e[0];
|
||||
value = _e[1];
|
||||
interpolated = tokens.length > 1;
|
||||
if (interpolated) {
|
||||
this.token('(', '(');
|
||||
}
|
||||
_h = tokens;
|
||||
for (i = 0, _i = _h.length; i < _i; i++) {
|
||||
token = _h[i];
|
||||
_j = token;
|
||||
tag = _j[0];
|
||||
value = _j[1];
|
||||
if (tag === 'TOKENS') {
|
||||
this.tokens = this.tokens.concat(value);
|
||||
} else if (tag === 'STRING' && escape_quotes) {
|
||||
} else if (tag === 'STRING' && escapeQuotes) {
|
||||
escaped = value.substring(1, value.length - 1).replace(/"/g, '\\"');
|
||||
this.token(tag, "\"" + escaped + "\"");
|
||||
this.token(tag, ("\"" + escaped + "\""));
|
||||
} else {
|
||||
this.token(tag, value);
|
||||
}
|
||||
@@ -534,130 +527,86 @@
|
||||
this.token('+', '+');
|
||||
}
|
||||
}
|
||||
if (interpolated) {
|
||||
this.token(')', ')');
|
||||
}
|
||||
return tokens;
|
||||
}
|
||||
};
|
||||
// Helpers
|
||||
// -------
|
||||
// Add a token to the results, taking note of the line number.
|
||||
Lexer.prototype.token = function token(tag, value) {
|
||||
Lexer.prototype.token = function(tag, value) {
|
||||
return this.tokens.push([tag, value, this.line]);
|
||||
};
|
||||
// Peek at a tag in the current token stream.
|
||||
Lexer.prototype.tag = function tag(index, tag) {
|
||||
Lexer.prototype.tag = function(index, newTag) {
|
||||
var tok;
|
||||
if (!(tok = this.prev(index))) {
|
||||
return null;
|
||||
}
|
||||
if ((typeof tag !== "undefined" && tag !== null)) {
|
||||
tok[0] = tag;
|
||||
if (typeof newTag !== "undefined" && newTag !== null) {
|
||||
tok[0] = newTag;
|
||||
return tok[0];
|
||||
}
|
||||
return tok[0];
|
||||
};
|
||||
// Peek at a value in the current token stream.
|
||||
Lexer.prototype.value = function value(index, val) {
|
||||
Lexer.prototype.value = function(index, val) {
|
||||
var tok;
|
||||
if (!(tok = this.prev(index))) {
|
||||
return null;
|
||||
}
|
||||
if ((typeof val !== "undefined" && val !== null)) {
|
||||
if (typeof val !== "undefined" && val !== null) {
|
||||
tok[1] = val;
|
||||
return tok[1];
|
||||
}
|
||||
return tok[1];
|
||||
};
|
||||
// Peek at a previous token, entire.
|
||||
Lexer.prototype.prev = function prev(index) {
|
||||
Lexer.prototype.prev = function(index) {
|
||||
return this.tokens[this.tokens.length - (index || 1)];
|
||||
};
|
||||
// Attempt to match a string against the current chunk, returning the indexed
|
||||
// match if successful, and `false` otherwise.
|
||||
Lexer.prototype.match = function match(regex, index) {
|
||||
Lexer.prototype.match = function(regex, index) {
|
||||
var m;
|
||||
if (!(m = this.chunk.match(regex))) {
|
||||
return false;
|
||||
}
|
||||
if (m) {
|
||||
return m[index];
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return m ? m[index] : false;
|
||||
};
|
||||
// Are we in the midst of an unfinished expression?
|
||||
Lexer.prototype.unfinished = function unfinished() {
|
||||
Lexer.prototype.unfinished = function() {
|
||||
var prev;
|
||||
prev = this.prev(2);
|
||||
return this.value() && this.value().match && this.value().match(NO_NEWLINE) && prev && (prev[0] !== '.') && !this.value().match(CODE);
|
||||
};
|
||||
// Lexer Properties
|
||||
// ----------------
|
||||
// There are no exensions to the core lexer by default.
|
||||
Lexer.extensions = [];
|
||||
return Lexer;
|
||||
}).call(this);
|
||||
// Constants
|
||||
// ---------
|
||||
// Keywords that CoffeeScript shares in common with JavaScript.
|
||||
})();
|
||||
JS_KEYWORDS = ["if", "else", "true", "false", "new", "return", "try", "catch", "finally", "throw", "break", "continue", "for", "in", "while", "delete", "instanceof", "typeof", "switch", "super", "extends", "class", "this", "null"];
|
||||
// CoffeeScript-only keywords, which we're more relaxed about allowing. They can't
|
||||
// be used standalone, but you can reference them as an attached property.
|
||||
COFFEE_ALIASES = ["and", "or", "is", "isnt", "not"];
|
||||
COFFEE_KEYWORDS = COFFEE_ALIASES.concat(["then", "unless", "yes", "no", "on", "off", "of", "by", "where", "when"]);
|
||||
// The combined list of keywords is the superset that gets passed verbatim to
|
||||
// the parser.
|
||||
KEYWORDS = JS_KEYWORDS.concat(COFFEE_KEYWORDS);
|
||||
// The list of keywords that are reserved by JavaScript, but not used, or are
|
||||
// used by CoffeeScript internally. We throw an error when these are encountered,
|
||||
// to avoid having a JavaScript error at runtime.
|
||||
RESERVED = ["case", "default", "do", "function", "var", "void", "with", "const", "let", "debugger", "enum", "export", "import", "native"];
|
||||
// The superset of both JavaScript keywords and reserved words, none of which may
|
||||
// be used as identifiers or properties.
|
||||
COFFEE_KEYWORDS = COFFEE_ALIASES.concat(["then", "unless", "until", "loop", "yes", "no", "on", "off", "of", "by", "where", "when"]);
|
||||
RESERVED = ["case", "default", "do", "function", "var", "void", "with", "const", "let", "enum", "export", "import", "native"];
|
||||
JS_FORBIDDEN = JS_KEYWORDS.concat(RESERVED);
|
||||
// Token matching regexes.
|
||||
IDENTIFIER = /^([a-zA-Z\$_](\w|\$)*)/;
|
||||
NUMBER = /^(\b((0(x|X)[0-9a-fA-F]+)|([0-9]+(\.[0-9]+)?(e[+\-]?[0-9]+)?)))\b/i;
|
||||
NUMBER = /^(((\b0(x|X)[0-9a-fA-F]+)|((\b[0-9]+(\.[0-9]+)?|\.[0-9]+)(e[+\-]?[0-9]+)?)))\b/i;
|
||||
HEREDOC = /^("{6}|'{6}|"{3}\n?([\s\S]*?)\n?([ \t]*)"{3}|'{3}\n?([\s\S]*?)\n?([ \t]*)'{3})/;
|
||||
INTERPOLATION = /^\$([a-zA-Z_@]\w*(\.\w+)*)/;
|
||||
OPERATOR = /^([+\*&|\/\-%=<>:!?]+)([ \t]*)/;
|
||||
OPERATOR = /^(-[\-=>]?|\+[+=]?|[*&|\/%=<>:!?]+)([ \t]*)/;
|
||||
WHITESPACE = /^([ \t]+)/;
|
||||
COMMENT = /^(((\n?[ \t]*)?#[^\n]*)+)/;
|
||||
COMMENT = /^(\s*#{3}(?!#)[ \t]*\n+([\s\S]*?)[ \t]*\n+[ \t]*#{3}|(\s*#(?!##[^#])[^\n]*)+)/;
|
||||
CODE = /^((-|=)>)/;
|
||||
MULTI_DENT = /^((\n([ \t]*))+)(\.)?/;
|
||||
LAST_DENTS = /\n([ \t]*)/g;
|
||||
LAST_DENT = /\n([ \t]*)/;
|
||||
ASSIGNMENT = /^(:|=)$/;
|
||||
// Regex-matching-regexes.
|
||||
ASSIGNMENT = /^[:=]$/;
|
||||
REGEX_START = /^\/[^\/ ]/;
|
||||
REGEX_INTERPOLATION = /([^\\]\$[a-zA-Z_@]|[^\\]\$\{.*[^\\]\})/;
|
||||
REGEX_FLAGS = /^[imgy]{0,4}/;
|
||||
REGEX_END = /^(([imgy]{1,4})\b|\W|$)/;
|
||||
REGEX_ESCAPE = /\\[^\$]/g;
|
||||
// Token cleaning regexes.
|
||||
JS_CLEANER = /(^`|`$)/g;
|
||||
MULTILINER = /\n/g;
|
||||
STRING_NEWLINES = /\n[ \t]*/g;
|
||||
COMMENT_CLEANER = /(^[ \t]*#|\n[ \t]*$)/mg;
|
||||
NO_NEWLINE = /^([+\*&|\/\-%=<>:!.\\][<>=&|]*|and|or|is|isnt|not|delete|typeof|instanceof)$/;
|
||||
HEREDOC_INDENT = /^[ \t]+/mg;
|
||||
// Tokens which a regular expression will never immediately follow, but which
|
||||
// a division operator might.
|
||||
// See: http://www.mozilla.org/js/language/js20-2002-04/rationale/syntax.html#regular-expressions
|
||||
// Our list is shorter, due to sans-parentheses method calls.
|
||||
NOT_REGEX = ['NUMBER', 'REGEX', '++', '--', 'FALSE', 'NULL', 'TRUE'];
|
||||
// Tokens which could legitimately be invoked or indexed. A opening
|
||||
// parentheses or bracket following these tokens will be recorded as the start
|
||||
// of a function invocation or indexing operation.
|
||||
CALLABLE = ['IDENTIFIER', 'SUPER', ')', ']', '}', 'STRING', '@', 'THIS'];
|
||||
// Tokens that indicate an access -- keywords immediately following will be
|
||||
// treated as identifiers.
|
||||
ACCESSORS = ['PROPERTY_ACCESS', 'PROTOTYPE_ACCESS', 'SOAK_ACCESS', '@'];
|
||||
// Tokens that, when immediately preceding a `WHEN`, indicate that the `WHEN`
|
||||
// occurs at the start of a line. We disambiguate these from trailing whens to
|
||||
// avoid an ambiguity in the grammar.
|
||||
HEREDOC_INDENT = /(\n+([ \t]*)|^([ \t]+))/g;
|
||||
ASSIGNED = /^([a-zA-Z\$_]\w*[ \t]*?[:=][^=])/;
|
||||
NEXT_CHARACTER = /^\s*(\S)/;
|
||||
NOT_REGEX = ['NUMBER', 'REGEX', '++', '--', 'FALSE', 'NULL', 'TRUE', ']'];
|
||||
CALLABLE = ['IDENTIFIER', 'SUPER', ')', ']', '}', 'STRING', '@', 'THIS', '?', '::'];
|
||||
LINE_BREAK = ['INDENT', 'OUTDENT', 'TERMINATOR'];
|
||||
// Half-assignments...
|
||||
HALF_ASSIGNMENTS = ['-', '+', '/', '*', '%', '||', '&&', '?'];
|
||||
// Conversions from CoffeeScript operators into JavaScript ones.
|
||||
HALF_ASSIGNMENTS = ['-', '+', '/', '*', '%', '||', '&&', '?', 'OP?'];
|
||||
CONVERSIONS = {
|
||||
'and': '&&',
|
||||
'or': '||',
|
||||
|
||||
2038
lib/nodes.js
2038
lib/nodes.js
File diff suppressed because it is too large
Load Diff
102
lib/optparse.js
102
lib/optparse.js
@@ -1,54 +1,43 @@
|
||||
(function(){
|
||||
var LONG_FLAG, MULTI_FLAG, OPTIONAL, OptionParser, SHORT_FLAG, build_rule, build_rules, normalize_arguments;
|
||||
// A simple **OptionParser** class to parse option flags from the command-line.
|
||||
// Use it like so:
|
||||
// parser: new OptionParser switches, help_banner
|
||||
// options: parser.parse process.argv
|
||||
var LONG_FLAG, MULTI_FLAG, OPTIONAL, OptionParser, SHORT_FLAG, buildRule, buildRules, normalizeArguments;
|
||||
exports.OptionParser = (function() {
|
||||
OptionParser = function OptionParser(rules, banner) {
|
||||
OptionParser = function(rules, banner) {
|
||||
this.banner = banner;
|
||||
this.rules = build_rules(rules);
|
||||
this.rules = buildRules(rules);
|
||||
return this;
|
||||
};
|
||||
// Initialize with a list of valid options, in the form:
|
||||
// [short-flag, long-flag, description]
|
||||
// Along with an an optional banner for the usage help.
|
||||
// Parse the list of arguments, populating an `options` object with all of the
|
||||
// specified options, and returning it. `options.arguments` will be an array
|
||||
// containing the remaning non-option arguments. This is a simpler API than
|
||||
// many option parsers that allow you to attach callback actions for every
|
||||
// flag. Instead, you're responsible for interpreting the options object.
|
||||
OptionParser.prototype.parse = function parse(args) {
|
||||
var _a, _b, _c, arg, is_option, matched_rule, options, rule;
|
||||
OptionParser.prototype.parse = function(args) {
|
||||
var _a, _b, _c, _d, _e, arg, i, isOption, matchedRule, options, rule;
|
||||
options = {
|
||||
arguments: []
|
||||
};
|
||||
args = normalize_arguments(args);
|
||||
while ((arg = args.shift())) {
|
||||
is_option = !!(arg.match(LONG_FLAG) || arg.match(SHORT_FLAG));
|
||||
matched_rule = false;
|
||||
_b = this.rules;
|
||||
for (_a = 0, _c = _b.length; _a < _c; _a++) {
|
||||
rule = _b[_a];
|
||||
if (rule.short_flag === arg || rule.long_flag === arg) {
|
||||
options[rule.name] = rule.has_argument ? args.shift() : true;
|
||||
matched_rule = true;
|
||||
args = normalizeArguments(args);
|
||||
_a = args;
|
||||
for (i = 0, _b = _a.length; i < _b; i++) {
|
||||
arg = _a[i];
|
||||
isOption = !!(arg.match(LONG_FLAG) || arg.match(SHORT_FLAG));
|
||||
matchedRule = false;
|
||||
_d = this.rules;
|
||||
for (_c = 0, _e = _d.length; _c < _e; _c++) {
|
||||
rule = _d[_c];
|
||||
if (rule.shortFlag === arg || rule.longFlag === arg) {
|
||||
options[rule.name] = rule.hasArgument ? args[i += 1] : true;
|
||||
matchedRule = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (is_option && !matched_rule) {
|
||||
if (isOption && !matchedRule) {
|
||||
throw new Error("unrecognized option: " + arg);
|
||||
}
|
||||
if (!(is_option)) {
|
||||
options.arguments.push(arg);
|
||||
if (!isOption) {
|
||||
options.arguments = args.slice(i, args.length);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return options;
|
||||
};
|
||||
// Return the help text for this **OptionParser**, listing and describing all
|
||||
// of the valid options, for `--help` and such.
|
||||
OptionParser.prototype.help = function help() {
|
||||
var _a, _b, _c, _d, _e, _f, _g, i, let_part, lines, rule, spaces;
|
||||
OptionParser.prototype.help = function() {
|
||||
var _a, _b, _c, _d, i, letPart, lines, rule, spaces;
|
||||
lines = ['Available options:'];
|
||||
if (this.banner) {
|
||||
lines.unshift("" + this.banner + "\n");
|
||||
@@ -56,31 +45,26 @@
|
||||
_b = this.rules;
|
||||
for (_a = 0, _c = _b.length; _a < _c; _a++) {
|
||||
rule = _b[_a];
|
||||
spaces = 15 - rule.long_flag.length;
|
||||
spaces = 15 - rule.longFlag.length;
|
||||
spaces = spaces > 0 ? (function() {
|
||||
_d = []; _f = 0; _g = spaces;
|
||||
for (_e = 0, i = _f; (_f <= _g ? i <= _g : i >= _g); (_f <= _g ? i += 1 : i -= 1), _e++) {
|
||||
_d = [];
|
||||
for (i = 0; i <= spaces; i += 1) {
|
||||
_d.push(' ');
|
||||
}
|
||||
return _d;
|
||||
}).call(this).join('') : '';
|
||||
let_part = rule.short_flag ? rule.short_flag + ', ' : ' ';
|
||||
lines.push(" " + let_part + (rule.long_flag) + spaces + (rule.description));
|
||||
})().join('') : '';
|
||||
letPart = rule.shortFlag ? rule.shortFlag + ', ' : ' ';
|
||||
lines.push(" " + letPart + rule.longFlag + spaces + rule.description);
|
||||
}
|
||||
return "\n" + (lines.join('\n')) + "\n";
|
||||
};
|
||||
return OptionParser;
|
||||
}).call(this);
|
||||
// Helpers
|
||||
// -------
|
||||
// Regex matchers for option flags.
|
||||
})();
|
||||
LONG_FLAG = /^(--\w[\w\-]+)/;
|
||||
SHORT_FLAG = /^(-\w)/;
|
||||
MULTI_FLAG = /^-(\w{2,})/;
|
||||
OPTIONAL = /\[(.+)\]/;
|
||||
// Build and return the list of option rules. If the optional *short-flag* is
|
||||
// unspecified, leave it out by padding with `null`.
|
||||
build_rules = function build_rules(rules) {
|
||||
buildRules = function(rules) {
|
||||
var _a, _b, _c, _d, tuple;
|
||||
_a = []; _c = rules;
|
||||
for (_b = 0, _d = _c.length; _b < _d; _b++) {
|
||||
@@ -89,28 +73,24 @@
|
||||
if (tuple.length < 3) {
|
||||
tuple.unshift(null);
|
||||
}
|
||||
return build_rule.apply(this, tuple);
|
||||
}).call(this));
|
||||
return buildRule.apply(this, tuple);
|
||||
})());
|
||||
}
|
||||
return _a;
|
||||
};
|
||||
// Build a rule from a `-o` short flag, a `--output [DIR]` long flag, and the
|
||||
// description of what the option does.
|
||||
build_rule = function build_rule(short_flag, long_flag, description) {
|
||||
buildRule = function(shortFlag, longFlag, description) {
|
||||
var match;
|
||||
match = long_flag.match(OPTIONAL);
|
||||
long_flag = long_flag.match(LONG_FLAG)[1];
|
||||
match = longFlag.match(OPTIONAL);
|
||||
longFlag = longFlag.match(LONG_FLAG)[1];
|
||||
return {
|
||||
name: long_flag.substr(2),
|
||||
short_flag: short_flag,
|
||||
long_flag: long_flag,
|
||||
name: longFlag.substr(2),
|
||||
shortFlag: shortFlag,
|
||||
longFlag: longFlag,
|
||||
description: description,
|
||||
has_argument: !!(match && match[1])
|
||||
hasArgument: !!(match && match[1])
|
||||
};
|
||||
};
|
||||
// Normalize arguments by expanding merged flags into multiple flags. This allows
|
||||
// you to have `-wl` be the same as `--watch --lint`.
|
||||
normalize_arguments = function normalize_arguments(args) {
|
||||
normalizeArguments = function(args) {
|
||||
var _a, _b, _c, _d, _e, _f, arg, l, match, result;
|
||||
args = args.slice(0);
|
||||
result = [];
|
||||
|
||||
547
lib/parser.js
547
lib/parser.js
File diff suppressed because one or more lines are too long
41
lib/repl.js
41
lib/repl.js
@@ -1,41 +1,38 @@
|
||||
(function(){
|
||||
var CoffeeScript, helpers, prompt, run;
|
||||
// A very simple Read-Eval-Print-Loop. Compiles one line at a time to JavaScript
|
||||
// and evaluates it. Good for simple tests, or poking around the **Node.js** API.
|
||||
// Using it looks like this:
|
||||
// coffee> puts "$num bottles of beer" for num in [99..1]
|
||||
// Require the **coffee-script** module to get access to the compiler.
|
||||
var CoffeeScript, helpers, readline, repl, run, stdio;
|
||||
CoffeeScript = require('./coffee-script');
|
||||
helpers = require('./helpers').helpers;
|
||||
// Our prompt.
|
||||
prompt = 'coffee> ';
|
||||
// Quick alias for quitting the REPL.
|
||||
readline = require('readline');
|
||||
stdio = process.openStdin();
|
||||
helpers.extend(global, {
|
||||
quit: function quit() {
|
||||
quit: function() {
|
||||
return process.exit(0);
|
||||
}
|
||||
});
|
||||
// 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 = function run(code) {
|
||||
run = function(buffer) {
|
||||
var val;
|
||||
try {
|
||||
val = CoffeeScript.run(code, {
|
||||
no_wrap: true,
|
||||
val = CoffeeScript.run(buffer.toString(), {
|
||||
noWrap: true,
|
||||
globals: true,
|
||||
source: 'repl'
|
||||
});
|
||||
if (val !== undefined) {
|
||||
p(val);
|
||||
puts(inspect(val));
|
||||
}
|
||||
} catch (err) {
|
||||
puts(err.stack || err.toString());
|
||||
}
|
||||
return print(prompt);
|
||||
return repl.prompt();
|
||||
};
|
||||
// Start up the REPL by opening **stdio** and listening for input.
|
||||
process.stdio.addListener('data', run);
|
||||
process.stdio.open();
|
||||
print(prompt);
|
||||
repl = readline.createInterface(stdio);
|
||||
repl.setPrompt('coffee> ');
|
||||
stdio.addListener('data', function(buffer) {
|
||||
return repl.write(buffer);
|
||||
});
|
||||
repl.addListener('close', function() {
|
||||
return stdio.destroy();
|
||||
});
|
||||
repl.addListener('line', run);
|
||||
repl.prompt();
|
||||
})();
|
||||
|
||||
434
lib/rewriter.js
434
lib/rewriter.js
@@ -1,52 +1,30 @@
|
||||
(function(){
|
||||
var BALANCED_PAIRS, EXPRESSION_CLOSE, EXPRESSION_END, EXPRESSION_START, IMPLICIT_BLOCK, IMPLICIT_CALL, IMPLICIT_END, IMPLICIT_FUNC, INVERSES, Rewriter, SINGLE_CLOSERS, SINGLE_LINERS, _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, helpers, include, pair;
|
||||
var __slice = Array.prototype.slice, __bind = function(func, obj, args) {
|
||||
return function() {
|
||||
return func.apply(obj || {}, args ? args.concat(__slice.call(arguments, 0)) : arguments);
|
||||
};
|
||||
}, __hasProp = Object.prototype.hasOwnProperty;
|
||||
// The CoffeeScript language has a good deal of optional syntax, implicit syntax,
|
||||
// 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 **Rewriter** to convert
|
||||
// shorthand into the unambiguous long form, add implicit indentation and
|
||||
// parentheses, balance incorrect nestings, and generally clean things up.
|
||||
// Set up exported variables for both Node.js and the browser.
|
||||
if ((typeof process !== "undefined" && process !== null)) {
|
||||
helpers = require('./helpers').helpers;
|
||||
var BALANCED_PAIRS, EXPRESSION_CLOSE, EXPRESSION_END, EXPRESSION_START, IMPLICIT_BLOCK, IMPLICIT_CALL, IMPLICIT_END, IMPLICIT_FUNC, INVERSES, Rewriter, SINGLE_CLOSERS, SINGLE_LINERS, _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, helpers, include, pair;
|
||||
var __hasProp = Object.prototype.hasOwnProperty;
|
||||
if (typeof process !== "undefined" && process !== null) {
|
||||
_a = require('./helpers');
|
||||
helpers = _a.helpers;
|
||||
} else {
|
||||
this.exports = this;
|
||||
helpers = this.helpers;
|
||||
}
|
||||
// Import the helpers we need.
|
||||
include = helpers.include;
|
||||
// The **Rewriter** class is used by the [Lexer](lexer.html), directly against
|
||||
// its internal array of tokens.
|
||||
_b = helpers;
|
||||
include = _b.include;
|
||||
exports.Rewriter = (function() {
|
||||
Rewriter = function Rewriter() { };
|
||||
// Rewrite the token stream in multiple passes, one logical filter at
|
||||
// a time. This could certainly be changed into a single pass through the
|
||||
// stream, with a big ol' efficient switch, but it's much nicer to work with
|
||||
// like this. The order of these passes matters -- indentation must be
|
||||
// corrected before implicit parentheses can be wrapped around blocks of code.
|
||||
Rewriter.prototype.rewrite = function rewrite(tokens) {
|
||||
Rewriter = function() { };
|
||||
Rewriter.prototype.rewrite = function(tokens) {
|
||||
this.tokens = tokens;
|
||||
this.adjust_comments();
|
||||
this.remove_leading_newlines();
|
||||
this.remove_mid_expression_newlines();
|
||||
this.close_open_calls_and_indexes();
|
||||
this.add_implicit_indentation();
|
||||
this.add_implicit_parentheses();
|
||||
this.ensure_balance(BALANCED_PAIRS);
|
||||
this.rewrite_closing_parens();
|
||||
this.adjustComments();
|
||||
this.removeLeadingNewlines();
|
||||
this.removeMidExpressionNewlines();
|
||||
this.closeOpenCallsAndIndexes();
|
||||
this.addImplicitIndentation();
|
||||
this.addImplicitParentheses();
|
||||
this.ensureBalance(BALANCED_PAIRS);
|
||||
this.rewriteClosingParens();
|
||||
return this.tokens;
|
||||
};
|
||||
// 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
|
||||
// as tokens are inserted and removed, and the stream changes length under
|
||||
// our feet.
|
||||
Rewriter.prototype.scan_tokens = function scan_tokens(block) {
|
||||
Rewriter.prototype.scanTokens = function(block) {
|
||||
var i, move;
|
||||
i = 0;
|
||||
while (true) {
|
||||
@@ -58,73 +36,80 @@
|
||||
}
|
||||
return true;
|
||||
};
|
||||
// Massage newlines and indentations so that comments don't have to be
|
||||
// correctly indented, or appear on a line of their own.
|
||||
Rewriter.prototype.adjust_comments = function adjust_comments() {
|
||||
return this.scan_tokens(__bind(function(prev, token, post, i) {
|
||||
var after;
|
||||
if (!(token[0] === 'COMMENT')) {
|
||||
Rewriter.prototype.adjustComments = function() {
|
||||
return this.scanTokens((function(__this) {
|
||||
var __func = function(prev, token, post, i) {
|
||||
var _c, _d, after, before;
|
||||
if (!(token[0] === 'HERECOMMENT')) {
|
||||
return 1;
|
||||
}
|
||||
after = this.tokens[i + 2];
|
||||
_c = [this.tokens[i - 2], this.tokens[i + 2]];
|
||||
before = _c[0];
|
||||
after = _c[1];
|
||||
if (after && after[0] === 'INDENT') {
|
||||
this.tokens.splice(i + 2, 1);
|
||||
this.tokens.splice(i, 0, after);
|
||||
return 1;
|
||||
} else if (prev && prev[0] !== 'TERMINATOR' && prev[0] !== 'INDENT' && prev[0] !== 'OUTDENT') {
|
||||
this.tokens.splice(i, 0, ['TERMINATOR', "\n", prev[2]]);
|
||||
before && before[0] === 'OUTDENT' && post && (prev[0] === post[0]) && (post[0] === 'TERMINATOR') ? this.tokens.splice(i - 2, 1) : this.tokens.splice(i, 0, after);
|
||||
} else if (prev && !('TERMINATOR' === (_d = prev[0]) || 'INDENT' === _d || 'OUTDENT' === _d)) {
|
||||
if (post && post[0] === 'TERMINATOR' && after && after[0] === 'OUTDENT') {
|
||||
this.tokens.splice.apply(this.tokens, [i + 3, 0].concat(this.tokens.splice(i, 2)));
|
||||
this.tokens.splice(i + 3, 0, ['TERMINATOR', "\n", prev[2]]);
|
||||
} else {
|
||||
this.tokens.splice(i, 0, ['TERMINATOR', "\n", prev[2]]);
|
||||
}
|
||||
return 2;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}, this));
|
||||
return 1;
|
||||
};
|
||||
return (function() {
|
||||
return __func.apply(__this, arguments);
|
||||
});
|
||||
})(this));
|
||||
};
|
||||
// Leading newlines would introduce an ambiguity in the grammar, so we
|
||||
// dispatch them here.
|
||||
Rewriter.prototype.remove_leading_newlines = function remove_leading_newlines() {
|
||||
var _a;
|
||||
_a = [];
|
||||
Rewriter.prototype.removeLeadingNewlines = function() {
|
||||
var _c;
|
||||
_c = [];
|
||||
while (this.tokens[0] && this.tokens[0][0] === 'TERMINATOR') {
|
||||
_a.push(this.tokens.shift());
|
||||
_c.push(this.tokens.shift());
|
||||
}
|
||||
return _a;
|
||||
return _c;
|
||||
};
|
||||
// Some blocks occur in the middle of expressions -- when we're expecting
|
||||
// this, remove their trailing newlines.
|
||||
Rewriter.prototype.remove_mid_expression_newlines = function remove_mid_expression_newlines() {
|
||||
return this.scan_tokens(__bind(function(prev, token, post, i) {
|
||||
Rewriter.prototype.removeMidExpressionNewlines = function() {
|
||||
return this.scanTokens((function(__this) {
|
||||
var __func = function(prev, token, post, i) {
|
||||
if (!(post && include(EXPRESSION_CLOSE, post[0]) && token[0] === 'TERMINATOR')) {
|
||||
return 1;
|
||||
}
|
||||
this.tokens.splice(i, 1);
|
||||
return 0;
|
||||
}, this));
|
||||
};
|
||||
return (function() {
|
||||
return __func.apply(__this, arguments);
|
||||
});
|
||||
})(this));
|
||||
};
|
||||
// The lexer has tagged the opening parenthesis of a method call, and the
|
||||
// opening bracket of an indexing operation. Match them with their paired
|
||||
// close.
|
||||
Rewriter.prototype.close_open_calls_and_indexes = function close_open_calls_and_indexes() {
|
||||
Rewriter.prototype.closeOpenCallsAndIndexes = function() {
|
||||
var brackets, parens;
|
||||
parens = [0];
|
||||
brackets = [0];
|
||||
return this.scan_tokens(__bind(function(prev, token, post, i) {
|
||||
var _a;
|
||||
if ((_a = token[0]) === 'CALL_START') {
|
||||
return this.scanTokens((function(__this) {
|
||||
var __func = function(prev, token, post, i) {
|
||||
var _c;
|
||||
if ((_c = token[0]) === 'CALL_START') {
|
||||
parens.push(0);
|
||||
} else if (_a === 'INDEX_START') {
|
||||
} else if (_c === 'INDEX_START') {
|
||||
brackets.push(0);
|
||||
} else if (_a === '(') {
|
||||
} else if (_c === '(') {
|
||||
parens[parens.length - 1] += 1;
|
||||
} else if (_a === '[') {
|
||||
} else if (_c === '[') {
|
||||
brackets[brackets.length - 1] += 1;
|
||||
} else if (_a === ')') {
|
||||
} else if (_c === ')') {
|
||||
if (parens[parens.length - 1] === 0) {
|
||||
parens.pop();
|
||||
token[0] = 'CALL_END';
|
||||
} else {
|
||||
parens[parens.length - 1] -= 1;
|
||||
}
|
||||
} else if (_a === ']') {
|
||||
} else if (_c === ']') {
|
||||
if (brackets[brackets.length - 1] === 0) {
|
||||
brackets.pop();
|
||||
token[0] = 'INDEX_END';
|
||||
@@ -133,86 +118,113 @@
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}, this));
|
||||
};
|
||||
return (function() {
|
||||
return __func.apply(__this, arguments);
|
||||
});
|
||||
})(this));
|
||||
};
|
||||
// Methods may be optionally called without parentheses, for simple cases.
|
||||
// Insert the implicit parentheses here, so that the parser doesn't have to
|
||||
// deal with them.
|
||||
Rewriter.prototype.add_implicit_parentheses = function add_implicit_parentheses() {
|
||||
var calls, parens, stack, start_parens;
|
||||
Rewriter.prototype.addImplicitParentheses = function() {
|
||||
var closeCalls, stack;
|
||||
stack = [0];
|
||||
calls = 0;
|
||||
parens = 0;
|
||||
start_parens = 0;
|
||||
return this.scan_tokens(__bind(function(prev, token, post, i) {
|
||||
var _a, _b, _c, idx, last, open, size, stack_pointer, tag, tmp;
|
||||
closeCalls = (function(__this) {
|
||||
var __func = function(i) {
|
||||
var _c, size, tmp;
|
||||
(_c = stack[stack.length - 1]);
|
||||
|
||||
for (tmp = 0; tmp < _c; tmp += 1) {
|
||||
this.tokens.splice(i, 0, ['CALL_END', ')', this.tokens[i][2]]);
|
||||
}
|
||||
size = stack[stack.length - 1] + 1;
|
||||
stack[stack.length - 1] = 0;
|
||||
return size;
|
||||
};
|
||||
return (function() {
|
||||
return __func.apply(__this, arguments);
|
||||
});
|
||||
})(this);
|
||||
return this.scanTokens((function(__this) {
|
||||
var __func = function(prev, token, post, i) {
|
||||
var _c, _d, j, nx, open, size, tag;
|
||||
tag = token[0];
|
||||
if (tag === 'CALL_START') {
|
||||
calls += 1;
|
||||
} else if (tag === 'CALL_END') {
|
||||
calls -= 1;
|
||||
} else if (tag === '(') {
|
||||
parens += 1;
|
||||
} else if (tag === ')') {
|
||||
parens -= 1;
|
||||
} else if (tag === 'INDENT') {
|
||||
stack.push(0);
|
||||
} else if (tag === 'OUTDENT') {
|
||||
last = stack.pop();
|
||||
stack[stack.length - 1] += last;
|
||||
if (tag === 'OUTDENT') {
|
||||
stack[stack.length - 2] += stack.pop();
|
||||
}
|
||||
open = stack[stack.length - 1] > 0;
|
||||
if (!(typeof post !== "undefined" && post !== null) || (start_parens > parens) || (parens === 0 && include(IMPLICIT_END, tag))) {
|
||||
if (tag === 'INDENT' && prev && include(IMPLICIT_BLOCK, prev[0])) {
|
||||
return 1;
|
||||
if (prev && prev.spaced && include(IMPLICIT_FUNC, prev[0]) && include(IMPLICIT_CALL, tag) && !(tag === '!' && (('IN' === (_c = post[0]) || 'OF' === _c)))) {
|
||||
this.tokens.splice(i, 0, ['CALL_START', '(', token[2]]);
|
||||
stack[stack.length - 1] += 1;
|
||||
if (include(EXPRESSION_START, tag)) {
|
||||
stack.push(0);
|
||||
}
|
||||
if (tag === 'OUTDENT' && token.generated) {
|
||||
return 1;
|
||||
return 2;
|
||||
}
|
||||
if (include(EXPRESSION_START, tag)) {
|
||||
if (tag === 'INDENT' && !token.generated && open && !(prev && include(IMPLICIT_BLOCK, prev[0]))) {
|
||||
size = closeCalls(i);
|
||||
stack.push(0);
|
||||
return size;
|
||||
}
|
||||
if (open || tag === 'INDENT') {
|
||||
idx = tag === 'OUTDENT' ? i + 1 : i;
|
||||
stack_pointer = tag === 'INDENT' ? 2 : 1;
|
||||
_b = 0; _c = stack[stack.length - stack_pointer];
|
||||
for (_a = 0, tmp = _b; (_b <= _c ? tmp < _c : tmp > _c); (_b <= _c ? tmp += 1 : tmp -= 1), _a++) {
|
||||
this.tokens.splice(idx, 0, ['CALL_END', ')', token[2]]);
|
||||
stack.push(0);
|
||||
return 1;
|
||||
}
|
||||
if (open && !token.generated && prev[0] !== ',' && (!post || include(IMPLICIT_END, tag))) {
|
||||
j = 1;
|
||||
while ((typeof (_d = (nx = this.tokens[i + j])) !== "undefined" && _d !== null) && include(IMPLICIT_END, nx[0])) {
|
||||
j++;
|
||||
}
|
||||
if ((typeof nx !== "undefined" && nx !== null) && nx[0] === ',') {
|
||||
if (tag === 'TERMINATOR') {
|
||||
this.tokens.splice(i, 1);
|
||||
}
|
||||
} else {
|
||||
size = closeCalls(i);
|
||||
if (tag !== 'OUTDENT' && include(EXPRESSION_END, tag)) {
|
||||
stack.pop();
|
||||
}
|
||||
size = stack[stack.length - stack_pointer] + 1;
|
||||
stack[stack.length - stack_pointer] = 0;
|
||||
return size;
|
||||
}
|
||||
}
|
||||
if (!(prev && include(IMPLICIT_FUNC, prev[0]) && include(IMPLICIT_CALL, tag))) {
|
||||
if (tag !== 'OUTDENT' && include(EXPRESSION_END, tag)) {
|
||||
stack[stack.length - 2] += stack.pop();
|
||||
return 1;
|
||||
}
|
||||
calls = 0;
|
||||
start_parens = tag === '(' ? parens - 1 : parens;
|
||||
this.tokens.splice(i, 0, ['CALL_START', '(', token[2]]);
|
||||
stack[stack.length - 1] += 1;
|
||||
return 2;
|
||||
}, this));
|
||||
return 1;
|
||||
};
|
||||
return (function() {
|
||||
return __func.apply(__this, arguments);
|
||||
});
|
||||
})(this));
|
||||
};
|
||||
// Because our grammar is LALR(1), it can't handle some single-line
|
||||
// expressions that lack ending delimiters. The **Rewriter** adds the implicit
|
||||
// blocks, so it doesn't need to. ')' can close a single-line block,
|
||||
// but we need to make sure it's balanced.
|
||||
Rewriter.prototype.add_implicit_indentation = function add_implicit_indentation() {
|
||||
return this.scan_tokens(__bind(function(prev, token, post, i) {
|
||||
var idx, insertion, outdent, parens, pre, starter, tok;
|
||||
Rewriter.prototype.addImplicitIndentation = function() {
|
||||
return this.scanTokens((function(__this) {
|
||||
var __func = function(prev, token, post, i) {
|
||||
var _c, idx, indent, insertion, outdent, parens, pre, starter, tok;
|
||||
if (token[0] === 'ELSE' && prev[0] !== 'OUTDENT') {
|
||||
this.tokens.splice.apply(this.tokens, [i, 0].concat(this.indentation(token)));
|
||||
return 2;
|
||||
}
|
||||
if (token[0] === 'CATCH' && this.tokens[i + 2][0] === 'TERMINATOR') {
|
||||
this.tokens.splice.apply(this.tokens, [i + 2, 0].concat(this.indentation(token)));
|
||||
return 4;
|
||||
}
|
||||
if (!(include(SINGLE_LINERS, token[0]) && post[0] !== 'INDENT' && !(token[0] === 'ELSE' && post[0] === 'IF'))) {
|
||||
return 1;
|
||||
}
|
||||
starter = token[0];
|
||||
this.tokens.splice(i + 1, 0, ['INDENT', 2, token[2]]);
|
||||
_c = this.indentation(token);
|
||||
indent = _c[0];
|
||||
outdent = _c[1];
|
||||
indent.generated = (outdent.generated = true);
|
||||
this.tokens.splice(i + 1, 0, indent);
|
||||
idx = i + 1;
|
||||
parens = 0;
|
||||
while (true) {
|
||||
idx += 1;
|
||||
tok = this.tokens[idx];
|
||||
pre = this.tokens[idx - 1];
|
||||
if ((!tok || (include(SINGLE_CLOSERS, tok[0]) && tok[1] !== ';') || (tok[0] === ')' && parens === 0)) && !(starter === 'ELSE' && tok[0] === 'ELSE')) {
|
||||
if ((!tok || (include(SINGLE_CLOSERS, tok[0]) && tok[1] !== ';' && parens === 0) || (tok[0] === ')' && parens === 0)) && !(tok[0] === 'ELSE' && !('IF' === starter || 'THEN' === starter))) {
|
||||
insertion = pre[0] === "," ? idx - 1 : idx;
|
||||
outdent = ['OUTDENT', 2, token[2]];
|
||||
outdent.generated = true;
|
||||
this.tokens.splice(insertion, 0, outdent);
|
||||
break;
|
||||
}
|
||||
@@ -228,26 +240,29 @@
|
||||
}
|
||||
this.tokens.splice(i, 1);
|
||||
return 0;
|
||||
}, this));
|
||||
};
|
||||
return (function() {
|
||||
return __func.apply(__this, arguments);
|
||||
});
|
||||
})(this));
|
||||
};
|
||||
// Ensure that all listed pairs of tokens are correctly balanced throughout
|
||||
// the course of the token stream.
|
||||
Rewriter.prototype.ensure_balance = function ensure_balance(pairs) {
|
||||
var _a, _b, key, levels, line, open, open_line, unclosed, value;
|
||||
Rewriter.prototype.ensureBalance = function(pairs) {
|
||||
var _c, _d, key, levels, line, open, openLine, unclosed, value;
|
||||
levels = {};
|
||||
open_line = {};
|
||||
this.scan_tokens(__bind(function(prev, token, post, i) {
|
||||
var _a, _b, _c, _d, close, open, pair;
|
||||
_b = pairs;
|
||||
for (_a = 0, _c = _b.length; _a < _c; _a++) {
|
||||
pair = _b[_a];
|
||||
_d = pair;
|
||||
open = _d[0];
|
||||
close = _d[1];
|
||||
openLine = {};
|
||||
this.scanTokens((function(__this) {
|
||||
var __func = function(prev, token, post, i) {
|
||||
var _c, _d, _e, _f, close, open, pair;
|
||||
_d = pairs;
|
||||
for (_c = 0, _e = _d.length; _c < _e; _c++) {
|
||||
pair = _d[_c];
|
||||
_f = pair;
|
||||
open = _f[0];
|
||||
close = _f[1];
|
||||
levels[open] = levels[open] || 0;
|
||||
if (token[0] === open) {
|
||||
if (levels[open] === 0) {
|
||||
open_line[open] = token[2];
|
||||
openLine[open] = token[2];
|
||||
}
|
||||
levels[open] += 1;
|
||||
}
|
||||
@@ -255,47 +270,41 @@
|
||||
levels[open] -= 1;
|
||||
}
|
||||
if (levels[open] < 0) {
|
||||
throw new Error("too many " + (token[1]) + " on line " + (token[2] + 1));
|
||||
throw new Error(("too many " + (token[1]) + " on line " + (token[2] + 1)));
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}, this));
|
||||
};
|
||||
return (function() {
|
||||
return __func.apply(__this, arguments);
|
||||
});
|
||||
})(this));
|
||||
unclosed = (function() {
|
||||
_a = []; _b = levels;
|
||||
for (key in _b) { if (__hasProp.call(_b, key)) {
|
||||
value = _b[key];
|
||||
value > 0 ? _a.push(key) : null;
|
||||
_c = []; _d = levels;
|
||||
for (key in _d) { if (__hasProp.call(_d, key)) {
|
||||
value = _d[key];
|
||||
value > 0 ? _c.push(key) : null;
|
||||
}}
|
||||
return _a;
|
||||
}).call(this);
|
||||
return _c;
|
||||
})();
|
||||
if (unclosed.length) {
|
||||
open = unclosed[0];
|
||||
line = open_line[open] + 1;
|
||||
line = openLine[open] + 1;
|
||||
throw new Error("unclosed " + open + " on line " + line);
|
||||
}
|
||||
};
|
||||
// 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.
|
||||
Rewriter.prototype.rewrite_closing_parens = function rewrite_closing_parens() {
|
||||
var _a, debt, key, stack, val;
|
||||
Rewriter.prototype.rewriteClosingParens = function() {
|
||||
var _c, debt, key, stack, val;
|
||||
stack = [];
|
||||
debt = {};
|
||||
_a = INVERSES;
|
||||
for (key in _a) { if (__hasProp.call(_a, key)) {
|
||||
val = _a[key];
|
||||
_c = INVERSES;
|
||||
for (key in _c) { if (__hasProp.call(_c, key)) {
|
||||
val = _c[key];
|
||||
(debt[key] = 0);
|
||||
}}
|
||||
return this.scan_tokens(__bind(function(prev, token, post, i) {
|
||||
var inv, match, mtag, tag;
|
||||
return this.scanTokens((function(__this) {
|
||||
var __func = function(prev, token, post, i) {
|
||||
var inv, match, mtag, oppos, tag;
|
||||
tag = token[0];
|
||||
inv = INVERSES[token[0]];
|
||||
if (include(EXPRESSION_START, tag)) {
|
||||
@@ -309,64 +318,63 @@
|
||||
} else {
|
||||
match = stack.pop();
|
||||
mtag = match[0];
|
||||
if (tag === INVERSES[mtag]) {
|
||||
oppos = INVERSES[mtag];
|
||||
if (tag === oppos) {
|
||||
return 1;
|
||||
}
|
||||
debt[mtag] += 1;
|
||||
val = mtag === 'INDENT' ? match[1] : INVERSES[mtag];
|
||||
this.tokens.splice(i, 0, [INVERSES[mtag], val]);
|
||||
val = [oppos, mtag === 'INDENT' ? match[1] : oppos];
|
||||
if ((this.tokens[i + 2] == undefined ? undefined : this.tokens[i + 2][0]) === mtag) {
|
||||
this.tokens.splice(i + 3, 0, val);
|
||||
stack.push(match);
|
||||
} else {
|
||||
this.tokens.splice(i, 0, val);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}, this));
|
||||
};
|
||||
return (function() {
|
||||
return __func.apply(__this, arguments);
|
||||
});
|
||||
})(this));
|
||||
};
|
||||
Rewriter.prototype.indentation = function(token) {
|
||||
return [['INDENT', 2, token[2]], ['OUTDENT', 2, token[2]]];
|
||||
};
|
||||
return Rewriter;
|
||||
}).call(this);
|
||||
// Constants
|
||||
// ---------
|
||||
// List of the token pairs that must be balanced.
|
||||
BALANCED_PAIRS = [['(', ')'], ['[', ']'], ['{', '}'], ['INDENT', 'OUTDENT'], ['PARAM_START', 'PARAM_END'], ['CALL_START', 'CALL_END'], ['INDEX_START', 'INDEX_END'], ['SOAKED_INDEX_START', 'SOAKED_INDEX_END']];
|
||||
// The inverse mappings of `BALANCED_PAIRS` we're trying to fix up, so we can
|
||||
// look things up from either end.
|
||||
})();
|
||||
BALANCED_PAIRS = [['(', ')'], ['[', ']'], ['{', '}'], ['INDENT', 'OUTDENT'], ['PARAM_START', 'PARAM_END'], ['CALL_START', 'CALL_END'], ['INDEX_START', 'INDEX_END']];
|
||||
INVERSES = {};
|
||||
_b = BALANCED_PAIRS;
|
||||
for (_a = 0, _c = _b.length; _a < _c; _a++) {
|
||||
pair = _b[_a];
|
||||
_d = BALANCED_PAIRS;
|
||||
for (_c = 0, _e = _d.length; _c < _e; _c++) {
|
||||
pair = _d[_c];
|
||||
INVERSES[pair[0]] = pair[1];
|
||||
INVERSES[pair[1]] = pair[0];
|
||||
}
|
||||
// The tokens that signal the start of a balanced pair.
|
||||
EXPRESSION_START = (function() {
|
||||
_d = []; _f = BALANCED_PAIRS;
|
||||
for (_e = 0, _g = _f.length; _e < _g; _e++) {
|
||||
pair = _f[_e];
|
||||
_d.push(pair[0]);
|
||||
_f = []; _h = BALANCED_PAIRS;
|
||||
for (_g = 0, _i = _h.length; _g < _i; _g++) {
|
||||
pair = _h[_g];
|
||||
_f.push(pair[0]);
|
||||
}
|
||||
return _d;
|
||||
}).call(this);
|
||||
// The tokens that signal the end of a balanced pair.
|
||||
return _f;
|
||||
})();
|
||||
EXPRESSION_END = (function() {
|
||||
_h = []; _j = BALANCED_PAIRS;
|
||||
for (_i = 0, _k = _j.length; _i < _k; _i++) {
|
||||
pair = _j[_i];
|
||||
_h.push(pair[1]);
|
||||
_j = []; _l = BALANCED_PAIRS;
|
||||
for (_k = 0, _m = _l.length; _k < _m; _k++) {
|
||||
pair = _l[_k];
|
||||
_j.push(pair[1]);
|
||||
}
|
||||
return _h;
|
||||
}).call(this);
|
||||
// Tokens that indicate the close of a clause of an expression.
|
||||
return _j;
|
||||
})();
|
||||
EXPRESSION_CLOSE = ['CATCH', 'WHEN', 'ELSE', 'FINALLY'].concat(EXPRESSION_END);
|
||||
// Tokens that, if followed by an `IMPLICIT_CALL`, indicate a function invocation.
|
||||
IMPLICIT_FUNC = ['IDENTIFIER', 'SUPER', ')', 'CALL_END', ']', 'INDEX_END', '<-'];
|
||||
// If preceded by an `IMPLICIT_FUNC`, indicates a function invocation.
|
||||
IMPLICIT_CALL = ['IDENTIFIER', 'NUMBER', 'STRING', 'JS', 'REGEX', 'NEW', 'PARAM_START', 'TRY', 'DELETE', 'TYPEOF', 'SWITCH', 'EXTENSION', 'TRUE', 'FALSE', 'YES', 'NO', 'ON', 'OFF', '!', '!!', 'NOT', 'THIS', 'NULL', '@', '->', '=>', '[', '(', '{'];
|
||||
// Tokens indicating that the implicit call must enclose a block of expressions.
|
||||
IMPLICIT_FUNC = ['IDENTIFIER', 'SUPER', ')', 'CALL_END', ']', 'INDEX_END', '@'];
|
||||
IMPLICIT_CALL = ['IDENTIFIER', 'NUMBER', 'STRING', 'JS', 'REGEX', 'NEW', 'PARAM_START', 'TRY', 'DELETE', 'TYPEOF', 'SWITCH', 'TRUE', 'FALSE', 'YES', 'NO', 'ON', 'OFF', '!', '!!', 'THIS', 'NULL', '@', '->', '=>', '[', '(', '{'];
|
||||
IMPLICIT_BLOCK = ['->', '=>', '{', '[', ','];
|
||||
// Tokens that always mark the end of an implicit call for single-liners.
|
||||
IMPLICIT_END = ['IF', 'UNLESS', 'FOR', 'WHILE', 'TERMINATOR', 'INDENT', 'OUTDENT'];
|
||||
// Single-line flavors of block expressions that have unclosed endings.
|
||||
// The grammar can't disambiguate them, so we insert the implicit indentation.
|
||||
IMPLICIT_END = ['IF', 'UNLESS', 'FOR', 'WHILE', 'UNTIL', 'LOOP', 'TERMINATOR', 'INDENT'].concat(EXPRESSION_END);
|
||||
SINGLE_LINERS = ['ELSE', "->", "=>", 'TRY', 'FINALLY', 'THEN'];
|
||||
SINGLE_CLOSERS = ['TERMINATOR', 'CATCH', 'FINALLY', 'ELSE', 'OUTDENT', 'LEADING_WHEN'];
|
||||
})();
|
||||
|
||||
81
lib/scope.js
81
lib/scope.js
@@ -1,18 +1,11 @@
|
||||
(function(){
|
||||
var Scope;
|
||||
var __hasProp = Object.prototype.hasOwnProperty;
|
||||
// The **Scope** class regulates lexical scoping within CoffeeScript. As you
|
||||
// generate code, you create a tree of scopes in the same shape as the nested
|
||||
// function bodies. Each scope knows about the variables declared within it,
|
||||
// and has a reference to its parent enclosing scope. In this way, we know which
|
||||
// variables are new and need to be declared with `var`, and which are shared
|
||||
// with the outside.
|
||||
// Set up exported variables for both **Node.js** and the browser.
|
||||
if (!((typeof process !== "undefined" && process !== null))) {
|
||||
if (!(typeof process !== "undefined" && process !== null)) {
|
||||
this.exports = this;
|
||||
}
|
||||
exports.Scope = (function() {
|
||||
Scope = function Scope(parent, expressions, method) {
|
||||
Scope = function(parent, expressions, method) {
|
||||
var _a;
|
||||
_a = [parent, expressions, method];
|
||||
this.parent = _a[0];
|
||||
@@ -20,30 +13,22 @@
|
||||
this.method = _a[2];
|
||||
this.variables = {};
|
||||
if (this.parent) {
|
||||
this.temp_var = this.parent.temp_var;
|
||||
this.tempVar = this.parent.tempVar;
|
||||
} else {
|
||||
Scope.root = this;
|
||||
this.temp_var = '_a';
|
||||
this.tempVar = '_a';
|
||||
}
|
||||
return this;
|
||||
};
|
||||
// The top-level **Scope** object.
|
||||
Scope.root = null;
|
||||
// Initialize a scope with its parent, for lookups up the chain,
|
||||
// as well as a reference to the **Expressions** node is belongs to, which is
|
||||
// where it should declare its variables, and a reference to the function that
|
||||
// it wraps.
|
||||
// Look up a variable name in lexical scope, and declare it if it does not
|
||||
// already exist.
|
||||
Scope.prototype.find = function find(name) {
|
||||
Scope.prototype.find = function(name) {
|
||||
if (this.check(name)) {
|
||||
return true;
|
||||
}
|
||||
this.variables[name] = 'var';
|
||||
return false;
|
||||
};
|
||||
// Test variables and return true the first time fn(v, k) returns true
|
||||
Scope.prototype.any = function any(fn) {
|
||||
Scope.prototype.any = function(fn) {
|
||||
var _a, k, v;
|
||||
_a = this.variables;
|
||||
for (v in _a) { if (__hasProp.call(_a, v)) {
|
||||
@@ -54,55 +39,43 @@
|
||||
}}
|
||||
return false;
|
||||
};
|
||||
// Reserve a variable name as originating from a function parameter for this
|
||||
// scope. No `var` required for internal references.
|
||||
Scope.prototype.parameter = function parameter(name) {
|
||||
Scope.prototype.parameter = function(name) {
|
||||
this.variables[name] = 'param';
|
||||
return this.variables[name];
|
||||
};
|
||||
// Just check to see if a variable has already been declared, without reserving.
|
||||
Scope.prototype.check = function check(name) {
|
||||
if (this.variables[name]) {
|
||||
Scope.prototype.check = function(name) {
|
||||
if (this.variables.hasOwnProperty(name)) {
|
||||
return true;
|
||||
}
|
||||
return !!(this.parent && this.parent.check(name));
|
||||
};
|
||||
// If we need to store an intermediate result, find an available name for a
|
||||
// compiler-generated variable. `_a`, `_b`, and so on...
|
||||
Scope.prototype.free_variable = function free_variable() {
|
||||
Scope.prototype.freeVariable = function() {
|
||||
var ordinal;
|
||||
while (this.check(this.temp_var)) {
|
||||
ordinal = 1 + parseInt(this.temp_var.substr(1), 36);
|
||||
this.temp_var = '_' + ordinal.toString(36).replace(/\d/g, 'a');
|
||||
while (this.check(this.tempVar)) {
|
||||
ordinal = 1 + parseInt(this.tempVar.substr(1), 36);
|
||||
this.tempVar = '_' + ordinal.toString(36).replace(/\d/g, 'a');
|
||||
}
|
||||
this.variables[this.temp_var] = 'var';
|
||||
return this.temp_var;
|
||||
this.variables[this.tempVar] = 'var';
|
||||
return this.tempVar;
|
||||
};
|
||||
// Ensure that an assignment is made at the top of this scope
|
||||
// (or at the top-level scope, if requested).
|
||||
Scope.prototype.assign = function assign(name, value) {
|
||||
Scope.prototype.assign = function(name, value) {
|
||||
this.variables[name] = {
|
||||
value: value,
|
||||
assigned: true
|
||||
};
|
||||
return this.variables[name];
|
||||
};
|
||||
// Does this scope reference any variables that need to be declared in the
|
||||
// given function body?
|
||||
Scope.prototype.has_declarations = function has_declarations(body) {
|
||||
Scope.prototype.hasDeclarations = function(body) {
|
||||
return body === this.expressions && this.any(function(k, val) {
|
||||
return val === 'var';
|
||||
});
|
||||
};
|
||||
// Does this scope reference any assignments that need to be declared at the
|
||||
// top of the given function body?
|
||||
Scope.prototype.has_assignments = function has_assignments(body) {
|
||||
Scope.prototype.hasAssignments = function(body) {
|
||||
return body === this.expressions && this.any(function(k, val) {
|
||||
return val.assigned;
|
||||
});
|
||||
};
|
||||
// Return the list of variables first declared in this scope.
|
||||
Scope.prototype.declared_variables = function declared_variables() {
|
||||
Scope.prototype.declaredVariables = function() {
|
||||
var _a, _b, key, val;
|
||||
return (function() {
|
||||
_a = []; _b = this.variables;
|
||||
@@ -113,24 +86,20 @@
|
||||
return _a;
|
||||
}).call(this).sort();
|
||||
};
|
||||
// Return the list of assignments that are supposed to be made at the top
|
||||
// of this scope.
|
||||
Scope.prototype.assigned_variables = function assigned_variables() {
|
||||
Scope.prototype.assignedVariables = function() {
|
||||
var _a, _b, key, val;
|
||||
_a = []; _b = this.variables;
|
||||
for (key in _b) { if (__hasProp.call(_b, key)) {
|
||||
val = _b[key];
|
||||
val.assigned ? _a.push("" + key + " = " + (val.value)) : null;
|
||||
val.assigned ? _a.push("" + key + " = " + val.value) : null;
|
||||
}}
|
||||
return _a;
|
||||
};
|
||||
// Compile the JavaScript for all of the variable declarations in this scope.
|
||||
Scope.prototype.compiled_declarations = function compiled_declarations() {
|
||||
return this.declared_variables().join(', ');
|
||||
Scope.prototype.compiledDeclarations = function() {
|
||||
return this.declaredVariables().join(', ');
|
||||
};
|
||||
// Compile the JavaScript for all of the variable assignments in this scope.
|
||||
Scope.prototype.compiled_assignments = function compiled_assignments() {
|
||||
return this.assigned_variables().join(', ');
|
||||
Scope.prototype.compiledAssignments = function() {
|
||||
return this.assignedVariables().join(', ');
|
||||
};
|
||||
return Scope;
|
||||
}).call(this);
|
||||
|
||||
12
package.json
12
package.json
@@ -3,5 +3,15 @@
|
||||
"description": "Unfancy JavaScript",
|
||||
"keywords": ["javascript", "language"],
|
||||
"author": "Jeremy Ashkenas",
|
||||
"version": "0.6.0"
|
||||
"version": "0.7.2",
|
||||
"licenses": [{
|
||||
"type": "MIT",
|
||||
"url": "http://github.com/jashkenas/coffee-script/raw/master/LICENSE"
|
||||
}],
|
||||
"engines": {
|
||||
"node": ">=0.1.99"
|
||||
},
|
||||
"scripts": {
|
||||
"install": "sudo bin/cake install"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,10 +22,11 @@ oparse: null
|
||||
# Mixin the top-level Cake functions for Cakefiles to use directly.
|
||||
helpers.extend global, {
|
||||
|
||||
# Define a Cake task with a short name, a sentence description,
|
||||
# Define a Cake task with a short name, an optional sentence description,
|
||||
# and the function to run as the action itself.
|
||||
task: (name, description, action) ->
|
||||
tasks[name]: {name: name, description: description, action: action}
|
||||
[action, description]: [description, action] unless action
|
||||
tasks[name]: {name, description, action}
|
||||
|
||||
# Define an option that the Cakefile accepts. The parsed options hash,
|
||||
# containing all of the command-line options passed, will be made available
|
||||
@@ -35,7 +36,7 @@ helpers.extend global, {
|
||||
|
||||
# Invoke another task in the current Cakefile.
|
||||
invoke: (name) ->
|
||||
no_such_task name unless tasks[name]
|
||||
missingTask name unless tasks[name]
|
||||
tasks[name].action options
|
||||
|
||||
}
|
||||
@@ -47,22 +48,23 @@ exports.run: ->
|
||||
path.exists 'Cakefile', (exists) ->
|
||||
throw new Error("Cakefile not found in ${process.cwd()}") unless exists
|
||||
args: process.argv[2...process.argv.length]
|
||||
CoffeeScript.run fs.readFileSync('Cakefile'), {source: 'Cakefile'}
|
||||
CoffeeScript.run fs.readFileSync('Cakefile').toString(), {source: 'Cakefile'}
|
||||
oparse: new optparse.OptionParser switches
|
||||
return print_tasks() unless args.length
|
||||
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`
|
||||
print_tasks: ->
|
||||
printTasks: ->
|
||||
puts ''
|
||||
for name, task of tasks
|
||||
spaces: 20 - name.length
|
||||
spaces: if spaces > 0 then (' ' for i in [0..spaces]).join('') else ''
|
||||
puts "cake $name$spaces # ${task.description}"
|
||||
desc: if task.description then "# $task.description" else ''
|
||||
puts "cake $name$spaces $desc"
|
||||
puts oparse.help() if switches.length
|
||||
|
||||
# Print an error and exit when attempting to all an undefined task.
|
||||
no_such_task: (task) ->
|
||||
process.stdio.writeError "No such task: \"$task\"\n"
|
||||
missingTask: (task) ->
|
||||
puts "No such task: \"$task\""
|
||||
process.exit 1
|
||||
|
||||
@@ -22,10 +22,10 @@ else
|
||||
helpers: this.helpers
|
||||
|
||||
# The current CoffeeScript version number.
|
||||
exports.VERSION: '0.6.0'
|
||||
exports.VERSION: '0.7.2'
|
||||
|
||||
# Instantiate a Lexer for our use here.
|
||||
lexer: new Lexer()
|
||||
lexer: new Lexer
|
||||
|
||||
# Compile a string of CoffeeScript code to JavaScript, using the Coffee/Jison
|
||||
# compiler.
|
||||
@@ -34,7 +34,7 @@ exports.compile: compile: (code, options) ->
|
||||
try
|
||||
(parser.parse lexer.tokenize code).compile options
|
||||
catch err
|
||||
err.message: "In ${options.source}, ${err.message}" if options.source
|
||||
err.message: "In $options.source, $err.message" if options.source
|
||||
throw err
|
||||
|
||||
# Tokenize a string of CoffeeScript code, and return the array of tokens.
|
||||
@@ -55,13 +55,6 @@ exports.run: ((code, options) ->
|
||||
eval exports.compile code, options
|
||||
)
|
||||
|
||||
# Extend CoffeeScript with a custom language extension. It should hook in to
|
||||
# the **Lexer** (as a peer of any of the lexer's tokenizing methods), and
|
||||
# push a token on to the stack that contains a **Node** as the value (as a
|
||||
# peer of the nodes in [nodes.coffee](nodes.html)).
|
||||
exports.extend: (func) ->
|
||||
Lexer.extensions.push func
|
||||
|
||||
# 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".
|
||||
@@ -76,7 +69,6 @@ parser.lexer: {
|
||||
@tokens: tokens
|
||||
@pos: 0
|
||||
upcomingInput: -> ""
|
||||
showPosition: -> @pos
|
||||
}
|
||||
|
||||
# Activate CoffeeScript in the browser by having it compile and evaluate
|
||||
@@ -84,10 +76,10 @@ parser.lexer: {
|
||||
# on page load. Unfortunately, the text contents of remote scripts cannot be
|
||||
# accessed from the browser, so only inline script tags will work.
|
||||
if document? and document.getElementsByTagName
|
||||
process_scripts: ->
|
||||
processScripts: ->
|
||||
for tag in document.getElementsByTagName('script') when tag.type is 'text/coffeescript'
|
||||
eval exports.compile tag.innerHTML
|
||||
if window.addEventListener
|
||||
window.addEventListener 'load', process_scripts, false
|
||||
window.addEventListener 'load', processScripts, false
|
||||
else if window.attachEvent
|
||||
window.attachEvent 'onload', process_scripts
|
||||
window.attachEvent 'onload', processScripts
|
||||
|
||||
@@ -5,10 +5,11 @@
|
||||
# interactive REPL.
|
||||
|
||||
# External dependencies.
|
||||
fs: require 'fs'
|
||||
path: require 'path'
|
||||
optparse: require './optparse'
|
||||
CoffeeScript: require './coffee-script'
|
||||
fs: require 'fs'
|
||||
path: require 'path'
|
||||
optparse: require './optparse'
|
||||
CoffeeScript: require './coffee-script'
|
||||
{spawn, exec}: require('child_process')
|
||||
|
||||
# The help banner that is printed when `coffee` is called without arguments.
|
||||
BANNER: '''
|
||||
@@ -38,98 +39,113 @@ SWITCHES: [
|
||||
# Top-level objects shared by all the functions.
|
||||
options: {}
|
||||
sources: []
|
||||
option_parser: null
|
||||
optionParser: null
|
||||
|
||||
# Run `coffee` by parsing passed options and determining what action to take.
|
||||
# Many flags cause us to divert before compiling anything. Flags passed after
|
||||
# `--` will be passed verbatim to your script as arguments in `process.argv`
|
||||
exports.run: ->
|
||||
parse_options()
|
||||
parseOptions()
|
||||
return usage() if options.help
|
||||
return version() if options.version
|
||||
return require './repl' if options.interactive
|
||||
return compile_stdio() if options.stdio
|
||||
return compile_script 'console', sources[0] if options.eval
|
||||
return usage() unless sources.length
|
||||
return compileStdio() if options.stdio
|
||||
return compileScript 'console', sources[0] if options.eval
|
||||
return require './repl' unless sources.length
|
||||
separator: sources.indexOf '--'
|
||||
flags: []
|
||||
if separator >= 0
|
||||
flags: sources[(separator + 1)...sources.length]
|
||||
flags: sources[(separator + 1)...sources.length]
|
||||
sources: sources[0...separator]
|
||||
if options.run
|
||||
flags: sources[1..sources.length].concat flags
|
||||
sources: [sources[0]]
|
||||
process.ARGV: process.argv: flags
|
||||
watch_scripts() if options.watch
|
||||
compile_scripts()
|
||||
compileScripts()
|
||||
|
||||
# Asynchronously read in each CoffeeScript in a list of source files and
|
||||
# compile them.
|
||||
compile_scripts: ->
|
||||
compile: (source) ->
|
||||
path.exists source, (exists) ->
|
||||
throw new Error "File not found: $source" unless exists
|
||||
fs.readFile source, (err, code) -> compile_script(source, code)
|
||||
compile(source) for source in sources
|
||||
# compile them. If a directory is passed, recursively compile all
|
||||
# '.coffee' extension source files in it and all subdirectories.
|
||||
compileScripts: ->
|
||||
for source in sources
|
||||
base: source
|
||||
compile: (source, topLevel) ->
|
||||
path.exists source, (exists) ->
|
||||
throw new Error "File not found: $source" unless exists
|
||||
fs.stat source, (err, stats) ->
|
||||
if stats.isDirectory()
|
||||
fs.readdir source, (err, files) ->
|
||||
for file in files
|
||||
compile path.join(source, file)
|
||||
else if topLevel or path.extname(source) is '.coffee'
|
||||
fs.readFile source, (err, code) -> compileScript(source, code.toString(), base)
|
||||
watch source, base if options.watch
|
||||
compile source, true
|
||||
|
||||
# Compile a single source script, containing the given code, according to the
|
||||
# requested options. Both compile_scripts and watch_scripts share this method
|
||||
# in common. If evaluating the script directly sets `__filename`, `__dirname`
|
||||
# and `module.filename` to be correct relative to the script's path.
|
||||
compile_script: (source, code) ->
|
||||
# requested options. If evaluating the script directly sets `__filename`,
|
||||
# `__dirname` and `module.filename` to be correct relative to the script's path.
|
||||
compileScript: (source, code, base) ->
|
||||
o: options
|
||||
code_opts: compile_options source
|
||||
codeOpts: compileOptions source
|
||||
try
|
||||
if o.tokens then print_tokens CoffeeScript.tokens code
|
||||
if o.tokens then printTokens CoffeeScript.tokens code
|
||||
else if o.nodes then puts CoffeeScript.nodes(code).toString()
|
||||
else if o.run then CoffeeScript.run code, code_opts
|
||||
else if o.run then CoffeeScript.run code, codeOpts
|
||||
else
|
||||
js: CoffeeScript.compile code, code_opts
|
||||
if o.print then process.stdio.write js
|
||||
else if o.compile then write_js source, js
|
||||
js: CoffeeScript.compile code, codeOpts
|
||||
if o.print then print js
|
||||
else if o.compile then writeJs source, js, base
|
||||
else if o.lint then lint js
|
||||
catch err
|
||||
if o.watch then puts err.message else throw err
|
||||
error(err.stack) and process.exit 1 unless o.watch
|
||||
puts err.message
|
||||
|
||||
# Attach the appropriate listeners to compile scripts incoming over **stdin**,
|
||||
# and write them back to **stdout**.
|
||||
compile_stdio: ->
|
||||
compileStdio: ->
|
||||
code: ''
|
||||
process.stdio.open()
|
||||
process.stdio.addListener 'data', (string) ->
|
||||
code: + string if string
|
||||
process.stdio.addListener 'close', ->
|
||||
compile_script 'stdio', code
|
||||
stdin: process.openStdin()
|
||||
stdin.addListener 'data', (buffer) ->
|
||||
code: + buffer.toString() if buffer
|
||||
stdin.addListener 'end', ->
|
||||
compileScript 'stdio', code
|
||||
|
||||
# Watch a list of source CoffeeScript files using `fs.watchFile`, recompiling
|
||||
# them every time the files are updated. May be used in combination with other
|
||||
# options, such as `--lint` or `--print`.
|
||||
watch_scripts: ->
|
||||
watch: (source) ->
|
||||
fs.watchFile source, {persistent: true, interval: 500}, (curr, prev) ->
|
||||
return if curr.mtime.getTime() is prev.mtime.getTime()
|
||||
fs.readFile source, (err, code) -> compile_script(source, code)
|
||||
watch(source) for source in sources
|
||||
# Watch a source CoffeeScript file using `fs.watchFile`, recompiling it every
|
||||
# time the file is updated. May be used in combination with other options,
|
||||
# such as `--lint` or `--print`.
|
||||
watch: (source, base) ->
|
||||
fs.watchFile source, {persistent: true, interval: 500}, (curr, prev) ->
|
||||
return if curr.mtime.getTime() is prev.mtime.getTime()
|
||||
fs.readFile source, (err, code) -> 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
|
||||
# directory can be customized with `--output`.
|
||||
write_js: (source, js) ->
|
||||
writeJs: (source, js, base) ->
|
||||
filename: path.basename(source, path.extname(source)) + '.js'
|
||||
dir: options.output or path.dirname(source)
|
||||
js_path: path.join dir, filename
|
||||
fs.writeFile js_path, js
|
||||
srcDir: path.dirname source
|
||||
baseDir: srcDir.substring base.length
|
||||
dir: if options.output then path.join options.output, baseDir else srcDir
|
||||
jsPath: path.join dir, filename
|
||||
compile: ->
|
||||
fs.writeFile jsPath, js, (err) ->
|
||||
puts "Compiled $source" if options.compile and options.watch
|
||||
path.exists dir, (exists) ->
|
||||
if exists then compile() else exec "mkdir -p $dir", compile
|
||||
|
||||
# Pipe compiled JS through JSLint (requires a working `jsl` command), printing
|
||||
# any errors or warnings that arise.
|
||||
lint: (js) ->
|
||||
jsl: process.createChildProcess('jsl', ['-nologo', '-stdin'])
|
||||
jsl.addListener 'output', (result) ->
|
||||
puts result.replace(/\n/g, '') if result
|
||||
jsl.addListener 'error', (result) ->
|
||||
puts result if result
|
||||
jsl.write js
|
||||
jsl.close()
|
||||
printIt: (buffer) -> print buffer.toString()
|
||||
jsl: spawn 'jsl', ['-nologo', '-stdin']
|
||||
jsl.stdout.addListener 'data', printIt
|
||||
jsl.stderr.addListener 'data', printIt
|
||||
jsl.stdin.write js
|
||||
jsl.stdin.end()
|
||||
|
||||
# Pretty-print a stream of tokens.
|
||||
print_tokens: (tokens) ->
|
||||
printTokens: (tokens) ->
|
||||
strings: for token in tokens
|
||||
[tag, value]: [token[0], token[1].toString().replace(/\n/, '\\n')]
|
||||
"[$tag $value]"
|
||||
@@ -137,25 +153,25 @@ print_tokens: (tokens) ->
|
||||
|
||||
# Use the [OptionParser module](optparse.html) to extract all options from
|
||||
# `process.argv` that are specified in `SWITCHES`.
|
||||
parse_options: ->
|
||||
option_parser: new optparse.OptionParser SWITCHES, BANNER
|
||||
o: options: option_parser.parse(process.argv)
|
||||
parseOptions: ->
|
||||
optionParser: new optparse.OptionParser SWITCHES, BANNER
|
||||
o: options: optionParser.parse(process.argv[2...process.argv.length])
|
||||
options.run: not (o.compile or o.print or o.lint)
|
||||
options.print: !! (o.print or (o.eval or o.stdio and o.compile))
|
||||
sources: options.arguments[2...options.arguments.length]
|
||||
sources: options.arguments
|
||||
|
||||
# The compile-time options to pass to the CoffeeScript compiler.
|
||||
compile_options: (source) ->
|
||||
o: {source: source}
|
||||
o['no_wrap']: options['no-wrap']
|
||||
compileOptions: (source) ->
|
||||
o: {source}
|
||||
o.noWrap: options['no-wrap']
|
||||
o
|
||||
|
||||
# Print the `--help` usage message and exit.
|
||||
usage: ->
|
||||
puts option_parser.help()
|
||||
puts optionParser.help()
|
||||
process.exit 0
|
||||
|
||||
# Print the `--version` message and exit.
|
||||
version: ->
|
||||
puts "CoffeeScript version ${CoffeeScript.VERSION}"
|
||||
puts "CoffeeScript version $CoffeeScript.VERSION"
|
||||
process.exit 0
|
||||
|
||||
@@ -30,10 +30,10 @@ unwrap: /function\s*\(\)\s*\{\s*return\s*([\s\S]*);\s*\}/
|
||||
# we pass the pattern-defining string, the action to run, and extra options,
|
||||
# optionally. If no action is specified, we simply pass the value of the
|
||||
# previous nonterminal.
|
||||
o: (pattern_string, action, options) ->
|
||||
return [pattern_string, '$$ = $1;', options] unless action
|
||||
o: (patternString, action, options) ->
|
||||
return [patternString, '$$ = $1;', options] unless action
|
||||
action: if match: (action + '').match(unwrap) then match[1] else "($action())"
|
||||
[pattern_string, "$$ = $action;", options]
|
||||
[patternString, "$$ = $action;", options]
|
||||
|
||||
# Grammatical Rules
|
||||
# -----------------
|
||||
@@ -53,35 +53,45 @@ grammar: {
|
||||
# The **Root** is the top-level node in the syntax tree. Since we parse bottom-up,
|
||||
# all parsing must end here.
|
||||
Root: [
|
||||
o "", -> new Expressions()
|
||||
o "TERMINATOR", -> new Expressions()
|
||||
o "Expressions"
|
||||
o "", -> new Expressions
|
||||
o "TERMINATOR", -> new Expressions
|
||||
o "Body"
|
||||
o "Block TERMINATOR"
|
||||
]
|
||||
|
||||
# Any list of expressions or method body, seperated by line breaks or
|
||||
# semicolons.
|
||||
Expressions: [
|
||||
o "Expression", -> Expressions.wrap [$1]
|
||||
o "Expressions TERMINATOR Expression", -> $1.push $3
|
||||
o "Expressions TERMINATOR"
|
||||
# Any list of statements and expressions, seperated by line breaks or semicolons.
|
||||
Body: [
|
||||
o "Line", -> Expressions.wrap [$1]
|
||||
o "Body TERMINATOR Line", -> $1.push $3
|
||||
o "Body TERMINATOR"
|
||||
]
|
||||
|
||||
# Expressions and statements, which make up a line in a body.
|
||||
Line: [
|
||||
o "Expression"
|
||||
o "Statement"
|
||||
]
|
||||
|
||||
# Pure statements which cannot be expressions.
|
||||
Statement: [
|
||||
o "Return"
|
||||
o "Throw"
|
||||
o "BREAK", -> new LiteralNode $1
|
||||
o "CONTINUE", -> new LiteralNode $1
|
||||
]
|
||||
|
||||
# All the different types of expressions in our language. The basic unit of
|
||||
# CoffeeScript is the **Expression** -- you'll notice that there is no
|
||||
# "statement" nonterminal. Expressions serve as the building blocks
|
||||
# of many other rules, making them somewhat circular.
|
||||
# CoffeeScript is the **Expression** -- everything that can be an expression
|
||||
# is one. Expressions serve as the building blocks of many other rules, making
|
||||
# them somewhat circular.
|
||||
Expression: [
|
||||
o "Value"
|
||||
o "Call"
|
||||
o "Curry"
|
||||
o "Code"
|
||||
o "Operation"
|
||||
o "Assign"
|
||||
o "If"
|
||||
o "Try"
|
||||
o "Throw"
|
||||
o "Return"
|
||||
o "While"
|
||||
o "For"
|
||||
o "Switch"
|
||||
@@ -90,38 +100,35 @@ grammar: {
|
||||
o "Splat"
|
||||
o "Existence"
|
||||
o "Comment"
|
||||
o "Extension"
|
||||
]
|
||||
|
||||
# A an indented block of expressions. Note that the [Rewriter](rewriter.html)
|
||||
# will convert some postfix forms into blocks for us, by adjusting the
|
||||
# token stream.
|
||||
Block: [
|
||||
o "INDENT Expressions OUTDENT", -> $2
|
||||
o "INDENT OUTDENT", -> new Expressions()
|
||||
o "INDENT Body OUTDENT", -> $2
|
||||
o "INDENT OUTDENT", -> new Expressions
|
||||
o "TERMINATOR Comment", -> Expressions.wrap [$2]
|
||||
]
|
||||
|
||||
# A literal identifier, a variable name or property.
|
||||
Identifier: [
|
||||
o "IDENTIFIER", -> new LiteralNode yytext
|
||||
o "IDENTIFIER", -> new LiteralNode $1
|
||||
]
|
||||
|
||||
# Alphanumerics are separated from the other **Literal** matchers because
|
||||
# they can also serve as keys in object literals.
|
||||
AlphaNumeric: [
|
||||
o "NUMBER", -> new LiteralNode yytext
|
||||
o "STRING", -> new LiteralNode yytext
|
||||
o "NUMBER", -> new LiteralNode $1
|
||||
o "STRING", -> new LiteralNode $1
|
||||
]
|
||||
|
||||
# All of our immediate values. These can (in general), be passed straight
|
||||
# through and printed to JavaScript.
|
||||
Literal: [
|
||||
o "AlphaNumeric"
|
||||
o "JS", -> new LiteralNode yytext
|
||||
o "REGEX", -> new LiteralNode yytext
|
||||
o "BREAK", -> new LiteralNode yytext
|
||||
o "CONTINUE", -> new LiteralNode yytext
|
||||
o "JS", -> new LiteralNode $1
|
||||
o "REGEX", -> new LiteralNode $1
|
||||
o "TRUE", -> new LiteralNode true
|
||||
o "FALSE", -> new LiteralNode false
|
||||
o "YES", -> new LiteralNode true
|
||||
@@ -138,6 +145,8 @@ grammar: {
|
||||
# Assignment when it happens within an object literal. The difference from
|
||||
# the ordinary **Assign** is that these allow numbers and strings as keys.
|
||||
AssignObj: [
|
||||
o "Identifier", -> new ValueNode $1
|
||||
o "AlphaNumeric"
|
||||
o "Identifier ASSIGN Expression", -> new AssignNode new ValueNode($1), $3, 'object'
|
||||
o "AlphaNumeric ASSIGN Expression", -> new AssignNode new ValueNode($1), $3, 'object'
|
||||
o "Comment"
|
||||
@@ -149,11 +158,9 @@ grammar: {
|
||||
o "RETURN", -> new ReturnNode new ValueNode new LiteralNode 'null'
|
||||
]
|
||||
|
||||
# A comment. Because CoffeeScript passes comments through to JavaScript, we
|
||||
# have to parse comments like any other construct, and identify all of the
|
||||
# positions in which they can occur in the grammar.
|
||||
# A block comment.
|
||||
Comment: [
|
||||
o "COMMENT", -> new CommentNode yytext
|
||||
o "HERECOMMENT", -> new CommentNode $1
|
||||
]
|
||||
|
||||
# [The existential operator](http://jashkenas.github.com/coffee-script/#existence).
|
||||
@@ -176,6 +183,12 @@ grammar: {
|
||||
o "=>", -> 'boundfunc'
|
||||
]
|
||||
|
||||
# An optional, trailing comma.
|
||||
OptComma: [
|
||||
o ''
|
||||
o ','
|
||||
]
|
||||
|
||||
# The list of parameters that a function accepts can be of any length.
|
||||
ParamList: [
|
||||
o "", -> []
|
||||
@@ -186,7 +199,7 @@ grammar: {
|
||||
# A single parameter in a function definition can be ordinary, or a splat
|
||||
# that hoovers up the remaining arguments.
|
||||
Param: [
|
||||
o "PARAM", -> new LiteralNode yytext
|
||||
o "PARAM", -> new LiteralNode $1
|
||||
o "Param . . .", -> new SplatNode $1
|
||||
]
|
||||
|
||||
@@ -235,15 +248,13 @@ grammar: {
|
||||
# Indexing into an object or array using bracket notation.
|
||||
Index: [
|
||||
o "INDEX_START Expression INDEX_END", -> new IndexNode $2
|
||||
o "SOAKED_INDEX_START Expression SOAKED_INDEX_END", -> new IndexNode $2, 'soak'
|
||||
o "INDEX_SOAK Index", -> $2.soakNode: yes; $2
|
||||
o "INDEX_PROTO Index", -> $2.proto: yes; $2
|
||||
]
|
||||
|
||||
# In CoffeeScript, an object literal is simply a list of assignments.
|
||||
Object: [
|
||||
o "{ AssignList }", -> new ObjectNode $2
|
||||
o "{ IndentedAssignList }", -> new ObjectNode $2
|
||||
o "{ AssignList , }", -> new ObjectNode $2
|
||||
o "{ IndentedAssignList , }", -> new ObjectNode $2
|
||||
o "{ AssignList OptComma }", -> new ObjectNode $2
|
||||
]
|
||||
|
||||
# Assignment of properties within an object literal can be separated by
|
||||
@@ -252,14 +263,8 @@ grammar: {
|
||||
o "", -> []
|
||||
o "AssignObj", -> [$1]
|
||||
o "AssignList , AssignObj", -> $1.concat [$3]
|
||||
o "AssignList TERMINATOR AssignObj", -> $1.concat [$3]
|
||||
o "AssignList , TERMINATOR AssignObj", -> $1.concat [$4]
|
||||
]
|
||||
|
||||
# An **AssignList** within a block indentation.
|
||||
IndentedAssignList: [
|
||||
o "INDENT AssignList OUTDENT", -> $2
|
||||
o "INDENT AssignList , OUTDENT", -> $2
|
||||
o "AssignList OptComma TERMINATOR AssignObj", -> $1.concat [$4]
|
||||
o "AssignList OptComma INDENT AssignList OptComma OUTDENT", -> $1.concat $4
|
||||
]
|
||||
|
||||
# Class definitions have optional bodies of prototype property assignments,
|
||||
@@ -281,20 +286,16 @@ grammar: {
|
||||
ClassBody: [
|
||||
o "", -> []
|
||||
o "ClassAssign", -> [$1]
|
||||
o "ClassBody TERMINATOR ClassAssign", -> $1.concat $3
|
||||
o "ClassBody TERMINATOR ClassAssign", -> $1.concat $3
|
||||
]
|
||||
|
||||
# The three flavors of function call: normal, object instantiation with `new`,
|
||||
# and calling `super()`
|
||||
Call: [
|
||||
o "Invocation"
|
||||
o "NEW Invocation", -> $2.new_instance()
|
||||
o "Super"
|
||||
]
|
||||
|
||||
# Binds a function call to a context and/or arguments.
|
||||
Curry: [
|
||||
o "Value <- Arguments", -> new CurryNode $1, $3
|
||||
o "NEW Invocation", -> $2.newInstance()
|
||||
o "NEW Value", -> (new CallNode($2, [])).newInstance()
|
||||
]
|
||||
|
||||
# Extending an object by setting its prototype chain to reference a parent
|
||||
@@ -311,14 +312,12 @@ grammar: {
|
||||
|
||||
# The list of arguments to a function call.
|
||||
Arguments: [
|
||||
o "CALL_START ArgList CALL_END", -> $2
|
||||
o "CALL_START ArgList , CALL_END", -> $2
|
||||
o "CALL_START ArgList OptComma CALL_END", -> $2
|
||||
]
|
||||
|
||||
# Calling super.
|
||||
Super: [
|
||||
o "SUPER CALL_START ArgList CALL_END", -> new CallNode 'super', $3
|
||||
o "SUPER CALL_START ArgList , CALL_END", -> new CallNode 'super', $3
|
||||
o "SUPER Arguments", -> new CallNode 'super', $2
|
||||
]
|
||||
|
||||
# A reference to the *this* current object.
|
||||
@@ -346,8 +345,7 @@ grammar: {
|
||||
|
||||
# The array literal.
|
||||
Array: [
|
||||
o "[ ArgList ]", -> new ArrayNode $2
|
||||
o "[ ArgList , ]", -> new ArrayNode $2
|
||||
o "[ ArgList OptComma ]", -> new ArrayNode $2
|
||||
]
|
||||
|
||||
# The **ArgList** is both the list of objects passed into a function call,
|
||||
@@ -356,13 +354,9 @@ grammar: {
|
||||
ArgList: [
|
||||
o "", -> []
|
||||
o "Expression", -> [$1]
|
||||
o "INDENT Expression", -> [$2]
|
||||
o "ArgList , Expression", -> $1.concat [$3]
|
||||
o "ArgList TERMINATOR Expression", -> $1.concat [$3]
|
||||
o "ArgList , TERMINATOR Expression", -> $1.concat [$4]
|
||||
o "ArgList , INDENT Expression", -> $1.concat [$4]
|
||||
o "ArgList OUTDENT"
|
||||
o "ArgList , OUTDENT"
|
||||
o "ArgList OptComma TERMINATOR Expression", -> $1.concat [$4]
|
||||
o "ArgList OptComma INDENT ArgList OptComma OUTDENT", -> $1.concat $4
|
||||
]
|
||||
|
||||
# Just simple, comma-separated, required arguments (no fancy syntax). We need
|
||||
@@ -396,103 +390,109 @@ grammar: {
|
||||
# where only values are accepted, wrapping it in parentheses will always do
|
||||
# the trick.
|
||||
Parenthetical: [
|
||||
o "( Expression )", -> new ParentheticalNode $2
|
||||
]
|
||||
|
||||
# A language extension to CoffeeScript from the outside. We simply pass
|
||||
# it through unaltered.
|
||||
Extension: [
|
||||
o "EXTENSION", -> yytext
|
||||
o "( Line )", -> new ParentheticalNode $2
|
||||
]
|
||||
|
||||
# The condition portion of a while loop.
|
||||
WhileSource: [
|
||||
o "WHILE Expression", -> new WhileNode $2
|
||||
o "WHILE Expression WHEN Expression", -> new WhileNode $2, {filter : $4}
|
||||
o "WHILE Expression WHEN Expression", -> new WhileNode $2, {guard : $4}
|
||||
o "UNTIL Expression", -> new WhileNode $2, {invert: true}
|
||||
o "UNTIL Expression WHEN Expression", -> new WhileNode $2, {invert: true, guard: $4}
|
||||
]
|
||||
|
||||
# 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.
|
||||
While: [
|
||||
o "WhileSource Block", -> $1.add_body $2
|
||||
o "Expression WhileSource", -> $2.add_body Expressions.wrap [$1]
|
||||
o "WhileSource Block", -> $1.addBody $2
|
||||
o "Statement WhileSource", -> $2.addBody Expressions.wrap [$1]
|
||||
o "Expression WhileSource", -> $2.addBody Expressions.wrap [$1]
|
||||
o "Loop", -> $1
|
||||
]
|
||||
|
||||
Loop: [
|
||||
o "LOOP Block", -> new WhileNode(new LiteralNode 'true').addBody $2
|
||||
o "LOOP Expression", -> new WhileNode(new LiteralNode 'true').addBody Expressions.wrap [$2]
|
||||
]
|
||||
|
||||
# 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.
|
||||
For: [
|
||||
o "Statement FOR ForVariables ForSource", -> new ForNode $1, $4, $3[0], $3[1]
|
||||
o "Expression FOR ForVariables ForSource", -> new ForNode $1, $4, $3[0], $3[1]
|
||||
o "FOR ForVariables ForSource Block", -> new ForNode $4, $3, $2[0], $2[1]
|
||||
]
|
||||
|
||||
# An array of all accepted values for a variable inside the loop. This
|
||||
# enables support for pattern matching.
|
||||
ForValue: [
|
||||
o "Identifier"
|
||||
o "Array", -> new ValueNode $1
|
||||
o "Object", -> new ValueNode $1
|
||||
]
|
||||
|
||||
# An array or range comprehension has variables for the current element and
|
||||
# (optional) reference to the current index. Or, *key, value*, in the case
|
||||
# of object comprehensions.
|
||||
ForVariables: [
|
||||
o "Identifier", -> [$1]
|
||||
o "Identifier , Identifier", -> [$1, $3]
|
||||
o "ForValue", -> [$1]
|
||||
o "ForValue , ForValue", -> [$1, $3]
|
||||
]
|
||||
|
||||
# The source of a comprehension is an array or object with an optional filter
|
||||
# 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.
|
||||
ForSource: [
|
||||
o "IN Expression", -> {source: $2}
|
||||
o "OF Expression", -> {source: $2, object: true}
|
||||
o "IN Expression WHEN Expression", -> {source: $2, filter: $4}
|
||||
o "OF Expression WHEN Expression", -> {source: $2, filter: $4, object: true}
|
||||
o "IN Expression WHEN Expression", -> {source: $2, guard: $4}
|
||||
o "OF Expression WHEN Expression", -> {source: $2, guard: $4, object: true}
|
||||
o "IN Expression BY Expression", -> {source: $2, step: $4}
|
||||
o "IN Expression WHEN Expression BY Expression", -> {source: $2, filter: $4; step: $6}
|
||||
o "IN Expression BY Expression WHEN Expression", -> {source: $2, step: $4, filter: $6}
|
||||
o "IN Expression WHEN Expression BY Expression", -> {source: $2, guard: $4, step: $6}
|
||||
o "IN Expression BY Expression WHEN Expression", -> {source: $2, step: $4, guard: $6}
|
||||
]
|
||||
|
||||
# The CoffeeScript switch/when/else block replaces the JavaScript
|
||||
# switch/case/default by compiling into an if-else chain.
|
||||
Switch: [
|
||||
o "SWITCH Expression INDENT Whens OUTDENT", -> $4.rewrite_condition $2
|
||||
o "SWITCH Expression INDENT Whens ELSE Block OUTDENT", -> $4.rewrite_condition($2).add_else $6, true
|
||||
o "SWITCH Expression INDENT Whens OUTDENT", -> $4.switchesOver $2
|
||||
o "SWITCH Expression INDENT Whens ELSE Block OUTDENT", -> $4.switchesOver($2).addElse $6, true
|
||||
o "SWITCH INDENT Whens OUTDENT", -> $3
|
||||
o "SWITCH INDENT Whens ELSE Block OUTDENT", -> $3.addElse $5, true
|
||||
]
|
||||
|
||||
# The inner list of whens is left recursive. At code-generation time, the
|
||||
# IfNode will rewrite them into a proper chain.
|
||||
Whens: [
|
||||
o "When"
|
||||
o "Whens When", -> $1.push $2
|
||||
o "Whens When", -> $1.addElse $2
|
||||
]
|
||||
|
||||
# An individual **When** clause, with action.
|
||||
When: [
|
||||
o "LEADING_WHEN SimpleArgs Block", -> new IfNode $2, $3, null, {statement: true}
|
||||
o "LEADING_WHEN SimpleArgs Block TERMINATOR", -> new IfNode $2, $3, null, {statement: true}
|
||||
o "Comment TERMINATOR When", -> $3.comment: $1; $3
|
||||
o "LEADING_WHEN SimpleArgs Block", -> new IfNode $2, $3, {statement: true}
|
||||
o "LEADING_WHEN SimpleArgs Block TERMINATOR", -> new IfNode $2, $3, {statement: true}
|
||||
]
|
||||
|
||||
# The most basic form of *if* is a condition and an action. The following
|
||||
# if-related rules are broken up along these lines in order to avoid
|
||||
# ambiguity.
|
||||
IfStart: [
|
||||
o "IF Expression Block", -> new IfNode $2, $3
|
||||
o "IfStart ElsIf", -> $1.add_else $2
|
||||
]
|
||||
|
||||
# An **IfStart** can optionally be followed by an else block.
|
||||
IfBlock: [
|
||||
o "IfStart"
|
||||
o "IfStart ELSE Block", -> $1.add_else $3
|
||||
]
|
||||
|
||||
# An *else if* continuation of the *if* expression.
|
||||
ElsIf: [
|
||||
o "ELSE IF Expression Block", -> (new IfNode($3, $4)).force_statement()
|
||||
o "IF Expression Block", -> new IfNode $2, $3
|
||||
o "UNLESS Expression Block", -> new IfNode $2, $3, {invert: true}
|
||||
o "IfBlock ELSE IF Expression Block", -> $1.addElse (new IfNode($4, $5)).forceStatement()
|
||||
o "IfBlock ELSE Block", -> $1.addElse $3
|
||||
]
|
||||
|
||||
# The full complement of *if* expressions, including postfix one-liner
|
||||
# *if* and *unless*.
|
||||
If: [
|
||||
o "IfBlock"
|
||||
o "Expression IF Expression", -> new IfNode $3, Expressions.wrap([$1]), null, {statement: true}
|
||||
o "Expression UNLESS Expression", -> new IfNode $3, Expressions.wrap([$1]), null, {statement: true, invert: true}
|
||||
o "Statement IF Expression", -> new IfNode $3, Expressions.wrap([$1]), {statement: true}
|
||||
o "Expression IF Expression", -> new IfNode $3, Expressions.wrap([$1]), {statement: true}
|
||||
o "Statement UNLESS Expression", -> new IfNode $3, Expressions.wrap([$1]), {statement: true, invert: true}
|
||||
o "Expression UNLESS Expression", -> new IfNode $3, Expressions.wrap([$1]), {statement: true, invert: true}
|
||||
]
|
||||
|
||||
# Arithmetic and logical operators, working on one or more operands.
|
||||
@@ -538,7 +538,7 @@ grammar: {
|
||||
|
||||
o "Expression && Expression", -> new OpNode '&&', $1, $3
|
||||
o "Expression || Expression", -> new OpNode '||', $1, $3
|
||||
o "Expression ? Expression", -> new OpNode '?', $1, $3
|
||||
o "Expression OP? Expression", -> new OpNode '?', $1, $3
|
||||
|
||||
o "Expression -= Expression", -> new OpNode '-=', $1, $3
|
||||
o "Expression += Expression", -> new OpNode '+=', $1, $3
|
||||
@@ -550,7 +550,10 @@ grammar: {
|
||||
o "Expression ?= Expression", -> new OpNode '?=', $1, $3
|
||||
|
||||
o "Expression INSTANCEOF Expression", -> new OpNode 'instanceof', $1, $3
|
||||
o "Expression IN Expression", -> new OpNode 'in', $1, $3
|
||||
o "Expression IN Expression", -> new InNode $1, $3
|
||||
o "Expression OF Expression", -> new OpNode 'in', $1, $3
|
||||
o "Expression ! IN Expression", -> new OpNode '!', new InNode $1, $4
|
||||
o "Expression ! OF Expression", -> new OpNode '!', new ParentheticalNode new OpNode 'in', $1, $4
|
||||
]
|
||||
|
||||
}
|
||||
@@ -576,16 +579,16 @@ operators: [
|
||||
["left", '<=', '<', '>', '>=']
|
||||
["right", 'DELETE', 'INSTANCEOF', 'TYPEOF']
|
||||
["left", '==', '!=']
|
||||
["left", '&&', '||']
|
||||
["left", '&&', '||', 'OP?']
|
||||
["right", '-=', '+=', '/=', '*=', '%=', '||=', '&&=', '?=']
|
||||
["left", '.']
|
||||
["right", 'INDENT']
|
||||
["left", 'OUTDENT']
|
||||
["right", 'WHEN', 'LEADING_WHEN', 'IN', 'OF', 'BY', 'THROW']
|
||||
["right", 'FOR', 'NEW', 'SUPER', 'CLASS']
|
||||
["right", 'FOR', 'WHILE', 'UNTIL', 'LOOP', 'NEW', 'SUPER', 'CLASS']
|
||||
["left", 'EXTENDS']
|
||||
["right", 'ASSIGN', 'RETURN']
|
||||
["right", '->', '=>', '<-', 'UNLESS', 'IF', 'ELSE', 'WHILE']
|
||||
["right", '->', '=>', 'UNLESS', 'IF', 'ELSE']
|
||||
]
|
||||
|
||||
# Wrapping Up
|
||||
|
||||
@@ -6,9 +6,17 @@
|
||||
this.exports: this unless process?
|
||||
helpers: exports.helpers: {}
|
||||
|
||||
# Cross-browser indexOf, so that IE can join the party.
|
||||
helpers.indexOf: indexOf: (array, item, from) ->
|
||||
return array.indexOf item, from if array.indexOf
|
||||
for other, index in array
|
||||
if other is item and (not from or (from <= index))
|
||||
return index
|
||||
-1
|
||||
|
||||
# Does a list include a value?
|
||||
helpers.include: include: (list, value) ->
|
||||
list.indexOf(value) >= 0
|
||||
indexOf(list, value) >= 0
|
||||
|
||||
# Peek at the beginning of a given string to see if it matches a sequence.
|
||||
helpers.starts: starts: (string, literal, start) ->
|
||||
@@ -20,10 +28,10 @@ helpers.compact: compact: (array) -> item for item in array when item
|
||||
# Count the number of occurences of a character in a string.
|
||||
helpers.count: count: (string, letter) ->
|
||||
num: 0
|
||||
pos: string.indexOf(letter)
|
||||
pos: indexOf string, letter
|
||||
while pos isnt -1
|
||||
num: + 1
|
||||
pos: string.indexOf(letter, pos + 1)
|
||||
pos: indexOf string, letter, pos + 1
|
||||
num
|
||||
|
||||
# Merge objects, returning a fresh copy with attributes from both sides.
|
||||
@@ -54,34 +62,3 @@ helpers.del: del: (obj, key) ->
|
||||
val: obj[key]
|
||||
delete obj[key]
|
||||
val
|
||||
|
||||
# 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
|
||||
# interpolations within strings, ad infinitum.
|
||||
helpers.balanced_string: balanced_string: (str, delimited, options) ->
|
||||
options: or {}
|
||||
slash: delimited[0][0] is '/'
|
||||
levels: []
|
||||
i: 0
|
||||
while i < str.length
|
||||
if levels.length and starts str, '\\', i
|
||||
i: + 1
|
||||
else
|
||||
for pair in delimited
|
||||
[open, close]: pair
|
||||
if levels.length and starts(str, close, i) and levels[levels.length - 1] is pair
|
||||
levels.pop()
|
||||
i: + close.length - 1
|
||||
i: + 1 unless levels.length
|
||||
break
|
||||
else if starts str, open, i
|
||||
levels.push(pair)
|
||||
i: + open.length - 1
|
||||
break
|
||||
break if not levels.length or slash and starts str, '\n', i
|
||||
i: + 1
|
||||
if levels.length
|
||||
return false if slash
|
||||
throw new Error "SyntaxError: Unterminated ${levels.pop()[0]} starting on line ${@line + 1}"
|
||||
if not i then false else str.substring(0, i)
|
||||
2
src/index.coffee
Normal file
2
src/index.coffee
Normal file
@@ -0,0 +1,2 @@
|
||||
# Loader for CoffeeScript as a Node.js library.
|
||||
(exports[key]: val) for key, val of require './coffee-script'
|
||||
353
src/lexer.coffee
353
src/lexer.coffee
@@ -3,25 +3,21 @@
|
||||
# a token is produced, we consume the match, and start again. Tokens are in the
|
||||
# form:
|
||||
#
|
||||
# [tag, value, line_number]
|
||||
# [tag, value, lineNumber]
|
||||
#
|
||||
# Which is a format that can be fed directly into [Jison](http://github.com/zaach/jison).
|
||||
|
||||
# Set up the Lexer for both Node.js and the browser, depending on where we are.
|
||||
if process?
|
||||
Rewriter: require('./rewriter').Rewriter
|
||||
helpers: require('./helpers').helpers
|
||||
{Rewriter}: require('./rewriter')
|
||||
{helpers}: require('./helpers')
|
||||
else
|
||||
this.exports: this
|
||||
Rewriter: this.Rewriter
|
||||
helpers: this.helpers
|
||||
|
||||
# Import the helpers we need.
|
||||
include: helpers.include
|
||||
count: helpers.count
|
||||
starts: helpers.starts
|
||||
compact: helpers.compact
|
||||
balanced_string: helpers.balanced_string
|
||||
{include, count, starts, compact}: helpers
|
||||
|
||||
# The Lexer Class
|
||||
# ---------------
|
||||
@@ -50,114 +46,130 @@ exports.Lexer: class Lexer
|
||||
@i : 0 # Current character position we're parsing.
|
||||
@line : o.line or 0 # The current line.
|
||||
@indent : 0 # The current indentation level.
|
||||
@outdebt : 0 # The under-outdentation of the last outdent.
|
||||
@indents : [] # The stack of all current indentation levels.
|
||||
@tokens : [] # Stream of parsed tokens in the form ['TYPE', value, line]
|
||||
while @i < @code.length
|
||||
@chunk: @code.slice @i
|
||||
@extract_next_token()
|
||||
@close_indentation()
|
||||
@extractNextToken()
|
||||
@closeIndentation()
|
||||
return @tokens if o.rewrite is off
|
||||
(new Rewriter()).rewrite @tokens
|
||||
(new Rewriter).rewrite @tokens
|
||||
|
||||
# At every position, run through this list of attempted matches,
|
||||
# short-circuiting if any of them succeed. Their order determines precedence:
|
||||
# `@literal_token` is the fallback catch-all.
|
||||
extract_next_token: ->
|
||||
return if @extension_token()
|
||||
return if @identifier_token()
|
||||
return if @number_token()
|
||||
return if @heredoc_token()
|
||||
return if @regex_token()
|
||||
return if @comment_token()
|
||||
return if @line_token()
|
||||
return if @whitespace_token()
|
||||
return if @js_token()
|
||||
return if @string_token()
|
||||
return @literal_token()
|
||||
# `@literalToken` is the fallback catch-all.
|
||||
extractNextToken: ->
|
||||
return if @identifierToken()
|
||||
return if @commentToken()
|
||||
return if @whitespaceToken()
|
||||
return if @lineToken()
|
||||
return if @heredocToken()
|
||||
return if @stringToken()
|
||||
return if @numberToken()
|
||||
return if @regexToken()
|
||||
return if @jsToken()
|
||||
return @literalToken()
|
||||
|
||||
# Tokenizers
|
||||
# ----------
|
||||
|
||||
# Language extensions get the highest priority, first chance to tag tokens
|
||||
# as something else.
|
||||
extension_token: ->
|
||||
for extension in Lexer.extensions
|
||||
return true if extension.call this
|
||||
false
|
||||
|
||||
# Matches identifying literals: variables, keywords, method names, etc.
|
||||
# Check to ensure that JavaScript reserved words aren't being used as
|
||||
# identifiers. Because CoffeeScript reserves a handful of keywords that are
|
||||
# allowed in JavaScript, we're careful not to tag them as keywords when
|
||||
# referenced as property names here, so you can still do `jQuery.is()` even
|
||||
# though `is` means `===` otherwise.
|
||||
identifier_token: ->
|
||||
identifierToken: ->
|
||||
return false unless id: @match IDENTIFIER, 1
|
||||
@name_access_type()
|
||||
accessed: include ACCESSORS, @tag 0
|
||||
tag: 'IDENTIFIER'
|
||||
tag: id.toUpperCase() if not accessed and include(KEYWORDS, id)
|
||||
@identifier_error id if include RESERVED, id
|
||||
tag: 'LEADING_WHEN' if tag is 'WHEN' and include LINE_BREAK, @tag()
|
||||
@i: + id.length
|
||||
if not accessed
|
||||
tag: id: CONVERSIONS[id] if include COFFEE_ALIASES, id
|
||||
return @tag_half_assignment tag if @prev() and @prev()[0] is 'ASSIGN' and include HALF_ASSIGNMENTS, tag
|
||||
forcedIdentifier: @tagAccessor() or @match ASSIGNED, 1
|
||||
tag: 'IDENTIFIER'
|
||||
tag: id.toUpperCase() if include(JS_KEYWORDS, id) or (not forcedIdentifier and include(COFFEE_KEYWORDS, id))
|
||||
tag: 'LEADING_WHEN' if tag is 'WHEN' and include LINE_BREAK, @tag()
|
||||
if include(JS_FORBIDDEN, id)
|
||||
if forcedIdentifier
|
||||
tag: 'STRING'
|
||||
id: "'$id'"
|
||||
if forcedIdentifier is 'accessor'
|
||||
close_index: true
|
||||
@tokens.pop() if @tag() isnt '@'
|
||||
@token 'INDEX_START', '['
|
||||
else if include(RESERVED, id)
|
||||
@identifierError id
|
||||
unless forcedIdentifier
|
||||
tag: id: CONVERSIONS[id] if include COFFEE_ALIASES, id
|
||||
return @tagHalfAssignment tag if @prev() and @prev()[0] is 'ASSIGN' and include HALF_ASSIGNMENTS, tag
|
||||
@token tag, id
|
||||
@token ']', ']' if close_index
|
||||
true
|
||||
|
||||
# Matches numbers, including decimals, hex, and exponential notation.
|
||||
number_token: ->
|
||||
# Be careful not to interfere with ranges-in-progress.
|
||||
numberToken: ->
|
||||
return false unless number: @match NUMBER, 1
|
||||
@token 'NUMBER', number
|
||||
return false if @tag() is '.' and starts number, '.'
|
||||
@i: + number.length
|
||||
@token 'NUMBER', number
|
||||
true
|
||||
|
||||
# Matches strings, including multi-line strings. Ensures that quotation marks
|
||||
# are balanced within the string's contents, and within nested interpolations.
|
||||
string_token: ->
|
||||
stringToken: ->
|
||||
return false unless starts(@chunk, '"') or starts(@chunk, "'")
|
||||
return false unless string:
|
||||
@balanced_token(['"', '"'], ['${', '}']) or
|
||||
@balanced_token ["'", "'"]
|
||||
@interpolate_string string.replace STRING_NEWLINES, " \\\n"
|
||||
@balancedToken(['"', '"'], ['${', '}']) or
|
||||
@balancedToken ["'", "'"]
|
||||
@interpolateString string.replace STRING_NEWLINES, " \\\n"
|
||||
@line: + count string, "\n"
|
||||
@i: + string.length
|
||||
true
|
||||
|
||||
# Matches heredocs, adjusting indentation to the correct level, as heredocs
|
||||
# preserve whitespace, but ignore indentation to the left.
|
||||
heredoc_token: ->
|
||||
heredocToken: ->
|
||||
return false unless match: @chunk.match(HEREDOC)
|
||||
quote: match[1].substr 0, 1
|
||||
doc: @sanitize_heredoc match[2] or match[4], quote
|
||||
@interpolate_string "$quote$doc$quote"
|
||||
doc: @sanitizeHeredoc match[2] or match[4], {quote}
|
||||
@interpolateString "$quote$doc$quote"
|
||||
@line: + count match[1], "\n"
|
||||
@i: + match[1].length
|
||||
true
|
||||
|
||||
# Matches and conumes comments.
|
||||
commentToken: ->
|
||||
return false unless match: @chunk.match(COMMENT)
|
||||
@line: + count match[1], "\n"
|
||||
@i: + match[1].length
|
||||
if match[2]
|
||||
comment: @sanitizeHeredoc match[2], {herecomment: true}
|
||||
@token 'HERECOMMENT', comment.split MULTILINER
|
||||
@token 'TERMINATOR', '\n'
|
||||
true
|
||||
|
||||
# Matches JavaScript interpolated directly into the source via backticks.
|
||||
js_token: ->
|
||||
jsToken: ->
|
||||
return false unless starts @chunk, '`'
|
||||
return false unless script: @balanced_token ['`', '`']
|
||||
return false unless script: @balancedToken ['`', '`']
|
||||
@token 'JS', script.replace JS_CLEANER, ''
|
||||
@i: + script.length
|
||||
true
|
||||
|
||||
# Matches regular expression literals. Lexing regular expressions is difficult
|
||||
# to distinguish from division, so we borrow some basic heuristics from
|
||||
# JavaScript and Ruby, borrow slash balancing from `@balanced_token`, and
|
||||
# borrow interpolation from `@interpolate_string`.
|
||||
regex_token: ->
|
||||
# JavaScript and Ruby, borrow slash balancing from `@balancedToken`, and
|
||||
# borrow interpolation from `@interpolateString`.
|
||||
regexToken: ->
|
||||
return false unless @chunk.match REGEX_START
|
||||
return false if include NOT_REGEX, @tag()
|
||||
return false unless regex: @balanced_token ['/', '/']
|
||||
regex: + (flags: @chunk.substr(regex.length).match REGEX_FLAGS)
|
||||
return false unless regex: @balancedToken ['/', '/']
|
||||
return false unless end: @chunk.substr(regex.length).match REGEX_END
|
||||
regex: + flags: end[2] if end[2]
|
||||
if regex.match REGEX_INTERPOLATION
|
||||
str: regex.substring(1).split('/')[0]
|
||||
str: str.replace REGEX_ESCAPE, (escaped) -> '\\' + escaped
|
||||
@tokens: @tokens.concat [['(', '('], ['NEW', 'new'], ['IDENTIFIER', 'RegExp'], ['CALL_START', '(']]
|
||||
@interpolate_string "\"$str\"", yes
|
||||
@interpolateString "\"$str\"", yes
|
||||
@tokens: @tokens.concat [[',', ','], ['STRING', "\"$flags\""], [')', ')'], [')', ')']]
|
||||
else
|
||||
@token 'REGEX', regex
|
||||
@@ -166,21 +178,8 @@ exports.Lexer: class Lexer
|
||||
|
||||
# Matches a token in which which the passed delimiter pairs must be correctly
|
||||
# balanced (ie. strings, JS literals).
|
||||
balanced_token: (delimited...) ->
|
||||
balanced_string @chunk, delimited
|
||||
|
||||
# Matches and conumes comments. We pass through comments into JavaScript,
|
||||
# so they're treated as real tokens, like any other part of the language.
|
||||
comment_token: ->
|
||||
return false unless comment: @match COMMENT, 1
|
||||
@line: + (comment.match(MULTILINER) or []).length
|
||||
lines: compact comment.replace(COMMENT_CLEANER, '').split MULTILINER
|
||||
i: @tokens.length - 1
|
||||
if @unfinished()
|
||||
i: - 1 while @tokens[i] and not include LINE_BREAK, @tokens[i][0]
|
||||
@tokens.splice(i + 1, 0, ['COMMENT', lines, @line], ['TERMINATOR', '\n', @line])
|
||||
@i: + comment.length
|
||||
true
|
||||
balancedToken: (delimited...) ->
|
||||
@balancedString @chunk, delimited
|
||||
|
||||
# Matches newlines, indents, and outdents, and determines which is which.
|
||||
# If we can detect that the current line is continued onto the the next line,
|
||||
@@ -192,40 +191,44 @@ exports.Lexer: class Lexer
|
||||
#
|
||||
# Keeps track of the level of indentation, because a single outdent token
|
||||
# can close multiple indents, so we need to know how far in we happen to be.
|
||||
line_token: ->
|
||||
lineToken: ->
|
||||
return false unless indent: @match MULTI_DENT, 1
|
||||
@line: + indent.match(MULTILINER).length
|
||||
@line: + count indent, "\n"
|
||||
@i : + indent.length
|
||||
prev: @prev(2)
|
||||
size: indent.match(LAST_DENTS).reverse()[0].match(LAST_DENT)[1].length
|
||||
next_character: @chunk.match(MULTI_DENT)[4]
|
||||
no_newlines: next_character is '.' or @unfinished()
|
||||
nextCharacter: @match NEXT_CHARACTER, 1
|
||||
noNewlines: nextCharacter is '.' or nextCharacter is ',' or @unfinished()
|
||||
if size is @indent
|
||||
return @suppress_newlines() if no_newlines
|
||||
return @newline_token indent
|
||||
return @suppressNewlines() if noNewlines
|
||||
return @newlineToken indent
|
||||
else if size > @indent
|
||||
return @suppress_newlines() if no_newlines
|
||||
return @suppressNewlines() if noNewlines
|
||||
diff: size - @indent
|
||||
@token 'INDENT', diff
|
||||
@indents.push diff
|
||||
else
|
||||
@outdent_token @indent - size, no_newlines
|
||||
@outdentToken @indent - size, noNewlines
|
||||
@indent: size
|
||||
true
|
||||
|
||||
# Record an outdent token or multiple tokens, if we happen to be moving back
|
||||
# inwards past several recorded indents.
|
||||
outdent_token: (move_out, no_newlines) ->
|
||||
while move_out > 0 and @indents.length
|
||||
last_indent: @indents.pop()
|
||||
@token 'OUTDENT', last_indent
|
||||
move_out: - last_indent
|
||||
@token 'TERMINATOR', "\n" unless @tag() is 'TERMINATOR' or no_newlines
|
||||
outdentToken: (moveOut, noNewlines) ->
|
||||
if moveOut > -@outdebt
|
||||
while moveOut > 0 and @indents.length
|
||||
lastIndent: @indents.pop()
|
||||
@token 'OUTDENT', lastIndent
|
||||
moveOut: - lastIndent
|
||||
else
|
||||
@outdebt: + moveOut
|
||||
@outdebt: moveOut unless noNewlines
|
||||
@token 'TERMINATOR', "\n" unless @tag() is 'TERMINATOR' or noNewlines
|
||||
true
|
||||
|
||||
# Matches and consumes non-meaningful whitespace. Tag the previous token
|
||||
# as being "spaced", because there are some cases where it makes a difference.
|
||||
whitespace_token: ->
|
||||
whitespaceToken: ->
|
||||
return false unless space: @match WHITESPACE, 1
|
||||
prev: @prev()
|
||||
prev.spaced: true if prev
|
||||
@@ -233,13 +236,13 @@ exports.Lexer: class Lexer
|
||||
true
|
||||
|
||||
# Generate a newline token. Consecutive newlines get merged together.
|
||||
newline_token: (newlines) ->
|
||||
newlineToken: (newlines) ->
|
||||
@token 'TERMINATOR', "\n" unless @tag() is 'TERMINATOR'
|
||||
true
|
||||
|
||||
# Use a `\` at a line-ending to suppress the newline.
|
||||
# The slash is removed here once its job is done.
|
||||
suppress_newlines: ->
|
||||
suppressNewlines: ->
|
||||
@tokens.pop() if @value() is "\\"
|
||||
true
|
||||
|
||||
@@ -248,31 +251,30 @@ exports.Lexer: class Lexer
|
||||
# the proper order of operations. There are some symbols that we tag specially
|
||||
# here. `;` and newlines are both treated as a `TERMINATOR`, we distinguish
|
||||
# parentheses that indicate a method call from regular parentheses, and so on.
|
||||
literal_token: ->
|
||||
literalToken: ->
|
||||
match: @chunk.match OPERATOR
|
||||
value: match and match[1]
|
||||
space: match and match[2]
|
||||
@tag_parameters() if value and value.match CODE
|
||||
@tagParameters() if value and value.match CODE
|
||||
value: or @chunk.substr 0, 1
|
||||
prev_spaced: @prev() and @prev().spaced
|
||||
prevSpaced: @prev() and @prev().spaced
|
||||
tag: value
|
||||
if value.match ASSIGNMENT
|
||||
tag: 'ASSIGN'
|
||||
@assignment_error() if include JS_FORBIDDEN, @value
|
||||
@assignmentError() if include JS_FORBIDDEN, @value
|
||||
else if value is ';'
|
||||
tag: 'TERMINATOR'
|
||||
else if value is '[' and @tag() is '?' and not prev_spaced
|
||||
tag: 'SOAKED_INDEX_START'
|
||||
@soaked_index: true
|
||||
@tokens.pop()
|
||||
else if value is ']' and @soaked_index
|
||||
tag: 'SOAKED_INDEX_END'
|
||||
@soaked_index: false
|
||||
else if include(CALLABLE, @tag()) and not prev_spaced
|
||||
tag: 'CALL_START' if value is '('
|
||||
tag: 'INDEX_START' if value is '['
|
||||
else if value is '?' and prevSpaced
|
||||
tag: 'OP?'
|
||||
else if include(CALLABLE, @tag()) and not prevSpaced
|
||||
if value is '('
|
||||
tag: 'CALL_START'
|
||||
else if value is '['
|
||||
tag: 'INDEX_START'
|
||||
@tag 1, 'INDEX_SOAK' if @tag() is '?'
|
||||
@tag 1, 'INDEX_PROTO' if @tag() is '::'
|
||||
@i: + value.length
|
||||
return @tag_half_assignment tag if space and prev_spaced and @prev()[0] is 'ASSIGN' and include HALF_ASSIGNMENTS, tag
|
||||
return @tagHalfAssignment tag if space and prevSpaced and @prev()[0] is 'ASSIGN' and include HALF_ASSIGNMENTS, tag
|
||||
@token tag, value
|
||||
true
|
||||
|
||||
@@ -280,26 +282,36 @@ exports.Lexer: class Lexer
|
||||
# ------------------
|
||||
|
||||
# As we consume a new `IDENTIFIER`, look at the previous token to determine
|
||||
# if it's a special kind of accessor.
|
||||
name_access_type: ->
|
||||
@tag(1, 'PROTOTYPE_ACCESS') if @value() is '::'
|
||||
if @value() is '.' and not (@value(2) is '.')
|
||||
# if it's a special kind of accessor. Return `true` if any type of accessor
|
||||
# is the previous token.
|
||||
tagAccessor: ->
|
||||
return false if (not prev: @prev()) or (prev and prev.spaced)
|
||||
accessor: if prev[1] is '::'
|
||||
@tag 1, 'PROTOTYPE_ACCESS'
|
||||
else if prev[1] is '.' and not (@value(2) is '.')
|
||||
if @tag(2) is '?'
|
||||
@tag(1, 'SOAK_ACCESS')
|
||||
@tokens.splice(-2, 1)
|
||||
else
|
||||
@tag 1, 'PROPERTY_ACCESS'
|
||||
else
|
||||
prev[0] is '@'
|
||||
if accessor then 'accessor' else false
|
||||
|
||||
# Sanitize a heredoc by escaping internal double quotes and erasing all
|
||||
# external indentation on the left-hand side.
|
||||
sanitize_heredoc: (doc, quote) ->
|
||||
indent: (doc.match(HEREDOC_INDENT) or ['']).sort()[0]
|
||||
doc.replace(new RegExp("^" +indent, 'gm'), '')
|
||||
.replace(MULTILINER, "\\n")
|
||||
.replace(new RegExp(quote, 'g'), '\\"')
|
||||
# Sanitize a heredoc or herecomment by escaping internal double quotes and
|
||||
# erasing all external indentation on the left-hand side.
|
||||
sanitizeHeredoc: (doc, options) ->
|
||||
while match: HEREDOC_INDENT.exec doc
|
||||
attempt: if match[2]? then match[2] else match[3]
|
||||
indent: attempt if not indent or attempt.length < indent.length
|
||||
doc: doc.replace(new RegExp("^" +indent, 'gm'), '')
|
||||
return doc if options.herecomment
|
||||
doc.replace(MULTILINER, "\\n")
|
||||
.replace(new RegExp(options.quote, 'g'), "\\$options.quote")
|
||||
|
||||
# Tag a half assignment.
|
||||
tag_half_assignment: (tag) ->
|
||||
tagHalfAssignment: (tag) ->
|
||||
tag: '?' if tag is 'OP?'
|
||||
last: @tokens.pop()
|
||||
@tokens.push ["$tag=", "$tag=", last[2]]
|
||||
true
|
||||
@@ -307,33 +319,64 @@ exports.Lexer: class Lexer
|
||||
# A source of ambiguity in our grammar used to be parameter lists in function
|
||||
# definitions versus argument lists in function calls. Walk backwards, tagging
|
||||
# parameters specially in order to make things easier for the parser.
|
||||
tag_parameters: ->
|
||||
tagParameters: ->
|
||||
return if @tag() isnt ')'
|
||||
i: 0
|
||||
while true
|
||||
loop
|
||||
i: + 1
|
||||
tok: @prev i
|
||||
return if not tok
|
||||
switch tok[0]
|
||||
when 'IDENTIFIER' then tok[0]: 'PARAM'
|
||||
when ')' then tok[0]: 'PARAM_END'
|
||||
when '(' then return tok[0]: 'PARAM_START'
|
||||
when 'IDENTIFIER' then tok[0]: 'PARAM'
|
||||
when ')' then tok[0]: 'PARAM_END'
|
||||
when '(', 'CALL_START' then return tok[0]: 'PARAM_START'
|
||||
true
|
||||
|
||||
# Close up all remaining open blocks at the end of the file.
|
||||
close_indentation: ->
|
||||
@outdent_token @indent
|
||||
closeIndentation: ->
|
||||
@outdentToken @indent
|
||||
|
||||
# The error for when you try to use a forbidden word in JavaScript as
|
||||
# an identifier.
|
||||
identifier_error: (word) ->
|
||||
identifierError: (word) ->
|
||||
throw new Error "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".
|
||||
assignment_error: ->
|
||||
assignmentError: ->
|
||||
throw new Error "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
|
||||
# interpolations within strings, ad infinitum.
|
||||
balancedString: (str, delimited, options) ->
|
||||
options: or {}
|
||||
slash: delimited[0][0] is '/'
|
||||
levels: []
|
||||
i: 0
|
||||
while i < str.length
|
||||
if levels.length and starts str, '\\', i
|
||||
i: + 1
|
||||
else
|
||||
for pair in delimited
|
||||
[open, close]: pair
|
||||
if levels.length and starts(str, close, i) and levels[levels.length - 1] is pair
|
||||
levels.pop()
|
||||
i: + close.length - 1
|
||||
i: + 1 unless levels.length
|
||||
break
|
||||
else if starts str, open, i
|
||||
levels.push(pair)
|
||||
i: + open.length - 1
|
||||
break
|
||||
break if not levels.length or slash and starts str, '\n', i
|
||||
i: + 1
|
||||
if levels.length
|
||||
return false if slash
|
||||
throw new Error "SyntaxError: Unterminated ${levels.pop()[0]} starting on line ${@line + 1}"
|
||||
if not i then false else str.substring(0, i)
|
||||
|
||||
# Expand variables and expressions inside double-quoted strings using
|
||||
# [ECMA Harmony's interpolation syntax](http://wiki.ecmascript.org/doku.php?id=strawman:string_interpolation)
|
||||
# for substitution of bare variables as well as arbitrary expressions.
|
||||
@@ -344,11 +387,11 @@ exports.Lexer: class Lexer
|
||||
# If it encounters an interpolation, this method will recursively create a
|
||||
# new Lexer, tokenize the interpolated contents, and merge them into the
|
||||
# token stream.
|
||||
interpolate_string: (str, escape_quotes) ->
|
||||
interpolateString: (str, escapeQuotes) ->
|
||||
if str.length < 3 or not starts str, '"'
|
||||
@token 'STRING', str
|
||||
else
|
||||
lexer: new Lexer()
|
||||
lexer: new Lexer
|
||||
tokens: []
|
||||
quote: str.substring 0, 1
|
||||
[i, pi]: [1, 1]
|
||||
@@ -362,11 +405,13 @@ exports.Lexer: class Lexer
|
||||
tokens.push ['IDENTIFIER', interp]
|
||||
i: + group.length - 1
|
||||
pi: i + 1
|
||||
else if (expr: balanced_string str.substring(i), [['${', '}']])
|
||||
else if (expr: @balancedString str.substring(i), [['${', '}']])
|
||||
tokens.push ['STRING', "$quote${ str.substring(pi, i) }$quote"] if pi < i
|
||||
inner: expr.substring(2, expr.length - 1)
|
||||
if inner.length
|
||||
nested: lexer.tokenize "($inner)", {rewrite: no, line: @line}
|
||||
inner: inner.replace new RegExp('\\\\' + quote, 'g'), quote
|
||||
nested: lexer.tokenize "($inner)", {line: @line}
|
||||
(tok[0]: ')') for tok, idx in nested when tok[0] is 'CALL_END'
|
||||
nested.pop()
|
||||
tokens.push ['TOKENS', nested]
|
||||
else
|
||||
@@ -376,16 +421,19 @@ exports.Lexer: class Lexer
|
||||
i: + 1
|
||||
tokens.push ['STRING', "$quote${ str.substring(pi, i) }$quote"] if pi < i and pi < str.length - 1
|
||||
tokens.unshift ['STRING', '""'] unless tokens[0][0] is 'STRING'
|
||||
interpolated: tokens.length > 1
|
||||
@token '(', '(' if interpolated
|
||||
for token, i in tokens
|
||||
[tag, value]: token
|
||||
if tag is 'TOKENS'
|
||||
@tokens: @tokens.concat value
|
||||
else if tag is 'STRING' and escape_quotes
|
||||
else if tag is 'STRING' and escapeQuotes
|
||||
escaped: value.substring(1, value.length - 1).replace(/"/g, '\\"')
|
||||
@token tag, "\"$escaped\""
|
||||
else
|
||||
@token tag, value
|
||||
@token '+', '+' if i < tokens.length - 1
|
||||
@token ')', ')' if interpolated
|
||||
tokens
|
||||
|
||||
# Helpers
|
||||
@@ -396,9 +444,9 @@ exports.Lexer: class Lexer
|
||||
@tokens.push [tag, value, @line]
|
||||
|
||||
# Peek at a tag in the current token stream.
|
||||
tag: (index, tag) ->
|
||||
tag: (index, newTag) ->
|
||||
return unless tok: @prev index
|
||||
return tok[0]: tag if tag?
|
||||
return tok[0]: newTag if newTag?
|
||||
tok[0]
|
||||
|
||||
# Peek at a value in the current token stream.
|
||||
@@ -423,12 +471,6 @@ exports.Lexer: class Lexer
|
||||
@value() and @value().match and @value().match(NO_NEWLINE) and
|
||||
prev and (prev[0] isnt '.') and not @value().match(CODE)
|
||||
|
||||
# Lexer Properties
|
||||
# ----------------
|
||||
|
||||
# There are no exensions to the core lexer by default.
|
||||
@extensions: []
|
||||
|
||||
# Constants
|
||||
# ---------
|
||||
|
||||
@@ -449,21 +491,17 @@ JS_KEYWORDS: [
|
||||
# be used standalone, but you can reference them as an attached property.
|
||||
COFFEE_ALIASES: ["and", "or", "is", "isnt", "not"]
|
||||
COFFEE_KEYWORDS: COFFEE_ALIASES.concat [
|
||||
"then", "unless",
|
||||
"then", "unless", "until", "loop",
|
||||
"yes", "no", "on", "off",
|
||||
"of", "by", "where", "when"
|
||||
]
|
||||
|
||||
# The combined list of keywords is the superset that gets passed verbatim to
|
||||
# the parser.
|
||||
KEYWORDS: JS_KEYWORDS.concat COFFEE_KEYWORDS
|
||||
|
||||
# The list of keywords that are reserved by JavaScript, but not used, or are
|
||||
# used by CoffeeScript internally. We throw an error when these are encountered,
|
||||
# to avoid having a JavaScript error at runtime.
|
||||
RESERVED: [
|
||||
"case", "default", "do", "function", "var", "void", "with"
|
||||
"const", "let", "debugger", "enum", "export", "import", "native"
|
||||
"const", "let", "enum", "export", "import", "native"
|
||||
]
|
||||
|
||||
# The superset of both JavaScript keywords and reserved words, none of which may
|
||||
@@ -472,31 +510,32 @@ JS_FORBIDDEN: JS_KEYWORDS.concat RESERVED
|
||||
|
||||
# Token matching regexes.
|
||||
IDENTIFIER : /^([a-zA-Z\$_](\w|\$)*)/
|
||||
NUMBER : /^(\b((0(x|X)[0-9a-fA-F]+)|([0-9]+(\.[0-9]+)?(e[+\-]?[0-9]+)?)))\b/i
|
||||
NUMBER : /^(((\b0(x|X)[0-9a-fA-F]+)|((\b[0-9]+(\.[0-9]+)?|\.[0-9]+)(e[+\-]?[0-9]+)?)))\b/i
|
||||
HEREDOC : /^("{6}|'{6}|"{3}\n?([\s\S]*?)\n?([ \t]*)"{3}|'{3}\n?([\s\S]*?)\n?([ \t]*)'{3})/
|
||||
INTERPOLATION : /^\$([a-zA-Z_@]\w*(\.\w+)*)/
|
||||
OPERATOR : /^([+\*&|\/\-%=<>:!?]+)([ \t]*)/
|
||||
OPERATOR : /^(-[\-=>]?|\+[+=]?|[*&|\/%=<>:!?]+)([ \t]*)/
|
||||
WHITESPACE : /^([ \t]+)/
|
||||
COMMENT : /^(((\n?[ \t]*)?#[^\n]*)+)/
|
||||
COMMENT : /^(\s*#{3}(?!#)[ \t]*\n+([\s\S]*?)[ \t]*\n+[ \t]*#{3}|(\s*#(?!##[^#])[^\n]*)+)/
|
||||
CODE : /^((-|=)>)/
|
||||
MULTI_DENT : /^((\n([ \t]*))+)(\.)?/
|
||||
LAST_DENTS : /\n([ \t]*)/g
|
||||
LAST_DENT : /\n([ \t]*)/
|
||||
ASSIGNMENT : /^(:|=)$/
|
||||
ASSIGNMENT : /^[:=]$/
|
||||
|
||||
# Regex-matching-regexes.
|
||||
REGEX_START : /^\/[^\/ ]/
|
||||
REGEX_INTERPOLATION: /([^\\]\$[a-zA-Z_@]|[^\\]\$\{.*[^\\]\})/
|
||||
REGEX_FLAGS : /^[imgy]{0,4}/
|
||||
REGEX_END : /^(([imgy]{1,4})\b|\W|$)/
|
||||
REGEX_ESCAPE : /\\[^\$]/g
|
||||
|
||||
# Token cleaning regexes.
|
||||
JS_CLEANER : /(^`|`$)/g
|
||||
MULTILINER : /\n/g
|
||||
STRING_NEWLINES : /\n[ \t]*/g
|
||||
COMMENT_CLEANER : /(^[ \t]*#|\n[ \t]*$)/mg
|
||||
NO_NEWLINE : /^([+\*&|\/\-%=<>:!.\\][<>=&|]*|and|or|is|isnt|not|delete|typeof|instanceof)$/
|
||||
HEREDOC_INDENT : /^[ \t]+/mg
|
||||
HEREDOC_INDENT : /(\n+([ \t]*)|^([ \t]+))/g
|
||||
ASSIGNED : /^([a-zA-Z\$_]\w*[ \t]*?[:=][^=])/
|
||||
NEXT_CHARACTER : /^\s*(\S)/
|
||||
|
||||
# Tokens which a regular expression will never immediately follow, but which
|
||||
# a division operator might.
|
||||
@@ -505,17 +544,13 @@ HEREDOC_INDENT : /^[ \t]+/mg
|
||||
#
|
||||
# Our list is shorter, due to sans-parentheses method calls.
|
||||
NOT_REGEX: [
|
||||
'NUMBER', 'REGEX', '++', '--', 'FALSE', 'NULL', 'TRUE'
|
||||
'NUMBER', 'REGEX', '++', '--', 'FALSE', 'NULL', 'TRUE', ']'
|
||||
]
|
||||
|
||||
# Tokens which could legitimately be invoked or indexed. A opening
|
||||
# parentheses or bracket following these tokens will be recorded as the start
|
||||
# of a function invocation or indexing operation.
|
||||
CALLABLE: ['IDENTIFIER', 'SUPER', ')', ']', '}', 'STRING', '@', 'THIS']
|
||||
|
||||
# Tokens that indicate an access -- keywords immediately following will be
|
||||
# treated as identifiers.
|
||||
ACCESSORS: ['PROPERTY_ACCESS', 'PROTOTYPE_ACCESS', 'SOAK_ACCESS', '@']
|
||||
CALLABLE: ['IDENTIFIER', 'SUPER', ')', ']', '}', 'STRING', '@', 'THIS', '?', '::']
|
||||
|
||||
# Tokens that, when immediately preceding a `WHEN`, indicate that the `WHEN`
|
||||
# occurs at the start of a line. We disambiguate these from trailing whens to
|
||||
@@ -523,7 +558,7 @@ ACCESSORS: ['PROPERTY_ACCESS', 'PROTOTYPE_ACCESS', 'SOAK_ACCESS', '@']
|
||||
LINE_BREAK: ['INDENT', 'OUTDENT', 'TERMINATOR']
|
||||
|
||||
# Half-assignments...
|
||||
HALF_ASSIGNMENTS: ['-', '+', '/', '*', '%', '||', '&&', '?']
|
||||
HALF_ASSIGNMENTS: ['-', '+', '/', '*', '%', '||', '&&', '?', 'OP?']
|
||||
|
||||
# Conversions from CoffeeScript operators into JavaScript ones.
|
||||
CONVERSIONS: {
|
||||
|
||||
1192
src/nodes.coffee
1192
src/nodes.coffee
File diff suppressed because it is too large
Load Diff
@@ -1,8 +1,11 @@
|
||||
# A simple **OptionParser** class to parse option flags from the command-line.
|
||||
# Use it like so:
|
||||
#
|
||||
# parser: new OptionParser switches, help_banner
|
||||
# parser: new OptionParser switches, helpBanner
|
||||
# options: parser.parse process.argv
|
||||
#
|
||||
# The first non-option is considered to be the start of the file (and file
|
||||
# option) list, and all subsequent arguments are left unparsed.
|
||||
exports.OptionParser: class OptionParser
|
||||
|
||||
# Initialize with a list of valid options, in the form:
|
||||
@@ -12,7 +15,7 @@ exports.OptionParser: class OptionParser
|
||||
# Along with an an optional banner for the usage help.
|
||||
constructor: (rules, banner) ->
|
||||
@banner: banner
|
||||
@rules: build_rules(rules)
|
||||
@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
|
||||
@@ -21,17 +24,19 @@ exports.OptionParser: class OptionParser
|
||||
# flag. Instead, you're responsible for interpreting the options object.
|
||||
parse: (args) ->
|
||||
options: {arguments: []}
|
||||
args: normalize_arguments args
|
||||
while (arg: args.shift())
|
||||
is_option: !!(arg.match(LONG_FLAG) or arg.match(SHORT_FLAG))
|
||||
matched_rule: no
|
||||
args: normalizeArguments args
|
||||
for arg, i in args
|
||||
isOption: !!(arg.match(LONG_FLAG) or arg.match(SHORT_FLAG))
|
||||
matchedRule: no
|
||||
for rule in @rules
|
||||
if rule.short_flag is arg or rule.long_flag is arg
|
||||
options[rule.name]: if rule.has_argument then args.shift() else true
|
||||
matched_rule: yes
|
||||
if rule.shortFlag is arg or rule.longFlag is arg
|
||||
options[rule.name]: if rule.hasArgument then args[i: + 1] else true
|
||||
matchedRule: yes
|
||||
break
|
||||
throw new Error "unrecognized option: $arg" if is_option and not matched_rule
|
||||
options.arguments.push arg unless is_option
|
||||
throw new Error "unrecognized option: $arg" if isOption and not matchedRule
|
||||
if not isOption
|
||||
options.arguments: args[i...args.length]
|
||||
break
|
||||
options
|
||||
|
||||
# Return the help text for this **OptionParser**, listing and describing all
|
||||
@@ -40,10 +45,10 @@ exports.OptionParser: class OptionParser
|
||||
lines: ['Available options:']
|
||||
lines.unshift "$@banner\n" if @banner
|
||||
for rule in @rules
|
||||
spaces: 15 - rule.long_flag.length
|
||||
spaces: 15 - rule.longFlag.length
|
||||
spaces: if spaces > 0 then (' ' for i in [0..spaces]).join('') else ''
|
||||
let_part: if rule.short_flag then rule.short_flag + ', ' else ' '
|
||||
lines.push " $let_part${rule.long_flag}$spaces${rule.description}"
|
||||
letPart: if rule.shortFlag then rule.shortFlag + ', ' else ' '
|
||||
lines.push " $letPart$rule.longFlag$spaces$rule.description"
|
||||
"\n${ lines.join('\n') }\n"
|
||||
|
||||
# Helpers
|
||||
@@ -57,27 +62,27 @@ OPTIONAL: /\[(.+)\]/
|
||||
|
||||
# Build and return the list of option rules. If the optional *short-flag* is
|
||||
# unspecified, leave it out by padding with `null`.
|
||||
build_rules: (rules) ->
|
||||
buildRules: (rules) ->
|
||||
for tuple in rules
|
||||
tuple.unshift null if tuple.length < 3
|
||||
build_rule tuple...
|
||||
buildRule tuple...
|
||||
|
||||
# Build a rule from a `-o` short flag, a `--output [DIR]` long flag, and the
|
||||
# description of what the option does.
|
||||
build_rule: (short_flag, long_flag, description) ->
|
||||
match: long_flag.match(OPTIONAL)
|
||||
long_flag: long_flag.match(LONG_FLAG)[1]
|
||||
buildRule: (shortFlag, longFlag, description) ->
|
||||
match: longFlag.match(OPTIONAL)
|
||||
longFlag: longFlag.match(LONG_FLAG)[1]
|
||||
{
|
||||
name: long_flag.substr 2
|
||||
short_flag: short_flag
|
||||
long_flag: long_flag
|
||||
name: longFlag.substr 2
|
||||
shortFlag: shortFlag
|
||||
longFlag: longFlag
|
||||
description: description
|
||||
has_argument: !!(match and match[1])
|
||||
hasArgument: !!(match and match[1])
|
||||
}
|
||||
|
||||
# Normalize arguments by expanding merged flags into multiple flags. This allows
|
||||
# you to have `-wl` be the same as `--watch --lint`.
|
||||
normalize_arguments: (args) ->
|
||||
normalizeArguments: (args) ->
|
||||
args: args.slice 0
|
||||
result: []
|
||||
for arg in args
|
||||
|
||||
@@ -7,9 +7,10 @@
|
||||
# Require the **coffee-script** module to get access to the compiler.
|
||||
CoffeeScript: require './coffee-script'
|
||||
helpers: require('./helpers').helpers
|
||||
readline: require 'readline'
|
||||
|
||||
# Our prompt.
|
||||
prompt: 'coffee> '
|
||||
# Start by opening up **stdio**.
|
||||
stdio: process.openStdin()
|
||||
|
||||
# Quick alias for quitting the REPL.
|
||||
helpers.extend global, {
|
||||
@@ -19,15 +20,18 @@ helpers.extend global, {
|
||||
# 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: (code) ->
|
||||
run: (buffer) ->
|
||||
try
|
||||
val: CoffeeScript.run code, {no_wrap: true, globals: true, source: 'repl'}
|
||||
p val if val isnt undefined
|
||||
val: CoffeeScript.run buffer.toString(), {noWrap: true, globals: true, source: 'repl'}
|
||||
puts inspect val if val isnt undefined
|
||||
catch err
|
||||
puts err.stack or err.toString()
|
||||
print prompt
|
||||
repl.prompt()
|
||||
|
||||
# Start up the REPL by opening **stdio** and listening for input.
|
||||
process.stdio.addListener 'data', run
|
||||
process.stdio.open()
|
||||
print prompt
|
||||
# Create the REPL by listening to **stdin**.
|
||||
repl: readline.createInterface stdio
|
||||
repl.setPrompt 'coffee> '
|
||||
stdio.addListener 'data', (buffer) -> repl.write buffer
|
||||
repl.addListener 'close', -> stdio.destroy()
|
||||
repl.addListener 'line', run
|
||||
repl.prompt()
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user