pax_global_header00006660000000000000000000000064120416007530014510gustar00rootroot0000000000000052 comment=158d37215a963c67e002b953041d7d499b6fcbeb coffee-script-1.4.0/000077500000000000000000000000001204160075300142435ustar00rootroot00000000000000coffee-script-1.4.0/.gitignore000066400000000000000000000002071204160075300162320ustar00rootroot00000000000000raw presentation test.coffee parser.output test/fixtures/underscore test/*.js examples/beautiful_code/parse.coffee *.gem /node_modules coffee-script-1.4.0/.npmignore000066400000000000000000000001521204160075300162400ustar00rootroot00000000000000*.coffee *.html .DS_Store .git* Cakefile documentation/ examples/ extras/coffee-script.js raw/ src/ test/ coffee-script-1.4.0/CNAME000066400000000000000000000000201204160075300150010ustar00rootroot00000000000000coffeescript.orgcoffee-script-1.4.0/CONTRIBUTING.md000066400000000000000000000014501204160075300164740ustar00rootroot00000000000000## How to contribute to CoffeeScript * Before you open a ticket or send a pull request, [search](https://github.com/jashkenas/coffee-script/issues) for previous discussions about the same feature or issue. Add to the earlier ticket if you find one. * Before sending a pull request for a feature, be sure to have [tests](https://github.com/jashkenas/coffee-script/tree/master/test). * Use the same coding style as the rest of the [codebase](https://github.com/jashkenas/coffee-script/tree/master/src). If you're just getting started with CoffeeScript, there's a nice [style guide](https://github.com/polarmobile/coffeescript-style-guide). * In your pull request, do not add documentation to `index.html` or re-build the minified `coffee-script.js` file. We'll do those things before cutting a new release.coffee-script-1.4.0/Cakefile000066400000000000000000000205521204160075300156750ustar00rootroot00000000000000fs = require 'fs' path = require 'path' {extend} = require './lib/coffee-script/helpers' CoffeeScript = require './lib/coffee-script' {spawn, exec} = require 'child_process' # ANSI Terminal Colors. enableColors = no unless process.platform is 'win32' enableColors = not process.env.NODE_DISABLE_COLORS bold = red = green = reset = '' if enableColors bold = '\x1B[0;1m' red = '\x1B[0;31m' green = '\x1B[0;32m' reset = '\x1B[0m' # Built file header. header = """ /** * CoffeeScript Compiler v#{CoffeeScript.VERSION} * http://coffeescript.org * * Copyright 2011, Jeremy Ashkenas * Released under the MIT License */ """ sources = [ 'coffee-script', 'grammar', 'helpers' 'lexer', 'nodes', 'rewriter', 'scope' ].map (filename) -> "src/#{filename}.coffee" # Run a CoffeeScript through our node/coffee interpreter. run = (args, cb) -> proc = spawn 'node', ['bin/coffee'].concat(args) proc.stderr.on 'data', (buffer) -> console.log buffer.toString() proc.on 'exit', (status) -> process.exit(1) if status != 0 cb() if typeof cb is 'function' # Log a message with a color. log = (message, color, explanation) -> console.log color + message + reset + ' ' + (explanation or '') option '-p', '--prefix [DIR]', 'set the installation prefix for `cake install`' task 'install', 'install CoffeeScript into /usr/local (or --prefix)', (options) -> base = options.prefix or '/usr/local' lib = "#{base}/lib/coffee-script" bin = "#{base}/bin" node = "~/.node_libraries/coffee-script" console.log "Installing CoffeeScript to #{lib}" console.log "Linking to #{node}" console.log "Linking 'coffee' to #{bin}/coffee" exec([ "mkdir -p #{lib} #{bin}" "cp -rf bin lib LICENSE README package.json src #{lib}" "ln -sfn #{lib}/bin/coffee #{bin}/coffee" "ln -sfn #{lib}/bin/cake #{bin}/cake" "mkdir -p ~/.node_libraries" "ln -sfn #{lib}/lib/coffee-script #{node}" ].join(' && '), (err, stdout, stderr) -> if err then console.log stderr.trim() else log 'done', green ) task 'build', 'build the CoffeeScript language from source', build = (cb) -> files = fs.readdirSync 'src' files = ('src/' + file for file in files when file.match(/\.coffee$/)) run ['-c', '-o', 'lib/coffee-script'].concat(files), cb task 'build:full', 'rebuild the source twice, and run the tests', -> build -> build -> csPath = './lib/coffee-script' delete require.cache[require.resolve csPath] unless runTests require csPath process.exit 1 task 'build:parser', 'rebuild the Jison parser (run build first)', -> extend global, require('util') require 'jison' parser = require('./lib/coffee-script/grammar').parser fs.writeFile 'lib/coffee-script/parser.js', parser.generate() task 'build:ultraviolet', 'build and install the Ultraviolet syntax highlighter', -> exec 'plist2syntax ../coffee-script-tmbundle/Syntaxes/CoffeeScript.tmLanguage', (err) -> throw err if err exec 'sudo mv coffeescript.yaml /usr/local/lib/ruby/gems/1.8/gems/ultraviolet-0.10.2/syntax/coffeescript.syntax' task 'build:browser', 'rebuild the merged script for inclusion in the browser', -> code = '' for name in ['helpers', 'rewriter', 'lexer', 'parser', 'scope', 'nodes', 'coffee-script', 'browser'] code += """ require['./#{name}'] = new function() { var exports = this; #{fs.readFileSync "lib/coffee-script/#{name}.js"} }; """ code = """ (function(root) { var CoffeeScript = function() { function require(path){ return require[path]; } #{code} return require['./coffee-script']; }(); if (typeof define === 'function' && define.amd) { define(function() { return CoffeeScript; }); } else { root.CoffeeScript = CoffeeScript; } }(this)); """ unless process.env.MINIFY is 'false' {parser, uglify} = require 'uglify-js' code = uglify.gen_code uglify.ast_squeeze uglify.ast_mangle parser.parse code fs.writeFileSync 'extras/coffee-script.js', header + '\n' + code console.log "built ... running browser tests:" invoke 'test:browser' task 'doc:site', 'watch and continually rebuild the documentation for the website', -> exec 'rake doc', (err) -> throw err if err task 'doc:source', 'rebuild the internal documentation', -> exec 'docco src/*.coffee && cp -rf docs documentation && rm -r docs', (err) -> throw err if err task 'doc:underscore', 'rebuild the Underscore.coffee documentation page', -> exec 'docco examples/underscore.coffee && cp -rf docs documentation && rm -r docs', (err) -> throw err if err task 'bench', 'quick benchmark of compilation time', -> {Rewriter} = require './lib/coffee-script/rewriter' co = sources.map((name) -> fs.readFileSync name).join '\n' fmt = (ms) -> " #{bold}#{ " #{ms}".slice -4 }#{reset} ms" total = 0 now = Date.now() time = -> total += ms = -(now - now = Date.now()); fmt ms tokens = CoffeeScript.tokens co, rewrite: false console.log "Lex #{time()} (#{tokens.length} tokens)" tokens = new Rewriter().rewrite tokens console.log "Rewrite#{time()} (#{tokens.length} tokens)" nodes = CoffeeScript.nodes tokens console.log "Parse #{time()}" js = nodes.compile bare: true console.log "Compile#{time()} (#{js.length} chars)" console.log "total #{ fmt total }" task 'loc', 'count the lines of source code in the CoffeeScript compiler', -> exec "cat #{ sources.join(' ') } | grep -v '^\\( *#\\|\\s*$\\)' | wc -l | tr -s ' '", (err, stdout) -> console.log stdout.trim() # Run the CoffeeScript test suite. runTests = (CoffeeScript) -> startTime = Date.now() currentFile = null passedTests = 0 failures = [] global[name] = func for name, func of require 'assert' # Convenience aliases. global.CoffeeScript = CoffeeScript # Our test helper function for delimiting different test cases. global.test = (description, fn) -> try fn.test = {description, currentFile} fn.call(fn) ++passedTests catch e e.description = description if description? e.source = fn.toString() if fn.toString? failures.push filename: currentFile, error: e # See http://wiki.ecmascript.org/doku.php?id=harmony:egal egal = (a, b) -> if a is b a isnt 0 or 1/a is 1/b else a isnt a and b isnt b # A recursive functional equivalence helper; uses egal for testing equivalence. arrayEgal = (a, b) -> if egal a, b then yes else if a instanceof Array and b instanceof Array return no unless a.length is b.length return no for el, idx in a when not arrayEgal el, b[idx] yes global.eq = (a, b, msg) -> ok egal(a, b), msg global.arrayEq = (a, b, msg) -> ok arrayEgal(a,b), msg # When all the tests have run, collect and print errors. # If a stacktrace is available, output the compiled function source. process.on 'exit', -> time = ((Date.now() - startTime) / 1000).toFixed(2) message = "passed #{passedTests} tests in #{time} seconds#{reset}" return log(message, green) unless failures.length log "failed #{failures.length} and #{message}", red for fail in failures {error, filename} = fail jsFilename = filename.replace(/\.coffee$/,'.js') match = error.stack?.match(new RegExp(fail.file+":(\\d+):(\\d+)")) match = error.stack?.match(/on line (\d+):/) unless match [match, line, col] = match if match console.log '' log " #{error.description}", red if error.description log " #{error.stack}", red log " #{jsFilename}: line #{line ? 'unknown'}, column #{col ? 'unknown'}", red console.log " #{error.source}" if error.source return # Run every test in the `test` folder, recording failures. files = fs.readdirSync 'test' for file in files when file.match /\.coffee$/i currentFile = filename = path.join 'test', file code = fs.readFileSync filename try CoffeeScript.run code.toString(), {filename} catch error failures.push {filename, error} return !failures.length task 'test', 'run the CoffeeScript language test suite', -> runTests CoffeeScript task 'test:browser', 'run the test suite against the merged browser script', -> source = fs.readFileSync 'extras/coffee-script.js', 'utf-8' result = {} global.testingBrowser = yes (-> eval source).call result runTests result.CoffeeScript coffee-script-1.4.0/LICENSE000066400000000000000000000020471204160075300152530ustar00rootroot00000000000000Copyright (c) 2009-2012 Jeremy Ashkenas Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.coffee-script-1.4.0/README000066400000000000000000000035101204160075300151220ustar00rootroot00000000000000 { } } { { { } } } }{ { { }{ } } _____ __ __ ( }{ }{ { ) / ____| / _|/ _| .- { { } { }} -. | | ___ | |_| |_ ___ ___ ( ( } { } { } } ) | | / _ \| _| _/ _ \/ _ \ |`-..________ ..-'| | |___| (_) | | | || __/ __/ | | \_____\___/|_| |_| \___|\___| | ;--. | (__ \ _____ _ _ | | ) ) / ____| (_) | | | |/ / | (___ ___ _ __ _ _ __ | |_ | ( / \___ \ / __| '__| | '_ \| __| | |/ ____) | (__| | | | |_) | |_ | | |_____/ \___|_| |_| .__/ \__| `-.._________..-' | | |_| CoffeeScript is a little language that compiles into JavaScript. Install Node.js, and then the CoffeeScript compiler: sudo bin/cake install Or, if you have the Node Package Manager installed: npm install -g coffee-script (Leave off the -g if you don't wish to install globally.) Execute a script: coffee /path/to/script.coffee Compile a script: coffee -c /path/to/script.coffee For documentation, usage, and examples, see: http://coffeescript.org/ To suggest a feature, report a bug, or general discussion: http://github.com/jashkenas/coffee-script/issues/ If you'd like to chat, drop by #coffeescript on Freenode IRC, or on webchat.freenode.net. The source repository: git://github.com/jashkenas/coffee-script.git All contributors are listed here: http://github.com/jashkenas/coffee-script/contributors coffee-script-1.4.0/Rakefile000066400000000000000000000043141204160075300157120ustar00rootroot00000000000000require 'rubygems' require 'erb' require 'fileutils' require 'rake/testtask' require 'json' desc "Build the documentation page" task :doc do source = 'documentation/index.html.erb' child = fork { exec "bin/coffee -bcw -o documentation/js documentation/coffee/*.coffee" } at_exit { Process.kill("INT", child) } Signal.trap("INT") { exit } loop do mtime = File.stat(source).mtime if !@mtime || mtime > @mtime rendered = ERB.new(File.read(source)).result(binding) File.open('index.html', 'w+') {|f| f.write(rendered) } end @mtime = mtime sleep 1 end end desc "Build coffee-script-source gem" task :gem do require 'rubygems' require 'rubygems/package' gemspec = Gem::Specification.new do |s| s.name = 'coffee-script-source' s.version = JSON.parse(File.read('package.json'))["version"] s.date = Time.now.strftime("%Y-%m-%d") s.homepage = "http://jashkenas.github.com/coffee-script/" s.summary = "The CoffeeScript Compiler" s.description = <<-EOS CoffeeScript is a little language that compiles into JavaScript. Underneath all of those embarrassing braces and semicolons, JavaScript has always had a gorgeous object model at its heart. CoffeeScript is an attempt to expose the good parts of JavaScript in a simple way. EOS s.files = [ 'lib/coffee_script/coffee-script.js', 'lib/coffee_script/source.rb' ] s.authors = ['Jeremy Ashkenas'] s.email = 'jashkenas@gmail.com' s.rubyforge_project = 'coffee-script-source' end file = File.open("coffee-script-source.gem", "w") Gem::Package.open(file, 'w') do |pkg| pkg.metadata = gemspec.to_yaml path = "lib/coffee_script/source.rb" contents = <<-ERUBY module CoffeeScript module Source def self.bundled_path File.expand_path("../coffee-script.js", __FILE__) end end end ERUBY pkg.add_file_simple(path, 0644, contents.size) do |tar_io| tar_io.write(contents) end contents = File.read("extras/coffee-script.js") path = "lib/coffee_script/coffee-script.js" pkg.add_file_simple(path, 0644, contents.size) do |tar_io| tar_io.write(contents) end end end coffee-script-1.4.0/bin/000077500000000000000000000000001204160075300150135ustar00rootroot00000000000000coffee-script-1.4.0/bin/cake000077500000000000000000000003031204160075300156400ustar00rootroot00000000000000#!/usr/bin/env node var path = require('path'); var fs = require('fs'); var lib = path.join(path.dirname(fs.realpathSync(__filename)), '../lib'); require(lib + '/coffee-script/cake').run(); coffee-script-1.4.0/bin/coffee000077500000000000000000000003061204160075300161670ustar00rootroot00000000000000#!/usr/bin/env node var path = require('path'); var fs = require('fs'); var lib = path.join(path.dirname(fs.realpathSync(__filename)), '../lib'); require(lib + '/coffee-script/command').run(); coffee-script-1.4.0/documentation/000077500000000000000000000000001204160075300171145ustar00rootroot00000000000000coffee-script-1.4.0/documentation/coffee/000077500000000000000000000000001204160075300203435ustar00rootroot00000000000000coffee-script-1.4.0/documentation/coffee/aliases.coffee000066400000000000000000000003371204160075300231400ustar00rootroot00000000000000launch() if ignition is on volume = 10 if band isnt SpinalTap letTheWildRumpusBegin() unless answer is no if car.speed < limit then accelerate() winner = yes if pick in [47, 92, 13] print inspect "My name is #{@name}" coffee-script-1.4.0/documentation/coffee/array_comprehensions.coffee000066400000000000000000000004731204160075300257520ustar00rootroot00000000000000# Eat lunch. eat food for food in ['toast', 'cheese', 'wine'] # Fine five course dining. courses = ['greens', 'caviar', 'truffles', 'roast', 'cake'] menu i + 1, dish for dish, i in courses # Health conscious meal. foods = ['broccoli', 'spinach', 'chocolate'] eat food for food in foods when food isnt 'chocolate' coffee-script-1.4.0/documentation/coffee/block_comment.coffee000066400000000000000000000001061204160075300243250ustar00rootroot00000000000000### CoffeeScript Compiler v1.4.0 Released under the MIT License ### coffee-script-1.4.0/documentation/coffee/cake_tasks.coffee000066400000000000000000000004351204160075300236260ustar00rootroot00000000000000fs = require 'fs' option '-o', '--output [DIR]', 'directory for compiled code' task 'build:parser', 'rebuild the Jison parser', (options) -> require 'jison' code = require('./lib/grammar').parser.generate() dir = options.output or 'lib' fs.writeFile "#{dir}/parser.js", codecoffee-script-1.4.0/documentation/coffee/classes.coffee000066400000000000000000000005411204160075300231510ustar00rootroot00000000000000class Animal constructor: (@name) -> move: (meters) -> alert @name + " moved #{meters}m." class Snake extends Animal move: -> alert "Slithering..." super 5 class Horse extends Animal move: -> alert "Galloping..." super 45 sam = new Snake "Sammy the Python" tom = new Horse "Tommy the Palomino" sam.move() tom.move() coffee-script-1.4.0/documentation/coffee/comparisons.coffee000066400000000000000000000000661204160075300240530ustar00rootroot00000000000000cholesterol = 127 healthy = 200 > cholesterol > 60 coffee-script-1.4.0/documentation/coffee/conditionals.coffee000066400000000000000000000002151204160075300242000ustar00rootroot00000000000000mood = greatlyImproved if singing if happy and knowsIt clapsHands() chaChaCha() else showIt() date = if friday then sue else jill coffee-script-1.4.0/documentation/coffee/default_args.coffee000066400000000000000000000001361204160075300241540ustar00rootroot00000000000000fill = (container, liquid = "coffee") -> "Filling the #{container} with #{liquid}..." coffee-script-1.4.0/documentation/coffee/do.coffee000066400000000000000000000002001204160075300221060ustar00rootroot00000000000000for filename in list do (filename) -> fs.readFile filename, (err, contents) -> compile filename, contents.toString()coffee-script-1.4.0/documentation/coffee/embedded.coffee000066400000000000000000000001231204160075300232410ustar00rootroot00000000000000hi = `function() { return [document.title, "Hello JavaScript"].join(": "); }` coffee-script-1.4.0/documentation/coffee/existence.coffee000066400000000000000000000001431204160075300235010ustar00rootroot00000000000000solipsism = true if mind? and not world? speed = 0 speed ?= 15 footprints = yeti ? "bear" coffee-script-1.4.0/documentation/coffee/expressions.coffee000066400000000000000000000002721204160075300240770ustar00rootroot00000000000000grade = (student) -> if student.excellentWork "A+" else if student.okayStuff if student.triedHard then "B" else "B-" else "C" eldest = if 24 > 21 then "Liz" else "Ike"coffee-script-1.4.0/documentation/coffee/expressions_assignment.coffee000066400000000000000000000000541204160075300263250ustar00rootroot00000000000000six = (one = 1) + (two = 2) + (three = 3) coffee-script-1.4.0/documentation/coffee/expressions_comprehension.coffee000066400000000000000000000001171204160075300270260ustar00rootroot00000000000000# The first ten global properties. globals = (name for name of window)[0...10]coffee-script-1.4.0/documentation/coffee/expressions_try.coffee000066400000000000000000000001361204160075300247740ustar00rootroot00000000000000alert( try nonexistent / undefined catch error "And the error is ... #{error}" ) coffee-script-1.4.0/documentation/coffee/fat_arrow.coffee000066400000000000000000000002201204160075300234720ustar00rootroot00000000000000Account = (customer, cart) -> @customer = customer @cart = cart $('.shopping_cart').bind 'click', (event) => @customer.purchase @cartcoffee-script-1.4.0/documentation/coffee/functions.coffee000066400000000000000000000000641204160075300235240ustar00rootroot00000000000000square = (x) -> x * x cube = (x) -> square(x) * x coffee-script-1.4.0/documentation/coffee/heredocs.coffee000066400000000000000000000001341204160075300233060ustar00rootroot00000000000000html = """ cup of coffeescript """ coffee-script-1.4.0/documentation/coffee/heregexes.coffee000066400000000000000000000004641204160075300234770ustar00rootroot00000000000000OPERATOR = /// ^ ( ?: [-=]> # function | [-+*/%<>&|^!?=]= # compound assign / compare | >>>=? # zero-fill right shift | ([-+:])\1 # doubles | ([&|<>])\2=? # logic / shift | \?\. # soak access | \.{2,3} # range or splat ) /// coffee-script-1.4.0/documentation/coffee/interpolation.coffee000066400000000000000000000002061204160075300244010ustar00rootroot00000000000000author = "Wittgenstein" quote = "A picture is a fact. -- #{ author }" sentence = "#{ 22 / 7 } is a decent approximation of π" coffee-script-1.4.0/documentation/coffee/multiple_return_values.coffee000066400000000000000000000002531204160075300263250ustar00rootroot00000000000000weatherReport = (location) -> # Make an Ajax request to fetch the weather... [location, 72, "Mostly Sunny"] [city, temp, forecast] = weatherReport "Berkeley, CA" coffee-script-1.4.0/documentation/coffee/object_comprehensions.coffee000066400000000000000000000001361204160075300260760ustar00rootroot00000000000000yearsOld = max: 10, ida: 9, tim: 11 ages = for child, age of yearsOld "#{child} is #{age}" coffee-script-1.4.0/documentation/coffee/object_extraction.coffee000066400000000000000000000003571204160075300252270ustar00rootroot00000000000000futurists = sculptor: "Umberto Boccioni" painter: "Vladimir Burliuk" poet: name: "F.T. Marinetti" address: [ "Via Roma 42R" "Bellagio, Italy 22021" ] {poet: {name, address: [street, city]}} = futurists coffee-script-1.4.0/documentation/coffee/objects_and_arrays.coffee000066400000000000000000000003261204160075300253510ustar00rootroot00000000000000song = ["do", "re", "mi", "fa", "so"] singers = {Jagger: "Rock", Elvis: "Roll"} bitlist = [ 1, 0, 1 0, 0, 1 1, 1, 0 ] kids = brother: name: "Max" age: 11 sister: name: "Ida" age: 9 coffee-script-1.4.0/documentation/coffee/objects_reserved.coffee000066400000000000000000000000671204160075300250470ustar00rootroot00000000000000$('.account').attr class: 'active' log object.class coffee-script-1.4.0/documentation/coffee/overview.coffee000066400000000000000000000006361204160075300233670ustar00rootroot00000000000000# Assignment: number = 42 opposite = true # Conditions: number = -42 if opposite # Functions: square = (x) -> x * x # Arrays: list = [1, 2, 3, 4, 5] # Objects: math = root: Math.sqrt square: square cube: (x) -> x * square x # Splats: race = (winner, runners...) -> print winner, runners # Existence: alert "I knew it!" if elvis? # Array comprehensions: cubes = (math.cube num for num in list) coffee-script-1.4.0/documentation/coffee/parallel_assignment.coffee000066400000000000000000000001211204160075300255320ustar00rootroot00000000000000theBait = 1000 theSwitch = 0 [theBait, theSwitch] = [theSwitch, theBait] coffee-script-1.4.0/documentation/coffee/patterns_and_splats.coffee000066400000000000000000000001071204160075300255620ustar00rootroot00000000000000tag = "" [open, contents..., close] = tag.split("") coffee-script-1.4.0/documentation/coffee/prototypes.coffee000066400000000000000000000000611204160075300237410ustar00rootroot00000000000000String::dasherize = -> this.replace /_/g, "-" coffee-script-1.4.0/documentation/coffee/range_comprehensions.coffee000066400000000000000000000000461204160075300257240ustar00rootroot00000000000000countdown = (num for num in [10..1]) coffee-script-1.4.0/documentation/coffee/scope.coffee000066400000000000000000000001161204160075300226230ustar00rootroot00000000000000outer = 1 changeNumbers = -> inner = -1 outer = 10 inner = changeNumbers()coffee-script-1.4.0/documentation/coffee/slices.coffee000066400000000000000000000002101204160075300227670ustar00rootroot00000000000000numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9] start = numbers[0..2] middle = numbers[3...6] end = numbers[6..] copy = numbers[..] coffee-script-1.4.0/documentation/coffee/soaks.coffee000066400000000000000000000000551204160075300226340ustar00rootroot00000000000000zip = lottery.drawWinner?().address?.zipcode coffee-script-1.4.0/documentation/coffee/splats.coffee000066400000000000000000000006401204160075300230220ustar00rootroot00000000000000gold = silver = rest = "unknown" awardMedals = (first, second, others...) -> gold = first silver = second rest = others contenders = [ "Michael Phelps" "Liu Xiang" "Yao Ming" "Allyson Felix" "Shawn Johnson" "Roman Sebrle" "Guo Jingjing" "Tyson Gay" "Asafa Powell" "Usain Bolt" ] awardMedals contenders... alert "Gold: " + gold alert "Silver: " + silver alert "The Field: " + rest coffee-script-1.4.0/documentation/coffee/splices.coffee000066400000000000000000000001171204160075300231550ustar00rootroot00000000000000numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] numbers[3..6] = [-3, -4, -5, -6] coffee-script-1.4.0/documentation/coffee/strings.coffee000066400000000000000000000003751204160075300232120ustar00rootroot00000000000000mobyDick = "Call me Ishmael. Some years ago -- never mind how long precisely -- having little or no money in my purse, and nothing particular to interest me on shore, I thought I would sail about a little and see the watery part of the world..." coffee-script-1.4.0/documentation/coffee/switch.coffee000066400000000000000000000003251204160075300230150ustar00rootroot00000000000000switch day when "Mon" then go work when "Tue" then go relax when "Thu" then go iceFishing when "Fri", "Sat" if day is bingoDay go bingo go dancing when "Sun" then go church else go workcoffee-script-1.4.0/documentation/coffee/try.coffee000066400000000000000000000001501204160075300223260ustar00rootroot00000000000000try allHellBreaksLoose() catsAndDogsLivingTogether() catch error print error finally cleanUp() coffee-script-1.4.0/documentation/coffee/while.coffee000066400000000000000000000003511204160075300226230ustar00rootroot00000000000000# Econ 101 if this.studyingEconomics buy() while supply > demand sell() until supply > demand # Nursery Rhyme num = 6 lyrics = while num -= 1 "#{num} little monkeys, jumping on the bed. One fell out and bumped his head." coffee-script-1.4.0/documentation/css/000077500000000000000000000000001204160075300177045ustar00rootroot00000000000000coffee-script-1.4.0/documentation/css/docs.css000066400000000000000000000237421204160075300213560ustar00rootroot00000000000000body { font-size: 14px; line-height: 21px; color: #333; background: #f6f6f6 url(../images/background.png); font-family: "Helvetica Neue", "Lucida Grande", "Lucida Sans Unicode", Helvetica, Arial, sans-serif !important; } .container { width: 950px; margin: 0; padding: 80px 0px 50px 50px; } p, li { width: 625px; } a { color: #191933; } h1, h2, h3, h4, h5, h6, b.header { font-size: 18px; color: #000; margin-top: 40px; margin-bottom: 15px; text-shadow: #fff 0 1px 1px; } br.clear { height: 0; clear: both; } ul { padding-left: 20px; } b.header { display: block; } li { margin-bottom: 10px; } table { margin: 16px 0 0 13px; padding: 0; width: 625px; } tr, td { margin: 0; padding: 0; } td { padding: 9px 15px 9px 0; vertical-align: top; } table.definitions { width: auto; margin: 30px 0; border-left: 5px solid rgba(0,0,0,0.2);; } table.definitions td { text-align: center; padding: 5px 20px; } code, pre, tt, textarea { font-family: Monaco, Consolas, "Lucida Console", monospace; font-size: 12px; line-height: 18px; color: #155; white-space: pre-wrap; word-wrap: break-word; } tt { display: inline-block; background: #fff; border: 1px solid #dedede; padding: 0px 0.2em; } pre { border-left: 5px solid rgba(0,0,0,0.2); padding: 3px 0 3px 12px; font-size: 12px; } pre.no_bar { border-left: 0; margin-left: 0; padding-left: 0; } .timestamp { font-size: 12px; font-weight: normal; color: black; } .timestamp small { font-size: 11px; text-transform: uppercase; } div.code { position: relative; background: #fff; border: 1px solid #d8d8d8; -webkit-box-shadow: 0px 0px 4px rgba(0,0,0,0.23); -moz-box-shadow: 0px 0px 4px rgba(0,0,0,0.23); box-shadow: 0px 0px 4px rgba(0,0,0,0.23); zoom: 1; } div.code .minibutton { text-transform: none; position: absolute; right: 8px; bottom: 8px; } div.code .load { left: 8px; right: auto; } div.code pre, div.code textarea { float: left; width: 450px; background: #fff; border-left: 1px dotted #d0d0d0; margin: 10px 0 15px 3px; padding: 0 0 0 12px; } div.code pre:first-child { border-left: 0; } #fadeout { z-index: 50; position: fixed; left: 0; top: 0; right: 0; height: 100px; background: -webkit-gradient(linear, left top, left bottom, from(rgba(255, 255, 255, 255)), to(rgba(255, 255, 255, 0))); background: -moz-linear-gradient(top, rgba(255, 255, 255, 255), rgba(255, 255, 255, 0)); } #flybar { position: fixed; z-index: 100; height: 50px; min-width: 490px; left: 40px; right: 40px; top: 25px; padding-left: 252px; background: #eee; background: -webkit-gradient(linear, left top, left bottom, from(#f8f8f8), to(#dadada)); background: -moz-linear-gradient(top, #f8f8f8, #dadada); border: 1px solid #aaa; border-top: 1px solid #bbb; border-bottom: 1px solid #888; -webkit-border-radius: 3px; -moz-border-radius: 3px; border-radius: 3px; -webkit-box-shadow: 0 3px 5px rgba(0,0,0,0.1); -moz-box-shadow: 0 3px 5px rgba(0,0,0,0.1); box-shadow: 0 3px 5px rgba(0,0,0,0.1); } #logo { display: block; width: 225px; height: 50px; background: url('../images/logo.png'); position: absolute; top: 0px; left: 10px; } #error { position: absolute; -webkit-border-radius: 2px; -moz-border-radius: 2px; border-radius: 2px; -webkit-border-top-left-radius: 0; -moz-border-radius-topleft: 0; border-top-left-radius: 0; -webkit-border-bottom-left-radius: 0; -moz-border-radius-bottomleft: 0; border-bottom-left-radius: 0; right: 0px; top: 0px; left: 726px; bottom: 0; padding: 0 0 0 15px; background: #fdcdcc; background: -webkit-gradient(linear, left top, left bottom, from(#ffedec), to(#ff9a95)); background: -moz-linear-gradient(top, #f8f8f8, #dadada); color: #862322; font-size: 10px; line-height: 50px; overflow: hidden; text-transform: uppercase; } .navigation { height: 50px; font-size: 11px; line-height: 50px; text-transform: uppercase; position: relative; float: left; padding: 0 20px; border: 1px solid #aaa; border-top: 0; border-bottom: 0; border-left-width: 0; cursor: pointer; } .navigation.toc { border-left-width: 1px; } .navigation:hover, .navigation.active { background: #eee; background: -webkit-gradient(linear, left top, left bottom, from(#eee), to(#f8f8f8)); background: -moz-linear-gradient(top, #eee, #f8f8f8); } .navigation.active { height: 51px; color: #000; background: -webkit-gradient(linear, left top, left bottom, from(#e5e5e5), to(#fff)); background: -moz-linear-gradient(top, #e5e5e5, #fff); } .navigation .button { font-weight: bold; } .navigation .button::selection { background: transparent; } .navigation .contents { display: none; position: absolute; background: #fff; opacity: 0.97; top: 51px; left: 0; padding: 5px 0; margin-left: -1px; border: 1px solid #aaa; -webkit-border-radius: 3px; -moz-border-radius: 3px; border-radius: 3px; -webkit-box-shadow: 0 3px 5px rgba(0,0,0,0.2); -moz-box-shadow: 0 3px 5px rgba(0,0,0,0.2); box-shadow: 0 3px 5px rgba(0,0,0,0.2); } .navigation .contents a { display: block; width: 290px; text-transform: none; text-decoration: none; height: 12px; line-height: 12px; padding: 4px 10px; border: 1px solid transparent; border-left: 0; border-right: 0; } .navigation .contents a:hover { border-color: #ddd; background: #eee; } .navigation.active .contents { display: block; } .navigation .contents.menu { border-top: 0; -webkit-border-top-left-radius: 0; -moz-border-radius-topleft: 0; border-top-left-radius: 0; -webkit-border-top-right-radius: 0; -moz-border-radius-topright: 0; border-top-right-radius: 0; } .navigation .contents.repl_wrapper { padding: 0; position: fixed; width: auto; height: auto; left: 40px; top: 90px; right: 40px; bottom: 30px; background: -webkit-gradient(linear, left top, left bottom, from(#fafafa), to(#eaeaea)); } .navigation .repl_bridge { position: absolute; height: 12px; left: -1px; right: -1px; bottom: -14px; border: 1px solid #aaa; z-index: 5; background: #fff; display: none; border-top-color: #fff; border-bottom-color: #fff; } .navigation.active .repl_bridge { display: block; } .navigation .code .minibutton { top: 10px; right: 10px; width: 40px; text-transform: none; } .navigation .code a.minibutton.permalink { top: 38px; display: block; } .bookmark { display: block; width: 0; height: 0; position: relative; top: -90px; } .navigation .contents.repl_wrapper .code { cursor: text; -webkit-box-shadow: none; -moz-box-shadow: none; box-shadow: none; background: #181a3a url(../images/banding.png); border: 2px solid #555; padding: 0; position: absolute; top: 15px; left: 15px; right: 15px; bottom: 15px; } .repl_wrapper .screenshadow { position: absolute; width: 200px; height: 150px; background: url(../images/screenshadow.png?2); } .repl_wrapper .screenshadow.tl { top: 0; left: 0; background-position: 0 0; } .repl_wrapper .screenshadow.tr { top: 0; right: 0; background-position: -200px 0; } .repl_wrapper .screenshadow.bl { bottom: 0; left: 0; background-position: 0 -150px; } .repl_wrapper .screenshadow.br { bottom: 0; right: 0; background-position: -200px -150px; } #repl_source, #repl_results { background: transparent; outline: none; margin: 5px 0 20px; color: #def; } #repl_results, #repl_source_wrap { width: auto; height: auto; position: absolute; margin-bottom: 0; top: 10px; left: 10px; right: 10px; bottom: 15px; } #repl_source_wrap { margin-left: 5px; width: 47%; right: 50%; float: left; } #repl_source { padding-left: 5px; width: 100%; height: 100%; border: 0; overflow-y: auto; resize: none; } #repl_results_wrap { white-space: pre; } #repl_results { text-transform: none; overflow-y: auto; left: 50%; border-left-color: #555; } /*----------------------------- Mini Buttons ---------------------------------*/ .minibutton { cursor: pointer; color: #333; text-shadow: #eee 0 1px 1px; font-weight: bold; font-size: 11px; line-height: 11px; padding: 5px 10px 6px; height: 11px; text-align: center; -webkit-border-radius: 3px; -moz-border-radius: 3px; border-radius: 3px; box-shadow: 0 1px 2px rgba(0,0,0,0.2); -webkit-box-shadow: 0 1px 2px rgba(0,0,0,0.2); -moz-box-shadow: 0 1px 2px rgba(0,0,0,0.2); border: 1px solid #b2b2b2; border-top-color: #c9c9c9; border-bottom-color: #9a9a9a; background: url(../images/button_bg.png) repeat-x left top; } .minibutton:active { border-color: #aaa; box-shadow: 0 1px 2px #e4e4e4; -webkit-box-shadow: 0 1px 2px #e4e4e4; -moz-box-shadow: 0 1px 2px #e4e4e4; } .minibutton::selection { background: transparent; } .minibutton ::-moz-selection { background: transparent; } .minibutton.ok { color: #fff; background-image: url(../images/button_bg_green.gif); border-color: #4ba47c; border-top-color: #53b388; border-bottom-color: #459671; text-shadow: #aaa 0 -1px 0; } .minibutton.dark { border: 0; color: #fff; box-shadow: none; -webkit-box-shadow: none; -moz-box-shadow: none; background-image: url(../images/button_bg_dark.gif); text-shadow: none; }coffee-script-1.4.0/documentation/css/idle.css000066400000000000000000000017271204160075300213420ustar00rootroot00000000000000pre.idle .InheritedClass { } pre.idle .TypeName { color: #21439C; } pre.idle .Number { } pre.idle .LibraryVariable { color: #A535AE; } pre.idle .Storage { color: #FF5600; } pre.idle .line-numbers { background-color: #BAD6FD; color: #000000; } pre.idle { background-color: #FFFFFF; color: #000000; } pre.idle .StringInterpolation { color: #990000; } pre.idle .TagName { } pre.idle .LibraryConstant { color: #A535AE; } pre.idle .FunctionArgument { color: #0076ad; } pre.idle .BuiltInConstant { color: #A535AE; } pre.idle .Invalid { background-color: #990000; color: #FFFFFF; } pre.idle .LibraryClassType { color: #A535AE; } pre.idle .LibraryFunction { color: #A535AE; } pre.idle .TagAttribute { } pre.idle .Keyword { color: #FF5600; } pre.idle .UserDefinedConstant { } pre.idle .String { color: #00A33F; } pre.idle .FunctionName { color: #21439C; } pre.idle .Variable { color: #A535AE; } pre.idle .Comment { color: #919191; } coffee-script-1.4.0/documentation/docs/000077500000000000000000000000001204160075300200445ustar00rootroot00000000000000coffee-script-1.4.0/documentation/docs/browser.html000066400000000000000000000262161204160075300224240ustar00rootroot00000000000000 browser.coffee

browser.coffee

Override exported methods for non-Node.js engines.

CoffeeScript = require './coffee-script'
CoffeeScript.require = require

Use standard JavaScript eval to eval code.

CoffeeScript.eval = (code, options = {}) ->
  options.bare ?= on
  eval CoffeeScript.compile code, options

Running code does not provide access to this scope.

CoffeeScript.run = (code, options = {}) ->
  options.bare = on
  Function(CoffeeScript.compile code, options)()

If we're not in a browser environment, we're finished with the public API.

return unless window?

Load a remote script from the current domain via XHR.

CoffeeScript.load = (url, callback) ->
  xhr = if window.ActiveXObject
    new window.ActiveXObject('Microsoft.XMLHTTP')
  else
    new XMLHttpRequest()
  xhr.open 'GET', url, true
  xhr.overrideMimeType 'text/plain' if 'overrideMimeType' of xhr
  xhr.onreadystatechange = ->
    if xhr.readyState is 4
      if xhr.status in [0, 200]
        CoffeeScript.run xhr.responseText
      else
        throw new Error "Could not load #{url}"
      callback() if callback
  xhr.send null

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.

runScripts = ->
  scripts = document.getElementsByTagName 'script'
  coffees = (s for s in scripts when s.type is 'text/coffeescript')
  index = 0
  length = coffees.length
  do execute = ->
    script = coffees[index++]
    if script?.type is 'text/coffeescript'
      if script.src
        CoffeeScript.load script.src, execute
      else
        CoffeeScript.run script.innerHTML
        execute()
  null

Listen for window load, both in browsers and in IE.

if window.addEventListener
  addEventListener 'DOMContentLoaded', runScripts, no
else
  attachEvent 'onload', runScripts

coffee-script-1.4.0/documentation/docs/cake.html000066400000000000000000000427261204160075300216500ustar00rootroot00000000000000 cake.coffee

cake.coffee

cake is a simplified version of Make (Rake, 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'
optparse     = require './optparse'
CoffeeScript = require './coffee-script'

existsSync   = fs.existsSync or path.existsSync

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, an optional sentence description, and the function to run as the action itself.

  task: (name, description, 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 as the first argument to the action.

  option: (letter, flag, description) ->
    switches.push [letter, flag, description]

Invoke another task in the current Cakefile.

  invoke: (name) ->
    missingTask name unless tasks[name]
    tasks[name].action options

Run cake. Executes all of the tasks you pass, in order. Note that Node's asynchrony may cause tasks to execute in a different order than you'd expect. If no tasks are passed, print the help screen. Keep a reference to the original directory name, when running Cake tasks from subdirectories.

exports.run = ->
  global.__originalDirname = fs.realpathSync '.'
  process.chdir cakefileDirectory __originalDirname
  args = process.argv[2..]
  CoffeeScript.run fs.readFileSync('Cakefile').toString(), filename: 'Cakefile'
  oparse = new optparse.OptionParser switches
  return printTasks() unless args.length
  try
    options = oparse.parse(args)
  catch e
    return fatalError "#{e}"
  invoke arg for arg in options.arguments

Display the list of Cake tasks in a format similar to rake -T

printTasks = ->
  relative = path.relative or path.resolve
  cakefilePath = path.join relative(__originalDirname, process.cwd()), 'Cakefile'
  console.log "#{cakefilePath} defines the following tasks:\n"
  for name, task of tasks
    spaces = 20 - name.length
    spaces = if spaces > 0 then Array(spaces + 1).join(' ') else ''
    desc   = if task.description then "# #{task.description}" else ''
    console.log "cake #{name}#{spaces} #{desc}"
  console.log oparse.help() if switches.length

Print an error and exit when attempting to use an invalid task/option.

fatalError = (message) ->
  console.error message + '\n'
  console.log 'To see a list of all tasks/options, run "cake"'
  process.exit 1

missingTask = (task) -> fatalError "No such task: #{task}"

When cake is invoked, search in the current and all parent directories to find the relevant Cakefile.

cakefileDirectory = (dir) ->
  return dir if existsSync path.join dir, 'Cakefile'
  parent = path.normalize path.join dir, '..'
  return cakefileDirectory parent unless parent is dir
  throw new Error "Cakefile not found in #{process.cwd()}"

coffee-script-1.4.0/documentation/docs/coffee-script.html000066400000000000000000000604721204160075300234740ustar00rootroot00000000000000 coffee-script.coffee

coffee-script.coffee

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 tokenizing, 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.

fs               = require 'fs'
path             = require 'path'
{Lexer,RESERVED} = require './lexer'
{parser}         = require './parser'
vm               = require 'vm'

stripBOM = (content) ->
  if content.charCodeAt(0) is 0xFEFF then content.substring 1 else content

if require.extensions
  require.extensions['.coffee'] = (module, filename) ->
    content = compile stripBOM(fs.readFileSync filename, 'utf8'), {filename}
    module._compile content, filename

The current CoffeeScript version number.

exports.VERSION = '1.4.0'

Words that cannot be used as identifiers in CoffeeScript code

exports.RESERVED = RESERVED

Expose helpers for testing.

exports.helpers = require './helpers'

Compile a string of CoffeeScript code to JavaScript, using the Coffee/Jison compiler.

exports.compile = compile = (code, options = {}) ->
  {merge} = exports.helpers
  try
    js = (parser.parse lexer.tokenize code).compile options
    return js unless options.header
  catch err
    err.message = "In #{options.filename}, #{err.message}" if options.filename
    throw err
  header = "Generated by CoffeeScript #{@VERSION}"
  "// #{header}\n#{js}"

Tokenize a string of CoffeeScript code, and return the array of tokens.

exports.tokens = (code, options) ->
  lexer.tokenize code, options

Parse a string of CoffeeScript code or an array of lexed tokens, and return the AST. You can then compile it by calling .compile() on the root, or traverse it by using .traverseChildren() with a callback.

exports.nodes = (source, options) ->
  if typeof source is 'string'
    parser.parse lexer.tokenize source, options
  else
    parser.parse source

Compile and execute a string of CoffeeScript (on the server), correctly setting __filename, __dirname, and relative require().

exports.run = (code, options = {}) ->
  mainModule = require.main

Set the filename.

  mainModule.filename = process.argv[1] =
      if options.filename then fs.realpathSync(options.filename) else '.'

Clear the module cache.

  mainModule.moduleCache and= {}

Assign paths for node_modules loading

  mainModule.paths = require('module')._nodeModulePaths path.dirname fs.realpathSync options.filename

Compile.

  if path.extname(mainModule.filename) isnt '.coffee' or require.extensions
    mainModule._compile compile(code, options), mainModule.filename
  else
    mainModule._compile code, mainModule.filename

Compile and evaluate a string of CoffeeScript (in a Node.js-like environment). The CoffeeScript REPL uses this to run the input.

exports.eval = (code, options = {}) ->
  return unless code = code.trim()
  Script = vm.Script
  if Script
    if options.sandbox?
      if options.sandbox instanceof Script.createContext().constructor
        sandbox = options.sandbox
      else
        sandbox = Script.createContext()
        sandbox[k] = v for own k, v of options.sandbox
      sandbox.global = sandbox.root = sandbox.GLOBAL = sandbox
    else
      sandbox = global
    sandbox.__filename = options.filename || 'eval'
    sandbox.__dirname  = path.dirname sandbox.__filename

define module/require only if they chose not to specify their own

    unless sandbox isnt global or sandbox.module or sandbox.require
      Module = require 'module'
      sandbox.module  = _module  = new Module(options.modulename || 'eval')
      sandbox.require = _require = (path) ->  Module._load path, _module, true
      _module.filename = sandbox.__filename
      _require[r] = require[r] for r in Object.getOwnPropertyNames require when r isnt 'paths'

use the same hack node currently uses for their own REPL

      _require.paths = _module.paths = Module._nodeModulePaths process.cwd()
      _require.resolve = (request) -> Module._resolveFilename request, _module
  o = {}
  o[k] = v for own k, v of options
  o.bare = on # ensure return value
  js = compile code, o
  if sandbox is global
    vm.runInThisContext js
  else
    vm.runInContext js, sandbox

Instantiate a Lexer for our use here.

lexer = new Lexer

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: ->
    [tag, @yytext, @yylineno] = @tokens[@pos++] or ['']
    tag
  setInput: (@tokens) ->
    @pos = 0
  upcomingInput: ->
    ""

parser.yy = require './nodes'

coffee-script-1.4.0/documentation/docs/command.html000066400000000000000000001765611204160075300223700ustar00rootroot00000000000000 command.coffee

command.coffee

The coffee utility. Handles command-line compilation of CoffeeScript into various forms: saved into .js files or printed to stdout, piped to JavaScript Lint 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.

fs             = require 'fs'
path           = require 'path'
helpers        = require './helpers'
optparse       = require './optparse'
CoffeeScript   = require './coffee-script'
{spawn, exec}  = require 'child_process'
{EventEmitter} = require 'events'

exists         = fs.exists or path.exists

Allow CoffeeScript to emit Node.js events.

helpers.extend CoffeeScript, new EventEmitter

printLine = (line) -> process.stdout.write line + '\n'
printWarn = (line) -> process.stderr.write line + '\n'

hidden = (file) -> /^\.|~$/.test file

The help banner that is printed when coffee is called without arguments.

BANNER = '''
  Usage: coffee [options] path/to/script.coffee -- [args]

  If called without options, `coffee` will run your script.
'''

The list of all the valid option flags that coffee knows how to handle.

SWITCHES = [
  ['-b', '--bare',            'compile without a top-level function wrapper']
  ['-c', '--compile',         'compile to JavaScript and save as .js files']
  ['-e', '--eval',            'pass a string from the command line as input']
  ['-h', '--help',            'display this help message']
  ['-i', '--interactive',     'run an interactive CoffeeScript REPL']
  ['-j', '--join [FILE]',     'concatenate the source CoffeeScript before compiling']
  ['-l', '--lint',            'pipe the compiled JavaScript through JavaScript Lint']
  ['-n', '--nodes',           'print out the parse tree that the parser produces']
  [      '--nodejs [ARGS]',   'pass options directly to the "node" binary']
  ['-o', '--output [DIR]',    'set the output directory for compiled JavaScript']
  ['-p', '--print',           'print out the compiled JavaScript']
  ['-r', '--require [FILE*]', 'require a library before executing your script']
  ['-s', '--stdio',           'listen for and compile scripts over stdio']
  ['-t', '--tokens',          'print out the tokens that the lexer/rewriter produce']
  ['-v', '--version',         'display the version number']
  ['-w', '--watch',           'watch scripts for changes and rerun commands']
]

Top-level objects shared by all the functions.

opts         = {}
sources      = []
sourceCode   = []
notSources   = {}
watchers     = {}
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 = ->
  parseOptions()
  return forkNode()                      if opts.nodejs
  return usage()                         if opts.help
  return version()                       if opts.version
  loadRequires()                         if opts.require
  return require './repl'                if opts.interactive
  if opts.watch and !fs.watch
    return printWarn "The --watch feature depends on Node v0.6.0+. You are running #{process.version}."
  return compileStdio()                  if opts.stdio
  return compileScript null, sources[0]  if opts.eval
  return require './repl'                unless sources.length
  literals = if opts.run then sources.splice 1 else []
  process.argv = process.argv[0..1].concat literals
  process.argv[0] = 'coffee'
  process.execPath = require.main.filename
  for source in sources
    compilePath source, yes, path.normalize source

Compile a path, which could be a script or a directory. If a directory is passed, recursively compile all '.coffee' extension source files in it and all subdirectories.

compilePath = (source, topLevel, base) ->
  fs.stat source, (err, stats) ->
    throw err if err and err.code isnt 'ENOENT'
    if err?.code is 'ENOENT'
      if topLevel and source[-7..] isnt '.coffee'
        source = sources[sources.indexOf(source)] = "#{source}.coffee"
        return compilePath source, topLevel, base
      if topLevel
        console.error "File not found: #{source}"
        process.exit 1
      return
    if stats.isDirectory()
      watchDir source, base if opts.watch
      fs.readdir source, (err, files) ->
        throw err if err and err.code isnt 'ENOENT'
        return if err?.code is 'ENOENT'
        index = sources.indexOf source
        files = files.filter (file) -> not hidden file
        sources[index..index] = (path.join source, file for file in files)
        sourceCode[index..index] = files.map -> null
        files.forEach (file) ->
          compilePath (path.join source, file), no, base
    else if topLevel or path.extname(source) is '.coffee'
      watch source, base if opts.watch
      fs.readFile source, (err, code) ->
        throw err if err and err.code isnt 'ENOENT'
        return if err?.code is 'ENOENT'
        compileScript(source, code.toString(), base)
    else
      notSources[source] = yes
      removeSource source, base

Compile a single source script, containing the given code, according to the requested options. If evaluating the script directly sets __filename, __dirname and module.filename to be correct relative to the script's path.

compileScript = (file, input, base) ->
  o = opts
  options = compileOptions file
  try
    t = task = {file, input, options}
    CoffeeScript.emit 'compile', task
    if      o.tokens      then printTokens CoffeeScript.tokens t.input
    else if o.nodes       then printLine CoffeeScript.nodes(t.input).toString().trim()
    else if o.run         then CoffeeScript.run t.input, t.options
    else if o.join and t.file isnt o.join
      sourceCode[sources.indexOf(t.file)] = t.input
      compileJoin()
    else
      t.output = CoffeeScript.compile t.input, t.options
      CoffeeScript.emit 'success', task
      if o.print          then printLine t.output.trim()
      else if o.compile   then writeJs t.file, t.output, base
      else if o.lint      then lint t.file, t.output
  catch err
    CoffeeScript.emit 'failure', err, task
    return if CoffeeScript.listeners('failure').length
    return printLine err.message + '\x07' if o.watch
    printWarn err instanceof Error and err.stack or "ERROR: #{err}"
    process.exit 1

Attach the appropriate listeners to compile scripts incoming over stdin, and write them back to stdout.

compileStdio = ->
  code = ''
  stdin = process.openStdin()
  stdin.on 'data', (buffer) ->
    code += buffer.toString() if buffer
  stdin.on 'end', ->
    compileScript null, code

If all of the source files are done being read, concatenate and compile them together.

joinTimeout = null
compileJoin = ->
  return unless opts.join
  unless sourceCode.some((code) -> code is null)
    clearTimeout joinTimeout
    joinTimeout = wait 100, ->
      compileScript opts.join, sourceCode.join('\n'), opts.join

Load files that are to-be-required before compilation occurs.

loadRequires = ->
  realFilename = module.filename
  module.filename = '.'
  require req for req in opts.require
  module.filename = realFilename

Watch a source CoffeeScript file using fs.watch, recompiling it every time the file is updated. May be used in combination with other options, such as --lint or --print.

watch = (source, base) ->

  prevStats = null
  compileTimeout = null

  watchErr = (e) ->
    if e.code is 'ENOENT'
      return if sources.indexOf(source) is -1
      try
        rewatch()
        compile()
      catch e
        removeSource source, base, yes
        compileJoin()
    else throw e

  compile = ->
    clearTimeout compileTimeout
    compileTimeout = wait 25, ->
      fs.stat source, (err, stats) ->
        return watchErr err if err
        return rewatch() if prevStats and stats.size is prevStats.size and
          stats.mtime.getTime() is prevStats.mtime.getTime()
        prevStats = stats
        fs.readFile source, (err, code) ->
          return watchErr err if err
          compileScript(source, code.toString(), base)
          rewatch()

  try
    watcher = fs.watch source, compile
  catch e
    watchErr e

  rewatch = ->
    watcher?.close()
    watcher = fs.watch source, compile

Watch a directory of files for new additions.

watchDir = (source, base) ->
  readdirTimeout = null
  try
    watcher = fs.watch source, ->
      clearTimeout readdirTimeout
      readdirTimeout = wait 25, ->
        fs.readdir source, (err, files) ->
          if err
            throw err unless err.code is 'ENOENT'
            watcher.close()
            return unwatchDir source, base
          for file in files when not hidden(file) and not notSources[file]
            file = path.join source, file
            continue if sources.some (s) -> s.indexOf(file) >= 0
            sources.push file
            sourceCode.push null
            compilePath file, no, base
  catch e
    throw e unless e.code is 'ENOENT'

unwatchDir = (source, base) ->
  prevSources = sources[..]
  toRemove = (file for file in sources when file.indexOf(source) >= 0)
  removeSource file, base, yes for file in toRemove
  return unless sources.some (s, i) -> prevSources[i] isnt s
  compileJoin()

Remove a file from our source list, and source code cache. Optionally remove the compiled JS version as well.

removeSource = (source, base, removeJs) ->
  index = sources.indexOf source
  sources.splice index, 1
  sourceCode.splice index, 1
  if removeJs and not opts.join
    jsPath = outputPath source, base
    exists jsPath, (itExists) ->
      if itExists
        fs.unlink jsPath, (err) ->
          throw err if err and err.code isnt 'ENOENT'
          timeLog "removed #{source}"

Get the corresponding output JavaScript path for a source file.

outputPath = (source, base) ->
  filename  = path.basename(source, path.extname(source)) + '.js'
  srcDir    = path.dirname source
  baseDir   = if base is '.' then srcDir else srcDir.substring base.length
  dir       = if opts.output then path.join opts.output, baseDir else srcDir
  path.join dir, filename

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.

writeJs = (source, js, base) ->
  jsPath = outputPath source, base
  jsDir  = path.dirname jsPath
  compile = ->
    js = ' ' if js.length <= 0
    fs.writeFile jsPath, js, (err) ->
      if err
        printLine err.message
      else if opts.compile and opts.watch
        timeLog "compiled #{source}"
  exists jsDir, (itExists) ->
    if itExists then compile() else exec "mkdir -p #{jsDir}", compile

Convenience for cleaner setTimeouts.

wait = (milliseconds, func) -> setTimeout func, milliseconds

When watching scripts, it's useful to log changes with the timestamp.

timeLog = (message) ->
  console.log "#{(new Date).toLocaleTimeString()} - #{message}"

Pipe compiled JS through JSLint (requires a working jsl command), printing any errors or warnings that arise.

lint = (file, js) ->
  printIt = (buffer) -> printLine file + ':\t' + buffer.toString().trim()
  conf = __dirname + '/../../extras/jsl.conf'
  jsl = spawn 'jsl', ['-nologo', '-stdin', '-conf', conf]
  jsl.stdout.on 'data', printIt
  jsl.stderr.on 'data', printIt
  jsl.stdin.write js
  jsl.stdin.end()

Pretty-print a stream of tokens.

printTokens = (tokens) ->
  strings = for token in tokens
    [tag, value] = [token[0], token[1].toString().replace(/\n/, '\\n')]
    "[#{tag} #{value}]"
  printLine strings.join(' ')

Use the OptionParser module to extract all options from process.argv that are specified in SWITCHES.

parseOptions = ->
  optionParser  = new optparse.OptionParser SWITCHES, BANNER
  o = opts      = optionParser.parse process.argv[2..]
  o.compile     or=  !!o.output
  o.run         = not (o.compile or o.print or o.lint)
  o.print       = !!  (o.print or (o.eval or o.stdio and o.compile))
  sources       = o.arguments
  sourceCode[i] = null for source, i in sources
  return

The compile-time options to pass to the CoffeeScript compiler.

compileOptions = (filename) ->
  {filename, bare: opts.bare, header: opts.compile}

Start up a new Node.js instance with the arguments in --nodejs passed to the node binary, preserving the other options.

forkNode = ->
  nodeArgs = opts.nodejs.split /\s+/
  args     = process.argv[1..]
  args.splice args.indexOf('--nodejs'), 2
  spawn process.execPath, nodeArgs.concat(args),
    cwd:        process.cwd()
    env:        process.env
    customFds:  [0, 1, 2]

Print the --help usage message and exit. Deprecated switches are not shown.

usage = ->
  printLine (new optparse.OptionParser SWITCHES, BANNER).help()

Print the --version message and exit.

version = ->
  printLine "CoffeeScript version #{CoffeeScript.VERSION}"

coffee-script-1.4.0/documentation/docs/docco.css000066400000000000000000000160471204160075300216550ustar00rootroot00000000000000/*--------------------- Layout and Typography ----------------------------*/ body { font-family: 'Palatino Linotype', 'Book Antiqua', Palatino, FreeSerif, serif; font-size: 15px; line-height: 22px; color: #252519; margin: 0; padding: 0; } a { color: #261a3b; } a:visited { color: #261a3b; } p { margin: 0 0 15px 0; } h1, h2, h3, h4, h5, h6 { margin: 0px 0 15px 0; } h1 { margin-top: 40px; } hr { border: 0 none; border-top: 1px solid #e5e5ee; height: 1px; margin: 20px 0; } #container { position: relative; } #background { position: fixed; top: 0; left: 525px; right: 0; bottom: 0; background: #f5f5ff; border-left: 1px solid #e5e5ee; z-index: -1; } #jump_to, #jump_page { background: white; -webkit-box-shadow: 0 0 25px #777; -moz-box-shadow: 0 0 25px #777; -webkit-border-bottom-left-radius: 5px; -moz-border-radius-bottomleft: 5px; font: 10px Arial; text-transform: uppercase; cursor: pointer; text-align: right; } #jump_to, #jump_wrapper { position: fixed; right: 0; top: 0; padding: 5px 10px; } #jump_wrapper { padding: 0; display: none; } #jump_to:hover #jump_wrapper { display: block; } #jump_page { padding: 5px 0 3px; margin: 0 0 25px 25px; } #jump_page .source { display: block; padding: 5px 10px; text-decoration: none; border-top: 1px solid #eee; } #jump_page .source:hover { background: #f5f5ff; } #jump_page .source:first-child { } table td { border: 0; outline: 0; } td.docs, th.docs { max-width: 450px; min-width: 450px; min-height: 5px; padding: 10px 25px 1px 50px; overflow-x: hidden; vertical-align: top; text-align: left; } .docs pre { margin: 15px 0 15px; padding-left: 15px; } .docs p tt, .docs p code { background: #f8f8ff; border: 1px solid #dedede; font-size: 12px; padding: 0 0.2em; } .pilwrap { position: relative; } .pilcrow { font: 12px Arial; text-decoration: none; color: #454545; position: absolute; top: 3px; left: -20px; padding: 1px 2px; opacity: 0; -webkit-transition: opacity 0.2s linear; } td.docs:hover .pilcrow { opacity: 1; } td.code, th.code { padding: 14px 15px 16px 25px; width: 100%; vertical-align: top; background: #f5f5ff; border-left: 1px solid #e5e5ee; } pre, tt, code { font-size: 12px; line-height: 18px; font-family: Menlo, Monaco, Consolas, "Lucida Console", monospace; margin: 0; padding: 0; } /*---------------------- Syntax Highlighting -----------------------------*/ td.linenos { background-color: #f0f0f0; padding-right: 10px; } span.lineno { background-color: #f0f0f0; padding: 0 5px 0 5px; } body .hll { background-color: #ffffcc } body .c { color: #408080; font-style: italic } /* Comment */ body .err { border: 1px solid #FF0000 } /* Error */ body .k { color: #954121 } /* Keyword */ body .o { color: #666666 } /* Operator */ body .cm { color: #408080; font-style: italic } /* Comment.Multiline */ body .cp { color: #BC7A00 } /* Comment.Preproc */ body .c1 { color: #408080; font-style: italic } /* Comment.Single */ body .cs { color: #408080; font-style: italic } /* Comment.Special */ body .gd { color: #A00000 } /* Generic.Deleted */ body .ge { font-style: italic } /* Generic.Emph */ body .gr { color: #FF0000 } /* Generic.Error */ body .gh { color: #000080; font-weight: bold } /* Generic.Heading */ body .gi { color: #00A000 } /* Generic.Inserted */ body .go { color: #808080 } /* Generic.Output */ body .gp { color: #000080; font-weight: bold } /* Generic.Prompt */ body .gs { font-weight: bold } /* Generic.Strong */ body .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ body .gt { color: #0040D0 } /* Generic.Traceback */ body .kc { color: #954121 } /* Keyword.Constant */ body .kd { color: #954121; font-weight: bold } /* Keyword.Declaration */ body .kn { color: #954121; font-weight: bold } /* Keyword.Namespace */ body .kp { color: #954121 } /* Keyword.Pseudo */ body .kr { color: #954121; font-weight: bold } /* Keyword.Reserved */ body .kt { color: #B00040 } /* Keyword.Type */ body .m { color: #666666 } /* Literal.Number */ body .s { color: #219161 } /* Literal.String */ body .na { color: #7D9029 } /* Name.Attribute */ body .nb { color: #954121 } /* Name.Builtin */ body .nc { color: #0000FF; font-weight: bold } /* Name.Class */ body .no { color: #880000 } /* Name.Constant */ body .nd { color: #AA22FF } /* Name.Decorator */ body .ni { color: #999999; font-weight: bold } /* Name.Entity */ body .ne { color: #D2413A; font-weight: bold } /* Name.Exception */ body .nf { color: #0000FF } /* Name.Function */ body .nl { color: #A0A000 } /* Name.Label */ body .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */ body .nt { color: #954121; font-weight: bold } /* Name.Tag */ body .nv { color: #19469D } /* Name.Variable */ body .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */ body .w { color: #bbbbbb } /* Text.Whitespace */ body .mf { color: #666666 } /* Literal.Number.Float */ body .mh { color: #666666 } /* Literal.Number.Hex */ body .mi { color: #666666 } /* Literal.Number.Integer */ body .mo { color: #666666 } /* Literal.Number.Oct */ body .sb { color: #219161 } /* Literal.String.Backtick */ body .sc { color: #219161 } /* Literal.String.Char */ body .sd { color: #219161; font-style: italic } /* Literal.String.Doc */ body .s2 { color: #219161 } /* Literal.String.Double */ body .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */ body .sh { color: #219161 } /* Literal.String.Heredoc */ body .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */ body .sx { color: #954121 } /* Literal.String.Other */ body .sr { color: #BB6688 } /* Literal.String.Regex */ body .s1 { color: #219161 } /* Literal.String.Single */ body .ss { color: #19469D } /* Literal.String.Symbol */ body .bp { color: #954121 } /* Name.Builtin.Pseudo */ body .vc { color: #19469D } /* Name.Variable.Class */ body .vg { color: #19469D } /* Name.Variable.Global */ body .vi { color: #19469D } /* Name.Variable.Instance */ body .il { color: #666666 } /* Literal.Number.Integer.Long */coffee-script-1.4.0/documentation/docs/grammar.html000066400000000000000000003036031204160075300223650ustar00rootroot00000000000000 grammar.coffee

grammar.coffee

The CoffeeScript parser is generated by Jison from this grammar file. Jison is a bottom-up parser generator, similar in style to Bison, implemented in JavaScript. It can recognize LALR(1), LR(0), SLR(1), and LR(1) 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 the token sequence against the rules below. When a match can be made, it reduces into the nonterminal (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'

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. 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 = (patternString, action, options) ->
  patternString = patternString.replace /\s{2,}/g, ' '
  return [patternString, '$$ = $1;', options] unless action
  action = if match = unwrap.exec action then match[1] else "(#{action}())"
  action = action.replace /\bnew /g, '$&yy.'
  action = action.replace /\b(?:Block\.wrap|extend)\b/g, 'yy.$&'
  [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 '',                                       -> new Block
    o 'Body'
    o 'Block TERMINATOR'
  ]

Any list of statements and expressions, separated by line breaks or semicolons.

  Body: [
    o 'Line',                                   -> Block.wrap [$1]
    o 'Body TERMINATOR Line',                   -> $1.push $3
    o 'Body TERMINATOR'
  ]

Block 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 'Comment'
    o 'STATEMENT',                              -> new Literal $1
  ]

All the different types of expressions in our language. The basic unit of CoffeeScript is the Expression -- everything that can be an expression is one. Blocks serve as the building blocks of many other rules, making them somewhat circular.

  Expression: [
    o 'Value'
    o 'Invocation'
    o 'Code'
    o 'Operation'
    o 'Assign'
    o 'If'
    o 'Try'
    o 'While'
    o 'For'
    o 'Switch'
    o 'Class'
    o 'Throw'
  ]

An indented block of expressions. Note that the Rewriter will convert some postfix forms into blocks for us, by adjusting the token stream.

  Block: [
    o 'INDENT OUTDENT',                         -> new Block
    o 'INDENT Body OUTDENT',                    -> $2
  ]

A literal identifier, a variable name or property.

  Identifier: [
    o 'IDENTIFIER',                             -> new Literal $1
  ]

Alphanumerics are separated from the other Literal matchers because they can also serve as keys in object literals.

  AlphaNumeric: [
    o 'NUMBER',                                 -> new Literal $1
    o 'STRING',                                 -> new Literal $1
  ]

All of our immediate values. Generally these can be passed straight through and printed to JavaScript.

  Literal: [
    o 'AlphaNumeric'
    o 'JS',                                     -> new Literal $1
    o 'REGEX',                                  -> new Literal $1
    o 'DEBUGGER',                               -> new Literal $1
    o 'UNDEFINED',                              -> new Undefined
    o 'NULL',                                   -> new Null
    o 'BOOL',                                   -> new Bool $1
  ]

Assignment of a variable, property, or index to a value.

  Assign: [
    o 'Assignable = Expression',                -> new Assign $1, $3
    o 'Assignable = TERMINATOR Expression',     -> new Assign $1, $4
    o 'Assignable = INDENT Expression OUTDENT', -> new Assign $1, $4
  ]

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 'ObjAssignable',                          -> new Value $1
    o 'ObjAssignable : Expression',             -> new Assign new Value($1), $3, 'object'
    o 'ObjAssignable :
       INDENT Expression OUTDENT',              -> new Assign new Value($1), $4, 'object'
    o 'Comment'
  ]

  ObjAssignable: [
    o 'Identifier'
    o 'AlphaNumeric'
    o 'ThisProperty'
  ]

A return statement from a function body.

  Return: [
    o 'RETURN Expression',                      -> new Return $2
    o 'RETURN',                                 -> new Return
  ]

A block comment.

  Comment: [
    o 'HERECOMMENT',                            -> new Comment $1
  ]

The Code node is the function literal. It's defined by an indented block of Block preceded by a function arrow, with an optional parameter list.

  Code: [
    o 'PARAM_START ParamList PARAM_END FuncGlyph Block', -> new Code $2, $5, $4
    o 'FuncGlyph Block',                        -> new Code [], $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 '->',                                     -> 'func'
    o '=>',                                     -> 'boundfunc'
  ]

An optional, trailing comma.

  OptComma: [
    o ''
    o ','
  ]

The list of parameters that a function accepts can be of any length.

  ParamList: [
    o '',                                       -> []
    o 'Param',                                  -> [$1]
    o 'ParamList , Param',                      -> $1.concat $3
    o 'ParamList OptComma TERMINATOR Param',    -> $1.concat $4
    o 'ParamList OptComma INDENT ParamList OptComma OUTDENT', -> $1.concat $4
  ]

A single parameter in a function definition can be ordinary, or a splat that hoovers up the remaining arguments.

  Param: [
    o 'ParamVar',                               -> new Param $1
    o 'ParamVar ...',                           -> new Param $1, null, on
    o 'ParamVar = Expression',                  -> new Param $1, $3
  ]

Function Parameters

  ParamVar: [
    o 'Identifier'
    o 'ThisProperty'
    o 'Array'
    o 'Object'
  ]

A splat that occurs outside of a parameter list.

  Splat: [
    o 'Expression ...',                         -> new Splat $1
  ]

Variables and properties that can be assigned to.

  SimpleAssignable: [
    o 'Identifier',                             -> new Value $1
    o 'Value Accessor',                         -> $1.add $2
    o 'Invocation Accessor',                    -> new Value $1, [].concat $2
    o 'ThisProperty'
  ]

Everything that can be assigned to.

  Assignable: [
    o 'SimpleAssignable'
    o 'Array',                                  -> new Value $1
    o 'Object',                                 -> new Value $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',                                -> new Value $1
    o 'Parenthetical',                          -> new Value $1
    o 'Range',                                  -> new Value $1
    o 'This'
  ]

The general group of accessors into an object, by property, by prototype or by array index or slice.

  Accessor: [
    o '.  Identifier',                          -> new Access $2
    o '?. Identifier',                          -> new Access $2, 'soak'
    o ':: Identifier',                          -> [(new Access new Literal 'prototype'), new Access $2]
    o '::',                                     -> new Access new Literal 'prototype'
    o 'Index'
  ]

Indexing into an object or array using bracket notation.

  Index: [
    o 'INDEX_START IndexValue INDEX_END',       -> $2
    o 'INDEX_SOAK  Index',                      -> extend $2, soak : yes
  ]

  IndexValue: [
    o 'Expression',                             -> new Index $1
    o 'Slice',                                  -> new Slice $1
  ]

In CoffeeScript, an object literal is simply a list of assignments.

  Object: [
    o '{ AssignList OptComma }',                -> new Obj $2, $1.generated
  ]

Assignment of properties within an object literal can be separated by comma, as in JavaScript, or simply by newline.

  AssignList: [
    o '',                                                       -> []
    o 'AssignObj',                                              -> [$1]
    o 'AssignList , AssignObj',                                 -> $1.concat $3
    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, and optional references to the superclass.

  Class: [
    o 'CLASS',                                           -> new Class
    o 'CLASS Block',                                     -> new Class null, null, $2
    o 'CLASS EXTENDS Expression',                        -> new Class null, $3
    o 'CLASS EXTENDS Expression Block',                  -> new Class null, $3, $4
    o 'CLASS SimpleAssignable',                          -> new Class $2
    o 'CLASS SimpleAssignable Block',                    -> new Class $2, null, $3
    o 'CLASS SimpleAssignable EXTENDS Expression',       -> new Class $2, $4
    o 'CLASS SimpleAssignable EXTENDS Expression Block', -> new Class $2, $4, $5
  ]

Ordinary function invocation, or a chained series of calls.

  Invocation: [
    o 'Value OptFuncExist Arguments',           -> new Call $1, $3, $2
    o 'Invocation OptFuncExist Arguments',      -> new Call $1, $3, $2
    o 'SUPER',                                  -> new Call 'super', [new Splat new Literal 'arguments']
    o 'SUPER Arguments',                        -> new Call 'super', $2
  ]

An optional existence check on a function.

  OptFuncExist: [
    o '',                                       -> no
    o 'FUNC_EXIST',                             -> yes
  ]

The list of arguments to a function call.

  Arguments: [
    o 'CALL_START CALL_END',                    -> []
    o 'CALL_START ArgList OptComma CALL_END',   -> $2
  ]

A reference to the this current object.

  This: [
    o 'THIS',                                   -> new Value new Literal 'this'
    o '@',                                      -> new Value new Literal 'this'
  ]

A reference to a property on this.

  ThisProperty: [
    o '@ Identifier',                           -> new Value new Literal('this'), [new Access($2)], 'this'
  ]

The array literal.

  Array: [
    o '[ ]',                                    -> new Arr []
    o '[ ArgList OptComma ]',                   -> new Arr $2
  ]

Inclusive and exclusive range dots.

  RangeDots: [
    o '..',                                     -> 'inclusive'
    o '...',                                    -> 'exclusive'
  ]

The CoffeeScript range literal.

  Range: [
    o '[ Expression RangeDots Expression ]',    -> new Range $2, $4, $3
  ]

Array slice literals.

  Slice: [
    o 'Expression RangeDots Expression',        -> new Range $1, $3, $2
    o 'Expression RangeDots',                   -> new Range $1, null, $2
    o 'RangeDots Expression',                   -> new Range null, $2, $1
    o 'RangeDots',                              -> new Range null, null, $1
  ]

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 'Arg',                                              -> [$1]
    o 'ArgList , Arg',                                    -> $1.concat $3
    o 'ArgList OptComma TERMINATOR Arg',                  -> $1.concat $4
    o 'INDENT ArgList OptComma OUTDENT',                  -> $2
    o 'ArgList OptComma INDENT ArgList OptComma OUTDENT', -> $1.concat $4
  ]

Valid arguments are Blocks or Splats.

  Arg: [
    o 'Expression'
    o 'Splat'
  ]

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',                -> [].concat $1, $3
  ]

The variants of try/catch/finally exception handling blocks.

  Try: [
    o 'TRY Block',                              -> new Try $2
    o 'TRY Block Catch',                        -> new Try $2, $3[0], $3[1]
    o 'TRY Block FINALLY Block',                -> new Try $2, null, null, $4
    o 'TRY Block Catch FINALLY Block',          -> new Try $2, $3[0], $3[1], $5
  ]

A catch clause names its error and runs a block of code.

  Catch: [
    o 'CATCH Identifier Block',                 -> [$2, $3]
  ]

Throw an exception object.

  Throw: [
    o 'THROW Expression',                       -> new Throw $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 '( Body )',                               -> new Parens $2
    o '( INDENT Body OUTDENT )',                -> new Parens $3
  ]

The condition portion of a while loop.

  WhileSource: [
    o 'WHILE Expression',                       -> new While $2
    o 'WHILE Expression WHEN Expression',       -> new While $2, guard: $4
    o 'UNTIL Expression',                       -> new While $2, invert: true
    o 'UNTIL Expression WHEN Expression',       -> new While $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.addBody $2
    o 'Statement  WhileSource',                 -> $2.addBody Block.wrap [$1]
    o 'Expression WhileSource',                 -> $2.addBody Block.wrap [$1]
    o 'Loop',                                   -> $1
  ]

  Loop: [
    o 'LOOP Block',                             -> new While(new Literal 'true').addBody $2
    o 'LOOP Expression',                        -> new While(new Literal 'true').addBody Block.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  ForBody',                     -> new For $1, $2
    o 'Expression ForBody',                     -> new For $1, $2
    o 'ForBody    Block',                       -> new For $2, $1
  ]

  ForBody: [
    o 'FOR Range',                              -> source: new Value($2)
    o 'ForStart ForSource',                     -> $2.own = $1.own; $2.name = $1[0]; $2.index = $1[1]; $2
  ]

  ForStart: [
    o 'FOR ForVariables',                       -> $2
    o 'FOR OWN ForVariables',                   -> $3.own = yes; $3
  ]

An array of all accepted values for a variable inside the loop. This enables support for pattern matching.

  ForValue: [
    o 'Identifier'
    o 'ThisProperty'
    o 'Array',                                  -> new Value $1
    o 'Object',                                 -> new Value $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 'ForValue',                               -> [$1]
    o 'ForValue , ForValue',                    -> [$1, $3]
  ]

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 'FORIN Expression',                               -> source: $2
    o 'FOROF Expression',                               -> source: $2, object: yes
    o 'FORIN Expression WHEN Expression',               -> source: $2, guard: $4
    o 'FOROF Expression WHEN Expression',               -> source: $2, guard: $4, object: yes
    o 'FORIN Expression BY Expression',                 -> source: $2, step:  $4
    o 'FORIN Expression WHEN Expression BY Expression', -> source: $2, guard: $4, step: $6
    o 'FORIN Expression BY Expression WHEN Expression', -> source: $2, step:  $4, guard: $6
  ]

  Switch: [
    o 'SWITCH Expression INDENT Whens OUTDENT',            -> new Switch $2, $4
    o 'SWITCH Expression INDENT Whens ELSE Block OUTDENT', -> new Switch $2, $4, $6
    o 'SWITCH INDENT Whens OUTDENT',                       -> new Switch null, $3
    o 'SWITCH INDENT Whens ELSE Block OUTDENT',            -> new Switch null, $3, $5
  ]

  Whens: [
    o 'When'
    o 'Whens When',                             -> $1.concat $2
  ]

An individual When clause, with action.

  When: [
    o 'LEADING_WHEN SimpleArgs Block',            -> [[$2, $3]]
    o 'LEADING_WHEN SimpleArgs Block TERMINATOR', -> [[$2, $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.

  IfBlock: [
    o 'IF Expression Block',                    -> new If $2, $3, type: $1
    o 'IfBlock ELSE IF Expression Block',       -> $1.addElse new If $4, $5, type: $3
  ]

The full complement of if expressions, including postfix one-liner if and unless.

  If: [
    o 'IfBlock'
    o 'IfBlock ELSE Block',                     -> $1.addElse $3
    o 'Statement  POST_IF Expression',          -> new If $3, Block.wrap([$1]), type: $2, statement: true
    o 'Expression POST_IF Expression',          -> new If $3, Block.wrap([$1]), type: $2, statement: 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 'UNARY Expression',                       -> new Op $1 , $2
    o '-     Expression',                      (-> new Op '-', $2), prec: 'UNARY'
    o '+     Expression',                      (-> new Op '+', $2), prec: 'UNARY'

    o '-- SimpleAssignable',                    -> new Op '--', $2
    o '++ SimpleAssignable',                    -> new Op '++', $2
    o 'SimpleAssignable --',                    -> new Op '--', $1, null, true
    o 'SimpleAssignable ++',                    -> new Op '++', $1, null, true

The existential operator.

    o 'Expression ?',                           -> new Existence $1

    o 'Expression +  Expression',               -> new Op '+' , $1, $3
    o 'Expression -  Expression',               -> new Op '-' , $1, $3

    o 'Expression MATH     Expression',         -> new Op $2, $1, $3
    o 'Expression SHIFT    Expression',         -> new Op $2, $1, $3
    o 'Expression COMPARE  Expression',         -> new Op $2, $1, $3
    o 'Expression LOGIC    Expression',         -> new Op $2, $1, $3
    o 'Expression RELATION Expression',         ->
      if $2.charAt(0) is '!'
        new Op($2[1..], $1, $3).invert()
      else
        new Op $2, $1, $3

    o 'SimpleAssignable COMPOUND_ASSIGN
       Expression',                             -> new Assign $1, $3, $2
    o 'SimpleAssignable COMPOUND_ASSIGN
       INDENT Expression OUTDENT',              -> new Assign $1, $4, $2
    o 'SimpleAssignable EXTENDS Expression',    -> new Extends $1, $3
  ]

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',      '.', '?.', '::']
  ['left',      'CALL_START', 'CALL_END']
  ['nonassoc',  '++', '--']
  ['left',      '?']
  ['right',     'UNARY']
  ['left',      'MATH']
  ['left',      '+', '-']
  ['left',      'SHIFT']
  ['left',      'RELATION']
  ['left',      'COMPARE']
  ['left',      'LOGIC']
  ['nonassoc',  'INDENT', 'OUTDENT']
  ['right',     '=', ':', 'COMPOUND_ASSIGN', 'RETURN', 'THROW', 'EXTENDS']
  ['right',     'FORIN', 'FOROF', 'BY', 'WHEN']
  ['right',     'IF', 'ELSE', 'FOR', 'WHILE', 'UNTIL', 'LOOP', 'SUPER', 'CLASS']
  ['right',     'POST_IF']
]

Wrapping Up

Finally, now that we have our grammar and our operators, we can create our Jison.Parser. We do this by processing all of our rules, recording all terminals (every symbol which does not appear as the name of a rule above) as "tokens".

tokens = []
for name, alternatives of grammar
  grammar[name] = for alt in alternatives
    for token in alt[0].split ' '
      tokens.push token unless grammar[token]
    alt[1] = "return #{alt[1]}" if name is 'Root'
    alt

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).

exports.parser = new Parser
  tokens      : tokens.join ' '
  bnf         : grammar
  operators   : operators.reverse()
  startSymbol : 'Root'

coffee-script-1.4.0/documentation/docs/helpers.html000066400000000000000000000301441204160075300223760ustar00rootroot00000000000000 helpers.coffee

helpers.coffee

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.

Peek at the beginning of a given string to see if it matches a sequence.

exports.starts = (string, literal, start) ->
  literal is string.substr start, literal.length

Peek at the end of a given string to see if it matches a sequence.

exports.ends = (string, literal, back) ->
  len = literal.length
  literal is string.substr string.length - len - (back or 0), len

Trim out all falsy values from an array.

exports.compact = (array) ->
  item for item in array when item

Count the number of occurrences of a string in a string.

exports.count = (string, substr) ->
  num = pos = 0
  return 1/0 unless substr.length
  num++ while pos = 1 + string.indexOf substr, pos
  num

Merge objects, returning a fresh copy with attributes from both sides. Used every time Base#compile is called, to allow properties in the options hash to propagate down the tree without polluting other branches.

exports.merge = (options, overrides) ->
  extend (extend {}, options), overrides

Extend a source object with the properties of another object (shallow copy).

extend = exports.extend = (object, properties) ->
  for key, val of properties
    object[key] = val
  object

Return a flattened version of an array. Handy for getting a list of children from the nodes.

exports.flatten = flatten = (array) ->
  flattened = []
  for element in array
    if element instanceof Array
      flattened = flattened.concat flatten element
    else
      flattened.push element
  flattened

Delete a key from an object, returning the value. Useful when a node is looking for a particular method in an options hash.

exports.del = (obj, key) ->
  val =  obj[key]
  delete obj[key]
  val

Gets the last item of an array(-like) object.

exports.last = (array, back) -> array[array.length - (back or 0) - 1]

Typical Array::some

exports.some = Array::some ? (fn) ->
  return true for e in this when fn e
  false

coffee-script-1.4.0/documentation/docs/index.html000066400000000000000000000062441204160075300220470ustar00rootroot00000000000000 index.coffee

index.coffee

Loader for CoffeeScript as a Node.js library.

exports[key] = val for key, val of require './coffee-script'

coffee-script-1.4.0/documentation/docs/lexer.html000066400000000000000000003434131204160075300220610ustar00rootroot00000000000000 lexer.coffee

lexer.coffee

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, lineNumber]

Which is a format that can be fed directly into Jison.

{Rewriter, INVERSES} = require './rewriter'

Import the helpers we need.

{count, starts, compact, last} = require './helpers'

The Lexer Class

The Lexer class reads a stream of CoffeeScript and divvies it up into tagged tokens. Some potential ambiguity in the grammar has been avoided by pushing some extra smarts into the Lexer.

exports.Lexer = class 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 returning the number of characters it has consumed.

Before returning the token stream, run it through the Rewriter unless explicitly asked not to.

  tokenize: (code, opts = {}) ->
    code     = "\n#{code}" if WHITESPACE.test code
    code     = code.replace(/\r/g, '').replace TRAILING_SPACES, ''

    @code    = code           # The remainder of the source code.
    @line    = opts.line or 0 # The current line.
    @indent  = 0              # The current indentation level.
    @indebt  = 0              # The over-indentation at the current level.
    @outdebt = 0              # The under-outdentation at the current level.
    @indents = []             # The stack of all current indentation levels.
    @ends    = []             # The stack for pairing up tokens.
    @tokens  = []             # Stream of parsed tokens in the form `['TYPE', value, line]`.

At every position, run through this list of attempted matches, short-circuiting if any of them succeed. Their order determines precedence: @literalToken is the fallback catch-all.

    i = 0
    while @chunk = code[i..]
      i += @identifierToken() or
           @commentToken()    or
           @whitespaceToken() or
           @lineToken()       or
           @heredocToken()    or
           @stringToken()     or
           @numberToken()     or
           @regexToken()      or
           @jsToken()         or
           @literalToken()

    @closeIndentation()
    @error "missing #{tag}" if tag = @ends.pop()
    return @tokens if opts.rewrite is off
    (new Rewriter).rewrite @tokens

Tokenizers

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.

  identifierToken: ->
    return 0 unless match = IDENTIFIER.exec @chunk
    [input, id, colon] = match

    if id is 'own' and @tag() is 'FOR'
      @token 'OWN', id
      return id.length
    forcedIdentifier = colon or
      (prev = last @tokens) and (prev[0] in ['.', '?.', '::'] or
      not prev.spaced and prev[0] is '@')
    tag = 'IDENTIFIER'

    if not forcedIdentifier and (id in JS_KEYWORDS or id in COFFEE_KEYWORDS)
      tag = id.toUpperCase()
      if tag is 'WHEN' and @tag() in LINE_BREAK
        tag = 'LEADING_WHEN'
      else if tag is 'FOR'
        @seenFor = yes
      else if tag is 'UNLESS'
        tag = 'IF'
      else if tag in UNARY
        tag = 'UNARY'
      else if tag in RELATION
        if tag isnt 'INSTANCEOF' and @seenFor
          tag = 'FOR' + tag
          @seenFor = no
        else
          tag = 'RELATION'
          if @value() is '!'
            @tokens.pop()
            id = '!' + id

    if id in JS_FORBIDDEN
      if forcedIdentifier
        tag = 'IDENTIFIER'
        id  = new String id
        id.reserved = yes
      else if id in RESERVED
        @error "reserved word \"#{id}\""

    unless forcedIdentifier
      id  = COFFEE_ALIAS_MAP[id] if id in COFFEE_ALIASES
      tag = switch id
        when '!'                 then 'UNARY'
        when '==', '!='          then 'COMPARE'
        when '&&', '||'          then 'LOGIC'
        when 'true', 'false'     then 'BOOL'
        when 'break', 'continue' then 'STATEMENT'
        else  tag

    @token tag, id
    @token ':', ':' if colon
    input.length

Matches numbers, including decimals, hex, and exponential notation. Be careful not to interfere with ranges-in-progress.

  numberToken: ->
    return 0 unless match = NUMBER.exec @chunk
    number = match[0]
    if /^0[BOX]/.test number
      @error "radix prefix '#{number}' must be lowercase"
    else if /E/.test(number) and not /^0x/.test number
      @error "exponential notation '#{number}' must be indicated with a lowercase 'e'"
    else if /^0\d*[89]/.test number
      @error "decimal literal '#{number}' must not be prefixed with '0'"
    else if /^0\d+/.test number
      @error "octal literal '#{number}' must be prefixed with '0o'"
    lexedLength = number.length
    if octalLiteral = /^0o([0-7]+)/.exec number
      number = '0x' + (parseInt octalLiteral[1], 8).toString 16
    if binaryLiteral = /^0b([01]+)/.exec number
      number = '0x' + (parseInt binaryLiteral[1], 2).toString 16
    @token 'NUMBER', number
    lexedLength

Matches strings, including multi-line strings. Ensures that quotation marks are balanced within the string's contents, and within nested interpolations.

  stringToken: ->
    switch @chunk.charAt 0
      when "'"
        return 0 unless match = SIMPLESTR.exec @chunk
        @token 'STRING', (string = match[0]).replace MULTILINER, '\\\n'
      when '"'
        return 0 unless string = @balancedString @chunk, '"'
        if 0 < string.indexOf '#{', 1
          @interpolateString string[1...-1]
        else
          @token 'STRING', @escapeLines string
      else
        return 0
    if octalEsc = /^(?:\\.|[^\\])*\\(?:0[0-7]|[1-7])/.test string
      @error "octal escape sequences #{string} are not allowed"
    @line += count string, '\n'
    string.length

Matches heredocs, adjusting indentation to the correct level, as heredocs preserve whitespace, but ignore indentation to the left.

  heredocToken: ->
    return 0 unless match = HEREDOC.exec @chunk
    heredoc = match[0]
    quote = heredoc.charAt 0
    doc = @sanitizeHeredoc match[2], quote: quote, indent: null
    if quote is '"' and 0 <= doc.indexOf '#{'
      @interpolateString doc, heredoc: yes
    else
      @token 'STRING', @makeString doc, quote, yes
    @line += count heredoc, '\n'
    heredoc.length

Matches and consumes comments.

  commentToken: ->
    return 0 unless match = @chunk.match COMMENT
    [comment, here] = match
    if here
      @token 'HERECOMMENT', @sanitizeHeredoc here,
        herecomment: true, indent: Array(@indent + 1).join(' ')
    @line += count comment, '\n'
    comment.length

Matches JavaScript interpolated directly into the source via backticks.

  jsToken: ->
    return 0 unless @chunk.charAt(0) is '`' and match = JSTOKEN.exec @chunk
    @token 'JS', (script = match[0])[1...-1]
    @line += count script, '\n'
    script.length

Matches regular expression literals. Lexing regular expressions is difficult to distinguish from division, so we borrow some basic heuristics from JavaScript and Ruby.

  regexToken: ->
    return 0 if @chunk.charAt(0) isnt '/'
    if match = HEREGEX.exec @chunk
      length = @heregexToken match
      @line += count match[0], '\n'
      return length

    prev = last @tokens
    return 0 if prev and (prev[0] in (if prev.spaced then NOT_REGEX else NOT_SPACED_REGEX))
    return 0 unless match = REGEX.exec @chunk
    [match, regex, flags] = match
    if regex[..1] is '/*' then @error 'regular expressions cannot begin with `*`'
    if regex is '//' then regex = '/(?:)/'
    @token 'REGEX', "#{regex}#{flags}"
    match.length

Matches multiline extended regular expressions.

  heregexToken: (match) ->
    [heregex, body, flags] = match
    if 0 > body.indexOf '#{'
      re = body.replace(HEREGEX_OMIT, '').replace(/\//g, '\\/')
      if re.match /^\*/ then @error 'regular expressions cannot begin with `*`'
      @token 'REGEX', "/#{ re or '(?:)' }/#{flags}"
      return heregex.length
    @token 'IDENTIFIER', 'RegExp'
    @tokens.push ['CALL_START', '(']
    tokens = []
    for [tag, value] in @interpolateString(body, regex: yes)
      if tag is 'TOKENS'
        tokens.push value...
      else
        continue unless value = value.replace HEREGEX_OMIT, ''
        value = value.replace /\\/g, '\\\\'
        tokens.push ['STRING', @makeString(value, '"', yes)]
      tokens.push ['+', '+']
    tokens.pop()
    @tokens.push ['STRING', '""'], ['+', '+'] unless tokens[0]?[0] is 'STRING'
    @tokens.push tokens...
    @tokens.push [',', ','], ['STRING', '"' + flags + '"'] if flags
    @token ')', ')'
    heregex.length

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.

  lineToken: ->
    return 0 unless match = MULTI_DENT.exec @chunk
    indent = match[0]
    @line += count indent, '\n'
    @seenFor = no
    size = indent.length - 1 - indent.lastIndexOf '\n'
    noNewlines = @unfinished()
    if size - @indebt is @indent
      if noNewlines then @suppressNewlines() else @newlineToken()
      return indent.length
    if size > @indent
      if noNewlines
        @indebt = size - @indent
        @suppressNewlines()
        return indent.length
      diff = size - @indent + @outdebt
      @token 'INDENT', diff
      @indents.push diff
      @ends.push 'OUTDENT'
      @outdebt = @indebt = 0
    else
      @indebt = 0
      @outdentToken @indent - size, noNewlines
    @indent = size
    indent.length

Record an outdent token or multiple tokens, if we happen to be moving back inwards past several recorded indents.

  outdentToken: (moveOut, noNewlines) ->
    while moveOut > 0
      len = @indents.length - 1
      if @indents[len] is undefined
        moveOut = 0
      else if @indents[len] is @outdebt
        moveOut -= @outdebt
        @outdebt = 0
      else if @indents[len] < @outdebt
        @outdebt -= @indents[len]
        moveOut  -= @indents[len]
      else
        dent = @indents.pop() - @outdebt
        moveOut -= dent
        @outdebt = 0
        @pair 'OUTDENT'
        @token 'OUTDENT', dent
    @outdebt -= moveOut if dent
    @tokens.pop() while @value() is ';'
    @token 'TERMINATOR', '\n' unless @tag() is 'TERMINATOR' or noNewlines
    this

Matches and consumes non-meaningful whitespace. Tag the previous token as being "spaced", because there are some cases where it makes a difference.

  whitespaceToken: ->
    return 0 unless (match = WHITESPACE.exec @chunk) or
                    (nline = @chunk.charAt(0) is '\n')
    prev = last @tokens
    prev[if match then 'spaced' else 'newLine'] = true if prev
    if match then match[0].length else 0

Generate a newline token. Consecutive newlines get merged together.

  newlineToken: ->
    @tokens.pop() while @value() is ';'
    @token 'TERMINATOR', '\n' unless @tag() is 'TERMINATOR'
    this

Use a \ at a line-ending to suppress the newline. The slash is removed here once its job is done.

  suppressNewlines: ->
    @tokens.pop() if @value() is '\\'
    this

We treat all other single characters as a token. E.g.: ( ) , . ! 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.

  literalToken: ->
    if match = OPERATOR.exec @chunk
      [value] = match
      @tagParameters() if CODE.test value
    else
      value = @chunk.charAt 0
    tag  = value
    prev = last @tokens
    if value is '=' and prev
      if not prev[1].reserved and prev[1] in JS_FORBIDDEN
        @error "reserved word \"#{@value()}\" can't be assigned"
      if prev[1] in ['||', '&&']
        prev[0] = 'COMPOUND_ASSIGN'
        prev[1] += '='
        return value.length
    if value is ';'
      @seenFor = no
      tag = 'TERMINATOR'
    else if value in MATH            then tag = 'MATH'
    else if value in COMPARE         then tag = 'COMPARE'
    else if value in COMPOUND_ASSIGN then tag = 'COMPOUND_ASSIGN'
    else if value in UNARY           then tag = 'UNARY'
    else if value in SHIFT           then tag = 'SHIFT'
    else if value in LOGIC or value is '?' and prev?.spaced then tag = 'LOGIC'
    else if prev and not prev.spaced
      if value is '(' and prev[0] in CALLABLE
        prev[0] = 'FUNC_EXIST' if prev[0] is '?'
        tag = 'CALL_START'
      else if value is '[' and prev[0] in INDEXABLE
        tag = 'INDEX_START'
        switch prev[0]
          when '?'  then prev[0] = 'INDEX_SOAK'
    switch value
      when '(', '{', '[' then @ends.push INVERSES[value]
      when ')', '}', ']' then @pair value
    @token tag, value
    value.length

Token Manipulators

Sanitize a heredoc or herecomment by erasing all external indentation on the left-hand side.

  sanitizeHeredoc: (doc, options) ->
    {indent, herecomment} = options
    if herecomment
      if HEREDOC_ILLEGAL.test doc
        @error "block comment cannot contain \"*/\", starting"
      return doc if doc.indexOf('\n') <= 0
    else
      while match = HEREDOC_INDENT.exec doc
        attempt = match[1]
        indent = attempt if indent is null or 0 < attempt.length < indent.length
    doc = doc.replace /// \n #{indent} ///g, '\n' if indent
    doc = doc.replace /^\n/, '' unless herecomment
    doc

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.

  tagParameters: ->
    return this if @tag() isnt ')'
    stack = []
    {tokens} = this
    i = tokens.length
    tokens[--i][0] = 'PARAM_END'
    while tok = tokens[--i]
      switch tok[0]
        when ')'
          stack.push tok
        when '(', 'CALL_START'
          if stack.length then stack.pop()
          else if tok[0] is '('
            tok[0] = 'PARAM_START'
            return this
          else return this
    this

Close up all remaining open blocks at the end of the file.

  closeIndentation: ->
    @outdentToken @indent

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, end) ->
    continueCount = 0
    stack = [end]
    for i in [1...str.length]
      if continueCount
        --continueCount
        continue
      switch letter = str.charAt i
        when '\\'
          ++continueCount
          continue
        when end
          stack.pop()
          unless stack.length
            return str[0..i]
          end = stack[stack.length - 1]
          continue
      if end is '}' and letter in ['"', "'"]
        stack.push end = letter
      else if end is '}' and letter is '/' and match = (HEREGEX.exec(str[i..]) or REGEX.exec(str[i..]))
        continueCount += match[0].length - 1
      else if end is '}' and letter is '{'
        stack.push end = '}'
      else if end is '"' and prev is '#' and letter is '{'
        stack.push end = '}'
      prev = letter
    @error "missing #{ stack.pop() }, starting"

Expand variables and expressions inside double-quoted strings using Ruby-like notation for substitution of arbitrary expressions.

"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.

  interpolateString: (str, options = {}) ->
    {heredoc, regex} = options
    tokens = []
    pi = 0
    i  = -1
    while letter = str.charAt i += 1
      if letter is '\\'
        i += 1
        continue
      unless letter is '#' and str.charAt(i+1) is '{' and
             (expr = @balancedString str[i + 1..], '}')
        continue
      tokens.push ['NEOSTRING', str[pi...i]] if pi < i
      inner = expr[1...-1]
      if inner.length
        nested = new Lexer().tokenize inner, line: @line, rewrite: off
        nested.pop()
        nested.shift() if nested[0]?[0] is 'TERMINATOR'
        if len = nested.length
          if len > 1
            nested.unshift ['(', '(', @line]
            nested.push    [')', ')', @line]
          tokens.push ['TOKENS', nested]
      i += expr.length
      pi = i + 1
    tokens.push ['NEOSTRING', str[pi..]] if i > pi < str.length
    return tokens if regex
    return @token 'STRING', '""' unless tokens.length
    tokens.unshift ['', ''] unless tokens[0][0] is 'NEOSTRING'
    @token '(', '(' if interpolated = tokens.length > 1
    for [tag, value], i in tokens
      @token '+', '+' if i
      if tag is 'TOKENS'
        @tokens.push value...
      else
        @token 'STRING', @makeString value, '"', heredoc
    @token ')', ')' if interpolated
    tokens

Pairs up a closing token, ensuring that all listed pairs of tokens are correctly balanced throughout the course of the token stream.

  pair: (tag) ->
    unless tag is wanted = last @ends
      @error "unmatched #{tag}" unless 'OUTDENT' is wanted

Auto-close INDENT to support syntax like this:

el.click((event) ->
  el.hide())
      @indent -= size = last @indents
      @outdentToken size, true
      return @pair tag
    @ends.pop()

Helpers

Add a token to the results, taking note of the line number.

  token: (tag, value) ->
    @tokens.push [tag, value, @line]

Peek at a tag in the current token stream.

  tag: (index, tag) ->
    (tok = last @tokens, index) and if tag then tok[0] = tag else tok[0]

Peek at a value in the current token stream.

  value: (index, val) ->
    (tok = last @tokens, index) and if val then tok[1] = val else tok[1]

Are we in the midst of an unfinished expression?

  unfinished: ->
    LINE_CONTINUER.test(@chunk) or
    @tag() in ['\\', '.', '?.', 'UNARY', 'MATH', '+', '-', 'SHIFT', 'RELATION'
               'COMPARE', 'LOGIC', 'THROW', 'EXTENDS']

Converts newlines for string literals.

  escapeLines: (str, heredoc) ->
    str.replace MULTILINER, if heredoc then '\\n' else ''

Constructs a string token by escaping quotes and newlines.

  makeString: (body, quote, heredoc) ->
    return quote + quote unless body
    body = body.replace /\\([\s\S])/g, (match, contents) ->
      if contents in ['\n', quote] then contents else match
    body = body.replace /// #{quote} ///g, '\\$&'
    quote + @escapeLines(body, heredoc) + quote

Throws a syntax error on the current @line.

  error: (message) ->
    throw SyntaxError "#{message} on line #{ @line + 1}"

Constants

Keywords that CoffeeScript shares in common with JavaScript.

JS_KEYWORDS = [
  'true', 'false', 'null', 'this'
  'new', 'delete', 'typeof', 'in', 'instanceof'
  'return', 'throw', 'break', 'continue', 'debugger'
  'if', 'else', 'switch', 'for', 'while', 'do', 'try', 'catch', 'finally'
  'class', 'extends', 'super'
]

CoffeeScript-only keywords.

COFFEE_KEYWORDS = ['undefined', 'then', 'unless', 'until', 'loop', 'of', 'by', 'when']

COFFEE_ALIAS_MAP =
  and  : '&&'
  or   : '||'
  is   : '=='
  isnt : '!='
  not  : '!'
  yes  : 'true'
  no   : 'false'
  on   : 'true'
  off  : 'false'

COFFEE_ALIASES  = (key for key of COFFEE_ALIAS_MAP)
COFFEE_KEYWORDS = COFFEE_KEYWORDS.concat COFFEE_ALIASES

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', 'function', 'var', 'void', 'with', 'const', 'let', 'enum'
  'export', 'import', 'native', '__hasProp', '__extends', '__slice', '__bind'
  '__indexOf', 'implements', 'interface', 'package', 'private', 'protected'
  'public', 'static', 'yield'
]

STRICT_PROSCRIBED = ['arguments', 'eval']

The superset of both JavaScript keywords and reserved words, none of which may be used as identifiers or properties.

JS_FORBIDDEN = JS_KEYWORDS.concat(RESERVED).concat(STRICT_PROSCRIBED)

exports.RESERVED = RESERVED.concat(JS_KEYWORDS).concat(COFFEE_KEYWORDS).concat(STRICT_PROSCRIBED)
exports.STRICT_PROSCRIBED = STRICT_PROSCRIBED

Token matching regexes.

IDENTIFIER = /// ^
  ( [$A-Za-z_\x7f-\uffff][$\w\x7f-\uffff]* )
  ( [^\n\S]* : (?!:) )?  # Is this a property name?
///

NUMBER     = ///
  ^ 0b[01]+    |              # binary
  ^ 0o[0-7]+   |              # octal
  ^ 0x[\da-f]+ |              # hex
  ^ \d*\.?\d+ (?:e[+-]?\d+)?  # decimal
///i

HEREDOC    = /// ^ ("""|''') ([\s\S]*?) (?:\n[^\n\S]*)? \1 ///

OPERATOR   = /// ^ (
  ?: [-=]>             # function
   | [-+*/%<>&|^!?=]=  # compound assign / compare
   | >>>=?             # zero-fill right shift
   | ([-+:])\1         # doubles
   | ([&|<>])\2=?      # logic / shift
   | \?\.              # soak access
   | \.{2,3}           # range or splat
) ///

WHITESPACE = /^[^\n\S]+/

COMMENT    = /^###([^#][\s\S]*?)(?:###[^\n\S]*|(?:###)?$)|^(?:\s*#(?!##[^#]).*)+/

CODE       = /^[-=]>/

MULTI_DENT = /^(?:\n[^\n\S]*)+/

SIMPLESTR  = /^'[^\\']*(?:\\.[^\\']*)*'/

JSTOKEN    = /^`[^\\`]*(?:\\.[^\\`]*)*`/

Regex-matching-regexes.

REGEX = /// ^
  (/ (?! [\s=] )   # disallow leading whitespace or equals signs
  [^ [ / \n \\ ]*  # every other thing
  (?:
    (?: \\[\s\S]   # anything escaped
      | \[         # character class
           [^ \] \n \\ ]*
           (?: \\[\s\S] [^ \] \n \\ ]* )*
         ]
    ) [^ [ / \n \\ ]*
  )*
  /) ([imgy]{0,4}) (?!\w)
///

HEREGEX      = /// ^ /{3} ([\s\S]+?) /{3} ([imgy]{0,4}) (?!\w) ///

HEREGEX_OMIT = /\s+(?:#.*)?/g

Token cleaning regexes.

MULTILINER      = /\n/g

HEREDOC_INDENT  = /\n+([^\n\S]*)/g

HEREDOC_ILLEGAL = /\*\//

LINE_CONTINUER  = /// ^ \s* (?: , | \??\.(?![.\d]) | :: ) ///

TRAILING_SPACES = /\s+$/

Compound assignment tokens.

COMPOUND_ASSIGN = [
  '-=', '+=', '/=', '*=', '%=', '||=', '&&=', '?=', '<<=', '>>=', '>>>=', '&=', '^=', '|='
]

Unary tokens.

UNARY   = ['!', '~', 'NEW', 'TYPEOF', 'DELETE', 'DO']

Logical tokens.

LOGIC   = ['&&', '||', '&', '|', '^']

Bit-shifting tokens.

SHIFT   = ['<<', '>>', '>>>']

Comparison tokens.

COMPARE = ['==', '!=', '<', '>', '<=', '>=']

Mathematical tokens.

MATH    = ['*', '/', '%']

Relational tokens that are negatable with not prefix.

RELATION = ['IN', 'OF', 'INSTANCEOF']

Boolean tokens.

BOOL = ['TRUE', 'FALSE']

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', 'BOOL', 'NULL', 'UNDEFINED', '++', '--', ']']

If the previous token is not spaced, there are more preceding tokens that force a division parse:

NOT_SPACED_REGEX = NOT_REGEX.concat ')', '}', 'THIS', 'IDENTIFIER', 'STRING'

Tokens which could legitimately be invoked or indexed. An opening parentheses or bracket following these tokens will be recorded as the start of a function invocation or indexing operation.

CALLABLE  = ['IDENTIFIER', 'STRING', 'REGEX', ')', ']', '}', '?', '::', '@', 'THIS', 'SUPER']
INDEXABLE = CALLABLE.concat 'NUMBER', 'BOOL', 'NULL', 'UNDEFINED'

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.

LINE_BREAK = ['INDENT', 'OUTDENT', 'TERMINATOR']

coffee-script-1.4.0/documentation/docs/nodes.html000066400000000000000000012673441204160075300220630ustar00rootroot00000000000000 nodes.coffee

nodes.coffee

nodes.coffee contains all of the node classes for the syntax tree. Most nodes are created as the result of actions in the grammar, but some are created by other nodes as a method of code generation. To convert the syntax tree into a string of JavaScript code, call compile() on the root.

{Scope} = require './scope'
{RESERVED, STRICT_PROSCRIBED} = require './lexer'

Import the helpers we plan to use.

{compact, flatten, extend, merge, del, starts, ends, last, some} = require './helpers'

exports.extend = extend  # for parser

Constant functions for nodes that don't need customization.

YES     = -> yes
NO      = -> no
THIS    = -> this
NEGATE  = -> @negated = not @negated; this

Base

The Base is the abstract base class for all nodes in the syntax tree. Each subclass implements the compileNode method, which performs the code generation for that node. To compile a node to JavaScript, call compile on it, which wraps compileNode in some generic extra smarts, to know when the generated code needs to be wrapped up in a closure. An options hash is passed and cloned throughout, containing information about the environment from higher in the tree (such as if a returned value is being requested by the surrounding function), information about the current scope, and indentation level.

exports.Base = class Base

Common logic for determining whether to wrap this node in a closure before compiling it, or to compile directly. We need to wrap if this node is a statement, and it's not a pureStatement, and we're not at the top level of a block (which would be unnecessary), and we haven't already been asked to return the result (because statements know how to return results).

  compile: (o, lvl) ->
    o        = extend {}, o
    o.level  = lvl if lvl
    node     = @unfoldSoak(o) or this
    node.tab = o.indent
    if o.level is LEVEL_TOP or not node.isStatement(o)
      node.compileNode o
    else
      node.compileClosure o

Statements converted into expressions via closure-wrapping share a scope object with their parent closure, to preserve the expected lexical scope.

  compileClosure: (o) ->
    if @jumps()
      throw SyntaxError 'cannot use a pure statement in an expression.'
    o.sharedScope = yes
    Closure.wrap(this).compileNode o

If the code generation wishes to use the result of a complex expression in multiple places, ensure that the expression is only ever evaluated once, by assigning it to a temporary variable. Pass a level to precompile.

  cache: (o, level, reused) ->
    unless @isComplex()
      ref = if level then @compile o, level else this
      [ref, ref]
    else
      ref = new Literal reused or o.scope.freeVariable 'ref'
      sub = new Assign ref, this
      if level then [sub.compile(o, level), ref.value] else [sub, ref]

Compile to a source/variable pair suitable for looping.

  compileLoopReference: (o, name) ->
    src = tmp = @compile o, LEVEL_LIST
    unless -Infinity < +src < Infinity or IDENTIFIER.test(src) and o.scope.check(src, yes)
      src = "#{ tmp = o.scope.freeVariable name } = #{src}"
    [src, tmp]

Construct a node that returns the current node's result. Note that this is overridden for smarter behavior for many statement nodes (e.g. If, For)...

  makeReturn: (res) ->
    me = @unwrapAll()
    if res
      new Call new Literal("#{res}.push"), [me]
    else
      new Return me

Does this node, or any of its children, contain a node of a certain kind? Recursively traverses down the children of the nodes, yielding to a block and returning true when the block finds a match. contains does not cross scope boundaries.

  contains: (pred) ->
    contains = no
    @traverseChildren no, (node) ->
      if pred node
        contains = yes
        return no
    contains

Is this node of a certain type, or does it contain the type?

  containsType: (type) ->
    this instanceof type or @contains (node) -> node instanceof type

Pull out the last non-comment node of a node list.

  lastNonComment: (list) ->
    i = list.length
    return list[i] while i-- when list[i] not instanceof Comment
    null

toString representation of the node, for inspecting the parse tree. This is what coffee --nodes prints out.

  toString: (idt = '', name = @constructor.name) ->
    tree = '\n' + idt + name
    tree += '?' if @soak
    @eachChild (node) -> tree += node.toString idt + TAB
    tree

Passes each child to a function, breaking when the function returns false.

  eachChild: (func) ->
    return this unless @children
    for attr in @children when @[attr]
      for child in flatten [@[attr]]
        return this if func(child) is false
    this

  traverseChildren: (crossScope, func) ->
    @eachChild (child) ->
      return false if func(child) is false
      child.traverseChildren crossScope, func

  invert: ->
    new Op '!', this

  unwrapAll: ->
    node = this
    continue until node is node = node.unwrap()
    node

Default implementations of the common node properties and methods. Nodes will override these with custom logic, if needed.

  children: []

  isStatement     : NO
  jumps           : NO
  isComplex       : YES
  isChainable     : NO
  isAssignable    : NO

  unwrap     : THIS
  unfoldSoak : NO

Is this node used to assign a certain variable?

  assigns: NO

Block

The block is the list of expressions that forms the body of an indented block of code -- the implementation of a function, a clause in an if, switch, or try, and so on...

exports.Block = class Block extends Base
  constructor: (nodes) ->
    @expressions = compact flatten nodes or []

  children: ['expressions']

Tack an expression on to the end of this expression list.

  push: (node) ->
    @expressions.push node
    this

Remove and return the last expression of this expression list.

  pop: ->
    @expressions.pop()

Add an expression at the beginning of this expression list.

  unshift: (node) ->
    @expressions.unshift node
    this

If this Block consists of just a single node, unwrap it by pulling it back out.

  unwrap: ->
    if @expressions.length is 1 then @expressions[0] else this

Is this an empty block of code?

  isEmpty: ->
    not @expressions.length

  isStatement: (o) ->
    for exp in @expressions when exp.isStatement o
      return yes
    no

  jumps: (o) ->
    for exp in @expressions
      return exp if exp.jumps o

A Block node does not return its entire body, rather it ensures that the final expression is returned.

  makeReturn: (res) ->
    len = @expressions.length
    while len--
      expr = @expressions[len]
      if expr not instanceof Comment
        @expressions[len] = expr.makeReturn res
        @expressions.splice(len, 1) if expr instanceof Return and not expr.expression
        break
    this

A Block is the only node that can serve as the root.

  compile: (o = {}, level) ->
    if o.scope then super o, level else @compileRoot o

Compile all expressions within the Block body. If we need to return the result, and it's an expression, simply return it. If it's a statement, ask the statement to do so.

  compileNode: (o) ->
    @tab  = o.indent
    top   = o.level is LEVEL_TOP
    codes = []
    for node in @expressions
      node = node.unwrapAll()
      node = (node.unfoldSoak(o) or node)
      if node instanceof Block

This is a nested block. We don't do anything special here like enclose it in a new scope; we just compile the statements in this block along with our own

        codes.push node.compileNode o
      else if top
        node.front = true
        code = node.compile o
        unless node.isStatement o
          code = "#{@tab}#{code};"
          code = "#{code}\n" if node instanceof Literal
        codes.push code
      else
        codes.push node.compile o, LEVEL_LIST
    if top
      if @spaced
        return "\n#{codes.join '\n\n'}\n"
      else
        return codes.join '\n'
    code = codes.join(', ') or 'void 0'
    if codes.length > 1 and o.level >= LEVEL_LIST then "(#{code})" else code

If we happen to be the top-level Block, wrap everything in a safety closure, unless requested not to. It would be better not to generate them in the first place, but for now, clean up obvious double-parentheses.

  compileRoot: (o) ->
    o.indent  = if o.bare then '' else TAB
    o.scope   = new Scope null, this, null
    o.level   = LEVEL_TOP
    @spaced   = yes
    prelude   = ""
    unless o.bare
      preludeExps = for exp, i in @expressions
        break unless exp.unwrap() instanceof Comment
        exp
      rest = @expressions[preludeExps.length...]
      @expressions = preludeExps
      prelude = "#{@compileNode merge(o, indent: '')}\n" if preludeExps.length
      @expressions = rest
    code = @compileWithDeclarations o
    return code if o.bare
    "#{prelude}(function() {\n#{code}\n}).call(this);\n"

Compile the expressions body for the contents of a function, with declarations of all inner variables pushed up to the top.

  compileWithDeclarations: (o) ->
    code = post = ''
    for exp, i in @expressions
      exp = exp.unwrap()
      break unless exp instanceof Comment or exp instanceof Literal
    o = merge(o, level: LEVEL_TOP)
    if i
      rest = @expressions.splice i, 9e9
      [spaced, @spaced] = [@spaced, no]
      [code  , @spaced] = [(@compileNode o), spaced]
      @expressions = rest
    post = @compileNode o
    {scope} = o
    if scope.expressions is this
      declars = o.scope.hasDeclarations()
      assigns = scope.hasAssignments
      if declars or assigns
        code += '\n' if i
        code += "#{@tab}var "
        if declars
          code += scope.declaredVariables().join ', '
        if assigns
          code += ",\n#{@tab + TAB}" if declars
          code += scope.assignedVariables().join ",\n#{@tab + TAB}"
        code += ';\n'
    code + post

Wrap up the given nodes as a Block, unless it already happens to be one.

  @wrap: (nodes) ->
    return nodes[0] if nodes.length is 1 and nodes[0] instanceof Block
    new Block nodes

Literal

Literals are static values that can be passed through directly into JavaScript without translation, such as: strings, numbers, true, false, null...

exports.Literal = class Literal extends Base
  constructor: (@value) ->

  makeReturn: ->
    if @isStatement() then this else super

  isAssignable: ->
    IDENTIFIER.test @value

  isStatement: ->
    @value in ['break', 'continue', 'debugger']

  isComplex: NO

  assigns: (name) ->
    name is @value

  jumps: (o) ->
    return this if @value is 'break' and not (o?.loop or o?.block)
    return this if @value is 'continue' and not o?.loop

  compileNode: (o) ->
    code = if @value is 'this'
      if o.scope.method?.bound then o.scope.method.context else @value
    else if @value.reserved
      "\"#{@value}\""
    else
      @value
    if @isStatement() then "#{@tab}#{code};" else code

  toString: ->
    ' "' + @value + '"'

class exports.Undefined extends Base
  isAssignable: NO
  isComplex: NO
  compileNode: (o) ->
    if o.level >= LEVEL_ACCESS then '(void 0)' else 'void 0'

class exports.Null extends Base
  isAssignable: NO
  isComplex: NO
  compileNode: -> "null"

class exports.Bool extends Base
  isAssignable: NO
  isComplex: NO
  compileNode: -> @val
  constructor: (@val) ->

Return

A return is a pureStatement -- wrapping it in a closure wouldn't make sense.

exports.Return = class Return extends Base
  constructor: (expr) ->
    @expression = expr if expr and not expr.unwrap().isUndefined

  children: ['expression']

  isStatement:     YES
  makeReturn:      THIS
  jumps:           THIS

  compile: (o, level) ->
    expr = @expression?.makeReturn()
    if expr and expr not instanceof Return then expr.compile o, level else super o, level

  compileNode: (o) ->
    @tab + "return#{[" #{@expression.compile o, LEVEL_PAREN}" if @expression]};"

Value

A value, variable or literal or parenthesized, indexed or dotted into, or vanilla.

exports.Value = class Value extends Base
  constructor: (base, props, tag) ->
    return base if not props and base instanceof Value
    @base       = base
    @properties = props or []
    @[tag]      = true if tag
    return this

  children: ['base', 'properties']

Add a property (or properties ) Access to the list.

  add: (props) ->
    @properties = @properties.concat props
    this

  hasProperties: ->
    !!@properties.length

Some boolean checks for the benefit of other nodes.

  isArray        : -> not @properties.length and @base instanceof Arr
  isComplex      : -> @hasProperties() or @base.isComplex()
  isAssignable   : -> @hasProperties() or @base.isAssignable()
  isSimpleNumber : -> @base instanceof Literal and SIMPLENUM.test @base.value
  isString       : -> @base instanceof Literal and IS_STRING.test @base.value
  isAtomic       : ->
    for node in @properties.concat @base
      return no if node.soak or node instanceof Call
    yes

  isStatement : (o)    -> not @properties.length and @base.isStatement o
  assigns     : (name) -> not @properties.length and @base.assigns name
  jumps       : (o)    -> not @properties.length and @base.jumps o

  isObject: (onlyGenerated) ->
    return no if @properties.length
    (@base instanceof Obj) and (not onlyGenerated or @base.generated)

  isSplice: ->
    last(@properties) instanceof Slice

The value can be unwrapped as its inner node, if there are no attached properties.

  unwrap: ->
    if @properties.length then this else @base

A reference has base part (this value) and name part. We cache them separately for compiling complex expressions. a()[b()] ?= c -> (_base = a())[_name = b()] ? _base[_name] = c

  cacheReference: (o) ->
    name = last @properties
    if @properties.length < 2 and not @base.isComplex() and not name?.isComplex()
      return [this, this]  # `a` `a.b`
    base = new Value @base, @properties[...-1]
    if base.isComplex()  # `a().b`
      bref = new Literal o.scope.freeVariable 'base'
      base = new Value new Parens new Assign bref, base
    return [base, bref] unless name  # `a()`
    if name.isComplex()  # `a[b()]`
      nref = new Literal o.scope.freeVariable 'name'
      name = new Index new Assign nref, name.index
      nref = new Index nref
    [base.add(name), new Value(bref or base.base, [nref or name])]

We compile a value to JavaScript by compiling and joining each property. Things get much more interesting if the chain of properties has soak operators ?. interspersed. Then we have to take care not to accidentally evaluate anything twice when building the soak chain.

  compileNode: (o) ->
    @base.front = @front
    props = @properties
    code  = @base.compile o, if props.length then LEVEL_ACCESS else null
    code  = "#{code}." if (@base instanceof Parens or props.length) and SIMPLENUM.test code
    code += prop.compile o for prop in props
    code

Unfold a soak into an If: a?.b -> a.b if a?

  unfoldSoak: (o) ->
    return @unfoldedSoak if @unfoldedSoak?
    result = do =>
      if ifn = @base.unfoldSoak o
        Array::push.apply ifn.body.properties, @properties
        return ifn
      for prop, i in @properties when prop.soak
        prop.soak = off
        fst = new Value @base, @properties[...i]
        snd = new Value @base, @properties[i..]
        if fst.isComplex()
          ref = new Literal o.scope.freeVariable 'ref'
          fst = new Parens new Assign ref, fst
          snd.base = ref
        return new If new Existence(fst), snd, soak: on
      null
    @unfoldedSoak = result or no

Comment

CoffeeScript passes through block comments as JavaScript block comments at the same position.

exports.Comment = class Comment extends Base
  constructor: (@comment) ->

  isStatement:     YES
  makeReturn:      THIS

  compileNode: (o, level) ->
    code = '/*' + multident(@comment, @tab) + "\n#{@tab}*/\n"
    code = o.indent + code if (level or o.level) is LEVEL_TOP
    code

Call

Node for a function invocation. Takes care of converting super() calls into calls against the prototype's function of the same name.

exports.Call = class Call extends Base
  constructor: (variable, @args = [], @soak) ->
    @isNew    = false
    @isSuper  = variable is 'super'
    @variable = if @isSuper then null else variable

  children: ['variable', 'args']

Tag this invocation as creating a new instance.

  newInstance: ->
    base = @variable?.base or @variable
    if base instanceof Call and not base.isNew
      base.newInstance()
    else
      @isNew = true
    this

Grab the reference to the superclass's implementation of the current method.

  superReference: (o) ->
    method = o.scope.namedMethod()
    throw SyntaxError 'cannot call super outside of a function.' unless method
    {name} = method
    throw SyntaxError 'cannot call super on an anonymous function.' unless name?
    if method.klass
      accesses = [new Access(new Literal '__super__')]
      accesses.push new Access new Literal 'constructor' if method.static
      accesses.push new Access new Literal name
      (new Value (new Literal method.klass), accesses).compile o
    else
      "#{name}.__super__.constructor"

The appropriate this value for a super call.

  superThis : (o) ->
    method = o.scope.method
    (method and not method.klass and method.context) or "this"

Soaked chained invocations unfold into if/else ternary structures.

  unfoldSoak: (o) ->
    if @soak
      if @variable
        return ifn if ifn = unfoldSoak o, this, 'variable'
        [left, rite] = new Value(@variable).cacheReference o
      else
        left = new Literal @superReference o
        rite = new Value left
      rite = new Call rite, @args
      rite.isNew = @isNew
      left = new Literal "typeof #{ left.compile o } === \"function\""
      return new If left, new Value(rite), soak: yes
    call = this
    list = []
    loop
      if call.variable instanceof Call
        list.push call
        call = call.variable
        continue
      break unless call.variable instanceof Value
      list.push call
      break unless (call = call.variable.base) instanceof Call
    for call in list.reverse()
      if ifn
        if call.variable instanceof Call
          call.variable = ifn
        else
          call.variable.base = ifn
      ifn = unfoldSoak o, call, 'variable'
    ifn

Walk through the objects in the arguments, moving over simple values. This allows syntax like call a: b, c into call({a: b}, c);

  filterImplicitObjects: (list) ->
    nodes = []
    for node in list
      unless node.isObject?() and node.base.generated
        nodes.push node
        continue
      obj = null
      for prop in node.base.properties
        if prop instanceof Assign or prop instanceof Comment
          nodes.push obj = new Obj properties = [], true if not obj
          properties.push prop
        else
          nodes.push prop
          obj = null
    nodes

Compile a vanilla function call.

  compileNode: (o) ->
    @variable?.front = @front
    if code = Splat.compileSplattedArray o, @args, true
      return @compileSplat o, code
    args = @filterImplicitObjects @args
    args = (arg.compile o, LEVEL_LIST for arg in args).join ', '
    if @isSuper
      @superReference(o) + ".call(#{@superThis(o)}#{ args and ', ' + args })"
    else
      (if @isNew then 'new ' else '') + @variable.compile(o, LEVEL_ACCESS) + "(#{args})"

super() is converted into a call against the superclass's implementation of the current function.

  compileSuper: (args, o) ->
    "#{@superReference(o)}.call(#{@superThis(o)}#{ if args.length then ', ' else '' }#{args})"

If you call a function with a splat, it's converted into a JavaScript .apply() call to allow an array of arguments to be passed. If it's a constructor, then things get real tricky. We have to inject an inner constructor in order to be able to pass the varargs.

  compileSplat: (o, splatArgs) ->
    return "#{ @superReference o }.apply(#{@superThis(o)}, #{splatArgs})" if @isSuper
    if @isNew
      idt = @tab + TAB
      return """
        (function(func, args, ctor) {
        #{idt}ctor.prototype = func.prototype;
        #{idt}var child = new ctor, result = func.apply(child, args);
        #{idt}return Object(result) === result ? result : child;
        #{@tab}})(#{ @variable.compile o, LEVEL_LIST }, #{splatArgs}, function(){})
      """
    base = new Value @variable
    if (name = base.properties.pop()) and base.isComplex()
      ref = o.scope.freeVariable 'ref'
      fun = "(#{ref} = #{ base.compile o, LEVEL_LIST })#{ name.compile o }"
    else
      fun = base.compile o, LEVEL_ACCESS
      fun = "(#{fun})" if SIMPLENUM.test fun
      if name
        ref = fun
        fun += name.compile o
      else
        ref = 'null'
    "#{fun}.apply(#{ref}, #{splatArgs})"

Extends

Node to extend an object's prototype with an ancestor object. After goog.inherits from the Closure Library.

exports.Extends = class Extends extends Base
  constructor: (@child, @parent) ->

  children: ['child', 'parent']

Hooks one constructor into another's prototype chain.

  compile: (o) ->
    new Call(new Value(new Literal utility 'extends'), [@child, @parent]).compile o

Access

A . access into a property of a value, or the :: shorthand for an access into the object's prototype.

exports.Access = class Access extends Base
  constructor: (@name, tag) ->
    @name.asKey = yes
    @soak  = tag is 'soak'

  children: ['name']

  compile: (o) ->
    name = @name.compile o
    if IDENTIFIER.test name then ".#{name}" else "[#{name}]"

  isComplex: NO

Index

A [ ... ] indexed access into an array or object.

exports.Index = class Index extends Base
  constructor: (@index) ->

  children: ['index']

  compile: (o) ->
    "[#{ @index.compile o, LEVEL_PAREN }]"

  isComplex: ->
    @index.isComplex()

Range

A range literal. Ranges can be used to extract portions (slices) of arrays, to specify a range for comprehensions, or as a value, to be expanded into the corresponding array of integers at runtime.

exports.Range = class Range extends Base

  children: ['from', 'to']

  constructor: (@from, @to, tag) ->
    @exclusive = tag is 'exclusive'
    @equals = if @exclusive then '' else '='

Compiles the range's source variables -- where it starts and where it ends. But only if they need to be cached to avoid double evaluation.

  compileVariables: (o) ->
    o = merge o, top: true
    [@fromC, @fromVar]  =  @from.cache o, LEVEL_LIST
    [@toC, @toVar]      =  @to.cache o, LEVEL_LIST
    [@step, @stepVar]   =  step.cache o, LEVEL_LIST if step = del o, 'step'
    [@fromNum, @toNum]  = [@fromVar.match(SIMPLENUM), @toVar.match(SIMPLENUM)]
    @stepNum            = @stepVar.match(SIMPLENUM) if @stepVar

When compiled normally, the range returns the contents of the for loop needed to iterate over the values in the range. Used by comprehensions.

  compileNode: (o) ->
    @compileVariables o unless @fromVar
    return @compileArray(o) unless o.index

Set up endpoints.

    known    = @fromNum and @toNum
    idx      = del o, 'index'
    idxName  = del o, 'name'
    namedIndex = idxName and idxName isnt idx
    varPart  = "#{idx} = #{@fromC}"
    varPart += ", #{@toC}" if @toC isnt @toVar
    varPart += ", #{@step}" if @step isnt @stepVar
    [lt, gt] = ["#{idx} <#{@equals}", "#{idx} >#{@equals}"]

Generate the condition.

    condPart = if @stepNum
      if +@stepNum > 0 then "#{lt} #{@toVar}" else "#{gt} #{@toVar}"
    else if known
      [from, to] = [+@fromNum, +@toNum]
      if from <= to then "#{lt} #{to}" else "#{gt} #{to}"
    else
      cond     = "#{@fromVar} <= #{@toVar}"
      "#{cond} ? #{lt} #{@toVar} : #{gt} #{@toVar}"

Generate the step.

    stepPart = if @stepVar
      "#{idx} += #{@stepVar}"
    else if known
      if namedIndex
        if from <= to then "++#{idx}" else "--#{idx}"
      else
        if from <= to then "#{idx}++" else "#{idx}--"
    else
      if namedIndex
        "#{cond} ? ++#{idx} : --#{idx}"
      else
        "#{cond} ? #{idx}++ : #{idx}--"

    varPart  = "#{idxName} = #{varPart}" if namedIndex
    stepPart = "#{idxName} = #{stepPart}" if namedIndex

The final loop body.

    "#{varPart}; #{condPart}; #{stepPart}"

When used as a value, expand the range into the equivalent array.

  compileArray: (o) ->
    if @fromNum and @toNum and Math.abs(@fromNum - @toNum) <= 20
      range = [+@fromNum..+@toNum]
      range.pop() if @exclusive
      return "[#{ range.join(', ') }]"
    idt    = @tab + TAB
    i      = o.scope.freeVariable 'i'
    result = o.scope.freeVariable 'results'
    pre    = "\n#{idt}#{result} = [];"
    if @fromNum and @toNum
      o.index = i
      body    = @compileNode o
    else
      vars    = "#{i} = #{@fromC}" + if @toC isnt @toVar then ", #{@toC}" else ''
      cond    = "#{@fromVar} <= #{@toVar}"
      body    = "var #{vars}; #{cond} ? #{i} <#{@equals} #{@toVar} : #{i} >#{@equals} #{@toVar}; #{cond} ? #{i}++ : #{i}--"
    post   = "{ #{result}.push(#{i}); }\n#{idt}return #{result};\n#{o.indent}"
    hasArgs = (node) -> node?.contains (n) -> n instanceof Literal and n.value is 'arguments' and not n.asKey
    args   = ', arguments' if hasArgs(@from) or hasArgs(@to)
    "(function() {#{pre}\n#{idt}for (#{body})#{post}}).apply(this#{args ? ''})"

Slice

An array slice literal. Unlike JavaScript's Array#slice, the second parameter specifies the index of the end of the slice, just as the first parameter is the index of the beginning.

exports.Slice = class Slice extends Base

  children: ['range']

  constructor: (@range) ->
    super()

We have to be careful when trying to slice through the end of the array, 9e9 is used because not all implementations respect undefined or 1/0. 9e9 should be safe because 9e9 > 2**32, the max array length.

  compileNode: (o) ->
    {to, from} = @range
    fromStr    = from and from.compile(o, LEVEL_PAREN) or '0'
    compiled   = to and to.compile o, LEVEL_PAREN
    if to and not (not @range.exclusive and +compiled is -1)
      toStr = ', ' + if @range.exclusive
        compiled
      else if SIMPLENUM.test compiled
        "#{+compiled + 1}"
      else
        compiled = to.compile o, LEVEL_ACCESS
        "+#{compiled} + 1 || 9e9"
    ".slice(#{ fromStr }#{ toStr or '' })"

Obj

An object literal, nothing fancy.

exports.Obj = class Obj extends Base
  constructor: (props, @generated = false) ->
    @objects = @properties = props or []

  children: ['properties']

  compileNode: (o) ->
    props = @properties
    return (if @front then '({})' else '{}') unless props.length
    if @generated
      for node in props when node instanceof Value
        throw new Error 'cannot have an implicit value in an implicit object'
    idt         = o.indent += TAB
    lastNoncom  = @lastNonComment @properties
    props = for prop, i in props
      join = if i is props.length - 1
        ''
      else if prop is lastNoncom or prop instanceof Comment
        '\n'
      else
        ',\n'
      indent = if prop instanceof Comment then '' else idt
      if prop instanceof Value and prop.this
        prop = new Assign prop.properties[0].name, prop, 'object'
      if prop not instanceof Comment
        if prop not instanceof Assign
          prop = new Assign prop, prop, 'object'
        (prop.variable.base or prop.variable).asKey = yes
      indent + prop.compile(o, LEVEL_TOP) + join
    props = props.join ''
    obj   = "{#{ props and '\n' + props + '\n' + @tab }}"
    if @front then "(#{obj})" else obj

  assigns: (name) ->
    for prop in @properties when prop.assigns name then return yes
    no

Arr

An array literal.

exports.Arr = class Arr extends Base
  constructor: (objs) ->
    @objects = objs or []

  children: ['objects']

  filterImplicitObjects: Call::filterImplicitObjects

  compileNode: (o) ->
    return '[]' unless @objects.length
    o.indent += TAB
    objs = @filterImplicitObjects @objects
    return code if code = Splat.compileSplattedArray o, objs
    code = (obj.compile o, LEVEL_LIST for obj in objs).join ', '
    if code.indexOf('\n') >= 0
      "[\n#{o.indent}#{code}\n#{@tab}]"
    else
      "[#{code}]"

  assigns: (name) ->
    for obj in @objects when obj.assigns name then return yes
    no

Class

The CoffeeScript class definition. Initialize a Class with its name, an optional superclass, and a list of prototype property assignments.

exports.Class = class Class extends Base
  constructor: (@variable, @parent, @body = new Block) ->
    @boundFuncs = []
    @body.classBody = yes

  children: ['variable', 'parent', 'body']

Figure out the appropriate name for the constructor function of this class.

  determineName: ->
    return null unless @variable
    decl = if tail = last @variable.properties
      tail instanceof Access and tail.name.value
    else
      @variable.base.value
    if decl in STRICT_PROSCRIBED
      throw SyntaxError "variable name may not be #{decl}"
    decl and= IDENTIFIER.test(decl) and decl

For all this-references and bound functions in the class definition, this is the Class being constructed.

  setContext: (name) ->
    @body.traverseChildren false, (node) ->
      return false if node.classBody
      if node instanceof Literal and node.value is 'this'
        node.value    = name
      else if node instanceof Code
        node.klass    = name
        node.context  = name if node.bound

Ensure that all functions bound to the instance are proxied in the constructor.

  addBoundFunctions: (o) ->
    if @boundFuncs.length
      for bvar in @boundFuncs
        lhs = (new Value (new Literal "this"), [new Access bvar]).compile o
        @ctor.body.unshift new Literal "#{lhs} = #{utility 'bind'}(#{lhs}, this)"

Merge the properties from a top-level object as prototypal properties on the class.

  addProperties: (node, name, o) ->
    props = node.base.properties[..]
    exprs = while assign = props.shift()
      if assign instanceof Assign
        base = assign.variable.base
        delete assign.context
        func = assign.value
        if base.value is 'constructor'
          if @ctor
            throw new Error 'cannot define more than one constructor in a class'
          if func.bound
            throw new Error 'cannot define a constructor as a bound function'
          if func instanceof Code
            assign = @ctor = func
          else
            @externalCtor = o.scope.freeVariable 'class'
            assign = new Assign new Literal(@externalCtor), func
        else
          if assign.variable.this
            func.static = yes
            if func.bound
              func.context = name
          else
            assign.variable = new Value(new Literal(name), [(new Access new Literal 'prototype'), new Access base ])
            if func instanceof Code and func.bound
              @boundFuncs.push base
              func.bound = no
      assign
    compact exprs

Walk the body of the class, looking for prototype properties to be converted.

  walkBody: (name, o) ->
    @traverseChildren false, (child) =>
      return false if child instanceof Class
      if child instanceof Block
        for node, i in exps = child.expressions
          if node instanceof Value and node.isObject(true)
            exps[i] = @addProperties node, name, o
        child.expressions = exps = flatten exps

use strict (and other directives) must be the first expression statement(s) of a function body. This method ensures the prologue is correctly positioned above the constructor.

  hoistDirectivePrologue: ->
    index = 0
    {expressions} = @body
    ++index while (node = expressions[index]) and node instanceof Comment or
      node instanceof Value and node.isString()
    @directives = expressions.splice 0, index

Make sure that a constructor is defined for the class, and properly configured.

  ensureConstructor: (name) ->
    if not @ctor
      @ctor = new Code
      @ctor.body.push new Literal "#{name}.__super__.constructor.apply(this, arguments)" if @parent
      @ctor.body.push new Literal "#{@externalCtor}.apply(this, arguments)" if @externalCtor
      @ctor.body.makeReturn()
      @body.expressions.unshift @ctor
    @ctor.ctor     = @ctor.name = name
    @ctor.klass    = null
    @ctor.noReturn = yes

Instead of generating the JavaScript string directly, we build up the equivalent syntax tree and compile that, in pieces. You can see the constructor, property assignments, and inheritance getting built out below.

  compileNode: (o) ->
    decl  = @determineName()
    name  = decl or '_Class'
    name = "_#{name}" if name.reserved
    lname = new Literal name

    @hoistDirectivePrologue()
    @setContext name
    @walkBody name, o
    @ensureConstructor name
    @body.spaced = yes
    @body.expressions.unshift @ctor unless @ctor instanceof Code
    @body.expressions.push lname
    @body.expressions.unshift @directives...
    @addBoundFunctions o

    call  = Closure.wrap @body

    if @parent
      @superClass = new Literal o.scope.freeVariable 'super', no
      @body.expressions.unshift new Extends lname, @superClass
      call.args.push @parent
      params = call.variable.params or call.variable.base.params
      params.push new Param @superClass

    klass = new Parens call, yes
    klass = new Assign @variable, klass if @variable
    klass.compile o

Assign

The Assign is used to assign a local variable to value, or to set the property of an object -- including within object literals.

exports.Assign = class Assign extends Base
  constructor: (@variable, @value, @context, options) ->
    @param = options and options.param
    @subpattern = options and options.subpattern
    forbidden = (name = @variable.unwrapAll().value) in STRICT_PROSCRIBED
    if forbidden and @context isnt 'object'
      throw SyntaxError "variable name may not be \"#{name}\""

  children: ['variable', 'value']

  isStatement: (o) ->
    o?.level is LEVEL_TOP and @context? and "?" in @context

  assigns: (name) ->
    @[if @context is 'object' then 'value' else 'variable'].assigns name

  unfoldSoak: (o) ->
    unfoldSoak o, this, 'variable'

Compile an assignment, delegating to compilePatternMatch or compileSplice if appropriate. Keep track of the name of the base object we've been assigned to, for correct internal references. If the variable has not been seen yet within the current scope, declare it.

  compileNode: (o) ->
    if isValue = @variable instanceof Value
      return @compilePatternMatch o if @variable.isArray() or @variable.isObject()
      return @compileSplice       o if @variable.isSplice()
      return @compileConditional  o if @context in ['||=', '&&=', '?=']
    name = @variable.compile o, LEVEL_LIST
    unless @context
      unless (varBase = @variable.unwrapAll()).isAssignable()
        throw SyntaxError "\"#{ @variable.compile o }\" cannot be assigned."
      unless varBase.hasProperties?()
        if @param
          o.scope.add name, 'var'
        else
          o.scope.find name
    if @value instanceof Code and match = METHOD_DEF.exec name
      @value.klass = match[1] if match[1]
      @value.name  = match[2] ? match[3] ? match[4] ? match[5]
    val = @value.compile o, LEVEL_LIST
    return "#{name}: #{val}" if @context is 'object'
    val = name + " #{ @context or '=' } " + val
    if o.level <= LEVEL_LIST then val else "(#{val})"

Brief implementation of recursive pattern matching, when assigning array or object literals to a value. Peeks at their properties to assign inner names. See the ECMAScript Harmony Wiki for details.

  compilePatternMatch: (o) ->
    top       = o.level is LEVEL_TOP
    {value}   = this
    {objects} = @variable.base
    unless olen = objects.length
      code = value.compile o
      return if o.level >= LEVEL_OP then "(#{code})" else code
    isObject = @variable.isObject()
    if top and olen is 1 and (obj = objects[0]) not instanceof Splat

Unroll simplest cases: {v} = x -> v = x.v

      if obj instanceof Assign
        {variable: {base: idx}, value: obj} = obj
      else
        if obj.base instanceof Parens
          [obj, idx] = new Value(obj.unwrapAll()).cacheReference o
        else
          idx = if isObject
            if obj.this then obj.properties[0].name else obj
          else
            new Literal 0
      acc   = IDENTIFIER.test idx.unwrap().value or 0
      value = new Value value
      value.properties.push new (if acc then Access else Index) idx
      if obj.unwrap().value in RESERVED
        throw new SyntaxError "assignment to a reserved word: #{obj.compile o} = #{value.compile o}"
      return new Assign(obj, value, null, param: @param).compile o, LEVEL_TOP
    vvar    = value.compile o, LEVEL_LIST
    assigns = []
    splat   = false
    if not IDENTIFIER.test(vvar) or @variable.assigns(vvar)
      assigns.push "#{ ref = o.scope.freeVariable 'ref' } = #{vvar}"
      vvar = ref
    for obj, i in objects

A regular array pattern-match.

      idx = i
      if isObject
        if obj instanceof Assign

A regular object pattern-match.

          {variable: {base: idx}, value: obj} = obj
        else

A shorthand {a, b, @c} = val pattern-match.

          if obj.base instanceof Parens
            [obj, idx] = new Value(obj.unwrapAll()).cacheReference o
          else
            idx = if obj.this then obj.properties[0].name else obj
      if not splat and obj instanceof Splat
        name = obj.name.unwrap().value
        obj = obj.unwrap()
        val = "#{olen} <= #{vvar}.length ? #{ utility 'slice' }.call(#{vvar}, #{i}"
        if rest = olen - i - 1
          ivar = o.scope.freeVariable 'i'
          val += ", #{ivar} = #{vvar}.length - #{rest}) : (#{ivar} = #{i}, [])"
        else
          val += ") : []"
        val   = new Literal val
        splat = "#{ivar}++"
      else
        name = obj.unwrap().value
        if obj instanceof Splat
          obj = obj.name.compile o
          throw new SyntaxError \
            "multiple splats are disallowed in an assignment: #{obj}..."
        if typeof idx is 'number'
          idx = new Literal splat or idx
          acc = no
        else
          acc = isObject and IDENTIFIER.test idx.unwrap().value or 0
        val = new Value new Literal(vvar), [new (if acc then Access else Index) idx]
      if name? and name in RESERVED
        throw new SyntaxError "assignment to a reserved word: #{obj.compile o} = #{val.compile o}"
      assigns.push new Assign(obj, val, null, param: @param, subpattern: yes).compile o, LEVEL_LIST
    assigns.push vvar unless top or @subpattern
    code = assigns.join ', '
    if o.level < LEVEL_LIST then code else "(#{code})"

When compiling a conditional assignment, take care to ensure that the operands are only evaluated once, even though we have to reference them more than once.

  compileConditional: (o) ->
    [left, right] = @variable.cacheReference o

Disallow conditional assignment of undefined variables.

    if not left.properties.length and left.base instanceof Literal and 
           left.base.value != "this" and not o.scope.check left.base.value
      throw new Error "the variable \"#{left.base.value}\" can't be assigned with #{@context} because it has not been defined."
    if "?" in @context then o.isExistentialEquals = true
    new Op(@context[...-1], left, new Assign(right, @value, '=') ).compile o

Compile the assignment from an array splice literal, using JavaScript's Array#splice method.

  compileSplice: (o) ->
    {range: {from, to, exclusive}} = @variable.properties.pop()
    name = @variable.compile o
    [fromDecl, fromRef] = from?.cache(o, LEVEL_OP) or ['0', '0']
    if to
      if from?.isSimpleNumber() and to.isSimpleNumber()
        to = +to.compile(o) - +fromRef
        to += 1 unless exclusive
      else
        to = to.compile(o, LEVEL_ACCESS) + ' - ' + fromRef
        to += ' + 1' unless exclusive
    else
      to = "9e9"
    [valDef, valRef] = @value.cache o, LEVEL_LIST
    code = "[].splice.apply(#{name}, [#{fromDecl}, #{to}].concat(#{valDef})), #{valRef}"
    if o.level > LEVEL_TOP then "(#{code})" else code

Code

A function definition. This is the only node that creates a new Scope. When for the purposes of walking the contents of a function body, the Code has no children -- they're within the inner scope.

exports.Code = class Code extends Base
  constructor: (params, body, tag) ->
    @params  = params or []
    @body    = body or new Block
    @bound   = tag is 'boundfunc'
    @context = '_this' if @bound

  children: ['params', 'body']

  isStatement: -> !!@ctor

  jumps: NO

Compilation creates a new scope unless explicitly asked to share with the outer scope. Handles splat parameters in the parameter list by peeking at the JavaScript arguments object. If the function is bound with the => arrow, generates a wrapper that saves the current value of this through a closure.

  compileNode: (o) ->
    o.scope         = new Scope o.scope, @body, this
    o.scope.shared  = del(o, 'sharedScope')
    o.indent        += TAB
    delete o.bare
    delete o.isExistentialEquals
    params = []
    exprs  = []
    for name in @paramNames() # this step must be performed before the others
      unless o.scope.check name then o.scope.parameter name
    for param in @params when param.splat
      for {name: p} in @params
        if p.this then p = p.properties[0].name
        if p.value then o.scope.add p.value, 'var', yes
      splats = new Assign new Value(new Arr(p.asReference o for p in @params)),
                          new Value new Literal 'arguments'
      break
    for param in @params
      if param.isComplex()
        val = ref = param.asReference o
        val = new Op '?', ref, param.value if param.value
        exprs.push new Assign new Value(param.name), val, '=', param: yes
      else
        ref = param
        if param.value
          lit = new Literal ref.name.value + ' == null'
          val = new Assign new Value(param.name), param.value, '='
          exprs.push new If lit, val
      params.push ref unless splats
    wasEmpty = @body.isEmpty()
    exprs.unshift splats if splats
    @body.expressions.unshift exprs... if exprs.length
    o.scope.parameter params[i] = p.compile o for p, i in params
    uniqs = []
    for name in @paramNames()
      throw SyntaxError "multiple parameters named '#{name}'" if name in uniqs
      uniqs.push name
    @body.makeReturn() unless wasEmpty or @noReturn
    if @bound
      if o.scope.parent.method?.bound
        @bound = @context = o.scope.parent.method.context
      else if not @static
        o.scope.parent.assign '_this', 'this'
    idt   = o.indent
    code  = 'function'
    code  += ' ' + @name if @ctor
    code  += '(' + params.join(', ') + ') {'
    code  += "\n#{ @body.compileWithDeclarations o }\n#{@tab}" unless @body.isEmpty()
    code  += '}'
    return @tab + code if @ctor
    if @front or (o.level >= LEVEL_ACCESS) then "(#{code})" else code

A list of parameter names, excluding those generated by the compiler.

  paramNames: ->
    names = []
    names.push param.names()... for param in @params
    names

Short-circuit traverseChildren method to prevent it from crossing scope boundaries unless crossScope is true.

  traverseChildren: (crossScope, func) ->
    super(crossScope, func) if crossScope

Param

A parameter in a function definition. Beyond a typical Javascript parameter, these parameters can also attach themselves to the context of the function, as well as be a splat, gathering up a group of parameters into an array.

exports.Param = class Param extends Base
  constructor: (@name, @value, @splat) ->
    if (name = @name.unwrapAll().value) in STRICT_PROSCRIBED
      throw SyntaxError "parameter name \"#{name}\" is not allowed"

  children: ['name', 'value']

  compile: (o) ->
    @name.compile o, LEVEL_LIST

  asReference: (o) ->
    return @reference if @reference
    node = @name
    if node.this
      node = node.properties[0].name
      if node.value.reserved
        node = new Literal o.scope.freeVariable node.value
    else if node.isComplex()
      node = new Literal o.scope.freeVariable 'arg'
    node = new Value node
    node = new Splat node if @splat
    @reference = node

  isComplex: ->
    @name.isComplex()

Finds the name or names of a Param; useful for detecting duplicates. In a sense, a destructured parameter represents multiple JS parameters, thus this method returns an Array of names. Reserved words used as param names, as well as the Object and Array literals used for destructured params, get a compiler generated name during the Code compilation step, so this is necessarily an incomplete list of a parameter's names.

  names: (name = @name)->
    atParam = (obj) ->
      {value} = obj.properties[0].name
      return if value.reserved then [] else [value]
  • simple literals foo
    return [name.value] if name instanceof Literal
  • at-params @foo
    return atParam(name) if name instanceof Value
    names = []
    for obj in name.objects
  • assignments within destructured parameters {foo:bar}
      if obj instanceof Assign
        names.push obj.value.unwrap().value
  • splats within destructured parameters [xs...]
      else if obj instanceof Splat
        names.push obj.name.unwrap().value
      else if obj instanceof Value
  • destructured parameters within destructured parameters [{a}]
        if obj.isArray() or obj.isObject()
          names.push @names(obj.base)...
  • at-params within destructured parameters {@foo}
        else if obj.this
          names.push atParam(obj)...
  • simple destructured parameters {foo}
        else names.push obj.base.value
      else
        throw SyntaxError "illegal parameter #{obj.compile()}"
    names

Splat

A splat, either as a parameter to a function, an argument to a call, or as part of a destructuring assignment.

exports.Splat = class Splat extends Base

  children: ['name']

  isAssignable: YES

  constructor: (name) ->
    @name = if name.compile then name else new Literal name

  assigns: (name) ->
    @name.assigns name

  compile: (o) ->
    if @index? then @compileParam o else @name.compile o

  unwrap: -> @name

Utility function that converts an arbitrary number of elements, mixed with splats, to a proper array.

  @compileSplattedArray: (o, list, apply) ->
    index = -1
    continue while (node = list[++index]) and node not instanceof Splat
    return '' if index >= list.length
    if list.length is 1
      code = list[0].compile o, LEVEL_LIST
      return code if apply
      return "#{ utility 'slice' }.call(#{code})"
    args = list[index..]
    for node, i in args
      code = node.compile o, LEVEL_LIST
      args[i] = if node instanceof Splat
      then "#{ utility 'slice' }.call(#{code})"
      else "[#{code}]"
    return args[0] + ".concat(#{ args[1..].join ', ' })" if index is 0
    base = (node.compile o, LEVEL_LIST for node in list[...index])
    "[#{ base.join ', ' }].concat(#{ args.join ', ' })"

While

A while loop, the only sort of low-level loop exposed by CoffeeScript. From it, all other loops can be manufactured. Useful in cases where you need more flexibility or more speed than a comprehension can provide.

exports.While = class While extends Base
  constructor: (condition, options) ->
    @condition = if options?.invert then condition.invert() else condition
    @guard     = options?.guard

  children: ['condition', 'guard', 'body']

  isStatement: YES

  makeReturn: (res) ->
    if res
      super
    else
      @returns = not @jumps loop: yes
      this

  addBody: (@body) ->
    this

  jumps: ->
    {expressions} = @body
    return no unless expressions.length
    for node in expressions
      return node if node.jumps loop: yes
    no

The main difference from a JavaScript while is that the CoffeeScript while can be used as a part of a larger expression -- while loops may return an array containing the computed result of each iteration.

  compileNode: (o) ->
    o.indent += TAB
    set      = ''
    {body}   = this
    if body.isEmpty()
      body = ''
    else
      if @returns
        body.makeReturn rvar = o.scope.freeVariable 'results'
        set  = "#{@tab}#{rvar} = [];\n"
      if @guard
        if body.expressions.length > 1
          body.expressions.unshift new If (new Parens @guard).invert(), new Literal "continue"
        else
          body = Block.wrap [new If @guard, body] if @guard
      body = "\n#{ body.compile o, LEVEL_TOP }\n#{@tab}"
    code = set + @tab + "while (#{ @condition.compile o, LEVEL_PAREN }) {#{body}}"
    if @returns
      code += "\n#{@tab}return #{rvar};"
    code

Op

Simple Arithmetic and logical operations. Performs some conversion from CoffeeScript operations into their JavaScript equivalents.

exports.Op = class Op extends Base
  constructor: (op, first, second, flip ) ->
    return new In first, second if op is 'in'
    if op is 'do'
      return @generateDo first
    if op is 'new'
      return first.newInstance() if first instanceof Call and not first.do and not first.isNew
      first = new Parens first   if first instanceof Code and first.bound or first.do
    @operator = CONVERSIONS[op] or op
    @first    = first
    @second   = second
    @flip     = !!flip
    return this

The map of conversions from CoffeeScript to JavaScript symbols.

  CONVERSIONS =
    '==': '==='
    '!=': '!=='
    'of': 'in'

The map of invertible operators.

  INVERSIONS =
    '!==': '==='
    '===': '!=='

  children: ['first', 'second']

  isSimpleNumber: NO

  isUnary: ->
    not @second

  isComplex: ->
    not (@isUnary() and (@operator in ['+', '-'])) or @first.isComplex()

Am I capable of Python-style comparison chaining?

  isChainable: ->
    @operator in ['<', '>', '>=', '<=', '===', '!==']

  invert: ->
    if @isChainable() and @first.isChainable()
      allInvertable = yes
      curr = this
      while curr and curr.operator
        allInvertable and= (curr.operator of INVERSIONS)
        curr = curr.first
      return new Parens(this).invert() unless allInvertable
      curr = this
      while curr and curr.operator
        curr.invert = !curr.invert
        curr.operator = INVERSIONS[curr.operator]
        curr = curr.first
      this
    else if op = INVERSIONS[@operator]
      @operator = op
      if @first.unwrap() instanceof Op
        @first.invert()
      this
    else if @second
      new Parens(this).invert()
    else if @operator is '!' and (fst = @first.unwrap()) instanceof Op and
                                  fst.operator in ['!', 'in', 'instanceof']
      fst
    else
      new Op '!', this

  unfoldSoak: (o) ->
    @operator in ['++', '--', 'delete'] and unfoldSoak o, this, 'first'

  generateDo: (exp) ->
    passedParams = []
    func = if exp instanceof Assign and (ref = exp.value.unwrap()) instanceof Code
      ref
    else
      exp
    for param in func.params or []
      if param.value
        passedParams.push param.value
        delete param.value
      else
        passedParams.push param
    call = new Call exp, passedParams
    call.do = yes
    call

  compileNode: (o) ->
    isChain = @isChainable() and @first.isChainable()

In chains, there's no need to wrap bare obj literals in parens, as the chained expression is wrapped.

    @first.front = @front unless isChain
    if @operator is 'delete' and o.scope.check(@first.unwrapAll().value)
      throw SyntaxError 'delete operand may not be argument or var'
    if @operator in ['--', '++'] and @first.unwrapAll().value in STRICT_PROSCRIBED
      throw SyntaxError 'prefix increment/decrement may not have eval or arguments operand'
    return @compileUnary     o if @isUnary()
    return @compileChain     o if isChain
    return @compileExistence o if @operator is '?'
    code = @first.compile(o, LEVEL_OP) + ' ' + @operator + ' ' +
           @second.compile(o, LEVEL_OP)
    if o.level <= LEVEL_OP then code else "(#{code})"

Mimic Python's chained comparisons when multiple comparison operators are used sequentially. For example:

bin/coffee -e 'console.log 50 < 65 > 10'
true
  compileChain: (o) ->
    [@first.second, shared] = @first.second.cache o
    fst = @first.compile o, LEVEL_OP
    code = "#{fst} #{if @invert then '&&' else '||'} #{ shared.compile o } #{@operator} #{ @second.compile o, LEVEL_OP }"
    "(#{code})"

  compileExistence: (o) ->
    if @first.isComplex()
      ref = new Literal o.scope.freeVariable 'ref'
      fst = new Parens new Assign ref, @first
    else
      fst = @first
      ref = fst
    new If(new Existence(fst), ref, type: 'if').addElse(@second).compile o

Compile a unary Op.

  compileUnary: (o) ->
    if o.level >= LEVEL_ACCESS
      return (new Parens this).compile o
    parts = [op = @operator]
    plusMinus = op in ['+', '-']
    parts.push ' ' if op in ['new', 'typeof', 'delete'] or
                      plusMinus and @first instanceof Op and @first.operator is op
    if (plusMinus && @first instanceof Op) or (op is 'new' and @first.isStatement o)
      @first = new Parens @first
    parts.push @first.compile o, LEVEL_OP
    parts.reverse() if @flip
    parts.join ''

  toString: (idt) ->
    super idt, @constructor.name + ' ' + @operator

In

exports.In = class In extends Base
  constructor: (@object, @array) ->

  children: ['object', 'array']

  invert: NEGATE

  compileNode: (o) ->
    if @array instanceof Value and @array.isArray()
      for obj in @array.base.objects when obj instanceof Splat
        hasSplat = yes
        break

compileOrTest only if we have an array literal with no splats

      return @compileOrTest o unless hasSplat
    @compileLoopTest o

  compileOrTest: (o) ->
    return "#{!!@negated}" if @array.base.objects.length is 0
    [sub, ref] = @object.cache o, LEVEL_OP
    [cmp, cnj] = if @negated then [' !== ', ' && '] else [' === ', ' || ']
    tests = for item, i in @array.base.objects
      (if i then ref else sub) + cmp + item.compile o, LEVEL_ACCESS
    tests = tests.join cnj
    if o.level < LEVEL_OP then tests else "(#{tests})"

  compileLoopTest: (o) ->
    [sub, ref] = @object.cache o, LEVEL_LIST
    code = utility('indexOf') + ".call(#{ @array.compile o, LEVEL_LIST }, #{ref}) " +
           if @negated then '< 0' else '>= 0'
    return code if sub is ref
    code = sub + ', ' + code
    if o.level < LEVEL_LIST then code else "(#{code})"

  toString: (idt) ->
    super idt, @constructor.name + if @negated then '!' else ''

Try

A classic try/catch/finally block.

exports.Try = class Try extends Base
  constructor: (@attempt, @error, @recovery, @ensure) ->

  children: ['attempt', 'recovery', 'ensure']

  isStatement: YES

  jumps: (o) -> @attempt.jumps(o) or @recovery?.jumps(o)

  makeReturn: (res) ->
    @attempt  = @attempt .makeReturn res if @attempt
    @recovery = @recovery.makeReturn res if @recovery
    this

Compilation is more or less as you would expect -- the finally clause is optional, the catch is not.

  compileNode: (o) ->
    o.indent  += TAB
    errorPart = if @error then " (#{ @error.compile o }) " else ' '
    tryPart   = @attempt.compile o, LEVEL_TOP

    catchPart = if @recovery
      if @error.value in STRICT_PROSCRIBED
        throw SyntaxError "catch variable may not be \"#{@error.value}\""
      o.scope.add @error.value, 'param' unless o.scope.check @error.value
      " catch#{errorPart}{\n#{ @recovery.compile o, LEVEL_TOP }\n#{@tab}}"
    else unless @ensure or @recovery
      ' catch (_error) {}'

    ensurePart = if @ensure then " finally {\n#{ @ensure.compile o, LEVEL_TOP }\n#{@tab}}" else ''

    """#{@tab}try {
    #{tryPart}
    #{@tab}}#{ catchPart or '' }#{ensurePart}"""

Throw

Simple node to throw an exception.

exports.Throw = class Throw extends Base
  constructor: (@expression) ->

  children: ['expression']

  isStatement: YES
  jumps:       NO

A Throw is already a return, of sorts...

  makeReturn: THIS

  compileNode: (o) ->
    @tab + "throw #{ @expression.compile o };"

Existence

Checks a variable for existence -- not null and not undefined. This is similar to .nil? in Ruby, and avoids having to consult a JavaScript truth table.

exports.Existence = class Existence extends Base
  constructor: (@expression) ->

  children: ['expression']

  invert: NEGATE

  compileNode: (o) ->
    @expression.front = @front
    code = @expression.compile o, LEVEL_OP
    if IDENTIFIER.test(code) and not o.scope.check code
      [cmp, cnj] = if @negated then ['===', '||'] else ['!==', '&&']
      code = "typeof #{code} #{cmp} \"undefined\" #{cnj} #{code} #{cmp} null"
    else

do not use strict equality here; it will break existing code

      code = "#{code} #{if @negated then '==' else '!='} null"
    if o.level <= LEVEL_COND then code else "(#{code})"

Parens

An extra set of parentheses, specified explicitly in the source. At one time we tried to clean up the results by detecting and removing redundant parentheses, but no longer -- you can put in as many as you please.

Parentheses are a good way to force any statement to become an expression.

exports.Parens = class Parens extends Base
  constructor: (@body) ->

  children: ['body']

  unwrap    : -> @body
  isComplex : -> @body.isComplex()

  compileNode: (o) ->
    expr = @body.unwrap()
    if expr instanceof Value and expr.isAtomic()
      expr.front = @front
      return expr.compile o
    code = expr.compile o, LEVEL_PAREN
    bare = o.level < LEVEL_OP and (expr instanceof Op or expr instanceof Call or
      (expr instanceof For and expr.returns))
    if bare then code else "(#{code})"

For

CoffeeScript's replacement for the for loop is our array and object comprehensions, that compile into for loops here. They also act as an expression, able to return the result of each filtered iteration.

Unlike Python array comprehensions, they can be multi-line, and you can pass the current index of the loop as a second parameter. Unlike Ruby blocks, you can map and filter in a single pass.

exports.For = class For extends While
  constructor: (body, source) ->
    {@source, @guard, @step, @name, @index} = source
    @body    = Block.wrap [body]
    @own     = !!source.own
    @object  = !!source.object
    [@name, @index] = [@index, @name] if @object
    throw SyntaxError 'index cannot be a pattern matching expression' if @index instanceof Value
    @range   = @source instanceof Value and @source.base instanceof Range and not @source.properties.length
    @pattern = @name instanceof Value
    throw SyntaxError 'indexes do not apply to range loops' if @range and @index
    throw SyntaxError 'cannot pattern match over range loops' if @range and @pattern
    @returns = false

  children: ['body', 'source', 'guard', 'step']

Welcome to the hairiest method in all of CoffeeScript. Handles the inner loop, filtering, stepping, and result saving for array, object, and range comprehensions. Some of the generated code can be shared in common, and some cannot.

  compileNode: (o) ->
    body      = Block.wrap [@body]
    lastJumps = last(body.expressions)?.jumps()
    @returns  = no if lastJumps and lastJumps instanceof Return
    source    = if @range then @source.base else @source
    scope     = o.scope
    name      = @name  and @name.compile o, LEVEL_LIST
    index     = @index and @index.compile o, LEVEL_LIST
    scope.find(name)  if name and not @pattern
    scope.find(index) if index
    rvar      = scope.freeVariable 'results' if @returns
    ivar      = (@object and index) or scope.freeVariable 'i'
    kvar      = (@range and name) or index or ivar
    kvarAssign = if kvar isnt ivar then "#{kvar} = " else ""

the _by variable is created twice in Ranges if we don't prevent it from being declared here

    stepvar   = scope.freeVariable "step" if @step and not @range
    name      = ivar if @pattern
    varPart   = ''
    guardPart = ''
    defPart   = ''
    idt1      = @tab + TAB
    if @range
      forPart = source.compile merge(o, {index: ivar, name, @step})
    else
      svar    = @source.compile o, LEVEL_LIST
      if (name or @own) and not IDENTIFIER.test svar
        defPart    = "#{@tab}#{ref = scope.freeVariable 'ref'} = #{svar};\n"
        svar       = ref
      if name and not @pattern
        namePart   = "#{name} = #{svar}[#{kvar}]"
      unless @object
        lvar       = scope.freeVariable 'len'
        forVarPart = "#{kvarAssign}#{ivar} = 0, #{lvar} = #{svar}.length"
        forVarPart += ", #{stepvar} = #{@step.compile o, LEVEL_OP}" if @step
        stepPart   = "#{kvarAssign}#{if @step then "#{ivar} += #{stepvar}" else (if kvar isnt ivar then "++#{ivar}" else "#{ivar}++")}"
        forPart    = "#{forVarPart}; #{ivar} < #{lvar}; #{stepPart}"
    if @returns
      resultPart   = "#{@tab}#{rvar} = [];\n"
      returnResult = "\n#{@tab}return #{rvar};"
      body.makeReturn rvar
    if @guard
      if body.expressions.length > 1
        body.expressions.unshift new If (new Parens @guard).invert(), new Literal "continue"
      else
        body = Block.wrap [new If @guard, body] if @guard
    if @pattern
      body.expressions.unshift new Assign @name, new Literal "#{svar}[#{kvar}]"
    defPart     += @pluckDirectCall o, body
    varPart     = "\n#{idt1}#{namePart};" if namePart
    if @object
      forPart   = "#{kvar} in #{svar}"
      guardPart = "\n#{idt1}if (!#{utility 'hasProp'}.call(#{svar}, #{kvar})) continue;" if @own
    body        = body.compile merge(o, indent: idt1), LEVEL_TOP
    body        = '\n' + body + '\n' if body
    """
    #{defPart}#{resultPart or ''}#{@tab}for (#{forPart}) {#{guardPart}#{varPart}#{body}#{@tab}}#{returnResult or ''}
    """

  pluckDirectCall: (o, body) ->
    defs = ''
    for expr, idx in body.expressions
      expr = expr.unwrapAll()
      continue unless expr instanceof Call
      val = expr.variable.unwrapAll()
      continue unless (val instanceof Code) or
                      (val instanceof Value and
                      val.base?.unwrapAll() instanceof Code and
                      val.properties.length is 1 and
                      val.properties[0].name?.value in ['call', 'apply'])
      fn    = val.base?.unwrapAll() or val
      ref   = new Literal o.scope.freeVariable 'fn'
      base  = new Value ref
      if val.base
        [val.base, base] = [base, val]
      body.expressions[idx] = new Call base, expr.args
      defs += @tab + new Assign(ref, fn).compile(o, LEVEL_TOP) + ';\n'
    defs

Switch

A JavaScript switch statement. Converts into a returnable expression on-demand.

exports.Switch = class Switch extends Base
  constructor: (@subject, @cases, @otherwise) ->

  children: ['subject', 'cases', 'otherwise']

  isStatement: YES

  jumps: (o = {block: yes}) ->
    for [conds, block] in @cases
      return block if block.jumps o
    @otherwise?.jumps o

  makeReturn: (res) ->
    pair[1].makeReturn res for pair in @cases
    @otherwise or= new Block [new Literal 'void 0'] if res
    @otherwise?.makeReturn res
    this

  compileNode: (o) ->
    idt1 = o.indent + TAB
    idt2 = o.indent = idt1 + TAB
    code = @tab + "switch (#{ @subject?.compile(o, LEVEL_PAREN) or false }) {\n"
    for [conditions, block], i in @cases
      for cond in flatten [conditions]
        cond  = cond.invert() unless @subject
        code += idt1 + "case #{ cond.compile o, LEVEL_PAREN }:\n"
      code += body + '\n' if body = block.compile o, LEVEL_TOP
      break if i is @cases.length - 1 and not @otherwise
      expr = @lastNonComment block.expressions
      continue if expr instanceof Return or (expr instanceof Literal and expr.jumps() and expr.value isnt 'debugger')
      code += idt2 + 'break;\n'
    code += idt1 + "default:\n#{ @otherwise.compile o, LEVEL_TOP }\n" if @otherwise and @otherwise.expressions.length
    code +  @tab + '}'

If

If/else statements. Acts as an expression by pushing down requested returns to the last line of each clause.

Single-expression Ifs are compiled into conditional operators if possible, because ternaries are already proper expressions, and don't need conversion.

exports.If = class If extends Base
  constructor: (condition, @body, options = {}) ->
    @condition = if options.type is 'unless' then condition.invert() else condition
    @elseBody  = null
    @isChain   = false
    {@soak}    = options

  children: ['condition', 'body', 'elseBody']

  bodyNode:     -> @body?.unwrap()
  elseBodyNode: -> @elseBody?.unwrap()

Rewrite a chain of Ifs to add a default case as the final else.

  addElse: (elseBody) ->
    if @isChain
      @elseBodyNode().addElse elseBody
    else
      @isChain  = elseBody instanceof If
      @elseBody = @ensureBlock elseBody
    this

The If only compiles into a statement if either of its bodies needs to be a statement. Otherwise a conditional operator is safe.

  isStatement: (o) ->
    o?.level is LEVEL_TOP or
      @bodyNode().isStatement(o) or @elseBodyNode()?.isStatement(o)

  jumps: (o) -> @body.jumps(o) or @elseBody?.jumps(o)

  compileNode: (o) ->
    if @isStatement o then @compileStatement o else @compileExpression o

  makeReturn: (res) ->
    @elseBody  or= new Block [new Literal 'void 0'] if res
    @body     and= new Block [@body.makeReturn res]
    @elseBody and= new Block [@elseBody.makeReturn res]
    this

  ensureBlock: (node) ->
    if node instanceof Block then node else new Block [node]

Compile the If as a regular if-else statement. Flattened chains force inner else bodies into statement form.

  compileStatement: (o) ->
    child    = del o, 'chainChild'
    exeq     = del o, 'isExistentialEquals'

    if exeq
      return new If(@condition.invert(), @elseBodyNode(), type: 'if').compile o

    cond     = @condition.compile o, LEVEL_PAREN
    o.indent += TAB
    body     = @ensureBlock(@body)
    ifPart   = "if (#{cond}) {\n#{body.compile(o)}\n#{@tab}}"
    ifPart   = @tab + ifPart unless child
    return ifPart unless @elseBody
    ifPart + ' else ' + if @isChain
      o.indent = @tab
      o.chainChild = yes
      @elseBody.unwrap().compile o, LEVEL_TOP
    else
      "{\n#{ @elseBody.compile o, LEVEL_TOP }\n#{@tab}}"

Compile the If as a conditional operator.

  compileExpression: (o) ->
    cond = @condition.compile o, LEVEL_COND
    body = @bodyNode().compile o, LEVEL_LIST
    alt  = if @elseBodyNode() then @elseBodyNode().compile(o, LEVEL_LIST) else 'void 0'
    code = "#{cond} ? #{body} : #{alt}"
    if o.level >= LEVEL_COND then "(#{code})" else code

  unfoldSoak: ->
    @soak and this

Faux-Nodes

Faux-nodes are never created by the grammar, but are used during code generation to generate other combinations of nodes.

Closure

A faux-node used to wrap an expressions body in a closure.

Closure =

Wrap the expressions body, unless it contains a pure statement, in which case, no dice. If the body mentions this or arguments, then make sure that the closure wrapper preserves the original values.

  wrap: (expressions, statement, noReturn) ->
    return expressions if expressions.jumps()
    func = new Code [], Block.wrap [expressions]
    args = []
    if (mentionsArgs = expressions.contains @literalArgs) or expressions.contains @literalThis
      meth = new Literal if mentionsArgs then 'apply' else 'call'
      args = [new Literal 'this']
      args.push new Literal 'arguments' if mentionsArgs
      func = new Value func, [new Access meth]
    func.noReturn = noReturn
    call = new Call func, args
    if statement then Block.wrap [call] else call

  literalArgs: (node) ->
    node instanceof Literal and node.value is 'arguments' and not node.asKey

  literalThis: (node) ->
    (node instanceof Literal and node.value is 'this' and not node.asKey) or
      (node instanceof Code and node.bound) or
      (node instanceof Call and node.isSuper)

Unfold a node's child if soak, then tuck the node under created If

unfoldSoak = (o, parent, name) ->
  return unless ifn = parent[name].unfoldSoak o
  parent[name] = ifn.body
  ifn.body = new Value parent
  ifn

Constants

UTILITIES =

Correctly set up a prototype chain for inheritance, including a reference to the superclass for super() calls, and copies of any static properties.

  extends: -> """
    function(child, parent) { for (var key in parent) { if (#{utility 'hasProp'}.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }
  """

Create a function bound to the current value of "this".

  bind: -> '''
    function(fn, me){ return function(){ return fn.apply(me, arguments); }; }
  '''

Discover if an item is in an array.

  indexOf: -> """
    [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }
  """

Shortcuts to speed up the lookup time for native functions.

  hasProp: -> '{}.hasOwnProperty'
  slice  : -> '[].slice'

Levels indicate a node's position in the AST. Useful for knowing if parens are necessary or superfluous.

LEVEL_TOP    = 1  # ...;
LEVEL_PAREN  = 2  # (...)
LEVEL_LIST   = 3  # [...]
LEVEL_COND   = 4  # ... ? x : y
LEVEL_OP     = 5  # !...
LEVEL_ACCESS = 6  # ...[0]

Tabs are two spaces for pretty printing.

TAB = '  '

IDENTIFIER_STR = "[$A-Za-z_\\x7f-\\uffff][$\\w\\x7f-\\uffff]*"
IDENTIFIER = /// ^ #{IDENTIFIER_STR} $ ///
SIMPLENUM  = /^[+-]?\d+$/
METHOD_DEF = ///
  ^
    (?:
      (#{IDENTIFIER_STR})
      \.prototype
      (?:
        \.(#{IDENTIFIER_STR})
      | \[("(?:[^\\"\r\n]|\\.)*"|'(?:[^\\'\r\n]|\\.)*')\]
      | \[(0x[\da-fA-F]+ | \d*\.?\d+ (?:[eE][+-]?\d+)?)\]
      )
    )
  |
    (#{IDENTIFIER_STR})
  $
///

Is a literal value a string?

IS_STRING = /^['"]/

Utility Functions

Helper for ensuring that utility functions are assigned at the top level.

utility = (name) ->
  ref = "__#{name}"
  Scope.root.assign ref, UTILITIES[name]()
  ref

multident = (code, tab) ->
  code = code.replace /\n/g, '$&' + tab
  code.replace /\s+$/, ''

coffee-script-1.4.0/documentation/docs/optparse.html000066400000000000000000000445561204160075300226050ustar00rootroot00000000000000 optparse.coffee

optparse.coffee

A simple OptionParser class to parse option flags from the command-line. Use it like so:

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:

[short-flag, long-flag, description]

Along with an an optional banner for the usage help.

  constructor: (rules, @banner) ->
    @rules = buildRules rules

Parse the list of arguments, populating an options object with all of the specified options, and return it. Options after the first non-option argument are treated as arguments. options.arguments will be an array containing the remaining 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.

  parse: (args) ->
    options = arguments: []
    skippingArgument = no
    originalArgs = args
    args = normalizeArguments args
    for arg, i in args
      if skippingArgument
        skippingArgument = no
        continue
      if arg is '--'
        pos = originalArgs.indexOf '--'
        options.arguments = options.arguments.concat originalArgs[(pos + 1)..]
        break
      isOption = !!(arg.match(LONG_FLAG) or arg.match(SHORT_FLAG))

the CS option parser is a little odd; options after the first non-option argument are treated as non-option arguments themselves

      seenNonOptionArg = options.arguments.length > 0
      unless seenNonOptionArg
        matchedRule = no
        for rule in @rules
          if rule.shortFlag is arg or rule.longFlag is arg
            value = true
            if rule.hasArgument
              skippingArgument = yes
              value = args[i + 1]
            options[rule.name] = if rule.isList then (options[rule.name] or []).concat value else value
            matchedRule = yes
            break
        throw new Error "unrecognized option: #{arg}" if isOption and not matchedRule
      if seenNonOptionArg or not isOption
        options.arguments.push arg
    options

Return the help text for this OptionParser, listing and describing all of the valid options, for --help and such.

  help: ->
    lines = []
    lines.unshift "#{@banner}\n" if @banner
    for rule in @rules
      spaces  = 15 - rule.longFlag.length
      spaces  = if spaces > 0 then Array(spaces + 1).join(' ') else ''
      letPart = if rule.shortFlag then rule.shortFlag + ', ' else '    '
      lines.push '  ' + letPart + rule.longFlag + spaces + rule.description
    "\n#{ lines.join('\n') }\n"

Helpers

Regex matchers for option flags.

LONG_FLAG  = /^(--\w[\w\-]*)/
SHORT_FLAG = /^(-\w)$/
MULTI_FLAG = /^-(\w{2,})/
OPTIONAL   = /\[(\w+(\*?))\]/

Build and return the list of option rules. If the optional short-flag is unspecified, leave it out by padding with null.

buildRules = (rules) ->
  for tuple in rules
    tuple.unshift null if tuple.length < 3
    buildRule tuple...

Build a rule from a -o short flag, a --output [DIR] long flag, and the description of what the option does.

buildRule = (shortFlag, longFlag, description, options = {}) ->
  match     = longFlag.match(OPTIONAL)
  longFlag  = longFlag.match(LONG_FLAG)[1]
  {
    name:         longFlag.substr 2
    shortFlag:    shortFlag
    longFlag:     longFlag
    description:  description
    hasArgument:  !!(match and match[1])
    isList:       !!(match and match[2])
  }

Normalize arguments by expanding merged flags into multiple flags. This allows you to have -wl be the same as --watch --lint.

normalizeArguments = (args) ->
  args = args[..]
  result = []
  for arg in args
    if match = arg.match MULTI_FLAG
      result.push '-' + l for l in match[1].split ''
    else
      result.push arg
  result

coffee-script-1.4.0/documentation/docs/repl.html000066400000000000000000001045611204160075300217030ustar00rootroot00000000000000 repl.coffee

repl.coffee

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> console.log "#{num} bottles of beer" for num in [99..1]

Start by opening up stdin and stdout.

stdin = process.openStdin()
stdout = process.stdout

Require the coffee-script module to get access to the compiler.

CoffeeScript = require './coffee-script'
readline     = require 'readline'
{inspect}    = require 'util'
{Script}     = require 'vm'
Module       = require 'module'

REPL Setup

Config

REPL_PROMPT = 'coffee> '
REPL_PROMPT_MULTILINE = '------> '
REPL_PROMPT_CONTINUATION = '......> '
enableColours = no
unless process.platform is 'win32'
  enableColours = not process.env.NODE_DISABLE_COLORS

Log an error.

error = (err) ->
  stdout.write (err.stack or err.toString()) + '\n'

Autocompletion

Regexes to match complete-able bits of text.

ACCESSOR  = /\s*([\w\.]+)(?:\.(\w*))$/
SIMPLEVAR = /(\w+)$/i

Returns a list of completions, and the completed text.

autocomplete = (text) ->
  completeAttribute(text) or completeVariable(text) or [[], text]

Attempt to autocomplete a chained dotted attribute: one.two.three.

completeAttribute = (text) ->
  if match = text.match ACCESSOR
    [all, obj, prefix] = match
    try obj = Script.runInThisContext obj
    catch e
      return
    return unless obj?
    obj = Object obj
    candidates = Object.getOwnPropertyNames obj
    while obj = Object.getPrototypeOf obj
      for key in Object.getOwnPropertyNames obj when key not in candidates
        candidates.push key
    completions = getCompletions prefix, candidates
    [completions, prefix]

Attempt to autocomplete an in-scope free variable: one.

completeVariable = (text) ->
  free = text.match(SIMPLEVAR)?[1]
  free = "" if text is ""
  if free?
    vars = Script.runInThisContext 'Object.getOwnPropertyNames(Object(this))'
    keywords = (r for r in CoffeeScript.RESERVED when r[..1] isnt '__')
    candidates = vars
    for key in keywords when key not in candidates
      candidates.push key
    completions = getCompletions free, candidates
    [completions, free]

Return elements of candidates for which prefix is a prefix.

getCompletions = (prefix, candidates) ->
  el for el in candidates when 0 is el.indexOf prefix

Make sure that uncaught exceptions don't kill the REPL.

process.on 'uncaughtException', error

The current backlog of multi-line code.

backlog = ''

The main REPL function. run is called every time a line of code is entered. Attempt to evaluate the command. If there's an exception, print it out instead of exiting.

run = (buffer) ->

remove single-line comments

  buffer = buffer.replace /(^|[\r\n]+)(\s*)##?(?:[^#\r\n][^\r\n]*|)($|[\r\n])/, "$1$2$3"

remove trailing newlines

  buffer = buffer.replace /[\r\n]+$/, ""
  if multilineMode
    backlog += "#{buffer}\n"
    repl.setPrompt REPL_PROMPT_CONTINUATION
    repl.prompt()
    return
  if !buffer.toString().trim() and !backlog
    repl.prompt()
    return
  code = backlog += buffer
  if code[code.length - 1] is '\\'
    backlog = "#{backlog[...-1]}\n"
    repl.setPrompt REPL_PROMPT_CONTINUATION
    repl.prompt()
    return
  repl.setPrompt REPL_PROMPT
  backlog = ''
  try
    _ = global._
    returnValue = CoffeeScript.eval "_=(#{code}\n)", {
      filename: 'repl'
      modulename: 'repl'
    }
    if returnValue is undefined
      global._ = _
    repl.output.write "#{inspect returnValue, no, 2, enableColours}\n"
  catch err
    error err
  repl.prompt()

if stdin.readable and stdin.isRaw

handle piped input

  pipedInput = ''
  repl =
    prompt: -> stdout.write @_prompt
    setPrompt: (p) -> @_prompt = p
    input: stdin
    output: stdout
    on: ->
  stdin.on 'data', (chunk) ->
    pipedInput += chunk
    return unless /\n/.test pipedInput
    lines = pipedInput.split "\n"
    pipedInput = lines[lines.length - 1]
    for line in lines[...-1] when line
      stdout.write "#{line}\n"
      run line
    return
  stdin.on 'end', ->
    for line in pipedInput.trim().split "\n" when line
      stdout.write "#{line}\n"
      run line
    stdout.write '\n'
    process.exit 0
else

Create the REPL by listening to stdin.

  if readline.createInterface.length < 3
    repl = readline.createInterface stdin, autocomplete
    stdin.on 'data', (buffer) -> repl.write buffer
  else
    repl = readline.createInterface stdin, stdout, autocomplete

multilineMode = off

Handle multi-line mode switch

repl.input.on 'keypress', (char, key) ->

test for Ctrl-v

  return unless key and key.ctrl and not key.meta and not key.shift and key.name is 'v'
  cursorPos = repl.cursor
  repl.output.cursorTo 0
  repl.output.clearLine 1
  multilineMode = not multilineMode
  repl._line() if not multilineMode and backlog
  backlog = ''
  repl.setPrompt (newPrompt = if multilineMode then REPL_PROMPT_MULTILINE else REPL_PROMPT)
  repl.prompt()
  repl.output.cursorTo newPrompt.length + (repl.cursor = cursorPos)

Handle Ctrl-d press at end of last line in multiline mode

repl.input.on 'keypress', (char, key) ->
  return unless multilineMode and repl.line

test for Ctrl-d

  return unless key and key.ctrl and not key.meta and not key.shift and key.name is 'd'
  multilineMode = off
  repl._line()

repl.on 'attemptClose', ->
  if multilineMode
    multilineMode = off
    repl.output.cursorTo 0
    repl.output.clearLine 1
    repl._onLine repl.line
    return
  if backlog or repl.line
    backlog = ''
    repl.historyIndex = -1
    repl.setPrompt REPL_PROMPT
    repl.output.write '\n(^C again to quit)'
    repl._line (repl.line = '')
  else
    repl.close()

repl.on 'close', ->
  repl.output.write '\n'
  repl.input.destroy()

repl.on 'line', run

repl.setPrompt REPL_PROMPT
repl.prompt()

coffee-script-1.4.0/documentation/docs/rewriter.html000066400000000000000000001705041204160075300226040ustar00rootroot00000000000000 rewriter.coffee

rewriter.coffee

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, and generally clean things up.

The Rewriter class is used by the Lexer, directly against its internal array of tokens.

class exports.Rewriter

Helpful snippet for debugging: console.log (t[0] + '/' + t[1] for t in @tokens).join ' '

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.

  rewrite: (@tokens) ->
    @removeLeadingNewlines()
    @removeMidExpressionNewlines()
    @closeOpenCalls()
    @closeOpenIndexes()
    @addImplicitIndentation()
    @tagPostfixConditionals()
    @addImplicitBraces()
    @addImplicitParentheses()
    @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.

  scanTokens: (block) ->
    {tokens} = this
    i = 0
    i += block.call this, token, i, tokens while token = tokens[i]
    true

  detectEnd: (i, condition, action) ->
    {tokens} = this
    levels = 0
    while token = tokens[i]
      return action.call this, token, i     if levels is 0 and condition.call this, token, i
      return action.call this, token, i - 1 if not token or levels < 0
      if token[0] in EXPRESSION_START
        levels += 1
      else if token[0] in EXPRESSION_END
        levels -= 1
      i += 1
    i - 1

Leading newlines would introduce an ambiguity in the grammar, so we dispatch them here.

  removeLeadingNewlines: ->
    break for [tag], i in @tokens when tag isnt 'TERMINATOR'
    @tokens.splice 0, i if i

Some blocks occur in the middle of expressions -- when we're expecting this, remove their trailing newlines.

  removeMidExpressionNewlines: ->
    @scanTokens (token, i, tokens) ->
      return 1 unless token[0] is 'TERMINATOR' and @tag(i + 1) in EXPRESSION_CLOSE
      tokens.splice i, 1
      0

The lexer has tagged the opening parenthesis of a method call. Match it with its paired close. We have the mis-nested outdent case included here for calls that close on the same line, just before their outdent.

  closeOpenCalls: ->

    condition = (token, i) ->
      token[0] in [')', 'CALL_END'] or
      token[0] is 'OUTDENT' and @tag(i - 1) is ')'

    action = (token, i) ->
      @tokens[if token[0] is 'OUTDENT' then i - 1 else i][0] = 'CALL_END'

    @scanTokens (token, i) ->
      @detectEnd i + 1, condition, action if token[0] is 'CALL_START'
      1

The lexer has tagged the opening parenthesis of an indexing operation call. Match it with its paired close.

  closeOpenIndexes: ->

    condition = (token, i) ->
      token[0] in [']', 'INDEX_END']

    action = (token, i) ->
      token[0] = 'INDEX_END'

    @scanTokens (token, i) ->
      @detectEnd i + 1, condition, action if token[0] is 'INDEX_START'
      1

Object literals may be written with implicit braces, for simple cases. Insert the missing braces here, so that the parser doesn't have to.

  addImplicitBraces: ->

    stack       = []
    start       = null
    startsLine  = null
    sameLine    = yes
    startIndent = 0
    startIndex  = 0

    condition = (token, i) ->
      [one, two, three] = @tokens[i + 1 .. i + 3]
      return no if 'HERECOMMENT' is one?[0]
      [tag] = token
      sameLine = no if tag in LINEBREAKS
      return (
        (tag in ['TERMINATOR', 'OUTDENT'] or 
          (tag in IMPLICIT_END and sameLine and not (i - startIndex is 1))) and
        ((!startsLine and @tag(i - 1) isnt ',') or
          not (two?[0] is ':' or one?[0] is '@' and three?[0] is ':'))) or
        (tag is ',' and one and
          one[0] not in ['IDENTIFIER', 'NUMBER', 'STRING', '@', 'TERMINATOR', 'OUTDENT']
      )

    action = (token, i) ->
      tok = @generate '}', '}', token[2]
      @tokens.splice i, 0, tok

    @scanTokens (token, i, tokens) ->
      if (tag = token[0]) in EXPRESSION_START
        stack.push [(if tag is 'INDENT' and @tag(i - 1) is '{' then '{' else tag), i]
        return 1
      if tag in EXPRESSION_END
        start = stack.pop()
        return 1
      return 1 unless tag is ':' and
        ((ago = @tag i - 2) is ':' or stack[stack.length - 1]?[0] isnt '{')
      sameLine = yes
      startIndex = i + 1
      stack.push ['{']
      idx =  if ago is '@' then i - 2 else i - 1
      idx -= 2 while @tag(idx - 2) is 'HERECOMMENT'
      prevTag = @tag(idx - 1)
      startsLine = not prevTag or (prevTag in LINEBREAKS)
      value = new String('{')
      value.generated = yes
      tok = @generate '{', value, token[2]
      tokens.splice idx, 0, tok
      @detectEnd i + 2, condition, action
      2

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.

  addImplicitParentheses: ->

    noCall = seenSingle = seenControl = no

    condition = (token, i) ->
      [tag] = token
      return yes if not seenSingle and token.fromThen
      seenSingle  = yes if tag in ['IF', 'ELSE', 'CATCH', '->', '=>', 'CLASS']
      seenControl = yes if tag in ['IF', 'ELSE', 'SWITCH', 'TRY', '=']
      return yes if tag in ['.', '?.', '::'] and @tag(i - 1) is 'OUTDENT'
      not token.generated and @tag(i - 1) isnt ',' and (tag in IMPLICIT_END or
        (tag is 'INDENT' and not seenControl)) and
        (tag isnt 'INDENT' or
          (@tag(i - 2) not in ['CLASS', 'EXTENDS'] and @tag(i - 1) not in IMPLICIT_BLOCK and
          not ((post = @tokens[i + 1]) and post.generated and post[0] is '{')))

    action = (token, i) ->
      @tokens.splice i, 0, @generate 'CALL_END', ')', token[2]

    @scanTokens (token, i, tokens) ->
      tag     = token[0]
      noCall  = yes if tag in ['CLASS', 'IF', 'FOR', 'WHILE']
      [prev, current, next] = tokens[i - 1 .. i + 1]
      callObject  = not noCall and tag is 'INDENT' and
                    next and next.generated and next[0] is '{' and
                    prev and prev[0] in IMPLICIT_FUNC
      seenSingle  = no
      seenControl = no
      noCall      = no if tag in LINEBREAKS
      token.call  = yes if prev and not prev.spaced and tag is '?'
      return 1 if token.fromThen
      return 1 unless callObject or
        prev?.spaced and (prev.call or prev[0] in IMPLICIT_FUNC) and
        (tag in IMPLICIT_CALL or not (token.spaced or token.newLine) and tag in IMPLICIT_UNSPACED_CALL)
      tokens.splice i, 0, @generate 'CALL_START', '(', token[2]
      @detectEnd i + 1, condition, action
      prev[0] = 'FUNC_EXIST' if prev[0] is '?'
      2

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.

  addImplicitIndentation: ->

    starter = indent = outdent = null

    condition = (token, i) ->
      token[1] isnt ';' and token[0] in SINGLE_CLOSERS and
      not (token[0] is 'ELSE' and starter not in ['IF', 'THEN'])

    action = (token, i) ->
      @tokens.splice (if @tag(i - 1) is ',' then i - 1 else i), 0, outdent

    @scanTokens (token, i, tokens) ->
      [tag] = token
      if tag is 'TERMINATOR' and @tag(i + 1) is 'THEN'
        tokens.splice i, 1
        return 0
      if tag is 'ELSE' and @tag(i - 1) isnt 'OUTDENT'
        tokens.splice i, 0, @indentation(token)...
        return 2
      if tag is 'CATCH' and @tag(i + 2) in ['OUTDENT', 'TERMINATOR', 'FINALLY']
        tokens.splice i + 2, 0, @indentation(token)...
        return 4
      if tag in SINGLE_LINERS and @tag(i + 1) isnt 'INDENT' and
         not (tag is 'ELSE' and @tag(i + 1) is 'IF')
        starter = tag
        [indent, outdent] = @indentation token, yes
        indent.fromThen   = true if starter is 'THEN'
        tokens.splice i + 1, 0, indent
        @detectEnd i + 2, condition, action
        tokens.splice i, 1 if tag is 'THEN'
        return 1
      return 1

Tag postfix conditionals as such, so that we can parse them with a different precedence.

  tagPostfixConditionals: ->

    original = null

    condition = (token, i) ->
      token[0] in ['TERMINATOR', 'INDENT']

    action = (token, i) ->
      if token[0] isnt 'INDENT' or (token.generated and not token.fromThen)
        original[0] = 'POST_' + original[0]

    @scanTokens (token, i) ->
      return 1 unless token[0] is 'IF'
      original = token
      @detectEnd i + 1, condition, action
      1

Generate the indentation tokens, based on another token on the same line.

  indentation: (token, implicit = no) ->
    indent  = ['INDENT', 2, token[2]]
    outdent = ['OUTDENT', 2, token[2]]
    indent.generated = outdent.generated = yes if implicit
    [indent, outdent]

Create a generated token: one that exists due to a use of implicit syntax.

  generate: (tag, value, line) ->
    tok = [tag, value, line]
    tok.generated = yes
    tok

Look up a tag by token index.

  tag: (i) -> @tokens[i]?[0]

Constants

List of the token pairs that must be balanced.

BALANCED_PAIRS = [
  ['(', ')']
  ['[', ']']
  ['{', '}']
  ['INDENT', 'OUTDENT'],
  ['CALL_START', 'CALL_END']
  ['PARAM_START', 'PARAM_END']
  ['INDEX_START', 'INDEX_END']
]

The inverse mappings of BALANCED_PAIRS we're trying to fix up, so we can look things up from either end.

exports.INVERSES = INVERSES = {}

The tokens that signal the start/end of a balanced pair.

EXPRESSION_START = []
EXPRESSION_END   = []

for [left, rite] in BALANCED_PAIRS
  EXPRESSION_START.push INVERSES[rite] = left
  EXPRESSION_END  .push INVERSES[left] = rite

Tokens that indicate the close of a clause of an expression.

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', '@', 'THIS']

If preceded by an IMPLICIT_FUNC, indicates a function invocation.

IMPLICIT_CALL    = [
  'IDENTIFIER', 'NUMBER', 'STRING', 'JS', 'REGEX', 'NEW', 'PARAM_START', 'CLASS'
  'IF', 'TRY', 'SWITCH', 'THIS', 'BOOL', 'NULL', 'UNDEFINED', 'UNARY', 'SUPER'
  '@', '->', '=>', '[', '(', '{', '--', '++'
]

IMPLICIT_UNSPACED_CALL = ['+', '-']

Tokens indicating that the implicit call must enclose a block of expressions.

IMPLICIT_BLOCK   = ['->', '=>', '{', '[', ',']

Tokens that always mark the end of an implicit call for single-liners.

IMPLICIT_END     = ['POST_IF', 'FOR', 'WHILE', 'UNTIL', 'WHEN', 'BY', 'LOOP', 'TERMINATOR']

Single-line flavors of block expressions that have unclosed endings. The grammar can't disambiguate them, so we insert the implicit indentation.

SINGLE_LINERS    = ['ELSE', '->', '=>', 'TRY', 'FINALLY', 'THEN']
SINGLE_CLOSERS   = ['TERMINATOR', 'CATCH', 'FINALLY', 'ELSE', 'OUTDENT', 'LEADING_WHEN']

Tokens that end a line.

LINEBREAKS       = ['TERMINATOR', 'INDENT', 'OUTDENT']

coffee-script-1.4.0/documentation/docs/scope.html000066400000000000000000000460121204160075300220460ustar00rootroot00000000000000 scope.coffee

scope.coffee

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.

Import the helpers we plan to use.

{extend, last} = require './helpers'

exports.Scope = class Scope

The top-level Scope object.

  @root: null

Initialize a scope with its parent, for lookups up the chain, as well as a reference to the Block node it belongs to, which is where it should declare its variables, and a reference to the function that it wraps.

  constructor: (@parent, @expressions, @method) ->
    @variables = [{name: 'arguments', type: 'arguments'}]
    @positions = {}
    Scope.root = this unless @parent

Adds a new variable or overrides an existing one.

  add: (name, type, immediate) ->
    return @parent.add name, type, immediate if @shared and not immediate
    if Object::hasOwnProperty.call @positions, name
      @variables[@positions[name]].type = type
    else
      @positions[name] = @variables.push({name, type}) - 1

When super is called, we need to find the name of the current method we're in, so that we know how to invoke the same method of the parent class. This can get complicated if super is being called from an inner function. namedMethod will walk up the scope tree until it either finds the first function object that has a name filled in, or bottoms out.

  namedMethod: ->
    return @method if @method.name or !@parent
    @parent.namedMethod()

Look up a variable name in lexical scope, and declare it if it does not already exist.

  find: (name) ->
    return yes if @check name
    @add name, 'var'
    no

Reserve a variable name as originating from a function parameter for this scope. No var required for internal references.

  parameter: (name) ->
    return if @shared and @parent.check name, yes
    @add name, 'param'

Just check to see if a variable has already been declared, without reserving, walks up to the root scope.

  check: (name) ->
    !!(@type(name) or @parent?.check(name))

Generate a temporary variable name at the given index.

  temporary: (name, index) ->
    if name.length > 1
      '_' + name + if index > 1 then index - 1 else ''
    else
      '_' + (index + parseInt name, 36).toString(36).replace /\d/g, 'a'

Gets the type of a variable.

  type: (name) ->
    return v.type for v in @variables when v.name is name
    null

If we need to store an intermediate result, find an available name for a compiler-generated variable. _var, _var2, and so on...

  freeVariable: (name, reserve=true) ->
    index = 0
    index++ while @check((temp = @temporary name, index))
    @add temp, 'var', yes if reserve
    temp

Ensure that an assignment is made at the top of this scope (or at the top-level scope, if requested).

  assign: (name, value) ->
    @add name, {value, assigned: yes}, yes
    @hasAssignments = yes

Does this scope have any declared variables?

  hasDeclarations: ->
    !!@declaredVariables().length

Return the list of variables first declared in this scope.

  declaredVariables: ->
    realVars = []
    tempVars = []
    for v in @variables when v.type is 'var'
      (if v.name.charAt(0) is '_' then tempVars else realVars).push v.name
    realVars.sort().concat tempVars.sort()

Return the list of assignments that are supposed to be made at the top of this scope.

  assignedVariables: ->
    "#{v.name} = #{v.type.value}" for v in @variables when v.type.assigned

coffee-script-1.4.0/documentation/docs/underscore.html000066400000000000000000003464161204160075300231210ustar00rootroot00000000000000 underscore.coffee

underscore.coffee

Underscore.coffee (c) 2011 Jeremy Ashkenas, DocumentCloud Inc. Underscore is freely distributable under the terms of the MIT license. Portions of Underscore are inspired by or borrowed from Prototype.js, Oliver Steele's Functional, and John Resig's Micro-Templating. For all details and documentation: http://documentcloud.github.com/underscore/

Baseline setup

Establish the root object, window in the browser, or global on the server.

root = this

Save the previous value of the _ variable.

previousUnderscore = root._

Establish the object that gets thrown to break out of a loop iteration. StopIteration is SOP on Mozilla.

breaker = if typeof(StopIteration) is 'undefined' then '__break__' else StopIteration

Helper function to escape RegExp contents, because JS doesn't have one.

escapeRegExp = (string) -> string.replace(/([.*+?^${}()|[\]\/\\])/g, '\\$1')

Save bytes in the minified (but not gzipped) version:

ArrayProto           = Array.prototype
ObjProto             = Object.prototype

Create quick reference variables for speed access to core prototypes.

slice                = ArrayProto.slice
unshift              = ArrayProto.unshift
toString             = ObjProto.toString
hasOwnProperty       = ObjProto.hasOwnProperty
propertyIsEnumerable = ObjProto.propertyIsEnumerable

All ECMA5 native implementations we hope to use are declared here.

nativeForEach        = ArrayProto.forEach
nativeMap            = ArrayProto.map
nativeReduce         = ArrayProto.reduce
nativeReduceRight    = ArrayProto.reduceRight
nativeFilter         = ArrayProto.filter
nativeEvery          = ArrayProto.every
nativeSome           = ArrayProto.some
nativeIndexOf        = ArrayProto.indexOf
nativeLastIndexOf    = ArrayProto.lastIndexOf
nativeIsArray        = Array.isArray
nativeKeys           = Object.keys

Create a safe reference to the Underscore object for use below.

_ = (obj) -> new wrapper(obj)

Export the Underscore object for CommonJS.

if typeof(exports) != 'undefined' then exports._ = _

Export Underscore to global scope.

root._ = _

Current version.

_.VERSION = '1.1.0'

Collection Functions

The cornerstone, an each implementation. Handles objects implementing forEach, arrays, and raw objects.

_.each = (obj, iterator, context) ->
  try
    if nativeForEach and obj.forEach is nativeForEach
      obj.forEach iterator, context
    else if _.isNumber obj.length
      iterator.call context, obj[i], i, obj for i in [0...obj.length]
    else
      iterator.call context, val, key, obj  for own key, val of obj
  catch e
    throw e if e isnt breaker
  obj

Return the results of applying the iterator to each element. Use JavaScript 1.6's version of map, if possible.

_.map = (obj, iterator, context) ->
  return obj.map(iterator, context) if nativeMap and obj.map is nativeMap
  results = []
  _.each obj, (value, index, list) ->
    results.push iterator.call context, value, index, list
  results

Reduce builds up a single result from a list of values. Also known as inject, or foldl. Uses JavaScript 1.8's version of reduce, if possible.

_.reduce = (obj, iterator, memo, context) ->
  if nativeReduce and obj.reduce is nativeReduce
    iterator = _.bind iterator, context if context
    return obj.reduce iterator, memo
  _.each obj, (value, index, list) ->
    memo = iterator.call context, memo, value, index, list
  memo

The right-associative version of reduce, also known as foldr. Uses JavaScript 1.8's version of reduceRight, if available.

_.reduceRight = (obj, iterator, memo, context) ->
  if nativeReduceRight and obj.reduceRight is nativeReduceRight
    iterator = _.bind iterator, context if context
    return obj.reduceRight iterator, memo
  reversed = _.clone(_.toArray(obj)).reverse()
  _.reduce reversed, iterator, memo, context

Return the first value which passes a truth test.

_.detect = (obj, iterator, context) ->
  result = null
  _.each obj, (value, index, list) ->
    if iterator.call context, value, index, list
      result = value
      _.breakLoop()
  result

Return all the elements that pass a truth test. Use JavaScript 1.6's filter, if it exists.

_.filter = (obj, iterator, context) ->
  return obj.filter iterator, context if nativeFilter and obj.filter is nativeFilter
  results = []
  _.each obj, (value, index, list) ->
    results.push value if iterator.call context, value, index, list
  results

Return all the elements for which a truth test fails.

_.reject = (obj, iterator, context) ->
  results = []
  _.each obj, (value, index, list) ->
    results.push value if not iterator.call context, value, index, list
  results

Determine whether all of the elements match a truth test. Delegate to JavaScript 1.6's every, if it is present.

_.every = (obj, iterator, context) ->
  iterator ||= _.identity
  return obj.every iterator, context if nativeEvery and obj.every is nativeEvery
  result = true
  _.each obj, (value, index, list) ->
    _.breakLoop() unless (result = result and iterator.call(context, value, index, list))
  result

Determine if at least one element in the object matches a truth test. Use JavaScript 1.6's some, if it exists.

_.some = (obj, iterator, context) ->
  iterator ||= _.identity
  return obj.some iterator, context if nativeSome and obj.some is nativeSome
  result = false
  _.each obj, (value, index, list) ->
    _.breakLoop() if (result = iterator.call(context, value, index, list))
  result

Determine if a given value is included in the array or object, based on ===.

_.include = (obj, target) ->
  return _.indexOf(obj, target) isnt -1 if nativeIndexOf and obj.indexOf is nativeIndexOf
  return true for own key, val of obj when val is target
  false

Invoke a method with arguments on every item in a collection.

_.invoke = (obj, method) ->
  args = _.rest arguments, 2
  (if method then val[method] else val).apply(val, args) for val in obj

Convenience version of a common use case of map: fetching a property.

_.pluck = (obj, key) ->
  _.map(obj, (val) -> val[key])

Return the maximum item or (item-based computation).

_.max = (obj, iterator, context) ->
  return Math.max.apply(Math, obj) if not iterator and _.isArray(obj)
  result = computed: -Infinity
  _.each obj, (value, index, list) ->
    computed = if iterator then iterator.call(context, value, index, list) else value
    computed >= result.computed and (result = {value: value, computed: computed})
  result.value

Return the minimum element (or element-based computation).

_.min = (obj, iterator, context) ->
  return Math.min.apply(Math, obj) if not iterator and _.isArray(obj)
  result = computed: Infinity
  _.each obj, (value, index, list) ->
    computed = if iterator then iterator.call(context, value, index, list) else value
    computed < result.computed and (result = {value: value, computed: computed})
  result.value

Sort the object's values by a criterion produced by an iterator.

_.sortBy = (obj, iterator, context) ->
  _.pluck(((_.map obj, (value, index, list) ->
    {value: value, criteria: iterator.call(context, value, index, list)}
  ).sort((left, right) ->
    a = left.criteria; b = right.criteria
    if a < b then -1 else if a > b then 1 else 0
  )), 'value')

Use a comparator function to figure out at what index an object should be inserted so as to maintain order. Uses binary search.

_.sortedIndex = (array, obj, iterator) ->
  iterator ||= _.identity
  low =  0
  high = array.length
  while low < high
    mid = (low + high) >> 1
    if iterator(array[mid]) < iterator(obj) then low = mid + 1 else high = mid
  low

Convert anything iterable into a real, live array.

_.toArray = (iterable) ->
  return []                   if (!iterable)
  return iterable.toArray()   if (iterable.toArray)
  return iterable             if (_.isArray(iterable))
  return slice.call(iterable) if (_.isArguments(iterable))
  _.values(iterable)

Return the number of elements in an object.

_.size = (obj) -> _.toArray(obj).length

Array Functions

Get the first element of an array. Passing n will return the first N values in the array. Aliased as head. The guard check allows it to work with map.

_.first = (array, n, guard) ->
  if n and not guard then slice.call(array, 0, n) else array[0]

Returns everything but the first entry of the array. Aliased as tail. Especially useful on the arguments object. Passing an index will return the rest of the values in the array from that index onward. The guard check allows it to work with map.

_.rest = (array, index, guard) ->
  slice.call(array, if _.isUndefined(index) or guard then 1 else index)

Get the last element of an array.

_.last = (array) -> array[array.length - 1]

Trim out all falsy values from an array.

_.compact = (array) -> item for item in array when item

Return a completely flattened version of an array.

_.flatten = (array) ->
  _.reduce array, (memo, value) ->
    return memo.concat(_.flatten(value)) if _.isArray value
    memo.push value
    memo
  , []

Return a version of the array that does not contain the specified value(s).

_.without = (array) ->
  values = _.rest arguments
  val for val in _.toArray(array) when not _.include values, val

Produce a duplicate-free version of the array. If the array has already been sorted, you have the option of using a faster algorithm.

_.uniq = (array, isSorted) ->
  memo = []
  for el, i in _.toArray array
    memo.push el if i is 0 || (if isSorted is true then _.last(memo) isnt el else not _.include(memo, el))
  memo

Produce an array that contains every item shared between all the passed-in arrays.

_.intersect = (array) ->
  rest = _.rest arguments
  _.select _.uniq(array), (item) ->
    _.all rest, (other) ->
      _.indexOf(other, item) >= 0

Zip together multiple lists into a single array -- elements that share an index go together.

_.zip = ->
  length =  _.max _.pluck arguments, 'length'
  results = new Array length
  for i in [0...length]
    results[i] = _.pluck arguments, String i
  results

If the browser doesn't supply us with indexOf (I'm looking at you, MSIE), we need this function. Return the position of the first occurrence of an item in an array, or -1 if the item is not included in the array.

_.indexOf = (array, item) ->
  return array.indexOf item if nativeIndexOf and array.indexOf is nativeIndexOf
  i = 0; l = array.length
  while l - i
    if array[i] is item then return i else i++
  -1

Provide JavaScript 1.6's lastIndexOf, delegating to the native function, if possible.

_.lastIndexOf = (array, item) ->
  return array.lastIndexOf(item) if nativeLastIndexOf and array.lastIndexOf is nativeLastIndexOf
  i = array.length
  while i
    if array[i] is item then return i else i--
  -1

Generate an integer Array containing an arithmetic progression. A port of the native Python range function.

_.range = (start, stop, step) ->
  a         = arguments
  solo      = a.length <= 1
  i = start = if solo then 0 else a[0]
  stop      = if solo then a[0] else a[1]
  step      = a[2] or 1
  len       = Math.ceil((stop - start) / step)
  return []   if len <= 0
  range     = new Array len
  idx       = 0
  loop
    return range if (if step > 0 then i - stop else stop - i) >= 0
    range[idx] = i
    idx++
    i+= step

Function Functions

Create a function bound to a given object (assigning this, and arguments, optionally). Binding with arguments is also known as curry.

_.bind = (func, obj) ->
  args = _.rest arguments, 2
  -> func.apply obj or root, args.concat arguments

Bind all of an object's methods to that object. Useful for ensuring that all callbacks defined on an object belong to it.

_.bindAll = (obj) ->
  funcs = if arguments.length > 1 then _.rest(arguments) else _.functions(obj)
  _.each funcs, (f) -> obj[f] = _.bind obj[f], obj
  obj

Delays a function for the given number of milliseconds, and then calls it with the arguments supplied.

_.delay = (func, wait) ->
  args = _.rest arguments, 2
  setTimeout((-> func.apply(func, args)), wait)

Memoize an expensive function by storing its results.

_.memoize = (func, hasher) ->
  memo = {}
  hasher or= _.identity
  ->
    key = hasher.apply this, arguments
    return memo[key] if key of memo
    memo[key] = func.apply this, arguments

Defers a function, scheduling it to run after the current call stack has cleared.

_.defer = (func) ->
  _.delay.apply _, [func, 1].concat _.rest arguments

Returns the first function passed as an argument to the second, allowing you to adjust arguments, run code before and after, and conditionally execute the original function.

_.wrap = (func, wrapper) ->
  -> wrapper.apply wrapper, [func].concat arguments

Returns a function that is the composition of a list of functions, each consuming the return value of the function that follows.

_.compose = ->
  funcs = arguments
  ->
    args = arguments
    for i in [funcs.length - 1..0] by -1
      args = [funcs[i].apply(this, args)]
    args[0]

Object Functions

Retrieve the names of an object's properties.

_.keys = nativeKeys or (obj) ->
  return _.range 0, obj.length if _.isArray(obj)
  key for key, val of obj

Retrieve the values of an object's properties.

_.values = (obj) ->
  _.map obj, _.identity

Return a sorted list of the function names available in Underscore.

_.functions = (obj) ->
  _.filter(_.keys(obj), (key) -> _.isFunction(obj[key])).sort()

Extend a given object with all of the properties in a source object.

_.extend = (obj) ->
  for source in _.rest(arguments)
    obj[key] = val for key, val of source
  obj

Create a (shallow-cloned) duplicate of an object.

_.clone = (obj) ->
  return obj.slice 0 if _.isArray obj
  _.extend {}, obj

Invokes interceptor with the obj, and then returns obj. The primary purpose of this method is to "tap into" a method chain, in order to perform operations on intermediate results within the chain.

_.tap = (obj, interceptor) ->
  interceptor obj
  obj

Perform a deep comparison to check if two objects are equal.

_.isEqual = (a, b) ->

Check object identity.

  return true if a is b

Different types?

  atype = typeof(a); btype = typeof(b)
  return false if atype isnt btype

Basic equality test (watch out for coercions).

  return true if `a == b`

One is falsy and the other truthy.

  return false if (!a and b) or (a and !b)

One of them implements an isEqual()?

  return a.isEqual(b) if a.isEqual

Check dates' integer values.

  return a.getTime() is b.getTime() if _.isDate(a) and _.isDate(b)

Both are NaN?

  return false if _.isNaN(a) and _.isNaN(b)

Compare regular expressions.

  if _.isRegExp(a) and _.isRegExp(b)
    return a.source     is b.source and
           a.global     is b.global and
           a.ignoreCase is b.ignoreCase and
           a.multiline  is b.multiline

If a is not an object by this point, we can't handle it.

  return false if atype isnt 'object'

Check for different array lengths before comparing contents.

  return false if a.length and (a.length isnt b.length)

Nothing else worked, deep compare the contents.

  aKeys = _.keys(a); bKeys = _.keys(b)

Different object sizes?

  return false if aKeys.length isnt bKeys.length

Recursive comparison of contents.

  return false for key, val of a when !(key of b) or !_.isEqual(val, b[key])
  true

Is a given array or object empty?

_.isEmpty = (obj) ->
  return obj.length is 0 if _.isArray(obj) or _.isString(obj)
  return false for own key of obj
  true

Is a given value a DOM element?

_.isElement   = (obj) -> obj and obj.nodeType is 1

Is a given value an array?

_.isArray     = nativeIsArray or (obj) -> !!(obj and obj.concat and obj.unshift and not obj.callee)

Is a given variable an arguments object?

_.isArguments = (obj) -> obj and obj.callee

Is the given value a function?

_.isFunction  = (obj) -> !!(obj and obj.constructor and obj.call and obj.apply)

Is the given value a string?

_.isString    = (obj) -> !!(obj is '' or (obj and obj.charCodeAt and obj.substr))

Is a given value a number?

_.isNumber    = (obj) -> (obj is +obj) or toString.call(obj) is '[object Number]'

Is a given value a boolean?

_.isBoolean   = (obj) -> obj is true or obj is false

Is a given value a Date?

_.isDate      = (obj) -> !!(obj and obj.getTimezoneOffset and obj.setUTCFullYear)

Is the given value a regular expression?

_.isRegExp    = (obj) -> !!(obj and obj.exec and (obj.ignoreCase or obj.ignoreCase is false))

Is the given value NaN -- this one is interesting. NaN != NaN, and isNaN(undefined) == true, so we make sure it's a number first.

_.isNaN       = (obj) -> _.isNumber(obj) and window.isNaN(obj)

Is a given value equal to null?

_.isNull      = (obj) -> obj is null

Is a given variable undefined?

_.isUndefined = (obj) -> typeof obj is 'undefined'

Utility Functions

Run Underscore.js in noConflict mode, returning the _ variable to its previous owner. Returns a reference to the Underscore object.

_.noConflict = ->
  root._ = previousUnderscore
  this

Keep the identity function around for default iterators.

_.identity = (value) -> value

Run a function n times.

_.times = (n, iterator, context) ->
  iterator.call context, i for i in [0...n]

Break out of the middle of an iteration.

_.breakLoop = -> throw breaker

Add your own custom functions to the Underscore object, ensuring that they're correctly added to the OOP wrapper as well.

_.mixin = (obj) ->
  for name in _.functions(obj)
    addToWrapper name, _[name] = obj[name]

Generate a unique integer id (unique within the entire client session). Useful for temporary DOM ids.

idCounter = 0
_.uniqueId = (prefix) ->
  (prefix or '') + idCounter++

By default, Underscore uses ERB-style template delimiters, change the following template settings to use alternative delimiters.

_.templateSettings = {
  start:        '<%'
  end:          '%>'
  interpolate:  /<%=(.+?)%>/g
}

JavaScript templating a-la ERB, pilfered from John Resig's Secrets of the JavaScript Ninja, page 83. Single-quote fix from Rick Strahl. With alterations for arbitrary delimiters, and to preserve whitespace.

_.template = (str, data) ->
  c = _.templateSettings
  endMatch = new RegExp("'(?=[^"+c.end.substr(0, 1)+"]*"+escapeRegExp(c.end)+")","g")
  fn = new Function 'obj',
    'var p=[],print=function(){p.push.apply(p,arguments);};' +
    'with(obj||{}){p.push(\'' +
    str.replace(/\r/g, '\\r')
       .replace(/\n/g, '\\n')
       .replace(/\t/g, '\\t')
       .replace(endMatch,"✄")
       .split("'").join("\\'")
       .split("✄").join("'")
       .replace(c.interpolate, "',$1,'")
       .split(c.start).join("');")
       .split(c.end).join("p.push('") +
       "');}return p.join('');"
  if data then fn(data) else fn

Aliases

_.forEach  = _.each
_.foldl    = _.inject = _.reduce
_.foldr    = _.reduceRight
_.select   = _.filter
_.all      = _.every
_.any      = _.some
_.contains = _.include
_.head     = _.first
_.tail     = _.rest
_.methods  = _.functions

Setup the OOP Wrapper

If Underscore is called as a function, it returns a wrapped object that can be used OO-style. This wrapper holds altered versions of all the underscore functions. Wrapped objects may be chained.

wrapper = (obj) ->
  this._wrapped = obj
  this

Helper function to continue chaining intermediate results.

result = (obj, chain) ->
  if chain then _(obj).chain() else obj

A method to easily add functions to the OOP wrapper.

addToWrapper = (name, func) ->
  wrapper.prototype[name] = ->
    args = _.toArray arguments
    unshift.call args, this._wrapped
    result func.apply(_, args), this._chain

Add all ofthe Underscore functions to the wrapper object.

_.mixin _

Add all mutator Array functions to the wrapper.

_.each ['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], (name) ->
  method = Array.prototype[name]
  wrapper.prototype[name] = ->
    method.apply(this._wrapped, arguments)
    result(this._wrapped, this._chain)

Add all accessor Array functions to the wrapper.

_.each ['concat', 'join', 'slice'], (name) ->
  method = Array.prototype[name]
  wrapper.prototype[name] = ->
    result(method.apply(this._wrapped, arguments), this._chain)

Start chaining a wrapped Underscore object.

wrapper::chain = ->
  this._chain = true
  this

Extracts the result from a wrapped and chained object.

wrapper::value = -> this._wrapped

coffee-script-1.4.0/documentation/images/000077500000000000000000000000001204160075300203615ustar00rootroot00000000000000coffee-script-1.4.0/documentation/images/background.png000066400000000000000000000001731204160075300232070ustar00rootroot00000000000000PNG  IHDR2^{tEXtSoftwareAdobe ImageReadyqe<IDATxb;,̃YL -Tjh[IENDB`coffee-script-1.4.0/documentation/images/banding.png000066400000000000000000000002041204160075300224650ustar00rootroot00000000000000PNG  IHDR&/tEXtSoftwareAdobe ImageReadyqe<&IDATxb?#BQ/P) z2`"Hٲ\IENDB`coffee-script-1.4.0/documentation/images/button_bg.png000066400000000000000000000002121204160075300230450ustar00rootroot00000000000000PNG  IHDRatEXtSoftwareAdobe ImageReadyqe<,IDATxb~)P{;w{FIENDB`coffee-script-1.4.0/documentation/images/button_bg_dark.gif000066400000000000000000000002241204160075300240320ustar00rootroot00000000000000GIF89aVVV}}}mmmwwwqqqkkk[[[uuueeebbbRRR|||___yyyiiisss~~~!, $b4B cJ;coffee-script-1.4.0/documentation/images/button_bg_green.gif000066400000000000000000000001371204160075300242140ustar00rootroot00000000000000GIF89a3n={*\:u0g-c2k;x9s,`6r>|!, pIg8)`HIB;coffee-script-1.4.0/documentation/images/favicon.ico000066400000000000000000000021761204160075300225100ustar00rootroot00000000000000 h(  3ooooqqy(eRR52226p__ $oo2222222||fSS=%%2;##2222222H22aMMʿMgTT222222222}mm2+q22222222222^y2222222222222K55 udd2222222222222ĽHcPP28 R==kYYoo||}}||}mmhVVN9962udd:>VpppiWWiVVkYYɉzzkR:<n^KKn\\B8(05VZzzuddhVVV*VBB$o^^_LL՛~$tdd&o]] q``b&raap__0^VAA|| ygUUgUU"?``ocoffee-script-1.4.0/documentation/images/logo.png000066400000000000000000000175011204160075300220330ustar00rootroot00000000000000PNG  IHDR2tEXtSoftwareAdobe ImageReadyqe<IDATx] |ELB $Kr)עr("x}ꪻ¢ *ꊮ+*ʱ"\H9I8$|ff_zzWUEm[ITI+Z*)J@**)J@**uS~UU膮QzTFJ$Ar\y,+/S" }FfEʔm@-jYV'M=`\gYF]gꊡnmYK 4 C дL7@6~ۖ|8PX# d͜pZ@`F5ƿMK ܀3gi4mG#[2>a@wsR*Qh;pB+0jeB#Y8k?[ssQ}ڡPp@]@kѢ54Mwwvb`_Ȧ}2OJo7︫.רQt۶FAO[##:X X=;7@50+2AШQVQ䅡'oWpOHC?7%33㺢O<9f (K/4O8?Cv n蘵`T-}cÆ?Gg?mF\_YW[>r|@ntdؖ5HMG)D^py_^WZ1 ֱ؎7AxGqa-(̌ӂ)ym!mصIЈcR[O.=<ؖ:͛.>ؤ gzGߨ:'HxA6cvZZ  GhΝ[O%Ĩ 3Am^Qj0*F9.4j&L!L3kAdA5$|,1nR`kKSZWӺQ4M}|f)[ԔoL3zRMh?`( `Jч4|}K<7oz{ˊ`ACL 2Bэvu,aq\!2߽l˴l5 ڥ{в}n4N``gp8!B[&x>ݟV dt ? 6_G31x3^Dhu+R(~07OZ2d$ u<[g>_q&9vL SXusakaUn2I3h@+1sD'j8ls=_F4N>0=EV(d磣3`Jۀ?j}LI8Vpe,3wZ$ۇsHBRAih,X'|0^"j}_pQ&[ SfL۹cOp̘Q&NxW  w:"0vSմn``i)ma:g~p/Wbiqю--5ӲҲL36QUQ0h OW0l+^KtTsY(N_Iecj]/{@SbtYRavUGx {K] YAd|{,^C|5ŃAXل;8' 3sur'XYv#s,7+cD/z5Td^@%B3缤rӒ<8d y=5>  n/**UuS}*N/I;KJ1OqsLqyE`m0DXgv@gn\:$7OVu{ӕmyQOrwgAEi e<܆W6i%%s:V)Y`[( hae2O AtQy5hP)_E"їny;n`S٢l*̚%OIv7fZ,qShcP1I5|"G<4?#t|oΨ(4ڟP>2~&#y|~ F8 ޥ lw#/ > :6>m1 :?0 4CЁ@ x1C" ty}!A~4hB?0SVD#᧽iiOd:n,F901~Q!(*C#;RV*r:ouԝ|iN[^抚3[͝Bν :nOO T 1`'KeH?оG/BīdpQ[cVW3 k5NO(>xSj<׀]GNh9_,c&~ RP2=_ -3NrNUx@hYG,@X&#׊FYbAg>3Ӌp>$q!ht eN.5cƂZ3 Jԫ,+={h|;VGhMmm=΢`azs)̀qgi-%jHKSgؤY-vq> l}jdw >ۭCI蠇pm)$*KZ}kOܟ~mk!Kpx4 L^0vL#C[?(gaڼ m E¿'q.YFh3,5Pi?{ۖm.<I%Ck#~FIL} ☔OD[n7`NgA!NgO!q`r 顴6M9m6D]VzQ1-)F1rS`Lt- #Y^ƃPZ $J |󅾅<z&;TwY qma|.qE=-&B7ןh:>/esV}xBěhe#h Ao{% si"E{A Qʃ\$ Д8($V_'^ʤk"YЄ#g59)c%S6e+ Pݕ{(UqNqTc6*ALB VJ 3c59qsK􊵖 4? 0l h͟$)jr?p%8w, >\~}Ks 5h|?KIdL;z{xrgOpnrA5Kp7W MMQ@buת+<&,+w= &NLìrܴ4/]%OhUbЕ$`^(ċMAZovcJ;9M3u.4 >h)G9 磈xU^n|)YEF{~{|&5~PS*5VE3ߕьIIpWZhμ ϑx,XmATE?ܪ02ўV)6dwI淂d.Kq'xS{az\zQbҪLJB?Xr.,a )@@XU1VD|ֆj &|᪬``)F\XםzfTH"sZFUWMa[ٕ$( W_B^:h[ Ap2bџ8 mi LZJc6SS`&$b  $xVɂU~!'&[ү*DW 3:!>*pM:-{U.-,֯#Y#V((έ>+5+jYf PV%i%woFg&lVwMJg~ڊc:)ȓ渶,œɶ#@B U1gIV ݉guᙒ^}UK0>}6Kr)5^7odA#g$=K S Lұ?ж Z2ӊ5Gaf] σ񚐦i]YڠD/ &W )S!~ ~w!@NN{~^+:\!|HR[&}"hܧ?'pY #(/mۘ*yܨ'YAH+eGhhRIcx=d_2&WhV+fTa2MRi@t.rtʔԖܞEZz{*7`lR7o"qdzQx⻠?o{%>3x>OCbߚ&LKzx %wmKx L~(hYZД:E_%=Qex>ڼTz}' 1sJܘ!|ip?@g>h@}'F; ޶*`7'ohRd9Q+d5-3UvO8аI2()FOMh64G(٪0x< 0Fahb{{&."40мFWĚ;8$ToZNINwK82&y&3d)hR(=5Dge맩3'r;Ũ1h6}n&4A%~k~qޣhAaKf=[vLi}&4c^_5]0yxna~xpU'Z11iK ɧBTg"-g-zޭG YUijI˜/u- r-NA]aHU 4o!Aj;)N۳r !ptO-P#hs):u--2ev7rLe uBgyQlĀÝǶnw`Uytqrh+h9ٖ'&Uբ}kMOӬ@w6FVJMQqM=tֻ֚ϣ9nǷО*˫:M, H1\cz fvqNқHZsKaуpKO)r;$د<' b^HvUHr)z0xp{Rm: !M$Yaʠ7@NzgmBH in&JatRtBTh"GW@PNI8 ,?soO$AdRH[㯂?J4`XLII!鎏Gku7r ~7%0nLj@_Kҝ]Uq Y<q6Wt1:[K@zSGԧ+0oLꪠ-0ç&q=4uآ&*h+:~Jai~p0mdi/vR~AcT屒):^|@\ߩfLPTV2֜9E g ʜJjߐ}gҚ+ i6TKD/ݖV{giW kqH5<S+ٓG8lC]F#x $G|Y7S)!`U>.@!鎋Q|p}#xd8'Q<C$6z,z VuH]epAemGG9Ck^[gZٮIwabZZcDdbUoN ghFz7 >ǖ0nIj9c܌[և$ms%5$ O4$j@NkRFR!D/l2F{Wn+ׁzywڜ%"5#n[Ʒױ|9|&ũu@nFFZzL@ ~@)HRkYև<<\( ~Gxc]Kj7%|3  @i(pz^Do'}Bw@f\{h̓&C(`u/Ђó9%rT [[!gq~YtMM? H [WwDw\ʊ֕E\ʊչei7. K}HxdЊcv8-xG@kghž a 544Є+9(,"zo~AxC*Dd΀`lŸU*N# P`Dx,"Fdʀ˚t* ζHgd=" >`ySqѷx$"7N<ҎhXq }c)Ƹ ~7 g@[[Y7@@ [w7 ߈ Z>4 O!C9@yyy ~]"~sq܈$ L:j@(?"` L!/` L!/i@@Ѐ+u UXr: "/ĩAm`R?>1p 6ԦL!(}-GܚBG( kB+ Y@% lD`89@4lg`        @@@@@@@@ ͏?6gwϟ_/wmN C/30xy""<*:. J@ L<R OF xZ@L!<5}\ O^0c# [u)]Sq+ HeQ;1p( >@DDL Yڊ@qؾc!TDxCá!y{k-g0tx7 "x ݿ`Xdc;?`+ ɣ/7Z=` X1v@ZJDRvpl"Px< !lMjRp< 飞/ʶr}&]nI`c;7"PP< FDffo4((s[gY<c7fixvyw~`%7m.Ьf47nz;Y*ۅ#"/c VEB*H<KY>8GYHT&Y0wwT7a/ M[r++--`*_ߺwkǢk൭{iՍnkصGiS.;Ԗ#qoǜlݱzܮa $G;ֵGiBDRʖֲvhj~%W> ϗ?nX%U@SGo|w +iĖz<<Wn۫ nwaTMrl[ VwfV:X3 Hτ#1֡Y ">FkGv߬1wTX9y1ēgHv`[ j7V<."Xԑśp(hܬ}xǶ:śuÇ#[4F+>'&i#rQ8r ct|]ntOmo" pD1mn&?ZmDΙ<9(a?}w)u1'Y#cGM"̞-8$-[8닊Ön|+ !u|v,ݜ[V{ -}Fgiz72@zFTxlC8vKގ>j}I)OTS 6GMm*~Ad;e[4ҟJʱXM\Qԑb@!c# Q@F[Tpt:ҟF F=!xTՍc+K 9dx3/݄hhh<*Tgj5Vrv6==u%dV5L#`Xɯk.dvwS~O+z!U\BI}?UԑU,LlQH+I'~aN0esx1 !)_ rÑik H;7Hָx^NT)J8\% D֐TW^`,5&!.*oYy] x&C8~HQH,FekJt1z8(ےfg|DH^RDE,B8V~HvQH7ñ±˚>{qQR KXknlVtdPmS cֱ IT2yX*q%PL>mtTjA }߿TXXťZA`6WiC@2J>z1yload" : '' button = executable ? "
#{run}
" : '' "
#{cshtml}#{jshtml}#{script}#{import}#{button}
" end %> CoffeeScript

CoffeeScript is a little language that compiles into JavaScript. Underneath all those awkward braces and semicolons, JavaScript has always had a gorgeous object model at its heart. CoffeeScript is an attempt to expose the good parts of JavaScript in a simple way.

The golden rule of CoffeeScript is: "It's just JavaScript". The code compiles one-to-one into the equivalent JS, and there is no interpretation at runtime. You can use any existing JavaScript library seamlessly from CoffeeScript (and vice-versa). The compiled output is readable and pretty-printed, passes through JavaScript Lint without warnings, will work in every JavaScript runtime, and tends to run as fast or faster than the equivalent handwritten JavaScript.

Latest Version: 1.4.0

Overview

CoffeeScript on the left, compiled JavaScript output on the right.

<%= code_for('overview', 'cubes', false) %>

Installation

The CoffeeScript compiler is itself written in CoffeeScript, using the Jison parser generator. The command-line version of coffee is available as a Node.js utility. The core compiler however, does not depend on Node, and can be run in any JavaScript environment, or in the browser (see "Try CoffeeScript", above).

To install, first make sure you have a working copy of the latest stable version of Node.js, and npm (the Node Package Manager). You can then install CoffeeScript with npm:

npm install -g coffee-script

(Leave off the -g if you don't wish to install globally.)

If you'd prefer to install the latest master version of CoffeeScript, you can clone the CoffeeScript source repository from GitHub, or download the source directly. To install the lastest master CoffeeScript compiler with npm:

npm install -g http://github.com/jashkenas/coffee-script/tarball/master

Or, if you want to install to /usr/local, and don't want to use npm to manage it, open the coffee-script directory and run:

sudo bin/cake install

Usage

Once installed, you should have access to the coffee command, which can execute scripts, compile .coffee files into .js, and provide an interactive REPL. The coffee command takes the following options:

-c, --compile Compile a .coffee script into a .js JavaScript file of the same name.
-i, --interactive Launch an interactive CoffeeScript session to try short snippets. Identical to calling coffee with no arguments.
-o, --output [DIR] Write out all compiled JavaScript files into the specified directory. Use in conjunction with --compile or --watch.
-j, --join [FILE] Before compiling, concatenate all scripts together in the order they were passed, and write them into the specified file. Useful for building large projects.
-w, --watch Watch files for changes, rerunning the specified command when any file is updated.
-p, --print Instead of writing out the JavaScript as a file, print it directly to stdout.
-l, --lint If the jsl (JavaScript Lint) command is installed, use it to check the compilation of a CoffeeScript file. (Handy in conjunction with
--watch)
-s, --stdio Pipe in CoffeeScript to STDIN and get back JavaScript over STDOUT. Good for use with processes written in other languages. An example:
cat src/cake.coffee | coffee -sc
-e, --eval Compile and print a little snippet of CoffeeScript directly from the command line. For example:
coffee -e "console.log num for num in [10..1]"
-r, --require Load a library before compiling or executing your script. Can be used to hook in to the compiler (to add Growl notifications, for example).
-b, --bare Compile the JavaScript without the top-level function safety wrapper.
-t, --tokens Instead of parsing the CoffeeScript, just lex it, and print out the token stream: [IDENTIFIER square] [ASSIGN =] [PARAM_START (] ...
-n, --nodes Instead of compiling the CoffeeScript, just lex and parse it, and print out the parse tree:
Expressions
  Assign
    Value "square"
    Code "x"
      Op *
        Value "x"
        Value "x"
--nodejs The node executable has some useful options you can set, such as
--debug, --debug-brk and --max-stack-size. Use this flag to forward options directly to Node.js.

Examples:

  • Compile a directory tree of .coffee files in src into a parallel tree of .js files in lib:
    coffee --compile --output lib/ src/
  • Watch a file for changes, and recompile it every time the file is saved:
    coffee --watch --compile experimental.coffee
  • Concatenate a list of files into a single script:
    coffee --join project.js --compile src/*.coffee
  • Print out the compiled JS from a one-liner:
    coffee -bpe "alert i for i in [0..10]"
  • All together now, watch and recompile an entire project as you work on it:
    coffee -o lib/ -cw src/
  • Start the CoffeeScript REPL (Ctrl-D to exit, Ctrl-Vfor multi-line):
    coffee

Language Reference

This reference is structured so that it can be read from top to bottom, if you like. Later sections use ideas and syntax previously introduced. Familiarity with JavaScript is assumed. In all of the following examples, the source CoffeeScript is provided on the left, and the direct compilation into JavaScript is on the right.

Many of the examples can be run (where it makes sense) by pressing the run button on the right, and can be loaded into the "Try CoffeeScript" console by pressing the load button on the left.

First, the basics: CoffeeScript uses significant whitespace to delimit blocks of code. You don't need to use semicolons ; to terminate expressions, ending the line will do just as well (although semicolons can still be used to fit multiple expressions onto a single line). Instead of using curly braces { } to surround blocks of code in functions, if-statements, switch, and try/catch, use indentation.

You don't need to use parentheses to invoke a function if you're passing arguments. The implicit call wraps forward to the end of the line or block expression.
console.log sys.inspect objectconsole.log(sys.inspect(object));

Functions Functions are defined by an optional list of parameters in parentheses, an arrow, and the function body. The empty function looks like this: ->

<%= code_for('functions', 'cube(5)') %>

Functions may also have default values for arguments. Override the default value by passing a non-null argument.

<%= code_for('default_args', 'fill("cup")') %>

Objects and Arrays The CoffeeScript literals for objects and arrays look very similar to their JavaScript cousins. When each property is listed on its own line, the commas are optional. Objects may be created using indentation instead of explicit braces, similar to YAML.

<%= code_for('objects_and_arrays', 'song.join(" ... ")') %>

In JavaScript, you can't use reserved words, like class, as properties of an object, without quoting them as strings. CoffeeScript notices reserved words used as keys in objects and quotes them for you, so you don't have to worry about it (say, when using jQuery).

<%= code_for('objects_reserved') %>

Lexical Scoping and Variable Safety The CoffeeScript compiler takes care to make sure that all of your variables are properly declared within lexical scope — you never need to write var yourself.

<%= code_for('scope', 'inner') %>

Notice how all of the variable declarations have been pushed up to the top of the closest scope, the first time they appear. outer is not redeclared within the inner function, because it's already in scope; inner within the function, on the other hand, should not be able to change the value of the external variable of the same name, and therefore has a declaration of its own.

This behavior is effectively identical to Ruby's scope for local variables. Because you don't have direct access to the var keyword, it's impossible to shadow an outer variable on purpose, you may only refer to it. So be careful that you're not reusing the name of an external variable accidentally, if you're writing a deeply nested function.

Although suppressed within this documentation for clarity, all CoffeeScript output is wrapped in an anonymous function: (function(){ ... })(); This safety wrapper, combined with the automatic generation of the var keyword, make it exceedingly difficult to pollute the global namespace by accident.

If you'd like to create top-level variables for other scripts to use, attach them as properties on window, or on the exports object in CommonJS. The existential operator (covered below), gives you a reliable way to figure out where to add them; if you're targeting both CommonJS and the browser: exports ? this

If, Else, Unless, and Conditional Assignment If/else statements can be written without the use of parentheses and curly brackets. As with functions and other block expressions, multi-line conditionals are delimited by indentation. There's also a handy postfix form, with the if or unless at the end.

CoffeeScript can compile if statements into JavaScript expressions, using the ternary operator when possible, and closure wrapping otherwise. There is no explicit ternary statement in CoffeeScript — you simply use a regular if statement on a single line.

<%= code_for('conditionals') %>

Splats... The JavaScript arguments object is a useful way to work with functions that accept variable numbers of arguments. CoffeeScript provides splats ..., both for function definition as well as invocation, making variable numbers of arguments a little bit more palatable.

<%= code_for('splats', true) %>

Loops and Comprehensions Most of the loops you'll write in CoffeeScript will be comprehensions over arrays, objects, and ranges. Comprehensions replace (and compile into) for loops, with optional guard clauses and the value of the current array index. Unlike for loops, array comprehensions are expressions, and can be returned and assigned.

<%= code_for('array_comprehensions') %>

Comprehensions should be able to handle most places where you otherwise would use a loop, each/forEach, map, or select/filter, for example: shortNames = (name for name in list when name.length < 5)
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.

<%= code_for('range_comprehensions', 'countdown') %>

Note how because we are assigning the value of the comprehensions to a variable in the example above, CoffeeScript is collecting the result of each iteration into an array. Sometimes functions end with loops that are intended to run only for their side-effects. Be careful that you're not accidentally returning the results of the comprehension in these cases, by adding a meaningful return value — like true — or null, to the bottom of your function.

To step through a range comprehension in fixed-size chunks, use by, for example:
evens = (x for x in [0..10] by 2)

Comprehensions can also be used to iterate over the keys and values in an object. Use of to signal comprehension over the properties of an object instead of the values in an array.

<%= code_for('object_comprehensions', 'ages.join(", ")') %>

If you would like to iterate over just the keys that are defined on the object itself, by adding a hasOwnProperty check to avoid properties that may be inherited from the prototype, use
for own key, value of object

The only low-level loop that CoffeeScript provides is the while loop. The main difference from JavaScript is that the while loop can be used as an expression, returning an array containing the result of each iteration through the loop.

<%= code_for('while', 'lyrics.join("\n")') %>

For readability, the until keyword is equivalent to while not, and the loop keyword is equivalent to while true.

When using a JavaScript loop to generate functions, it's common to insert a closure wrapper in order to ensure that loop variables are closed over, and all the generated functions don't just share the final values. CoffeeScript provides the do keyword, which immediately invokes a passed function, forwarding any arguments.

<%= code_for('do') %>

Array Slicing and Splicing with Ranges Ranges can also be used to extract slices of arrays. With two dots (3..6), the range is inclusive (3, 4, 5, 6); with three dots (3...6), the range excludes the end (3, 4, 5). Slices indices have useful defaults. An omitted first index defaults to zero and an omitted second index defaults to the size of the array.

<%= code_for('slices', 'middle') %>

The same syntax can be used with assignment to replace a segment of an array with new values, splicing it.

<%= code_for('splices', 'numbers') %>

Note that JavaScript strings are immutable, and can't be spliced.

Everything is an Expression (at least, as much as possible) You might have noticed how even though we don't add return statements to CoffeeScript functions, they nonetheless return their final value. The CoffeeScript compiler tries to make sure that all statements in the language can be used as expressions. Watch how the return gets pushed down into each possible branch of execution in the function below.

<%= code_for('expressions', 'eldest') %>

Even though functions will always return their final value, it's both possible and encouraged to return early from a function body writing out the explicit return (return value), when you know that you're done.

Because variable declarations occur at the top of scope, assignment can be used within expressions, even for variables that haven't been seen before:

<%= code_for('expressions_assignment', 'six') %>

Things that would otherwise be statements in JavaScript, when used as part of an expression in CoffeeScript, are converted into expressions by wrapping them in a closure. This lets you do useful things, like assign the result of a comprehension to a variable:

<%= code_for('expressions_comprehension', 'globals') %>

As well as silly things, like passing a try/catch statement directly into a function call:

<%= code_for('expressions_try', true) %>

There are a handful of statements in JavaScript that can't be meaningfully converted into expressions, namely break, continue, and return. If you make use of them within a block of code, CoffeeScript won't try to perform the conversion.

Operators and Aliases Because the == operator frequently causes undesirable coercion, is intransitive, and has a different meaning than in other languages, CoffeeScript compiles == into ===, and != into !==. In addition, is compiles into ===, and isnt into !==.

You can use not as an alias for !.

For logic, and compiles to &&, and or into ||.

Instead of a newline or semicolon, then can be used to separate conditions from expressions, in while, if/else, and switch/when statements.

As in YAML, on and yes are the same as boolean true, while off and no are boolean false.

unless can be used as the inverse of if.

As a shortcut for this.property, you can use @property.

You can use in to test for array presence, and of to test for JavaScript object-key presence.

All together now:

CoffeeScriptJavaScript
is===
isnt!==
not!
and&&
or||
true, yes, ontrue
false, no, offfalse
@, thisthis
ofin
inno JS equivalent
<%= code_for('aliases') %>

The Existential Operator It's a little difficult to check for the existence of a variable in JavaScript. if (variable) ... comes close, but fails for zero, the empty string, and false. CoffeeScript's existential operator ? returns true unless a variable is null or undefined, which makes it analogous to Ruby's nil?

It can also be used for safer conditional assignment than ||= provides, for cases where you may be handling numbers or strings.

<%= code_for('existence', 'footprints') %>

The accessor variant of the existential operator ?. can be used to soak up null references in a chain of properties. Use it instead of the dot accessor . in cases where the base value may be null or undefined. If all of the properties exist then you'll get the expected result, if the chain is broken, undefined is returned instead of the TypeError that would be raised otherwise.

<%= code_for('soaks') %>

Soaking up nulls is similar to Ruby's andand gem, and to the safe navigation operator in Groovy.

Classes, Inheritance, and Super JavaScript's prototypal inheritance has always been a bit of a brain-bender, with a whole family tree of libraries that provide a cleaner syntax for classical inheritance on top of JavaScript's prototypes: Base2, Prototype.js, JS.Class, etc. The libraries provide syntactic sugar, but the built-in inheritance would be completely usable if it weren't for a couple of small exceptions: it's awkward to call super (the prototype object's implementation of the current function), and it's awkward to correctly set the prototype chain.

Instead of repetitively attaching functions to a prototype, CoffeeScript provides a basic class structure that allows you to name your class, set the superclass, assign prototypal properties, and define the constructor, in a single assignable expression.

Constructor functions are named, to better support helpful stack traces. In the first class in the example below, this.constructor.name is "Animal".

<%= code_for('classes', true) %>

If structuring your prototypes classically isn't your cup of tea, CoffeeScript provides a couple of lower-level conveniences. The extends operator helps with proper prototype setup, and can be used to create an inheritance chain between any pair of constructor functions; :: gives you quick access to an object's prototype; and super() is converted into a call against the immediate ancestor's method of the same name.

<%= code_for('prototypes', '"one_two".dasherize()') %>

Finally, class definitions are blocks of executable code, which make for interesting metaprogramming possibilities. Because in the context of a class definition, this is the class object itself (the constructor function), you can assign static properties by using
@property: value, and call functions defined in parent classes: @attr 'title', type: 'text'

Destructuring Assignment To make extracting values from complex arrays and objects more convenient, CoffeeScript implements ECMAScript Harmony's proposed destructuring assignment syntax. When you assign an array or object literal to a value, CoffeeScript breaks up and matches both sides against each other, assigning the values on the right to the variables on the left. In the simplest case, it can be used for parallel assignment:

<%= code_for('parallel_assignment', 'theBait') %>

But it's also helpful for dealing with functions that return multiple values.

<%= code_for('multiple_return_values', 'forecast') %>

Destructuring assignment can be used with any depth of array and object nesting, to help pull out deeply nested properties.

<%= code_for('object_extraction', 'name + " — " + street') %>

Destructuring assignment can even be combined with splats.

<%= code_for('patterns_and_splats', 'contents.join("")') %>

Function binding In JavaScript, the this keyword is dynamically scoped to mean the object that the current function is attached to. If you pass a function as a callback or attach it to a different object, the original value of this will be lost. If you're not familiar with this behavior, this Digital Web article gives a good overview of the quirks.

The fat arrow => can be used to both define a function, and to bind it to the current value of this, right on the spot. This is helpful when using callback-based libraries like Prototype or jQuery, for creating iterator functions to pass to each, or event-handler functions to use with bind. Functions created with the fat arrow are able to access properties of the this where they're defined.

<%= code_for('fat_arrow') %>

If we had used -> in the callback above, @customer would have referred to the undefined "customer" property of the DOM element, and trying to call purchase() on it would have raised an exception.

When used in a class definition, methods declared with the fat arrow will be automatically bound to each instance of the class when the instance is constructed.

Embedded JavaScript Hopefully, you'll never need to use it, but if you ever need to intersperse snippets of JavaScript within your CoffeeScript, you can use backticks to pass it straight through.

<%= code_for('embedded', 'hi()') %>

Switch/When/Else Switch statements in JavaScript are a bit awkward. You need to remember to break at the end of every case statement to avoid accidentally falling through to the default case. CoffeeScript prevents accidental fall-through, and can convert the switch into a returnable, assignable expression. The format is: switch condition, when clauses, else the default case.

As in Ruby, switch statements in CoffeeScript can take multiple values for each when clause. If any of the values match, the clause runs.

<%= code_for('switch') %>

Try/Catch/Finally Try/catch statements are just about the same as JavaScript (although they work as expressions).

<%= code_for('try') %>

Chained Comparisons CoffeeScript borrows chained comparisons from Python — making it easy to test if a value falls within a certain range.

<%= code_for('comparisons', 'healthy') %>

String Interpolation, Block Strings, and Block Comments Ruby-style string interpolation is included in CoffeeScript. Double-quoted strings allow for interpolated values, using #{ ... }, and single-quoted strings are literal.

<%= code_for('interpolation', 'sentence') %>

Multiline strings are allowed in CoffeeScript.

<%= code_for('strings', 'mobyDick') %>

Block strings can be used to hold formatted or indentation-sensitive text (or, if you just don't feel like escaping quotes and apostrophes). The indentation level that begins the block is maintained throughout, so you can keep it all aligned with the body of your code.

<%= code_for('heredocs', 'html') %>

Double-quoted block strings, like other double-quoted strings, allow interpolation.

Sometimes you'd like to pass a block comment through to the generated JavaScript. For example, when you need to embed a licensing header at the top of a file. Block comments, which mirror the syntax for block strings, are preserved in the generated code.

<%= code_for('block_comment') %>

Block Regular Expressions Similar to block strings and comments, CoffeeScript supports block regexes — extended regular expressions that ignore internal whitespace and can contain comments and interpolation. Modeled after Perl's /x modifier, CoffeeSctipt's block regexes are delimited by /// and go a long way towards making complex regular expressions readable. To quote from the CoffeeScript source:

<%= code_for('heregexes') %>

Cake, and Cakefiles

CoffeeScript includes a (very) simple build system similar to Make and Rake. Naturally, it's called Cake, and is used for the tasks that build and test the CoffeeScript language itself. Tasks are defined in a file named Cakefile, and can be invoked by running cake [task] from within the directory. To print a list of all the tasks and options, just type cake.

Task definitions are written in CoffeeScript, so you can put arbitrary code in your Cakefile. Define a task with a name, a long description, and the function to invoke when the task is run. If your task takes a command-line option, you can define the option with short and long flags, and it will be made available in the options object. Here's a task that uses the Node.js API to rebuild CoffeeScript's parser:

<%= code_for('cake_tasks') %>

If you need to invoke one task before another — for example, running build before test, you can use the invoke function: invoke 'build'. Cake tasks are a minimal way to expose your CoffeeScript functions to the command line, so don't expect any fanciness built-in. If you need dependencies, or async callbacks, it's best to put them in your code itself — not the cake task.

"text/coffeescript" Script Tags

While it's not recommended for serious use, CoffeeScripts may be included directly within the browser using <script type="text/coffeescript"> tags. The source includes a compressed and minified version of the compiler (Download current version here, 39k when gzipped) as extras/coffee-script.js. Include this file on a page with inline CoffeeScript tags, and it will compile and evaluate them in order.

In fact, the little bit of glue script that runs "Try CoffeeScript" above, as well as the jQuery for the menu, is implemented in just this way. View source and look at the bottom of the page to see the example. Including the script also gives you access to CoffeeScript.compile() so you can pop open Firebug and try compiling some strings.

The usual caveats about CoffeeScript apply — your inline scripts will run within a closure wrapper, so if you want to expose global variables or functions, attach them to the window object.

Books

There are a number of excellent resources to help you get started with CoffeeScript, some of which are freely available online.

Screencasts

  • A Sip of CoffeeScript is a Code School Course which combines 6 screencasts with in-browser coding to make learning fun. The first level is free to try out.
  • Meet CoffeeScript is a 75-minute long screencast by PeepCode. Highly memorable for its animations which demonstrate transforming CoffeeScript into the equivalent JS.
  • If you're looking for less of a time commitment, RailsCasts' CoffeeScript Basics should have you covered, hitting all of the important notes about CoffeeScript in 11 minutes.

Examples

The best list of open-source CoffeeScript examples can be found on GitHub. But just to throw out few more:

  • github's Hubot, a friendly IRC robot that can perform any number of useful and useless tasks.
  • sstephenson's Pow, a zero-configuration Rack server, with comprehensive annotated source.
  • frank06's riak-js, a Node.js client for Riak, with support for HTTP and Protocol Buffers.
  • technoweenie's Coffee-Resque, a port of Resque for Node.js.
  • assaf's Zombie.js, a headless, full-stack, faux-browser testing library for Node.js.
  • jashkenas' Underscore.coffee, a port of the Underscore.js library of helper functions.
  • stephank's Orona, a remake of the Bolo tank game for modern browsers.
  • josh's nack, a Node.js-powered Rack server.

Resources

  • Source Code
    Use bin/coffee to test your changes,
    bin/cake test to run the test suite,
    bin/cake build to rebuild the CoffeeScript compiler, and
    bin/cake build:parser to regenerate the Jison parser if you're working on the grammar.

    git checkout lib && bin/cake build:full is a good command to run when you're working on the core language. It'll refresh the lib directory (in case you broke something), build your altered compiler, use that to rebuild itself (a good sanity test) and then run all of the tests. If they pass, there's a good chance you've made a successful change.
  • CoffeeScript Issues
    Bug reports, feature proposals, and ideas for changes to the language belong here.
  • CoffeeScript Google Group
    If you'd like to ask a question, the mailing list is a good place to get help.
  • The CoffeeScript Wiki
    If you've ever learned a neat CoffeeScript tip or trick, or ran into a gotcha — share it on the wiki. The wiki also serves as a directory of handy text editor extensions, web framework plugins, and general CoffeeScript build tools.
  • The FAQ
    Perhaps your CoffeeScript-related question has been asked before. Check the FAQ first.
  • High-Rez Logo
    The CoffeeScript logo is available in Illustrator, EPS and PSD formats, for use in presentations.

Web Chat (IRC)

Quick help and advice can usually be found in the CoffeeScript IRC room. Join #coffeescript on irc.freenode.net, or click the button below to open a webchat session on this page.

Change Log

1.4.0 Oct 23, 2012

  • The CoffeeScript compiler now strips Microsoft's UTF-8 BOM if it exists, allowing you to compile BOM-borked source files.
  • Fix Node/compiler deprecation warnings by removing registerExtension, and moving from path.exists to fs.exists.
  • Small tweaks to splat compilation, backticks, slicing, and the error for duplicate keys in object literals.

1.3.3 May 15, 2012

  • Due to the new semantics of JavaScript's strict mode, CoffeeScript no longer guarantees that constructor functions have names in all runtimes. See #2052 for discussion.
  • Inside of a nested function inside of an instance method, it's now possible to call super more reliably (walks recursively up).
  • Named loop variables no longer have different scoping heuristics than other local variables. (Reverts #643)
  • Fix for splats nested within the LHS of destructuring assignment.
  • Corrections to our compile time strict mode forbidding of octal literals.

1.3.1 April 10, 2012

  • CoffeeScript now enforces all of JavaScript's Strict Mode early syntax errors at compile time. This includes old-style octal literals, duplicate property names in object literals, duplicate parameters in a function definition, deleting naked variables, setting the value of eval or arguments, and more. See a full discussion at #1547.
  • The REPL now has a handy new multi-line mode for entering large blocks of code. It's useful when copy-and-pasting examples into the REPL. Enter multi-line mode with Ctrl-V. You may also now pipe input directly into the REPL.
  • CoffeeScript now prints a Generated by CoffeeScript VERSION header at the top of each compiled file.
  • Conditional assignment of previously undefined variables a or= b is now considered a syntax error.
  • A tweak to the semantics of do, which can now be used to more easily simulate a namespace: do (x = 1, y = 2) -> ...
  • Loop indices are now mutable within a loop iteration, and immutable between them.
  • Both endpoints of a slice are now allowed to be omitted for consistency, effectively creating a shallow copy of the list.
  • Additional tweaks and improvments to coffee --watch under Node's "new" file watching API. Watch will now beep by default if you introduce a syntax error into a watched script. We also now ignore hidden directories by default when watching recursively.

1.2.0 Dec. 18, 2011

  • Multiple improvements to coffee --watch and --join. You may now use both together, as well as add and remove files and directories within a --watch'd folder.
  • The throw statement can now be used as part of an expression.
  • Block comments at the top of the file will now appear outside of the safety closure wrapper.
  • Fixed a number of minor 1.1.3 regressions having to do with trailing operators and unfinished lines, and a more major 1.1.3 regression that caused bound functions within bound class functions to have the incorrect this.

1.1.3 Nov. 8, 2011

  • Ahh, whitespace. CoffeeScript's compiled JS now tries to space things out and keep it readable, as you can see in the examples on this page.
  • You can now call super in class level methods in class bodies, and bound class methods now preserve their correct context.
  • JavaScript has always supported octal numbers 010 is 8, and hexadecimal numbers 0xf is 15, but CoffeeScript now also supports binary numbers: 0b10 is 2.
  • The CoffeeScript module has been nested under a subdirectory to make it easier to require individual components separately, without having to use npm. For example, after adding the CoffeeScript folder to your path: require('coffee-script/lexer')
  • There's a new "link" feature in Try CoffeeScript on this webpage. Use it to get a shareable permalink for your example script.
  • The coffee --watch feature now only works on Node.js 0.6.0 and higher, but now also works properly on Windows.
  • Lots of small bug fixes from @michaelficarra, @geraldalewis, @satyr, and @trevorburnham.

1.1.2 August 4, 2011 Fixes for block comment formatting, ?= compilation, implicit calls against control structures, implicit invocation of a try/catch block, variadic arguments leaking from local scope, line numbers in syntax errors following heregexes, property access on parenthesized number literals, bound class methods and super with reserved names, a REPL overhaul, consecutive compiled semicolons, block comments in implicitly called objects, and a Chrome bug.

1.1.1 May 10, 2011 Bugfix release for classes with external constructor functions, see issue #1182.

1.1.0 May 1, 2011 When running via the coffee executable, process.argv and friends now report coffee instead of node. Better compatibility with Node.js 0.4.x module lookup changes. The output in the REPL is now colorized, like Node's is. Giving your concatenated CoffeeScripts a name when using --join is now mandatory. Fix for lexing compound division /= as a regex accidentally. All text/coffeescript tags should now execute in the order they're included. Fixed an issue with extended subclasses using external constructor functions. Fixed an edge-case infinite loop in addImplicitParentheses. Fixed exponential slowdown with long chains of function calls. Globals no longer leak into the CoffeeScript REPL. Splatted parameters are declared local to the function.

1.0.1 Jan 31, 2011 Fixed a lexer bug with Unicode identifiers. Updated REPL for compatibility with Node.js 0.3.7. Fixed requiring relative paths in the REPL. Trailing return and return undefined are now optimized away. Stopped requiring the core Node.js "util" module for back-compatibility with Node.js 0.2.5. Fixed a case where a conditional return would cause fallthrough in a switch statement. Optimized empty objects in destructuring assignment.

1.0.0 Dec 24, 2010 CoffeeScript loops no longer try to preserve block scope when functions are being generated within the loop body. Instead, you can use the do keyword to create a convenient closure wrapper. Added a --nodejs flag for passing through options directly to the node executable. Better behavior around the use of pure statements within expressions. Fixed inclusive slicing through -1, for all browsers, and splicing with arbitrary expressions as endpoints.

0.9.6 Dec 6, 2010 The REPL now properly formats stacktraces, and stays alive through asynchronous exceptions. Using --watch now prints timestamps as files are compiled. Fixed some accidentally-leaking variables within plucked closure-loops. Constructors now maintain their declaration location within a class body. Dynamic object keys were removed. Nested classes are now supported. Fixes execution context for naked splatted functions. Bugfix for inversion of chained comparisons. Chained class instantiation now works properly with splats.

0.9.5 Nov 21, 2010 0.9.5 should be considered the first release candidate for CoffeeScript 1.0. There have been a large number of internal changes since the previous release, many contributed from satyr's Coco dialect of CoffeeScript. Heregexes (extended regexes) were added. Functions can now have default arguments. Class bodies are now executable code. Improved syntax errors for invalid CoffeeScript. undefined now works like null, and cannot be assigned a new value. There was a precedence change with respect to single-line comprehensions: result = i for i in list
used to parse as result = (i for i in list) by default ... it now parses as
(result = i) for i in list.

0.9.4 Sep 21, 2010 CoffeeScript now uses appropriately-named temporary variables, and recycles their references after use. Added require.extensions support for Node.js 0.3. Loading CoffeeScript in the browser now adds just a single CoffeeScript object to global scope. Fixes for implicit object and block comment edge cases.

0.9.3 Sep 16, 2010 CoffeeScript switch statements now compile into JS switch statements — they previously compiled into if/else chains for JavaScript 1.3 compatibility. Soaking a function invocation is now supported. Users of the RubyMine editor should now be able to use --watch mode.

0.9.2 Aug 23, 2010 Specifying the start and end of a range literal is now optional, eg. array[3..]. You can now say a not instanceof b. Fixed important bugs with nested significant and non-significant indentation (Issue #637). Added a --require flag that allows you to hook into the coffee command. Added a custom jsl.conf file for our preferred JavaScriptLint setup. Sped up Jison grammar compilation time by flattening rules for operations. Block comments can now be used with JavaScript-minifier-friendly syntax. Added JavaScript's compound assignment bitwise operators. Bugfixes to implicit object literals with leading number and string keys, as the subject of implicit calls, and as part of compound assignment.

0.9.1 Aug 11, 2010 Bugfix release for 0.9.1. Greatly improves the handling of mixed implicit objects, implicit function calls, and implicit indentation. String and regex interpolation is now strictly #{ ... } (Ruby style). The compiler now takes a --require flag, which specifies scripts to run before compilation.

0.9.0 Aug 4, 2010 The CoffeeScript 0.9 series is considered to be a release candidate for 1.0; let's give her a shakedown cruise. 0.9.0 introduces a massive backwards-incompatible change: Assignment now uses =, and object literals use :, as in JavaScript. This allows us to have implicit object literals, and YAML-style object definitions. Half assignments are removed, in favor of +=, or=, and friends. Interpolation now uses a hash mark # instead of the dollar sign $ — because dollar signs may be part of a valid JS identifier. Downwards range comprehensions are now safe again, and are optimized to straight for loops when created with integer endpoints. A fast, unguarded form of object comprehension was added: for all key, value of object. Mentioning the super keyword with no arguments now forwards all arguments passed to the function, as in Ruby. If you extend class B from parent class A, if A has an extended method defined, it will be called, passing in B — this enables static inheritance, among other things. Cleaner output for functions bound with the fat arrow. @variables can now be used in parameter lists, with the parameter being automatically set as a property on the object — useful in constructors and setter functions. Constructor functions can now take splats.

0.7.2 Jul 12, 2010 Quick bugfix (right after 0.7.1) for a problem that prevented coffee command-line options from being parsed in some circumstances.

0.7.1 Jul 11, 2010 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.

0.7.0 Jun 28, 2010 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 by -1 if you'd like to iterate downward. Reporting of syntax errors is greatly improved from the previous release. Running coffee with no arguments now launches the REPL, with Readline support. The <- bind operator has been removed from CoffeeScript. The loop keyword was added, which is equivalent to a while true loop. Comprehensions that contain closures will now close over their variables, like the semantics of a forEach. You can now use bound function in class definitions (bound to the instance). For consistency, a in b is now an array presence check, and a of b is an object-key check. Comments are no longer passed through to the generated JavaScript.

0.6.2 May 15, 2010 The coffee 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: {name, length}: func. Pattern matching is now allowed within comprehension variables. unless is now allowed in block form. until loops were added, as the inverse of while loops. switch statements are now allowed without switch object clauses. Compatible with Node.js v0.1.95.

0.6.1 Apr 12, 2010 Upgraded CoffeeScript for compatibility with the new Node.js v0.1.90 series.

0.6.0 Apr 3, 2010 Trailing commas are now allowed, a-la Python. Static properties may be assigned directly within class definitions, using @property notation.

0.5.6 Mar 23, 2010 Interpolation can now be used within regular expressions and heredocs, as well as strings. Added the <- bind operator. Allowing assignment to half-expressions instead of special ||=-style operators. The arguments object is no longer automatically converted into an array. After requiring coffee-script, Node.js can now directly load .coffee files, thanks to registerExtension. Multiple splats can now be used in function calls, arrays, and pattern matching.

0.5.5 Mar 8, 2010 String interpolation, contributed by Stan Angeloff. Since --run has been the default since 0.5.3, updating --stdio and --eval to run by default, pass --compile as well if you'd like to print the result.

0.5.4 Mar 3, 2010 Bugfix that corrects the Node.js global constants __filename and __dirname. Tweaks for more flexible parsing of nested function literals and improperly-indented comments. Updates for the latest Node.js API.

0.5.3 Feb 27, 2010 CoffeeScript now has a syntax for defining classes. Many of the core components (Nodes, Lexer, Rewriter, Scope, Optparse) are using them. Cakefiles can use optparse.coffee to define options for tasks. --run is now the default flag for the coffee command, use --compile to save JavaScripts. Bugfix for an ambiguity between RegExp literals and chained divisions.

0.5.2 Feb 25, 2010 Added a compressed version of the compiler for inclusion in web pages as
extras/coffee-script.js. It'll automatically run any script tags with type text/coffeescript for you. Added a --stdio option to the coffee command, for piped-in compiles.

0.5.1 Feb 24, 2010 Improvements to null soaking with the existential operator, including soaks on indexed properties. Added conditions to while loops, so you can use them as filters with when, in the same manner as comprehensions.

0.5.0 Feb 21, 2010 CoffeeScript 0.5.0 is a major release, While there are no language changes, the Ruby compiler has been removed in favor of a self-hosting compiler written in pure CoffeeScript.

0.3.2 Feb 8, 2010 @property is now a shorthand for this.property.
Switched the default JavaScript engine from Narwhal to Node.js. Pass the --narwhal flag if you'd like to continue using it.

0.3.0 Jan 26, 2010 CoffeeScript 0.3 includes major syntax changes:
The function symbol was changed to ->, and the bound function symbol is now =>.
Parameter lists in function definitions must now be wrapped in parentheses.
Added property soaking, with the ?. operator.
Made parentheses optional, when invoking functions with arguments.
Removed the obsolete block literal syntax.

0.2.6 Jan 17, 2010 Added Python-style chained comparisons, the conditional existence operator ?=, and some examples from Beautiful Code. Bugfixes relating to statement-to-expression conversion, arguments-to-array conversion, and the TextMate syntax highlighter.

0.2.5 Jan 13, 2010 The conditions in switch statements can now take multiple values at once — If any of them are true, the case will run. Added the long arrow ==>, which defines and immediately binds a function to this. While loops can now be used as expressions, in the same way that comprehensions can. Splats can be used within pattern matches to soak up the rest of an array.

0.2.4 Jan 12, 2010 Added ECMAScript Harmony style destructuring assignment, for dealing with extracting values from nested arrays and objects. Added indentation-sensitive heredocs for nicely formatted strings or chunks of code.

0.2.3 Jan 11, 2010 Axed the unsatisfactory ino keyword, replacing it with of for object comprehensions. They now look like: for prop, value of object.

0.2.2 Jan 10, 2010 When performing a comprehension over an object, use ino, instead of in, which helps us generate smaller, more efficient code at compile time.
Added :: as a shorthand for saying .prototype.
The "splat" symbol has been changed from a prefix asterisk *, to a postfix ellipsis ...
Added JavaScript's in operator, empty return statements, and empty while loops.
Constructor functions that start with capital letters now include a safety check to make sure that the new instance of the object is returned.
The extends keyword now functions identically to goog.inherits in Google's Closure Library.

0.2.1 Jan 5, 2010 Arguments objects are now converted into real arrays when referenced.

0.2.0 Jan 5, 2010 Major release. Significant whitespace. Better statement-to-expression conversion. Splats. Splice literals. Object comprehensions. Blocks. The existential operator. Many thanks to all the folks who posted issues, with special thanks to Liam O'Connor-Davis for whitespace and expression help.

0.1.6 Dec 27, 2009 Bugfix for running coffee --interactive and --run from outside of the CoffeeScript directory. Bugfix for nested function/if-statements.

0.1.5 Dec 26, 2009 Array slice literals and array comprehensions can now both take Ruby-style ranges to specify the start and end. JavaScript variable declaration is now pushed up to the top of the scope, making all assignment statements into expressions. You can use \ to escape newlines. The coffee-script command is now called coffee.

0.1.4 Dec 25, 2009 The official CoffeeScript extension is now .coffee instead of .cs, which properly belongs to C#. Due to popular demand, you can now also use = to assign. Unlike JavaScript, = can also be used within object literals, interchangeably with :. Made a grammatical fix for chained function calls like func(1)(2)(3)(4). Inheritance and super no longer use __proto__, so they should be IE-compatible now.

0.1.3 Dec 25, 2009 The coffee command now includes --interactive, which launches an interactive CoffeeScript session, and --run, which directly compiles and executes a script. Both options depend on a working installation of Narwhal. The aint keyword has been replaced by isnt, which goes together a little smoother with is. Quoted strings are now allowed as identifiers within object literals: eg. {"5+5": 10}. All assignment operators now use a colon: +:, -:, *:, etc.

0.1.2 Dec 24, 2009 Fixed a bug with calling super() through more than one level of inheritance, with the re-addition of the extends keyword. Added experimental Narwhal support (as a Tusk package), contributed by Tom Robinson, including bin/cs as a CoffeeScript REPL and interpreter. New --no-wrap option to suppress the safety function wrapper.

0.1.1 Dec 24, 2009 Added instanceof and typeof as operators.

0.1.0 Dec 24, 2009 Initial CoffeeScript release.

coffee-script-1.4.0/documentation/js/000077500000000000000000000000001204160075300175305ustar00rootroot00000000000000coffee-script-1.4.0/documentation/js/aliases.js000066400000000000000000000005361204160075300215130ustar00rootroot00000000000000// Generated by CoffeeScript 1.4.0 var volume, winner; if (ignition === true) { launch(); } if (band !== SpinalTap) { volume = 10; } if (answer !== false) { letTheWildRumpusBegin(); } if (car.speed < limit) { accelerate(); } if (pick === 47 || pick === 92 || pick === 13) { winner = true; } print(inspect("My name is " + this.name)); coffee-script-1.4.0/documentation/js/array_comprehensions.js000066400000000000000000000011011204160075300243110ustar00rootroot00000000000000// Generated by CoffeeScript 1.4.0 var courses, dish, food, foods, i, _i, _j, _k, _len, _len1, _len2, _ref; _ref = ['toast', 'cheese', 'wine']; for (_i = 0, _len = _ref.length; _i < _len; _i++) { food = _ref[_i]; eat(food); } courses = ['greens', 'caviar', 'truffles', 'roast', 'cake']; for (i = _j = 0, _len1 = courses.length; _j < _len1; i = ++_j) { dish = courses[i]; menu(i + 1, dish); } foods = ['broccoli', 'spinach', 'chocolate']; for (_k = 0, _len2 = foods.length; _k < _len2; _k++) { food = foods[_k]; if (food !== 'chocolate') { eat(food); } } coffee-script-1.4.0/documentation/js/block_comment.js000066400000000000000000000001471204160075300227040ustar00rootroot00000000000000// Generated by CoffeeScript 1.4.0 /* CoffeeScript Compiler v1.4.0 Released under the MIT License */ coffee-script-1.4.0/documentation/js/cake_tasks.js000066400000000000000000000005731204160075300222030ustar00rootroot00000000000000// Generated by CoffeeScript 1.4.0 var fs; fs = require('fs'); option('-o', '--output [DIR]', 'directory for compiled code'); task('build:parser', 'rebuild the Jison parser', function(options) { var code, dir; require('jison'); code = require('./lib/grammar').parser.generate(); dir = options.output || 'lib'; return fs.writeFile("" + dir + "/parser.js", code); }); coffee-script-1.4.0/documentation/js/classes.js000066400000000000000000000024271204160075300215300ustar00rootroot00000000000000// Generated by CoffeeScript 1.4.0 var Animal, Horse, Snake, sam, tom, __hasProp = {}.hasOwnProperty, __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }; Animal = (function() { function Animal(name) { this.name = name; } Animal.prototype.move = function(meters) { return alert(this.name + (" moved " + meters + "m.")); }; return Animal; })(); Snake = (function(_super) { __extends(Snake, _super); function Snake() { return Snake.__super__.constructor.apply(this, arguments); } Snake.prototype.move = function() { alert("Slithering..."); return Snake.__super__.move.call(this, 5); }; return Snake; })(Animal); Horse = (function(_super) { __extends(Horse, _super); function Horse() { return Horse.__super__.constructor.apply(this, arguments); } Horse.prototype.move = function() { alert("Galloping..."); return Horse.__super__.move.call(this, 45); }; return Horse; })(Animal); sam = new Snake("Sammy the Python"); tom = new Horse("Tommy the Palomino"); sam.move(); tom.move(); coffee-script-1.4.0/documentation/js/comparisons.js000066400000000000000000000002051204160075300224200ustar00rootroot00000000000000// Generated by CoffeeScript 1.4.0 var cholesterol, healthy; cholesterol = 127; healthy = (200 > cholesterol && cholesterol > 60); coffee-script-1.4.0/documentation/js/conditionals.js000066400000000000000000000003131204160075300225510ustar00rootroot00000000000000// Generated by CoffeeScript 1.4.0 var date, mood; if (singing) { mood = greatlyImproved; } if (happy && knowsIt) { clapsHands(); chaChaCha(); } else { showIt(); } date = friday ? sue : jill; coffee-script-1.4.0/documentation/js/default_args.js000066400000000000000000000003121204160075300225220ustar00rootroot00000000000000// Generated by CoffeeScript 1.4.0 var fill; fill = function(container, liquid) { if (liquid == null) { liquid = "coffee"; } return "Filling the " + container + " with " + liquid + "..."; }; coffee-script-1.4.0/documentation/js/do.js000066400000000000000000000004571204160075300204760ustar00rootroot00000000000000// Generated by CoffeeScript 1.4.0 var filename, _fn, _i, _len; _fn = function(filename) { return fs.readFile(filename, function(err, contents) { return compile(filename, contents.toString()); }); }; for (_i = 0, _len = list.length; _i < _len; _i++) { filename = list[_i]; _fn(filename); } coffee-script-1.4.0/documentation/js/embedded.js000066400000000000000000000001731204160075300216200ustar00rootroot00000000000000// Generated by CoffeeScript 1.4.0 var hi; hi = function() { return [document.title, "Hello JavaScript"].join(": "); }; coffee-script-1.4.0/documentation/js/existence.js000066400000000000000000000005051204160075300220550ustar00rootroot00000000000000// Generated by CoffeeScript 1.4.0 var footprints, solipsism, speed; if ((typeof mind !== "undefined" && mind !== null) && !(typeof world !== "undefined" && world !== null)) { solipsism = true; } speed = 0; if (speed == null) { speed = 15; } footprints = typeof yeti !== "undefined" && yeti !== null ? yeti : "bear"; coffee-script-1.4.0/documentation/js/expressions.js000066400000000000000000000004771204160075300224600ustar00rootroot00000000000000// Generated by CoffeeScript 1.4.0 var eldest, grade; grade = function(student) { if (student.excellentWork) { return "A+"; } else if (student.okayStuff) { if (student.triedHard) { return "B"; } else { return "B-"; } } else { return "C"; } }; eldest = 24 > 21 ? "Liz" : "Ike"; coffee-script-1.4.0/documentation/js/expressions_assignment.js000066400000000000000000000001511204160075300246750ustar00rootroot00000000000000// Generated by CoffeeScript 1.4.0 var one, six, three, two; six = (one = 1) + (two = 2) + (three = 3); coffee-script-1.4.0/documentation/js/expressions_comprehension.js000066400000000000000000000003161204160075300254010ustar00rootroot00000000000000// Generated by CoffeeScript 1.4.0 var globals, name; globals = ((function() { var _results; _results = []; for (name in window) { _results.push(name); } return _results; })()).slice(0, 10); coffee-script-1.4.0/documentation/js/expressions_try.js000066400000000000000000000002541204160075300233470ustar00rootroot00000000000000// Generated by CoffeeScript 1.4.0 alert((function() { try { return nonexistent / void 0; } catch (error) { return "And the error is ... " + error; } })()); coffee-script-1.4.0/documentation/js/fat_arrow.js000066400000000000000000000004201204160075300220460ustar00rootroot00000000000000// Generated by CoffeeScript 1.4.0 var Account; Account = function(customer, cart) { var _this = this; this.customer = customer; this.cart = cart; return $('.shopping_cart').bind('click', function(event) { return _this.customer.purchase(_this.cart); }); }; coffee-script-1.4.0/documentation/js/functions.js000066400000000000000000000002211204160075300220710ustar00rootroot00000000000000// Generated by CoffeeScript 1.4.0 var cube, square; square = function(x) { return x * x; }; cube = function(x) { return square(x) * x; }; coffee-script-1.4.0/documentation/js/heredocs.js000066400000000000000000000001431204160075300216600ustar00rootroot00000000000000// Generated by CoffeeScript 1.4.0 var html; html = "\n cup of coffeescript\n"; coffee-script-1.4.0/documentation/js/heregexes.js000066400000000000000000000002071204160075300220440ustar00rootroot00000000000000// Generated by CoffeeScript 1.4.0 var OPERATOR; OPERATOR = /^(?:[-=]>|[-+*\/%<>&|^!?=]=|>>>=?|([-+:])\1|([&|<>])\2=?|\?\.|\.{2,3})/; coffee-script-1.4.0/documentation/js/interpolation.js000066400000000000000000000003101204160075300227470ustar00rootroot00000000000000// Generated by CoffeeScript 1.4.0 var author, quote, sentence; author = "Wittgenstein"; quote = "A picture is a fact. -- " + author; sentence = "" + (22 / 7) + " is a decent approximation of π"; coffee-script-1.4.0/documentation/js/multiple_return_values.js000066400000000000000000000003771204160075300247060ustar00rootroot00000000000000// Generated by CoffeeScript 1.4.0 var city, forecast, temp, weatherReport, _ref; weatherReport = function(location) { return [location, 72, "Mostly Sunny"]; }; _ref = weatherReport("Berkeley, CA"), city = _ref[0], temp = _ref[1], forecast = _ref[2]; coffee-script-1.4.0/documentation/js/object_comprehensions.js000066400000000000000000000004541204160075300244530ustar00rootroot00000000000000// Generated by CoffeeScript 1.4.0 var age, ages, child, yearsOld; yearsOld = { max: 10, ida: 9, tim: 11 }; ages = (function() { var _results; _results = []; for (child in yearsOld) { age = yearsOld[child]; _results.push("" + child + " is " + age); } return _results; })(); coffee-script-1.4.0/documentation/js/object_extraction.js000066400000000000000000000005531204160075300235770ustar00rootroot00000000000000// Generated by CoffeeScript 1.4.0 var city, futurists, name, street, _ref, _ref1; futurists = { sculptor: "Umberto Boccioni", painter: "Vladimir Burliuk", poet: { name: "F.T. Marinetti", address: ["Via Roma 42R", "Bellagio, Italy 22021"] } }; _ref = futurists.poet, name = _ref.name, (_ref1 = _ref.address, street = _ref1[0], city = _ref1[1]); coffee-script-1.4.0/documentation/js/objects_and_arrays.js000066400000000000000000000004571204160075300237300ustar00rootroot00000000000000// Generated by CoffeeScript 1.4.0 var bitlist, kids, singers, song; song = ["do", "re", "mi", "fa", "so"]; singers = { Jagger: "Rock", Elvis: "Roll" }; bitlist = [1, 0, 1, 0, 0, 1, 1, 1, 0]; kids = { brother: { name: "Max", age: 11 }, sister: { name: "Ida", age: 9 } }; coffee-script-1.4.0/documentation/js/objects_reserved.js000066400000000000000000000001501204160075300234120ustar00rootroot00000000000000// Generated by CoffeeScript 1.4.0 $('.account').attr({ "class": 'active' }); log(object["class"]); coffee-script-1.4.0/documentation/js/overview.js000066400000000000000000000014521204160075300217360ustar00rootroot00000000000000// Generated by CoffeeScript 1.4.0 var cubes, list, math, num, number, opposite, race, square, __slice = [].slice; number = 42; opposite = true; if (opposite) { number = -42; } square = function(x) { return x * x; }; list = [1, 2, 3, 4, 5]; math = { root: Math.sqrt, square: square, cube: function(x) { return x * square(x); } }; race = function() { var runners, winner; winner = arguments[0], runners = 2 <= arguments.length ? __slice.call(arguments, 1) : []; return print(winner, runners); }; if (typeof elvis !== "undefined" && elvis !== null) { alert("I knew it!"); } cubes = (function() { var _i, _len, _results; _results = []; for (_i = 0, _len = list.length; _i < _len; _i++) { num = list[_i]; _results.push(math.cube(num)); } return _results; })(); coffee-script-1.4.0/documentation/js/parallel_assignment.js000066400000000000000000000002501204160075300241070ustar00rootroot00000000000000// Generated by CoffeeScript 1.4.0 var theBait, theSwitch, _ref; theBait = 1000; theSwitch = 0; _ref = [theSwitch, theBait], theBait = _ref[0], theSwitch = _ref[1]; coffee-script-1.4.0/documentation/js/patterns_and_splats.js000066400000000000000000000004171204160075300241400ustar00rootroot00000000000000// Generated by CoffeeScript 1.4.0 var close, contents, open, tag, _i, _ref, __slice = [].slice; tag = ""; _ref = tag.split(""), open = _ref[0], contents = 3 <= _ref.length ? __slice.call(_ref, 1, _i = _ref.length - 1) : (_i = 1, []), close = _ref[_i++]; coffee-script-1.4.0/documentation/js/prototypes.js000066400000000000000000000001631204160075300223160ustar00rootroot00000000000000// Generated by CoffeeScript 1.4.0 String.prototype.dasherize = function() { return this.replace(/_/g, "-"); }; coffee-script-1.4.0/documentation/js/range_comprehensions.js000066400000000000000000000003311204160075300242730ustar00rootroot00000000000000// Generated by CoffeeScript 1.4.0 var countdown, num; countdown = (function() { var _i, _results; _results = []; for (num = _i = 10; _i >= 1; num = --_i) { _results.push(num); } return _results; })(); coffee-script-1.4.0/documentation/js/scope.js000066400000000000000000000002731204160075300212010ustar00rootroot00000000000000// Generated by CoffeeScript 1.4.0 var changeNumbers, inner, outer; outer = 1; changeNumbers = function() { var inner; inner = -1; return outer = 10; }; inner = changeNumbers(); coffee-script-1.4.0/documentation/js/slices.js000066400000000000000000000003421204160075300213470ustar00rootroot00000000000000// Generated by CoffeeScript 1.4.0 var copy, end, middle, numbers, start; numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9]; start = numbers.slice(0, 3); middle = numbers.slice(3, 6); end = numbers.slice(6); copy = numbers.slice(0); coffee-script-1.4.0/documentation/js/soaks.js000066400000000000000000000002641204160075300212100ustar00rootroot00000000000000// Generated by CoffeeScript 1.4.0 var zip, _ref; zip = typeof lottery.drawWinner === "function" ? (_ref = lottery.drawWinner().address) != null ? _ref.zipcode : void 0 : void 0; coffee-script-1.4.0/documentation/js/splats.js000066400000000000000000000012271204160075300213760ustar00rootroot00000000000000// Generated by CoffeeScript 1.4.0 var awardMedals, contenders, gold, rest, silver, __slice = [].slice; gold = silver = rest = "unknown"; awardMedals = function() { var first, others, second; first = arguments[0], second = arguments[1], others = 3 <= arguments.length ? __slice.call(arguments, 2) : []; gold = first; silver = second; return rest = others; }; contenders = ["Michael Phelps", "Liu Xiang", "Yao Ming", "Allyson Felix", "Shawn Johnson", "Roman Sebrle", "Guo Jingjing", "Tyson Gay", "Asafa Powell", "Usain Bolt"]; awardMedals.apply(null, contenders); alert("Gold: " + gold); alert("Silver: " + silver); alert("The Field: " + rest); coffee-script-1.4.0/documentation/js/splices.js000066400000000000000000000002521204160075300215270ustar00rootroot00000000000000// Generated by CoffeeScript 1.4.0 var numbers, _ref; numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; [].splice.apply(numbers, [3, 4].concat(_ref = [-3, -4, -5, -6])), _ref; coffee-script-1.4.0/documentation/js/strings.js000066400000000000000000000004511204160075300215570ustar00rootroot00000000000000// Generated by CoffeeScript 1.4.0 var mobyDick; mobyDick = "Call me Ishmael. Some years ago -- never mind how long precisely -- having little or no money in my purse, and nothing particular to interest me on shore, I thought I would sail about a little and see the watery part of the world..."; coffee-script-1.4.0/documentation/js/switch.js000066400000000000000000000005401204160075300213660ustar00rootroot00000000000000// Generated by CoffeeScript 1.4.0 switch (day) { case "Mon": go(work); break; case "Tue": go(relax); break; case "Thu": go(iceFishing); break; case "Fri": case "Sat": if (day === bingoDay) { go(bingo); go(dancing); } break; case "Sun": go(church); break; default: go(work); } coffee-script-1.4.0/documentation/js/try.js000066400000000000000000000002361204160075300207050ustar00rootroot00000000000000// Generated by CoffeeScript 1.4.0 try { allHellBreaksLoose(); catsAndDogsLivingTogether(); } catch (error) { print(error); } finally { cleanUp(); } coffee-script-1.4.0/documentation/js/while.js000066400000000000000000000006171204160075300212020ustar00rootroot00000000000000// Generated by CoffeeScript 1.4.0 var lyrics, num; if (this.studyingEconomics) { while (supply > demand) { buy(); } while (!(supply > demand)) { sell(); } } num = 6; lyrics = (function() { var _results; _results = []; while (num -= 1) { _results.push("" + num + " little monkeys, jumping on the bed. One fell out and bumped his head."); } return _results; })(); coffee-script-1.4.0/documentation/vendor/000077500000000000000000000000001204160075300204115ustar00rootroot00000000000000coffee-script-1.4.0/documentation/vendor/jquery-1.6.4.js000066400000000000000000007211171204160075300227430ustar00rootroot00000000000000/*! * jQuery JavaScript Library v1.6.4 * http://jquery.com/ * * Copyright 2011, John Resig * Dual licensed under the MIT or GPL Version 2 licenses. * http://jquery.org/license * * Includes Sizzle.js * http://sizzlejs.com/ * Copyright 2011, The Dojo Foundation * Released under the MIT, BSD, and GPL Licenses. * * Date: Mon Sep 12 18:54:48 2011 -0400 */ (function( window, undefined ) { // Use the correct document accordingly with window argument (sandbox) var document = window.document, navigator = window.navigator, location = window.location; var jQuery = (function() { // Define a local copy of jQuery var jQuery = function( selector, context ) { // The jQuery object is actually just the init constructor 'enhanced' return new jQuery.fn.init( selector, context, rootjQuery ); }, // Map over jQuery in case of overwrite _jQuery = window.jQuery, // Map over the $ in case of overwrite _$ = window.$, // A central reference to the root jQuery(document) rootjQuery, // A simple way to check for HTML strings or ID strings // Prioritize #id over to avoid XSS via location.hash (#9521) quickExpr = /^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/, // Check if a string has a non-whitespace character in it rnotwhite = /\S/, // Used for trimming whitespace trimLeft = /^\s+/, trimRight = /\s+$/, // Check for digits rdigit = /\d/, // Match a standalone tag rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>)?$/, // JSON RegExp rvalidchars = /^[\],:{}\s]*$/, rvalidescape = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, rvalidtokens = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g, // Useragent RegExp rwebkit = /(webkit)[ \/]([\w.]+)/, ropera = /(opera)(?:.*version)?[ \/]([\w.]+)/, rmsie = /(msie) ([\w.]+)/, rmozilla = /(mozilla)(?:.*? rv:([\w.]+))?/, // Matches dashed string for camelizing rdashAlpha = /-([a-z]|[0-9])/ig, rmsPrefix = /^-ms-/, // Used by jQuery.camelCase as callback to replace() fcamelCase = function( all, letter ) { return ( letter + "" ).toUpperCase(); }, // Keep a UserAgent string for use with jQuery.browser userAgent = navigator.userAgent, // For matching the engine and version of the browser browserMatch, // The deferred used on DOM ready readyList, // The ready event handler DOMContentLoaded, // Save a reference to some core methods toString = Object.prototype.toString, hasOwn = Object.prototype.hasOwnProperty, push = Array.prototype.push, slice = Array.prototype.slice, trim = String.prototype.trim, indexOf = Array.prototype.indexOf, // [[Class]] -> type pairs class2type = {}; jQuery.fn = jQuery.prototype = { constructor: jQuery, init: function( selector, context, rootjQuery ) { var match, elem, ret, doc; // Handle $(""), $(null), or $(undefined) if ( !selector ) { return this; } // Handle $(DOMElement) if ( selector.nodeType ) { this.context = this[0] = selector; this.length = 1; return this; } // The body element only exists once, optimize finding it if ( selector === "body" && !context && document.body ) { this.context = document; this[0] = document.body; this.selector = selector; this.length = 1; return this; } // Handle HTML strings if ( typeof selector === "string" ) { // Are we dealing with HTML string or an ID? if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) { // Assume that strings that start and end with <> are HTML and skip the regex check match = [ null, selector, null ]; } else { match = quickExpr.exec( selector ); } // Verify a match, and that no context was specified for #id if ( match && (match[1] || !context) ) { // HANDLE: $(html) -> $(array) if ( match[1] ) { context = context instanceof jQuery ? context[0] : context; doc = (context ? context.ownerDocument || context : document); // If a single string is passed in and it's a single tag // just do a createElement and skip the rest ret = rsingleTag.exec( selector ); if ( ret ) { if ( jQuery.isPlainObject( context ) ) { selector = [ document.createElement( ret[1] ) ]; jQuery.fn.attr.call( selector, context, true ); } else { selector = [ doc.createElement( ret[1] ) ]; } } else { ret = jQuery.buildFragment( [ match[1] ], [ doc ] ); selector = (ret.cacheable ? jQuery.clone(ret.fragment) : ret.fragment).childNodes; } return jQuery.merge( this, selector ); // HANDLE: $("#id") } else { elem = document.getElementById( match[2] ); // Check parentNode to catch when Blackberry 4.6 returns // nodes that are no longer in the document #6963 if ( elem && elem.parentNode ) { // Handle the case where IE and Opera return items // by name instead of ID if ( elem.id !== match[2] ) { return rootjQuery.find( selector ); } // Otherwise, we inject the element directly into the jQuery object this.length = 1; this[0] = elem; } this.context = document; this.selector = selector; return this; } // HANDLE: $(expr, $(...)) } else if ( !context || context.jquery ) { return (context || rootjQuery).find( selector ); // HANDLE: $(expr, context) // (which is just equivalent to: $(context).find(expr) } else { return this.constructor( context ).find( selector ); } // HANDLE: $(function) // Shortcut for document ready } else if ( jQuery.isFunction( selector ) ) { return rootjQuery.ready( selector ); } if (selector.selector !== undefined) { this.selector = selector.selector; this.context = selector.context; } return jQuery.makeArray( selector, this ); }, // Start with an empty selector selector: "", // The current version of jQuery being used jquery: "1.6.4", // The default length of a jQuery object is 0 length: 0, // The number of elements contained in the matched element set size: function() { return this.length; }, toArray: function() { return slice.call( this, 0 ); }, // Get the Nth element in the matched element set OR // Get the whole matched element set as a clean array get: function( num ) { return num == null ? // Return a 'clean' array this.toArray() : // Return just the object ( num < 0 ? this[ this.length + num ] : this[ num ] ); }, // Take an array of elements and push it onto the stack // (returning the new matched element set) pushStack: function( elems, name, selector ) { // Build a new jQuery matched element set var ret = this.constructor(); if ( jQuery.isArray( elems ) ) { push.apply( ret, elems ); } else { jQuery.merge( ret, elems ); } // Add the old object onto the stack (as a reference) ret.prevObject = this; ret.context = this.context; if ( name === "find" ) { ret.selector = this.selector + (this.selector ? " " : "") + selector; } else if ( name ) { ret.selector = this.selector + "." + name + "(" + selector + ")"; } // Return the newly-formed element set return ret; }, // Execute a callback for every element in the matched set. // (You can seed the arguments with an array of args, but this is // only used internally.) each: function( callback, args ) { return jQuery.each( this, callback, args ); }, ready: function( fn ) { // Attach the listeners jQuery.bindReady(); // Add the callback readyList.done( fn ); return this; }, eq: function( i ) { return i === -1 ? this.slice( i ) : this.slice( i, +i + 1 ); }, first: function() { return this.eq( 0 ); }, last: function() { return this.eq( -1 ); }, slice: function() { return this.pushStack( slice.apply( this, arguments ), "slice", slice.call(arguments).join(",") ); }, map: function( callback ) { return this.pushStack( jQuery.map(this, function( elem, i ) { return callback.call( elem, i, elem ); })); }, end: function() { return this.prevObject || this.constructor(null); }, // For internal use only. // Behaves like an Array's method, not like a jQuery method. push: push, sort: [].sort, splice: [].splice }; // Give the init function the jQuery prototype for later instantiation jQuery.fn.init.prototype = jQuery.fn; jQuery.extend = jQuery.fn.extend = function() { var options, name, src, copy, copyIsArray, clone, target = arguments[0] || {}, i = 1, length = arguments.length, deep = false; // Handle a deep copy situation if ( typeof target === "boolean" ) { deep = target; target = arguments[1] || {}; // skip the boolean and the target i = 2; } // Handle case when target is a string or something (possible in deep copy) if ( typeof target !== "object" && !jQuery.isFunction(target) ) { target = {}; } // extend jQuery itself if only one argument is passed if ( length === i ) { target = this; --i; } for ( ; i < length; i++ ) { // Only deal with non-null/undefined values if ( (options = arguments[ i ]) != null ) { // Extend the base object for ( name in options ) { src = target[ name ]; copy = options[ name ]; // Prevent never-ending loop if ( target === copy ) { continue; } // Recurse if we're merging plain objects or arrays if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) { if ( copyIsArray ) { copyIsArray = false; clone = src && jQuery.isArray(src) ? src : []; } else { clone = src && jQuery.isPlainObject(src) ? src : {}; } // Never move original objects, clone them target[ name ] = jQuery.extend( deep, clone, copy ); // Don't bring in undefined values } else if ( copy !== undefined ) { target[ name ] = copy; } } } } // Return the modified object return target; }; jQuery.extend({ noConflict: function( deep ) { if ( window.$ === jQuery ) { window.$ = _$; } if ( deep && window.jQuery === jQuery ) { window.jQuery = _jQuery; } return jQuery; }, // Is the DOM ready to be used? Set to true once it occurs. isReady: false, // A counter to track how many items to wait for before // the ready event fires. See #6781 readyWait: 1, // Hold (or release) the ready event holdReady: function( hold ) { if ( hold ) { jQuery.readyWait++; } else { jQuery.ready( true ); } }, // Handle when the DOM is ready ready: function( wait ) { // Either a released hold or an DOMready/load event and not yet ready if ( (wait === true && !--jQuery.readyWait) || (wait !== true && !jQuery.isReady) ) { // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). if ( !document.body ) { return setTimeout( jQuery.ready, 1 ); } // Remember that the DOM is ready jQuery.isReady = true; // If a normal DOM Ready event fired, decrement, and wait if need be if ( wait !== true && --jQuery.readyWait > 0 ) { return; } // If there are functions bound, to execute readyList.resolveWith( document, [ jQuery ] ); // Trigger any bound ready events if ( jQuery.fn.trigger ) { jQuery( document ).trigger( "ready" ).unbind( "ready" ); } } }, bindReady: function() { if ( readyList ) { return; } readyList = jQuery._Deferred(); // Catch cases where $(document).ready() is called after the // browser event has already occurred. if ( document.readyState === "complete" ) { // Handle it asynchronously to allow scripts the opportunity to delay ready return setTimeout( jQuery.ready, 1 ); } // Mozilla, Opera and webkit nightlies currently support this event if ( document.addEventListener ) { // Use the handy event callback document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false ); // A fallback to window.onload, that will always work window.addEventListener( "load", jQuery.ready, false ); // If IE event model is used } else if ( document.attachEvent ) { // ensure firing before onload, // maybe late but safe also for iframes document.attachEvent( "onreadystatechange", DOMContentLoaded ); // A fallback to window.onload, that will always work window.attachEvent( "onload", jQuery.ready ); // If IE and not a frame // continually check to see if the document is ready var toplevel = false; try { toplevel = window.frameElement == null; } catch(e) {} if ( document.documentElement.doScroll && toplevel ) { doScrollCheck(); } } }, // See test/unit/core.js for details concerning isFunction. // Since version 1.3, DOM methods and functions like alert // aren't supported. They return false on IE (#2968). isFunction: function( obj ) { return jQuery.type(obj) === "function"; }, isArray: Array.isArray || function( obj ) { return jQuery.type(obj) === "array"; }, // A crude way of determining if an object is a window isWindow: function( obj ) { return obj && typeof obj === "object" && "setInterval" in obj; }, isNaN: function( obj ) { return obj == null || !rdigit.test( obj ) || isNaN( obj ); }, type: function( obj ) { return obj == null ? String( obj ) : class2type[ toString.call(obj) ] || "object"; }, isPlainObject: function( obj ) { // Must be an Object. // Because of IE, we also have to check the presence of the constructor property. // Make sure that DOM nodes and window objects don't pass through, as well if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) { return false; } try { // Not own constructor property must be Object if ( obj.constructor && !hasOwn.call(obj, "constructor") && !hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) { return false; } } catch ( e ) { // IE8,9 Will throw exceptions on certain host objects #9897 return false; } // Own properties are enumerated firstly, so to speed up, // if last one is own, then all properties are own. var key; for ( key in obj ) {} return key === undefined || hasOwn.call( obj, key ); }, isEmptyObject: function( obj ) { for ( var name in obj ) { return false; } return true; }, error: function( msg ) { throw msg; }, parseJSON: function( data ) { if ( typeof data !== "string" || !data ) { return null; } // Make sure leading/trailing whitespace is removed (IE can't handle it) data = jQuery.trim( data ); // Attempt to parse using the native JSON parser first if ( window.JSON && window.JSON.parse ) { return window.JSON.parse( data ); } // Make sure the incoming data is actual JSON // Logic borrowed from http://json.org/json2.js if ( rvalidchars.test( data.replace( rvalidescape, "@" ) .replace( rvalidtokens, "]" ) .replace( rvalidbraces, "")) ) { return (new Function( "return " + data ))(); } jQuery.error( "Invalid JSON: " + data ); }, // Cross-browser xml parsing parseXML: function( data ) { var xml, tmp; try { if ( window.DOMParser ) { // Standard tmp = new DOMParser(); xml = tmp.parseFromString( data , "text/xml" ); } else { // IE xml = new ActiveXObject( "Microsoft.XMLDOM" ); xml.async = "false"; xml.loadXML( data ); } } catch( e ) { xml = undefined; } if ( !xml || !xml.documentElement || xml.getElementsByTagName( "parsererror" ).length ) { jQuery.error( "Invalid XML: " + data ); } return xml; }, noop: function() {}, // Evaluates a script in a global context // Workarounds based on findings by Jim Driscoll // http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context globalEval: function( data ) { if ( data && rnotwhite.test( data ) ) { // We use execScript on Internet Explorer // We use an anonymous function so that context is window // rather than jQuery in Firefox ( window.execScript || function( data ) { window[ "eval" ].call( window, data ); } )( data ); } }, // Convert dashed to camelCase; used by the css and data modules // Microsoft forgot to hump their vendor prefix (#9572) camelCase: function( string ) { return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); }, nodeName: function( elem, name ) { return elem.nodeName && elem.nodeName.toUpperCase() === name.toUpperCase(); }, // args is for internal usage only each: function( object, callback, args ) { var name, i = 0, length = object.length, isObj = length === undefined || jQuery.isFunction( object ); if ( args ) { if ( isObj ) { for ( name in object ) { if ( callback.apply( object[ name ], args ) === false ) { break; } } } else { for ( ; i < length; ) { if ( callback.apply( object[ i++ ], args ) === false ) { break; } } } // A special, fast, case for the most common use of each } else { if ( isObj ) { for ( name in object ) { if ( callback.call( object[ name ], name, object[ name ] ) === false ) { break; } } } else { for ( ; i < length; ) { if ( callback.call( object[ i ], i, object[ i++ ] ) === false ) { break; } } } } return object; }, // Use native String.trim function wherever possible trim: trim ? function( text ) { return text == null ? "" : trim.call( text ); } : // Otherwise use our own trimming functionality function( text ) { return text == null ? "" : text.toString().replace( trimLeft, "" ).replace( trimRight, "" ); }, // results is for internal usage only makeArray: function( array, results ) { var ret = results || []; if ( array != null ) { // The window, strings (and functions) also have 'length' // The extra typeof function check is to prevent crashes // in Safari 2 (See: #3039) // Tweaked logic slightly to handle Blackberry 4.7 RegExp issues #6930 var type = jQuery.type( array ); if ( array.length == null || type === "string" || type === "function" || type === "regexp" || jQuery.isWindow( array ) ) { push.call( ret, array ); } else { jQuery.merge( ret, array ); } } return ret; }, inArray: function( elem, array ) { if ( !array ) { return -1; } if ( indexOf ) { return indexOf.call( array, elem ); } for ( var i = 0, length = array.length; i < length; i++ ) { if ( array[ i ] === elem ) { return i; } } return -1; }, merge: function( first, second ) { var i = first.length, j = 0; if ( typeof second.length === "number" ) { for ( var l = second.length; j < l; j++ ) { first[ i++ ] = second[ j ]; } } else { while ( second[j] !== undefined ) { first[ i++ ] = second[ j++ ]; } } first.length = i; return first; }, grep: function( elems, callback, inv ) { var ret = [], retVal; inv = !!inv; // Go through the array, only saving the items // that pass the validator function for ( var i = 0, length = elems.length; i < length; i++ ) { retVal = !!callback( elems[ i ], i ); if ( inv !== retVal ) { ret.push( elems[ i ] ); } } return ret; }, // arg is for internal usage only map: function( elems, callback, arg ) { var value, key, ret = [], i = 0, length = elems.length, // jquery objects are treated as arrays isArray = elems instanceof jQuery || length !== undefined && typeof length === "number" && ( ( length > 0 && elems[ 0 ] && elems[ length -1 ] ) || length === 0 || jQuery.isArray( elems ) ) ; // Go through the array, translating each of the items to their if ( isArray ) { for ( ; i < length; i++ ) { value = callback( elems[ i ], i, arg ); if ( value != null ) { ret[ ret.length ] = value; } } // Go through every key on the object, } else { for ( key in elems ) { value = callback( elems[ key ], key, arg ); if ( value != null ) { ret[ ret.length ] = value; } } } // Flatten any nested arrays return ret.concat.apply( [], ret ); }, // A global GUID counter for objects guid: 1, // Bind a function to a context, optionally partially applying any // arguments. proxy: function( fn, context ) { if ( typeof context === "string" ) { var tmp = fn[ context ]; context = fn; fn = tmp; } // Quick check to determine if target is callable, in the spec // this throws a TypeError, but we will just return undefined. if ( !jQuery.isFunction( fn ) ) { return undefined; } // Simulated bind var args = slice.call( arguments, 2 ), proxy = function() { return fn.apply( context, args.concat( slice.call( arguments ) ) ); }; // Set the guid of unique handler to the same of original handler, so it can be removed proxy.guid = fn.guid = fn.guid || proxy.guid || jQuery.guid++; return proxy; }, // Mutifunctional method to get and set values to a collection // The value/s can optionally be executed if it's a function access: function( elems, key, value, exec, fn, pass ) { var length = elems.length; // Setting many attributes if ( typeof key === "object" ) { for ( var k in key ) { jQuery.access( elems, k, key[k], exec, fn, value ); } return elems; } // Setting one attribute if ( value !== undefined ) { // Optionally, function values get executed if exec is true exec = !pass && exec && jQuery.isFunction(value); for ( var i = 0; i < length; i++ ) { fn( elems[i], key, exec ? value.call( elems[i], i, fn( elems[i], key ) ) : value, pass ); } return elems; } // Getting an attribute return length ? fn( elems[0], key ) : undefined; }, now: function() { return (new Date()).getTime(); }, // Use of jQuery.browser is frowned upon. // More details: http://docs.jquery.com/Utilities/jQuery.browser uaMatch: function( ua ) { ua = ua.toLowerCase(); var match = rwebkit.exec( ua ) || ropera.exec( ua ) || rmsie.exec( ua ) || ua.indexOf("compatible") < 0 && rmozilla.exec( ua ) || []; return { browser: match[1] || "", version: match[2] || "0" }; }, sub: function() { function jQuerySub( selector, context ) { return new jQuerySub.fn.init( selector, context ); } jQuery.extend( true, jQuerySub, this ); jQuerySub.superclass = this; jQuerySub.fn = jQuerySub.prototype = this(); jQuerySub.fn.constructor = jQuerySub; jQuerySub.sub = this.sub; jQuerySub.fn.init = function init( selector, context ) { if ( context && context instanceof jQuery && !(context instanceof jQuerySub) ) { context = jQuerySub( context ); } return jQuery.fn.init.call( this, selector, context, rootjQuerySub ); }; jQuerySub.fn.init.prototype = jQuerySub.fn; var rootjQuerySub = jQuerySub(document); return jQuerySub; }, browser: {} }); // Populate the class2type map jQuery.each("Boolean Number String Function Array Date RegExp Object".split(" "), function(i, name) { class2type[ "[object " + name + "]" ] = name.toLowerCase(); }); browserMatch = jQuery.uaMatch( userAgent ); if ( browserMatch.browser ) { jQuery.browser[ browserMatch.browser ] = true; jQuery.browser.version = browserMatch.version; } // Deprecated, use jQuery.browser.webkit instead if ( jQuery.browser.webkit ) { jQuery.browser.safari = true; } // IE doesn't match non-breaking spaces with \s if ( rnotwhite.test( "\xA0" ) ) { trimLeft = /^[\s\xA0]+/; trimRight = /[\s\xA0]+$/; } // All jQuery objects should point back to these rootjQuery = jQuery(document); // Cleanup functions for the document ready method if ( document.addEventListener ) { DOMContentLoaded = function() { document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false ); jQuery.ready(); }; } else if ( document.attachEvent ) { DOMContentLoaded = function() { // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). if ( document.readyState === "complete" ) { document.detachEvent( "onreadystatechange", DOMContentLoaded ); jQuery.ready(); } }; } // The DOM ready check for Internet Explorer function doScrollCheck() { if ( jQuery.isReady ) { return; } try { // If IE is used, use the trick by Diego Perini // http://javascript.nwbox.com/IEContentLoaded/ document.documentElement.doScroll("left"); } catch(e) { setTimeout( doScrollCheck, 1 ); return; } // and execute any waiting functions jQuery.ready(); } return jQuery; })(); var // Promise methods promiseMethods = "done fail isResolved isRejected promise then always pipe".split( " " ), // Static reference to slice sliceDeferred = [].slice; jQuery.extend({ // Create a simple deferred (one callbacks list) _Deferred: function() { var // callbacks list callbacks = [], // stored [ context , args ] fired, // to avoid firing when already doing so firing, // flag to know if the deferred has been cancelled cancelled, // the deferred itself deferred = { // done( f1, f2, ...) done: function() { if ( !cancelled ) { var args = arguments, i, length, elem, type, _fired; if ( fired ) { _fired = fired; fired = 0; } for ( i = 0, length = args.length; i < length; i++ ) { elem = args[ i ]; type = jQuery.type( elem ); if ( type === "array" ) { deferred.done.apply( deferred, elem ); } else if ( type === "function" ) { callbacks.push( elem ); } } if ( _fired ) { deferred.resolveWith( _fired[ 0 ], _fired[ 1 ] ); } } return this; }, // resolve with given context and args resolveWith: function( context, args ) { if ( !cancelled && !fired && !firing ) { // make sure args are available (#8421) args = args || []; firing = 1; try { while( callbacks[ 0 ] ) { callbacks.shift().apply( context, args ); } } finally { fired = [ context, args ]; firing = 0; } } return this; }, // resolve with this as context and given arguments resolve: function() { deferred.resolveWith( this, arguments ); return this; }, // Has this deferred been resolved? isResolved: function() { return !!( firing || fired ); }, // Cancel cancel: function() { cancelled = 1; callbacks = []; return this; } }; return deferred; }, // Full fledged deferred (two callbacks list) Deferred: function( func ) { var deferred = jQuery._Deferred(), failDeferred = jQuery._Deferred(), promise; // Add errorDeferred methods, then and promise jQuery.extend( deferred, { then: function( doneCallbacks, failCallbacks ) { deferred.done( doneCallbacks ).fail( failCallbacks ); return this; }, always: function() { return deferred.done.apply( deferred, arguments ).fail.apply( this, arguments ); }, fail: failDeferred.done, rejectWith: failDeferred.resolveWith, reject: failDeferred.resolve, isRejected: failDeferred.isResolved, pipe: function( fnDone, fnFail ) { return jQuery.Deferred(function( newDefer ) { jQuery.each( { done: [ fnDone, "resolve" ], fail: [ fnFail, "reject" ] }, function( handler, data ) { var fn = data[ 0 ], action = data[ 1 ], returned; if ( jQuery.isFunction( fn ) ) { deferred[ handler ](function() { returned = fn.apply( this, arguments ); if ( returned && jQuery.isFunction( returned.promise ) ) { returned.promise().then( newDefer.resolve, newDefer.reject ); } else { newDefer[ action + "With" ]( this === deferred ? newDefer : this, [ returned ] ); } }); } else { deferred[ handler ]( newDefer[ action ] ); } }); }).promise(); }, // Get a promise for this deferred // If obj is provided, the promise aspect is added to the object promise: function( obj ) { if ( obj == null ) { if ( promise ) { return promise; } promise = obj = {}; } var i = promiseMethods.length; while( i-- ) { obj[ promiseMethods[i] ] = deferred[ promiseMethods[i] ]; } return obj; } }); // Make sure only one callback list will be used deferred.done( failDeferred.cancel ).fail( deferred.cancel ); // Unexpose cancel delete deferred.cancel; // Call given func if any if ( func ) { func.call( deferred, deferred ); } return deferred; }, // Deferred helper when: function( firstParam ) { var args = arguments, i = 0, length = args.length, count = length, deferred = length <= 1 && firstParam && jQuery.isFunction( firstParam.promise ) ? firstParam : jQuery.Deferred(); function resolveFunc( i ) { return function( value ) { args[ i ] = arguments.length > 1 ? sliceDeferred.call( arguments, 0 ) : value; if ( !( --count ) ) { // Strange bug in FF4: // Values changed onto the arguments object sometimes end up as undefined values // outside the $.when method. Cloning the object into a fresh array solves the issue deferred.resolveWith( deferred, sliceDeferred.call( args, 0 ) ); } }; } if ( length > 1 ) { for( ; i < length; i++ ) { if ( args[ i ] && jQuery.isFunction( args[ i ].promise ) ) { args[ i ].promise().then( resolveFunc(i), deferred.reject ); } else { --count; } } if ( !count ) { deferred.resolveWith( deferred, args ); } } else if ( deferred !== firstParam ) { deferred.resolveWith( deferred, length ? [ firstParam ] : [] ); } return deferred.promise(); } }); jQuery.support = (function() { var div = document.createElement( "div" ), documentElement = document.documentElement, all, a, select, opt, input, marginDiv, support, fragment, body, testElementParent, testElement, testElementStyle, tds, events, eventName, i, isSupported; // Preliminary tests div.setAttribute("className", "t"); div.innerHTML = "
a"; all = div.getElementsByTagName( "*" ); a = div.getElementsByTagName( "a" )[ 0 ]; // Can't get basic test support if ( !all || !all.length || !a ) { return {}; } // First batch of supports tests select = document.createElement( "select" ); opt = select.appendChild( document.createElement("option") ); input = div.getElementsByTagName( "input" )[ 0 ]; support = { // IE strips leading whitespace when .innerHTML is used leadingWhitespace: ( div.firstChild.nodeType === 3 ), // Make sure that tbody elements aren't automatically inserted // IE will insert them into empty tables tbody: !div.getElementsByTagName( "tbody" ).length, // Make sure that link elements get serialized correctly by innerHTML // This requires a wrapper element in IE htmlSerialize: !!div.getElementsByTagName( "link" ).length, // Get the style information from getAttribute // (IE uses .cssText instead) style: /top/.test( a.getAttribute("style") ), // Make sure that URLs aren't manipulated // (IE normalizes it by default) hrefNormalized: ( a.getAttribute( "href" ) === "/a" ), // Make sure that element opacity exists // (IE uses filter instead) // Use a regex to work around a WebKit issue. See #5145 opacity: /^0.55$/.test( a.style.opacity ), // Verify style float existence // (IE uses styleFloat instead of cssFloat) cssFloat: !!a.style.cssFloat, // Make sure that if no value is specified for a checkbox // that it defaults to "on". // (WebKit defaults to "" instead) checkOn: ( input.value === "on" ), // Make sure that a selected-by-default option has a working selected property. // (WebKit defaults to false instead of true, IE too, if it's in an optgroup) optSelected: opt.selected, // Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7) getSetAttribute: div.className !== "t", // Will be defined later submitBubbles: true, changeBubbles: true, focusinBubbles: false, deleteExpando: true, noCloneEvent: true, inlineBlockNeedsLayout: false, shrinkWrapBlocks: false, reliableMarginRight: true }; // Make sure checked status is properly cloned input.checked = true; support.noCloneChecked = input.cloneNode( true ).checked; // Make sure that the options inside disabled selects aren't marked as disabled // (WebKit marks them as disabled) select.disabled = true; support.optDisabled = !opt.disabled; // Test to see if it's possible to delete an expando from an element // Fails in Internet Explorer try { delete div.test; } catch( e ) { support.deleteExpando = false; } if ( !div.addEventListener && div.attachEvent && div.fireEvent ) { div.attachEvent( "onclick", function() { // Cloning a node shouldn't copy over any // bound event handlers (IE does this) support.noCloneEvent = false; }); div.cloneNode( true ).fireEvent( "onclick" ); } // Check if a radio maintains it's value // after being appended to the DOM input = document.createElement("input"); input.value = "t"; input.setAttribute("type", "radio"); support.radioValue = input.value === "t"; input.setAttribute("checked", "checked"); div.appendChild( input ); fragment = document.createDocumentFragment(); fragment.appendChild( div.firstChild ); // WebKit doesn't clone checked state correctly in fragments support.checkClone = fragment.cloneNode( true ).cloneNode( true ).lastChild.checked; div.innerHTML = ""; // Figure out if the W3C box model works as expected div.style.width = div.style.paddingLeft = "1px"; body = document.getElementsByTagName( "body" )[ 0 ]; // We use our own, invisible, body unless the body is already present // in which case we use a div (#9239) testElement = document.createElement( body ? "div" : "body" ); testElementStyle = { visibility: "hidden", width: 0, height: 0, border: 0, margin: 0, background: "none" }; if ( body ) { jQuery.extend( testElementStyle, { position: "absolute", left: "-1000px", top: "-1000px" }); } for ( i in testElementStyle ) { testElement.style[ i ] = testElementStyle[ i ]; } testElement.appendChild( div ); testElementParent = body || documentElement; testElementParent.insertBefore( testElement, testElementParent.firstChild ); // Check if a disconnected checkbox will retain its checked // value of true after appended to the DOM (IE6/7) support.appendChecked = input.checked; support.boxModel = div.offsetWidth === 2; if ( "zoom" in div.style ) { // Check if natively block-level elements act like inline-block // elements when setting their display to 'inline' and giving // them layout // (IE < 8 does this) div.style.display = "inline"; div.style.zoom = 1; support.inlineBlockNeedsLayout = ( div.offsetWidth === 2 ); // Check if elements with layout shrink-wrap their children // (IE 6 does this) div.style.display = ""; div.innerHTML = "
"; support.shrinkWrapBlocks = ( div.offsetWidth !== 2 ); } div.innerHTML = "
t
"; tds = div.getElementsByTagName( "td" ); // Check if table cells still have offsetWidth/Height when they are set // to display:none and there are still other visible table cells in a // table row; if so, offsetWidth/Height are not reliable for use when // determining if an element has been hidden directly using // display:none (it is still safe to use offsets if a parent element is // hidden; don safety goggles and see bug #4512 for more information). // (only IE 8 fails this test) isSupported = ( tds[ 0 ].offsetHeight === 0 ); tds[ 0 ].style.display = ""; tds[ 1 ].style.display = "none"; // Check if empty table cells still have offsetWidth/Height // (IE < 8 fail this test) support.reliableHiddenOffsets = isSupported && ( tds[ 0 ].offsetHeight === 0 ); div.innerHTML = ""; // Check if div with explicit width and no margin-right incorrectly // gets computed margin-right based on width of container. For more // info see bug #3333 // Fails in WebKit before Feb 2011 nightlies // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right if ( document.defaultView && document.defaultView.getComputedStyle ) { marginDiv = document.createElement( "div" ); marginDiv.style.width = "0"; marginDiv.style.marginRight = "0"; div.appendChild( marginDiv ); support.reliableMarginRight = ( parseInt( ( document.defaultView.getComputedStyle( marginDiv, null ) || { marginRight: 0 } ).marginRight, 10 ) || 0 ) === 0; } // Remove the body element we added testElement.innerHTML = ""; testElementParent.removeChild( testElement ); // Technique from Juriy Zaytsev // http://thinkweb2.com/projects/prototype/detecting-event-support-without-browser-sniffing/ // We only care about the case where non-standard event systems // are used, namely in IE. Short-circuiting here helps us to // avoid an eval call (in setAttribute) which can cause CSP // to go haywire. See: https://developer.mozilla.org/en/Security/CSP if ( div.attachEvent ) { for( i in { submit: 1, change: 1, focusin: 1 } ) { eventName = "on" + i; isSupported = ( eventName in div ); if ( !isSupported ) { div.setAttribute( eventName, "return;" ); isSupported = ( typeof div[ eventName ] === "function" ); } support[ i + "Bubbles" ] = isSupported; } } // Null connected elements to avoid leaks in IE testElement = fragment = select = opt = body = marginDiv = div = input = null; return support; })(); // Keep track of boxModel jQuery.boxModel = jQuery.support.boxModel; var rbrace = /^(?:\{.*\}|\[.*\])$/, rmultiDash = /([A-Z])/g; jQuery.extend({ cache: {}, // Please use with caution uuid: 0, // Unique for each copy of jQuery on the page // Non-digits removed to match rinlinejQuery expando: "jQuery" + ( jQuery.fn.jquery + Math.random() ).replace( /\D/g, "" ), // The following elements throw uncatchable exceptions if you // attempt to add expando properties to them. noData: { "embed": true, // Ban all objects except for Flash (which handle expandos) "object": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000", "applet": true }, hasData: function( elem ) { elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ]; return !!elem && !isEmptyDataObject( elem ); }, data: function( elem, name, data, pvt /* Internal Use Only */ ) { if ( !jQuery.acceptData( elem ) ) { return; } var thisCache, ret, internalKey = jQuery.expando, getByName = typeof name === "string", // We have to handle DOM nodes and JS objects differently because IE6-7 // can't GC object references properly across the DOM-JS boundary isNode = elem.nodeType, // Only DOM nodes need the global jQuery cache; JS object data is // attached directly to the object so GC can occur automatically cache = isNode ? jQuery.cache : elem, // Only defining an ID for JS objects if its cache already exists allows // the code to shortcut on the same path as a DOM node with no cache id = isNode ? elem[ jQuery.expando ] : elem[ jQuery.expando ] && jQuery.expando; // Avoid doing any more work than we need to when trying to get data on an // object that has no data at all if ( (!id || (pvt && id && (cache[ id ] && !cache[ id ][ internalKey ]))) && getByName && data === undefined ) { return; } if ( !id ) { // Only DOM nodes need a new unique ID for each element since their data // ends up in the global cache if ( isNode ) { elem[ jQuery.expando ] = id = ++jQuery.uuid; } else { id = jQuery.expando; } } if ( !cache[ id ] ) { cache[ id ] = {}; // TODO: This is a hack for 1.5 ONLY. Avoids exposing jQuery // metadata on plain JS objects when the object is serialized using // JSON.stringify if ( !isNode ) { cache[ id ].toJSON = jQuery.noop; } } // An object can be passed to jQuery.data instead of a key/value pair; this gets // shallow copied over onto the existing cache if ( typeof name === "object" || typeof name === "function" ) { if ( pvt ) { cache[ id ][ internalKey ] = jQuery.extend(cache[ id ][ internalKey ], name); } else { cache[ id ] = jQuery.extend(cache[ id ], name); } } thisCache = cache[ id ]; // Internal jQuery data is stored in a separate object inside the object's data // cache in order to avoid key collisions between internal data and user-defined // data if ( pvt ) { if ( !thisCache[ internalKey ] ) { thisCache[ internalKey ] = {}; } thisCache = thisCache[ internalKey ]; } if ( data !== undefined ) { thisCache[ jQuery.camelCase( name ) ] = data; } // TODO: This is a hack for 1.5 ONLY. It will be removed in 1.6. Users should // not attempt to inspect the internal events object using jQuery.data, as this // internal data object is undocumented and subject to change. if ( name === "events" && !thisCache[name] ) { return thisCache[ internalKey ] && thisCache[ internalKey ].events; } // Check for both converted-to-camel and non-converted data property names // If a data property was specified if ( getByName ) { // First Try to find as-is property data ret = thisCache[ name ]; // Test for null|undefined property data if ( ret == null ) { // Try to find the camelCased property ret = thisCache[ jQuery.camelCase( name ) ]; } } else { ret = thisCache; } return ret; }, removeData: function( elem, name, pvt /* Internal Use Only */ ) { if ( !jQuery.acceptData( elem ) ) { return; } var thisCache, // Reference to internal data cache key internalKey = jQuery.expando, isNode = elem.nodeType, // See jQuery.data for more information cache = isNode ? jQuery.cache : elem, // See jQuery.data for more information id = isNode ? elem[ jQuery.expando ] : jQuery.expando; // If there is already no cache entry for this object, there is no // purpose in continuing if ( !cache[ id ] ) { return; } if ( name ) { thisCache = pvt ? cache[ id ][ internalKey ] : cache[ id ]; if ( thisCache ) { // Support interoperable removal of hyphenated or camelcased keys if ( !thisCache[ name ] ) { name = jQuery.camelCase( name ); } delete thisCache[ name ]; // If there is no data left in the cache, we want to continue // and let the cache object itself get destroyed if ( !isEmptyDataObject(thisCache) ) { return; } } } // See jQuery.data for more information if ( pvt ) { delete cache[ id ][ internalKey ]; // Don't destroy the parent cache unless the internal data object // had been the only thing left in it if ( !isEmptyDataObject(cache[ id ]) ) { return; } } var internalCache = cache[ id ][ internalKey ]; // Browsers that fail expando deletion also refuse to delete expandos on // the window, but it will allow it on all other JS objects; other browsers // don't care // Ensure that `cache` is not a window object #10080 if ( jQuery.support.deleteExpando || !cache.setInterval ) { delete cache[ id ]; } else { cache[ id ] = null; } // We destroyed the entire user cache at once because it's faster than // iterating through each key, but we need to continue to persist internal // data if it existed if ( internalCache ) { cache[ id ] = {}; // TODO: This is a hack for 1.5 ONLY. Avoids exposing jQuery // metadata on plain JS objects when the object is serialized using // JSON.stringify if ( !isNode ) { cache[ id ].toJSON = jQuery.noop; } cache[ id ][ internalKey ] = internalCache; // Otherwise, we need to eliminate the expando on the node to avoid // false lookups in the cache for entries that no longer exist } else if ( isNode ) { // IE does not allow us to delete expando properties from nodes, // nor does it have a removeAttribute function on Document nodes; // we must handle all of these cases if ( jQuery.support.deleteExpando ) { delete elem[ jQuery.expando ]; } else if ( elem.removeAttribute ) { elem.removeAttribute( jQuery.expando ); } else { elem[ jQuery.expando ] = null; } } }, // For internal use only. _data: function( elem, name, data ) { return jQuery.data( elem, name, data, true ); }, // A method for determining if a DOM node can handle the data expando acceptData: function( elem ) { if ( elem.nodeName ) { var match = jQuery.noData[ elem.nodeName.toLowerCase() ]; if ( match ) { return !(match === true || elem.getAttribute("classid") !== match); } } return true; } }); jQuery.fn.extend({ data: function( key, value ) { var data = null; if ( typeof key === "undefined" ) { if ( this.length ) { data = jQuery.data( this[0] ); if ( this[0].nodeType === 1 ) { var attr = this[0].attributes, name; for ( var i = 0, l = attr.length; i < l; i++ ) { name = attr[i].name; if ( name.indexOf( "data-" ) === 0 ) { name = jQuery.camelCase( name.substring(5) ); dataAttr( this[0], name, data[ name ] ); } } } } return data; } else if ( typeof key === "object" ) { return this.each(function() { jQuery.data( this, key ); }); } var parts = key.split("."); parts[1] = parts[1] ? "." + parts[1] : ""; if ( value === undefined ) { data = this.triggerHandler("getData" + parts[1] + "!", [parts[0]]); // Try to fetch any internally stored data first if ( data === undefined && this.length ) { data = jQuery.data( this[0], key ); data = dataAttr( this[0], key, data ); } return data === undefined && parts[1] ? this.data( parts[0] ) : data; } else { return this.each(function() { var $this = jQuery( this ), args = [ parts[0], value ]; $this.triggerHandler( "setData" + parts[1] + "!", args ); jQuery.data( this, key, value ); $this.triggerHandler( "changeData" + parts[1] + "!", args ); }); } }, removeData: function( key ) { return this.each(function() { jQuery.removeData( this, key ); }); } }); function dataAttr( elem, key, data ) { // If nothing was found internally, try to fetch any // data from the HTML5 data-* attribute if ( data === undefined && elem.nodeType === 1 ) { var name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase(); data = elem.getAttribute( name ); if ( typeof data === "string" ) { try { data = data === "true" ? true : data === "false" ? false : data === "null" ? null : !jQuery.isNaN( data ) ? parseFloat( data ) : rbrace.test( data ) ? jQuery.parseJSON( data ) : data; } catch( e ) {} // Make sure we set the data so it isn't changed later jQuery.data( elem, key, data ); } else { data = undefined; } } return data; } // TODO: This is a hack for 1.5 ONLY to allow objects with a single toJSON // property to be considered empty objects; this property always exists in // order to make sure JSON.stringify does not expose internal metadata function isEmptyDataObject( obj ) { for ( var name in obj ) { if ( name !== "toJSON" ) { return false; } } return true; } function handleQueueMarkDefer( elem, type, src ) { var deferDataKey = type + "defer", queueDataKey = type + "queue", markDataKey = type + "mark", defer = jQuery.data( elem, deferDataKey, undefined, true ); if ( defer && ( src === "queue" || !jQuery.data( elem, queueDataKey, undefined, true ) ) && ( src === "mark" || !jQuery.data( elem, markDataKey, undefined, true ) ) ) { // Give room for hard-coded callbacks to fire first // and eventually mark/queue something else on the element setTimeout( function() { if ( !jQuery.data( elem, queueDataKey, undefined, true ) && !jQuery.data( elem, markDataKey, undefined, true ) ) { jQuery.removeData( elem, deferDataKey, true ); defer.resolve(); } }, 0 ); } } jQuery.extend({ _mark: function( elem, type ) { if ( elem ) { type = (type || "fx") + "mark"; jQuery.data( elem, type, (jQuery.data(elem,type,undefined,true) || 0) + 1, true ); } }, _unmark: function( force, elem, type ) { if ( force !== true ) { type = elem; elem = force; force = false; } if ( elem ) { type = type || "fx"; var key = type + "mark", count = force ? 0 : ( (jQuery.data( elem, key, undefined, true) || 1 ) - 1 ); if ( count ) { jQuery.data( elem, key, count, true ); } else { jQuery.removeData( elem, key, true ); handleQueueMarkDefer( elem, type, "mark" ); } } }, queue: function( elem, type, data ) { if ( elem ) { type = (type || "fx") + "queue"; var q = jQuery.data( elem, type, undefined, true ); // Speed up dequeue by getting out quickly if this is just a lookup if ( data ) { if ( !q || jQuery.isArray(data) ) { q = jQuery.data( elem, type, jQuery.makeArray(data), true ); } else { q.push( data ); } } return q || []; } }, dequeue: function( elem, type ) { type = type || "fx"; var queue = jQuery.queue( elem, type ), fn = queue.shift(), defer; // If the fx queue is dequeued, always remove the progress sentinel if ( fn === "inprogress" ) { fn = queue.shift(); } if ( fn ) { // Add a progress sentinel to prevent the fx queue from being // automatically dequeued if ( type === "fx" ) { queue.unshift("inprogress"); } fn.call(elem, function() { jQuery.dequeue(elem, type); }); } if ( !queue.length ) { jQuery.removeData( elem, type + "queue", true ); handleQueueMarkDefer( elem, type, "queue" ); } } }); jQuery.fn.extend({ queue: function( type, data ) { if ( typeof type !== "string" ) { data = type; type = "fx"; } if ( data === undefined ) { return jQuery.queue( this[0], type ); } return this.each(function() { var queue = jQuery.queue( this, type, data ); if ( type === "fx" && queue[0] !== "inprogress" ) { jQuery.dequeue( this, type ); } }); }, dequeue: function( type ) { return this.each(function() { jQuery.dequeue( this, type ); }); }, // Based off of the plugin by Clint Helfers, with permission. // http://blindsignals.com/index.php/2009/07/jquery-delay/ delay: function( time, type ) { time = jQuery.fx ? jQuery.fx.speeds[time] || time : time; type = type || "fx"; return this.queue( type, function() { var elem = this; setTimeout(function() { jQuery.dequeue( elem, type ); }, time ); }); }, clearQueue: function( type ) { return this.queue( type || "fx", [] ); }, // Get a promise resolved when queues of a certain type // are emptied (fx is the type by default) promise: function( type, object ) { if ( typeof type !== "string" ) { object = type; type = undefined; } type = type || "fx"; var defer = jQuery.Deferred(), elements = this, i = elements.length, count = 1, deferDataKey = type + "defer", queueDataKey = type + "queue", markDataKey = type + "mark", tmp; function resolve() { if ( !( --count ) ) { defer.resolveWith( elements, [ elements ] ); } } while( i-- ) { if (( tmp = jQuery.data( elements[ i ], deferDataKey, undefined, true ) || ( jQuery.data( elements[ i ], queueDataKey, undefined, true ) || jQuery.data( elements[ i ], markDataKey, undefined, true ) ) && jQuery.data( elements[ i ], deferDataKey, jQuery._Deferred(), true ) )) { count++; tmp.done( resolve ); } } resolve(); return defer.promise(); } }); var rclass = /[\n\t\r]/g, rspace = /\s+/, rreturn = /\r/g, rtype = /^(?:button|input)$/i, rfocusable = /^(?:button|input|object|select|textarea)$/i, rclickable = /^a(?:rea)?$/i, rboolean = /^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i, nodeHook, boolHook; jQuery.fn.extend({ attr: function( name, value ) { return jQuery.access( this, name, value, true, jQuery.attr ); }, removeAttr: function( name ) { return this.each(function() { jQuery.removeAttr( this, name ); }); }, prop: function( name, value ) { return jQuery.access( this, name, value, true, jQuery.prop ); }, removeProp: function( name ) { name = jQuery.propFix[ name ] || name; return this.each(function() { // try/catch handles cases where IE balks (such as removing a property on window) try { this[ name ] = undefined; delete this[ name ]; } catch( e ) {} }); }, addClass: function( value ) { var classNames, i, l, elem, setClass, c, cl; if ( jQuery.isFunction( value ) ) { return this.each(function( j ) { jQuery( this ).addClass( value.call(this, j, this.className) ); }); } if ( value && typeof value === "string" ) { classNames = value.split( rspace ); for ( i = 0, l = this.length; i < l; i++ ) { elem = this[ i ]; if ( elem.nodeType === 1 ) { if ( !elem.className && classNames.length === 1 ) { elem.className = value; } else { setClass = " " + elem.className + " "; for ( c = 0, cl = classNames.length; c < cl; c++ ) { if ( !~setClass.indexOf( " " + classNames[ c ] + " " ) ) { setClass += classNames[ c ] + " "; } } elem.className = jQuery.trim( setClass ); } } } } return this; }, removeClass: function( value ) { var classNames, i, l, elem, className, c, cl; if ( jQuery.isFunction( value ) ) { return this.each(function( j ) { jQuery( this ).removeClass( value.call(this, j, this.className) ); }); } if ( (value && typeof value === "string") || value === undefined ) { classNames = (value || "").split( rspace ); for ( i = 0, l = this.length; i < l; i++ ) { elem = this[ i ]; if ( elem.nodeType === 1 && elem.className ) { if ( value ) { className = (" " + elem.className + " ").replace( rclass, " " ); for ( c = 0, cl = classNames.length; c < cl; c++ ) { className = className.replace(" " + classNames[ c ] + " ", " "); } elem.className = jQuery.trim( className ); } else { elem.className = ""; } } } } return this; }, toggleClass: function( value, stateVal ) { var type = typeof value, isBool = typeof stateVal === "boolean"; if ( jQuery.isFunction( value ) ) { return this.each(function( i ) { jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal ); }); } return this.each(function() { if ( type === "string" ) { // toggle individual class names var className, i = 0, self = jQuery( this ), state = stateVal, classNames = value.split( rspace ); while ( (className = classNames[ i++ ]) ) { // check each className given, space seperated list state = isBool ? state : !self.hasClass( className ); self[ state ? "addClass" : "removeClass" ]( className ); } } else if ( type === "undefined" || type === "boolean" ) { if ( this.className ) { // store className if set jQuery._data( this, "__className__", this.className ); } // toggle whole className this.className = this.className || value === false ? "" : jQuery._data( this, "__className__" ) || ""; } }); }, hasClass: function( selector ) { var className = " " + selector + " "; for ( var i = 0, l = this.length; i < l; i++ ) { if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) > -1 ) { return true; } } return false; }, val: function( value ) { var hooks, ret, elem = this[0]; if ( !arguments.length ) { if ( elem ) { hooks = jQuery.valHooks[ elem.nodeName.toLowerCase() ] || jQuery.valHooks[ elem.type ]; if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) { return ret; } ret = elem.value; return typeof ret === "string" ? // handle most common string cases ret.replace(rreturn, "") : // handle cases where value is null/undef or number ret == null ? "" : ret; } return undefined; } var isFunction = jQuery.isFunction( value ); return this.each(function( i ) { var self = jQuery(this), val; if ( this.nodeType !== 1 ) { return; } if ( isFunction ) { val = value.call( this, i, self.val() ); } else { val = value; } // Treat null/undefined as ""; convert numbers to string if ( val == null ) { val = ""; } else if ( typeof val === "number" ) { val += ""; } else if ( jQuery.isArray( val ) ) { val = jQuery.map(val, function ( value ) { return value == null ? "" : value + ""; }); } hooks = jQuery.valHooks[ this.nodeName.toLowerCase() ] || jQuery.valHooks[ this.type ]; // If set returns undefined, fall back to normal setting if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) { this.value = val; } }); } }); jQuery.extend({ valHooks: { option: { get: function( elem ) { // attributes.value is undefined in Blackberry 4.7 but // uses .value. See #6932 var val = elem.attributes.value; return !val || val.specified ? elem.value : elem.text; } }, select: { get: function( elem ) { var value, index = elem.selectedIndex, values = [], options = elem.options, one = elem.type === "select-one"; // Nothing was selected if ( index < 0 ) { return null; } // Loop through all the selected options for ( var i = one ? index : 0, max = one ? index + 1 : options.length; i < max; i++ ) { var option = options[ i ]; // Don't return options that are disabled or in a disabled optgroup if ( option.selected && (jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null) && (!option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" )) ) { // Get the specific value for the option value = jQuery( option ).val(); // We don't need an array for one selects if ( one ) { return value; } // Multi-Selects return an array values.push( value ); } } // Fixes Bug #2551 -- select.val() broken in IE after form.reset() if ( one && !values.length && options.length ) { return jQuery( options[ index ] ).val(); } return values; }, set: function( elem, value ) { var values = jQuery.makeArray( value ); jQuery(elem).find("option").each(function() { this.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0; }); if ( !values.length ) { elem.selectedIndex = -1; } return values; } } }, attrFn: { val: true, css: true, html: true, text: true, data: true, width: true, height: true, offset: true }, attrFix: { // Always normalize to ensure hook usage tabindex: "tabIndex" }, attr: function( elem, name, value, pass ) { var nType = elem.nodeType; // don't get/set attributes on text, comment and attribute nodes if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { return undefined; } if ( pass && name in jQuery.attrFn ) { return jQuery( elem )[ name ]( value ); } // Fallback to prop when attributes are not supported if ( !("getAttribute" in elem) ) { return jQuery.prop( elem, name, value ); } var ret, hooks, notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); // Normalize the name if needed if ( notxml ) { name = jQuery.attrFix[ name ] || name; hooks = jQuery.attrHooks[ name ]; if ( !hooks ) { // Use boolHook for boolean attributes if ( rboolean.test( name ) ) { hooks = boolHook; // Use nodeHook if available( IE6/7 ) } else if ( nodeHook ) { hooks = nodeHook; } } } if ( value !== undefined ) { if ( value === null ) { jQuery.removeAttr( elem, name ); return undefined; } else if ( hooks && "set" in hooks && notxml && (ret = hooks.set( elem, value, name )) !== undefined ) { return ret; } else { elem.setAttribute( name, "" + value ); return value; } } else if ( hooks && "get" in hooks && notxml && (ret = hooks.get( elem, name )) !== null ) { return ret; } else { ret = elem.getAttribute( name ); // Non-existent attributes return null, we normalize to undefined return ret === null ? undefined : ret; } }, removeAttr: function( elem, name ) { var propName; if ( elem.nodeType === 1 ) { name = jQuery.attrFix[ name ] || name; jQuery.attr( elem, name, "" ); elem.removeAttribute( name ); // Set corresponding property to false for boolean attributes if ( rboolean.test( name ) && (propName = jQuery.propFix[ name ] || name) in elem ) { elem[ propName ] = false; } } }, attrHooks: { type: { set: function( elem, value ) { // We can't allow the type property to be changed (since it causes problems in IE) if ( rtype.test( elem.nodeName ) && elem.parentNode ) { jQuery.error( "type property can't be changed" ); } else if ( !jQuery.support.radioValue && value === "radio" && jQuery.nodeName(elem, "input") ) { // Setting the type on a radio button after the value resets the value in IE6-9 // Reset value to it's default in case type is set after value // This is for element creation var val = elem.value; elem.setAttribute( "type", value ); if ( val ) { elem.value = val; } return value; } } }, // Use the value property for back compat // Use the nodeHook for button elements in IE6/7 (#1954) value: { get: function( elem, name ) { if ( nodeHook && jQuery.nodeName( elem, "button" ) ) { return nodeHook.get( elem, name ); } return name in elem ? elem.value : null; }, set: function( elem, value, name ) { if ( nodeHook && jQuery.nodeName( elem, "button" ) ) { return nodeHook.set( elem, value, name ); } // Does not return so that setAttribute is also used elem.value = value; } } }, propFix: { tabindex: "tabIndex", readonly: "readOnly", "for": "htmlFor", "class": "className", maxlength: "maxLength", cellspacing: "cellSpacing", cellpadding: "cellPadding", rowspan: "rowSpan", colspan: "colSpan", usemap: "useMap", frameborder: "frameBorder", contenteditable: "contentEditable" }, prop: function( elem, name, value ) { var nType = elem.nodeType; // don't get/set properties on text, comment and attribute nodes if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { return undefined; } var ret, hooks, notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); if ( notxml ) { // Fix name and attach hooks name = jQuery.propFix[ name ] || name; hooks = jQuery.propHooks[ name ]; } if ( value !== undefined ) { if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) { return ret; } else { return (elem[ name ] = value); } } else { if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) { return ret; } else { return elem[ name ]; } } }, propHooks: { tabIndex: { get: function( elem ) { // elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ var attributeNode = elem.getAttributeNode("tabindex"); return attributeNode && attributeNode.specified ? parseInt( attributeNode.value, 10 ) : rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ? 0 : undefined; } } } }); // Add the tabindex propHook to attrHooks for back-compat jQuery.attrHooks.tabIndex = jQuery.propHooks.tabIndex; // Hook for boolean attributes boolHook = { get: function( elem, name ) { // Align boolean attributes with corresponding properties // Fall back to attribute presence where some booleans are not supported var attrNode; return jQuery.prop( elem, name ) === true || ( attrNode = elem.getAttributeNode( name ) ) && attrNode.nodeValue !== false ? name.toLowerCase() : undefined; }, set: function( elem, value, name ) { var propName; if ( value === false ) { // Remove boolean attributes when set to false jQuery.removeAttr( elem, name ); } else { // value is true since we know at this point it's type boolean and not false // Set boolean attributes to the same name and set the DOM property propName = jQuery.propFix[ name ] || name; if ( propName in elem ) { // Only set the IDL specifically if it already exists on the element elem[ propName ] = true; } elem.setAttribute( name, name.toLowerCase() ); } return name; } }; // IE6/7 do not support getting/setting some attributes with get/setAttribute if ( !jQuery.support.getSetAttribute ) { // Use this for any attribute in IE6/7 // This fixes almost every IE6/7 issue nodeHook = jQuery.valHooks.button = { get: function( elem, name ) { var ret; ret = elem.getAttributeNode( name ); // Return undefined if nodeValue is empty string return ret && ret.nodeValue !== "" ? ret.nodeValue : undefined; }, set: function( elem, value, name ) { // Set the existing or create a new attribute node var ret = elem.getAttributeNode( name ); if ( !ret ) { ret = document.createAttribute( name ); elem.setAttributeNode( ret ); } return (ret.nodeValue = value + ""); } }; // Set width and height to auto instead of 0 on empty string( Bug #8150 ) // This is for removals jQuery.each([ "width", "height" ], function( i, name ) { jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], { set: function( elem, value ) { if ( value === "" ) { elem.setAttribute( name, "auto" ); return value; } } }); }); } // Some attributes require a special call on IE if ( !jQuery.support.hrefNormalized ) { jQuery.each([ "href", "src", "width", "height" ], function( i, name ) { jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], { get: function( elem ) { var ret = elem.getAttribute( name, 2 ); return ret === null ? undefined : ret; } }); }); } if ( !jQuery.support.style ) { jQuery.attrHooks.style = { get: function( elem ) { // Return undefined in the case of empty string // Normalize to lowercase since IE uppercases css property names return elem.style.cssText.toLowerCase() || undefined; }, set: function( elem, value ) { return (elem.style.cssText = "" + value); } }; } // Safari mis-reports the default selected property of an option // Accessing the parent's selectedIndex property fixes it if ( !jQuery.support.optSelected ) { jQuery.propHooks.selected = jQuery.extend( jQuery.propHooks.selected, { get: function( elem ) { var parent = elem.parentNode; if ( parent ) { parent.selectedIndex; // Make sure that it also works with optgroups, see #5701 if ( parent.parentNode ) { parent.parentNode.selectedIndex; } } return null; } }); } // Radios and checkboxes getter/setter if ( !jQuery.support.checkOn ) { jQuery.each([ "radio", "checkbox" ], function() { jQuery.valHooks[ this ] = { get: function( elem ) { // Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified return elem.getAttribute("value") === null ? "on" : elem.value; } }; }); } jQuery.each([ "radio", "checkbox" ], function() { jQuery.valHooks[ this ] = jQuery.extend( jQuery.valHooks[ this ], { set: function( elem, value ) { if ( jQuery.isArray( value ) ) { return (elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0); } } }); }); var rnamespaces = /\.(.*)$/, rformElems = /^(?:textarea|input|select)$/i, rperiod = /\./g, rspaces = / /g, rescape = /[^\w\s.|`]/g, fcleanup = function( nm ) { return nm.replace(rescape, "\\$&"); }; /* * A number of helper functions used for managing events. * Many of the ideas behind this code originated from * Dean Edwards' addEvent library. */ jQuery.event = { // Bind an event to an element // Original by Dean Edwards add: function( elem, types, handler, data ) { if ( elem.nodeType === 3 || elem.nodeType === 8 ) { return; } if ( handler === false ) { handler = returnFalse; } else if ( !handler ) { // Fixes bug #7229. Fix recommended by jdalton return; } var handleObjIn, handleObj; if ( handler.handler ) { handleObjIn = handler; handler = handleObjIn.handler; } // Make sure that the function being executed has a unique ID if ( !handler.guid ) { handler.guid = jQuery.guid++; } // Init the element's event structure var elemData = jQuery._data( elem ); // If no elemData is found then we must be trying to bind to one of the // banned noData elements if ( !elemData ) { return; } var events = elemData.events, eventHandle = elemData.handle; if ( !events ) { elemData.events = events = {}; } if ( !eventHandle ) { elemData.handle = eventHandle = function( e ) { // Discard the second event of a jQuery.event.trigger() and // when an event is called after a page has unloaded return typeof jQuery !== "undefined" && (!e || jQuery.event.triggered !== e.type) ? jQuery.event.handle.apply( eventHandle.elem, arguments ) : undefined; }; } // Add elem as a property of the handle function // This is to prevent a memory leak with non-native events in IE. eventHandle.elem = elem; // Handle multiple events separated by a space // jQuery(...).bind("mouseover mouseout", fn); types = types.split(" "); var type, i = 0, namespaces; while ( (type = types[ i++ ]) ) { handleObj = handleObjIn ? jQuery.extend({}, handleObjIn) : { handler: handler, data: data }; // Namespaced event handlers if ( type.indexOf(".") > -1 ) { namespaces = type.split("."); type = namespaces.shift(); handleObj.namespace = namespaces.slice(0).sort().join("."); } else { namespaces = []; handleObj.namespace = ""; } handleObj.type = type; if ( !handleObj.guid ) { handleObj.guid = handler.guid; } // Get the current list of functions bound to this event var handlers = events[ type ], special = jQuery.event.special[ type ] || {}; // Init the event handler queue if ( !handlers ) { handlers = events[ type ] = []; // Check for a special event handler // Only use addEventListener/attachEvent if the special // events handler returns false if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) { // Bind the global event handler to the element if ( elem.addEventListener ) { elem.addEventListener( type, eventHandle, false ); } else if ( elem.attachEvent ) { elem.attachEvent( "on" + type, eventHandle ); } } } if ( special.add ) { special.add.call( elem, handleObj ); if ( !handleObj.handler.guid ) { handleObj.handler.guid = handler.guid; } } // Add the function to the element's handler list handlers.push( handleObj ); // Keep track of which events have been used, for event optimization jQuery.event.global[ type ] = true; } // Nullify elem to prevent memory leaks in IE elem = null; }, global: {}, // Detach an event or set of events from an element remove: function( elem, types, handler, pos ) { // don't do events on text and comment nodes if ( elem.nodeType === 3 || elem.nodeType === 8 ) { return; } if ( handler === false ) { handler = returnFalse; } var ret, type, fn, j, i = 0, all, namespaces, namespace, special, eventType, handleObj, origType, elemData = jQuery.hasData( elem ) && jQuery._data( elem ), events = elemData && elemData.events; if ( !elemData || !events ) { return; } // types is actually an event object here if ( types && types.type ) { handler = types.handler; types = types.type; } // Unbind all events for the element if ( !types || typeof types === "string" && types.charAt(0) === "." ) { types = types || ""; for ( type in events ) { jQuery.event.remove( elem, type + types ); } return; } // Handle multiple events separated by a space // jQuery(...).unbind("mouseover mouseout", fn); types = types.split(" "); while ( (type = types[ i++ ]) ) { origType = type; handleObj = null; all = type.indexOf(".") < 0; namespaces = []; if ( !all ) { // Namespaced event handlers namespaces = type.split("."); type = namespaces.shift(); namespace = new RegExp("(^|\\.)" + jQuery.map( namespaces.slice(0).sort(), fcleanup ).join("\\.(?:.*\\.)?") + "(\\.|$)"); } eventType = events[ type ]; if ( !eventType ) { continue; } if ( !handler ) { for ( j = 0; j < eventType.length; j++ ) { handleObj = eventType[ j ]; if ( all || namespace.test( handleObj.namespace ) ) { jQuery.event.remove( elem, origType, handleObj.handler, j ); eventType.splice( j--, 1 ); } } continue; } special = jQuery.event.special[ type ] || {}; for ( j = pos || 0; j < eventType.length; j++ ) { handleObj = eventType[ j ]; if ( handler.guid === handleObj.guid ) { // remove the given handler for the given type if ( all || namespace.test( handleObj.namespace ) ) { if ( pos == null ) { eventType.splice( j--, 1 ); } if ( special.remove ) { special.remove.call( elem, handleObj ); } } if ( pos != null ) { break; } } } // remove generic event handler if no more handlers exist if ( eventType.length === 0 || pos != null && eventType.length === 1 ) { if ( !special.teardown || special.teardown.call( elem, namespaces ) === false ) { jQuery.removeEvent( elem, type, elemData.handle ); } ret = null; delete events[ type ]; } } // Remove the expando if it's no longer used if ( jQuery.isEmptyObject( events ) ) { var handle = elemData.handle; if ( handle ) { handle.elem = null; } delete elemData.events; delete elemData.handle; if ( jQuery.isEmptyObject( elemData ) ) { jQuery.removeData( elem, undefined, true ); } } }, // Events that are safe to short-circuit if no handlers are attached. // Native DOM events should not be added, they may have inline handlers. customEvent: { "getData": true, "setData": true, "changeData": true }, trigger: function( event, data, elem, onlyHandlers ) { // Event object or event type var type = event.type || event, namespaces = [], exclusive; if ( type.indexOf("!") >= 0 ) { // Exclusive events trigger only for the exact event (no namespaces) type = type.slice(0, -1); exclusive = true; } if ( type.indexOf(".") >= 0 ) { // Namespaced trigger; create a regexp to match event type in handle() namespaces = type.split("."); type = namespaces.shift(); namespaces.sort(); } if ( (!elem || jQuery.event.customEvent[ type ]) && !jQuery.event.global[ type ] ) { // No jQuery handlers for this event type, and it can't have inline handlers return; } // Caller can pass in an Event, Object, or just an event type string event = typeof event === "object" ? // jQuery.Event object event[ jQuery.expando ] ? event : // Object literal new jQuery.Event( type, event ) : // Just the event type (string) new jQuery.Event( type ); event.type = type; event.exclusive = exclusive; event.namespace = namespaces.join("."); event.namespace_re = new RegExp("(^|\\.)" + namespaces.join("\\.(?:.*\\.)?") + "(\\.|$)"); // triggerHandler() and global events don't bubble or run the default action if ( onlyHandlers || !elem ) { event.preventDefault(); event.stopPropagation(); } // Handle a global trigger if ( !elem ) { // TODO: Stop taunting the data cache; remove global events and always attach to document jQuery.each( jQuery.cache, function() { // internalKey variable is just used to make it easier to find // and potentially change this stuff later; currently it just // points to jQuery.expando var internalKey = jQuery.expando, internalCache = this[ internalKey ]; if ( internalCache && internalCache.events && internalCache.events[ type ] ) { jQuery.event.trigger( event, data, internalCache.handle.elem ); } }); return; } // Don't do events on text and comment nodes if ( elem.nodeType === 3 || elem.nodeType === 8 ) { return; } // Clean up the event in case it is being reused event.result = undefined; event.target = elem; // Clone any incoming data and prepend the event, creating the handler arg list data = data != null ? jQuery.makeArray( data ) : []; data.unshift( event ); var cur = elem, // IE doesn't like method names with a colon (#3533, #8272) ontype = type.indexOf(":") < 0 ? "on" + type : ""; // Fire event on the current element, then bubble up the DOM tree do { var handle = jQuery._data( cur, "handle" ); event.currentTarget = cur; if ( handle ) { handle.apply( cur, data ); } // Trigger an inline bound script if ( ontype && jQuery.acceptData( cur ) && cur[ ontype ] && cur[ ontype ].apply( cur, data ) === false ) { event.result = false; event.preventDefault(); } // Bubble up to document, then to window cur = cur.parentNode || cur.ownerDocument || cur === event.target.ownerDocument && window; } while ( cur && !event.isPropagationStopped() ); // If nobody prevented the default action, do it now if ( !event.isDefaultPrevented() ) { var old, special = jQuery.event.special[ type ] || {}; if ( (!special._default || special._default.call( elem.ownerDocument, event ) === false) && !(type === "click" && jQuery.nodeName( elem, "a" )) && jQuery.acceptData( elem ) ) { // Call a native DOM method on the target with the same name name as the event. // Can't use an .isFunction)() check here because IE6/7 fails that test. // IE<9 dies on focus to hidden element (#1486), may want to revisit a try/catch. try { if ( ontype && elem[ type ] ) { // Don't re-trigger an onFOO event when we call its FOO() method old = elem[ ontype ]; if ( old ) { elem[ ontype ] = null; } jQuery.event.triggered = type; elem[ type ](); } } catch ( ieError ) {} if ( old ) { elem[ ontype ] = old; } jQuery.event.triggered = undefined; } } return event.result; }, handle: function( event ) { event = jQuery.event.fix( event || window.event ); // Snapshot the handlers list since a called handler may add/remove events. var handlers = ((jQuery._data( this, "events" ) || {})[ event.type ] || []).slice(0), run_all = !event.exclusive && !event.namespace, args = Array.prototype.slice.call( arguments, 0 ); // Use the fix-ed Event rather than the (read-only) native event args[0] = event; event.currentTarget = this; for ( var j = 0, l = handlers.length; j < l; j++ ) { var handleObj = handlers[ j ]; // Triggered event must 1) be non-exclusive and have no namespace, or // 2) have namespace(s) a subset or equal to those in the bound event. if ( run_all || event.namespace_re.test( handleObj.namespace ) ) { // Pass in a reference to the handler function itself // So that we can later remove it event.handler = handleObj.handler; event.data = handleObj.data; event.handleObj = handleObj; var ret = handleObj.handler.apply( this, args ); if ( ret !== undefined ) { event.result = ret; if ( ret === false ) { event.preventDefault(); event.stopPropagation(); } } if ( event.isImmediatePropagationStopped() ) { break; } } } return event.result; }, props: "altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "), fix: function( event ) { if ( event[ jQuery.expando ] ) { return event; } // store a copy of the original event object // and "clone" to set read-only properties var originalEvent = event; event = jQuery.Event( originalEvent ); for ( var i = this.props.length, prop; i; ) { prop = this.props[ --i ]; event[ prop ] = originalEvent[ prop ]; } // Fix target property, if necessary if ( !event.target ) { // Fixes #1925 where srcElement might not be defined either event.target = event.srcElement || document; } // check if target is a textnode (safari) if ( event.target.nodeType === 3 ) { event.target = event.target.parentNode; } // Add relatedTarget, if necessary if ( !event.relatedTarget && event.fromElement ) { event.relatedTarget = event.fromElement === event.target ? event.toElement : event.fromElement; } // Calculate pageX/Y if missing and clientX/Y available if ( event.pageX == null && event.clientX != null ) { var eventDocument = event.target.ownerDocument || document, doc = eventDocument.documentElement, body = eventDocument.body; event.pageX = event.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc && doc.clientLeft || body && body.clientLeft || 0); event.pageY = event.clientY + (doc && doc.scrollTop || body && body.scrollTop || 0) - (doc && doc.clientTop || body && body.clientTop || 0); } // Add which for key events if ( event.which == null && (event.charCode != null || event.keyCode != null) ) { event.which = event.charCode != null ? event.charCode : event.keyCode; } // Add metaKey to non-Mac browsers (use ctrl for PC's and Meta for Macs) if ( !event.metaKey && event.ctrlKey ) { event.metaKey = event.ctrlKey; } // Add which for click: 1 === left; 2 === middle; 3 === right // Note: button is not normalized, so don't use it if ( !event.which && event.button !== undefined ) { event.which = (event.button & 1 ? 1 : ( event.button & 2 ? 3 : ( event.button & 4 ? 2 : 0 ) )); } return event; }, // Deprecated, use jQuery.guid instead guid: 1E8, // Deprecated, use jQuery.proxy instead proxy: jQuery.proxy, special: { ready: { // Make sure the ready event is setup setup: jQuery.bindReady, teardown: jQuery.noop }, live: { add: function( handleObj ) { jQuery.event.add( this, liveConvert( handleObj.origType, handleObj.selector ), jQuery.extend({}, handleObj, {handler: liveHandler, guid: handleObj.handler.guid}) ); }, remove: function( handleObj ) { jQuery.event.remove( this, liveConvert( handleObj.origType, handleObj.selector ), handleObj ); } }, beforeunload: { setup: function( data, namespaces, eventHandle ) { // We only want to do this special case on windows if ( jQuery.isWindow( this ) ) { this.onbeforeunload = eventHandle; } }, teardown: function( namespaces, eventHandle ) { if ( this.onbeforeunload === eventHandle ) { this.onbeforeunload = null; } } } } }; jQuery.removeEvent = document.removeEventListener ? function( elem, type, handle ) { if ( elem.removeEventListener ) { elem.removeEventListener( type, handle, false ); } } : function( elem, type, handle ) { if ( elem.detachEvent ) { elem.detachEvent( "on" + type, handle ); } }; jQuery.Event = function( src, props ) { // Allow instantiation without the 'new' keyword if ( !this.preventDefault ) { return new jQuery.Event( src, props ); } // Event object if ( src && src.type ) { this.originalEvent = src; this.type = src.type; // Events bubbling up the document may have been marked as prevented // by a handler lower down the tree; reflect the correct value. this.isDefaultPrevented = (src.defaultPrevented || src.returnValue === false || src.getPreventDefault && src.getPreventDefault()) ? returnTrue : returnFalse; // Event type } else { this.type = src; } // Put explicitly provided properties onto the event object if ( props ) { jQuery.extend( this, props ); } // timeStamp is buggy for some events on Firefox(#3843) // So we won't rely on the native value this.timeStamp = jQuery.now(); // Mark it as fixed this[ jQuery.expando ] = true; }; function returnFalse() { return false; } function returnTrue() { return true; } // jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding // http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html jQuery.Event.prototype = { preventDefault: function() { this.isDefaultPrevented = returnTrue; var e = this.originalEvent; if ( !e ) { return; } // if preventDefault exists run it on the original event if ( e.preventDefault ) { e.preventDefault(); // otherwise set the returnValue property of the original event to false (IE) } else { e.returnValue = false; } }, stopPropagation: function() { this.isPropagationStopped = returnTrue; var e = this.originalEvent; if ( !e ) { return; } // if stopPropagation exists run it on the original event if ( e.stopPropagation ) { e.stopPropagation(); } // otherwise set the cancelBubble property of the original event to true (IE) e.cancelBubble = true; }, stopImmediatePropagation: function() { this.isImmediatePropagationStopped = returnTrue; this.stopPropagation(); }, isDefaultPrevented: returnFalse, isPropagationStopped: returnFalse, isImmediatePropagationStopped: returnFalse }; // Checks if an event happened on an element within another element // Used in jQuery.event.special.mouseenter and mouseleave handlers var withinElement = function( event ) { // Check if mouse(over|out) are still within the same parent element var related = event.relatedTarget, inside = false, eventType = event.type; event.type = event.data; if ( related !== this ) { if ( related ) { inside = jQuery.contains( this, related ); } if ( !inside ) { jQuery.event.handle.apply( this, arguments ); event.type = eventType; } } }, // In case of event delegation, we only need to rename the event.type, // liveHandler will take care of the rest. delegate = function( event ) { event.type = event.data; jQuery.event.handle.apply( this, arguments ); }; // Create mouseenter and mouseleave events jQuery.each({ mouseenter: "mouseover", mouseleave: "mouseout" }, function( orig, fix ) { jQuery.event.special[ orig ] = { setup: function( data ) { jQuery.event.add( this, fix, data && data.selector ? delegate : withinElement, orig ); }, teardown: function( data ) { jQuery.event.remove( this, fix, data && data.selector ? delegate : withinElement ); } }; }); // submit delegation if ( !jQuery.support.submitBubbles ) { jQuery.event.special.submit = { setup: function( data, namespaces ) { if ( !jQuery.nodeName( this, "form" ) ) { jQuery.event.add(this, "click.specialSubmit", function( e ) { // Avoid triggering error on non-existent type attribute in IE VML (#7071) var elem = e.target, type = jQuery.nodeName( elem, "input" ) || jQuery.nodeName( elem, "button" ) ? elem.type : ""; if ( (type === "submit" || type === "image") && jQuery( elem ).closest("form").length ) { trigger( "submit", this, arguments ); } }); jQuery.event.add(this, "keypress.specialSubmit", function( e ) { var elem = e.target, type = jQuery.nodeName( elem, "input" ) || jQuery.nodeName( elem, "button" ) ? elem.type : ""; if ( (type === "text" || type === "password") && jQuery( elem ).closest("form").length && e.keyCode === 13 ) { trigger( "submit", this, arguments ); } }); } else { return false; } }, teardown: function( namespaces ) { jQuery.event.remove( this, ".specialSubmit" ); } }; } // change delegation, happens here so we have bind. if ( !jQuery.support.changeBubbles ) { var changeFilters, getVal = function( elem ) { var type = jQuery.nodeName( elem, "input" ) ? elem.type : "", val = elem.value; if ( type === "radio" || type === "checkbox" ) { val = elem.checked; } else if ( type === "select-multiple" ) { val = elem.selectedIndex > -1 ? jQuery.map( elem.options, function( elem ) { return elem.selected; }).join("-") : ""; } else if ( jQuery.nodeName( elem, "select" ) ) { val = elem.selectedIndex; } return val; }, testChange = function testChange( e ) { var elem = e.target, data, val; if ( !rformElems.test( elem.nodeName ) || elem.readOnly ) { return; } data = jQuery._data( elem, "_change_data" ); val = getVal(elem); // the current data will be also retrieved by beforeactivate if ( e.type !== "focusout" || elem.type !== "radio" ) { jQuery._data( elem, "_change_data", val ); } if ( data === undefined || val === data ) { return; } if ( data != null || val ) { e.type = "change"; e.liveFired = undefined; jQuery.event.trigger( e, arguments[1], elem ); } }; jQuery.event.special.change = { filters: { focusout: testChange, beforedeactivate: testChange, click: function( e ) { var elem = e.target, type = jQuery.nodeName( elem, "input" ) ? elem.type : ""; if ( type === "radio" || type === "checkbox" || jQuery.nodeName( elem, "select" ) ) { testChange.call( this, e ); } }, // Change has to be called before submit // Keydown will be called before keypress, which is used in submit-event delegation keydown: function( e ) { var elem = e.target, type = jQuery.nodeName( elem, "input" ) ? elem.type : ""; if ( (e.keyCode === 13 && !jQuery.nodeName( elem, "textarea" ) ) || (e.keyCode === 32 && (type === "checkbox" || type === "radio")) || type === "select-multiple" ) { testChange.call( this, e ); } }, // Beforeactivate happens also before the previous element is blurred // with this event you can't trigger a change event, but you can store // information beforeactivate: function( e ) { var elem = e.target; jQuery._data( elem, "_change_data", getVal(elem) ); } }, setup: function( data, namespaces ) { if ( this.type === "file" ) { return false; } for ( var type in changeFilters ) { jQuery.event.add( this, type + ".specialChange", changeFilters[type] ); } return rformElems.test( this.nodeName ); }, teardown: function( namespaces ) { jQuery.event.remove( this, ".specialChange" ); return rformElems.test( this.nodeName ); } }; changeFilters = jQuery.event.special.change.filters; // Handle when the input is .focus()'d changeFilters.focus = changeFilters.beforeactivate; } function trigger( type, elem, args ) { // Piggyback on a donor event to simulate a different one. // Fake originalEvent to avoid donor's stopPropagation, but if the // simulated event prevents default then we do the same on the donor. // Don't pass args or remember liveFired; they apply to the donor event. var event = jQuery.extend( {}, args[ 0 ] ); event.type = type; event.originalEvent = {}; event.liveFired = undefined; jQuery.event.handle.call( elem, event ); if ( event.isDefaultPrevented() ) { args[ 0 ].preventDefault(); } } // Create "bubbling" focus and blur events if ( !jQuery.support.focusinBubbles ) { jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) { // Attach a single capturing handler while someone wants focusin/focusout var attaches = 0; jQuery.event.special[ fix ] = { setup: function() { if ( attaches++ === 0 ) { document.addEventListener( orig, handler, true ); } }, teardown: function() { if ( --attaches === 0 ) { document.removeEventListener( orig, handler, true ); } } }; function handler( donor ) { // Donor event is always a native one; fix it and switch its type. // Let focusin/out handler cancel the donor focus/blur event. var e = jQuery.event.fix( donor ); e.type = fix; e.originalEvent = {}; jQuery.event.trigger( e, null, e.target ); if ( e.isDefaultPrevented() ) { donor.preventDefault(); } } }); } jQuery.each(["bind", "one"], function( i, name ) { jQuery.fn[ name ] = function( type, data, fn ) { var handler; // Handle object literals if ( typeof type === "object" ) { for ( var key in type ) { this[ name ](key, data, type[key], fn); } return this; } if ( arguments.length === 2 || data === false ) { fn = data; data = undefined; } if ( name === "one" ) { handler = function( event ) { jQuery( this ).unbind( event, handler ); return fn.apply( this, arguments ); }; handler.guid = fn.guid || jQuery.guid++; } else { handler = fn; } if ( type === "unload" && name !== "one" ) { this.one( type, data, fn ); } else { for ( var i = 0, l = this.length; i < l; i++ ) { jQuery.event.add( this[i], type, handler, data ); } } return this; }; }); jQuery.fn.extend({ unbind: function( type, fn ) { // Handle object literals if ( typeof type === "object" && !type.preventDefault ) { for ( var key in type ) { this.unbind(key, type[key]); } } else { for ( var i = 0, l = this.length; i < l; i++ ) { jQuery.event.remove( this[i], type, fn ); } } return this; }, delegate: function( selector, types, data, fn ) { return this.live( types, data, fn, selector ); }, undelegate: function( selector, types, fn ) { if ( arguments.length === 0 ) { return this.unbind( "live" ); } else { return this.die( types, null, fn, selector ); } }, trigger: function( type, data ) { return this.each(function() { jQuery.event.trigger( type, data, this ); }); }, triggerHandler: function( type, data ) { if ( this[0] ) { return jQuery.event.trigger( type, data, this[0], true ); } }, toggle: function( fn ) { // Save reference to arguments for access in closure var args = arguments, guid = fn.guid || jQuery.guid++, i = 0, toggler = function( event ) { // Figure out which function to execute var lastToggle = ( jQuery.data( this, "lastToggle" + fn.guid ) || 0 ) % i; jQuery.data( this, "lastToggle" + fn.guid, lastToggle + 1 ); // Make sure that clicks stop event.preventDefault(); // and execute the function return args[ lastToggle ].apply( this, arguments ) || false; }; // link all the functions, so any of them can unbind this click handler toggler.guid = guid; while ( i < args.length ) { args[ i++ ].guid = guid; } return this.click( toggler ); }, hover: function( fnOver, fnOut ) { return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver ); } }); var liveMap = { focus: "focusin", blur: "focusout", mouseenter: "mouseover", mouseleave: "mouseout" }; jQuery.each(["live", "die"], function( i, name ) { jQuery.fn[ name ] = function( types, data, fn, origSelector /* Internal Use Only */ ) { var type, i = 0, match, namespaces, preType, selector = origSelector || this.selector, context = origSelector ? this : jQuery( this.context ); if ( typeof types === "object" && !types.preventDefault ) { for ( var key in types ) { context[ name ]( key, data, types[key], selector ); } return this; } if ( name === "die" && !types && origSelector && origSelector.charAt(0) === "." ) { context.unbind( origSelector ); return this; } if ( data === false || jQuery.isFunction( data ) ) { fn = data || returnFalse; data = undefined; } types = (types || "").split(" "); while ( (type = types[ i++ ]) != null ) { match = rnamespaces.exec( type ); namespaces = ""; if ( match ) { namespaces = match[0]; type = type.replace( rnamespaces, "" ); } if ( type === "hover" ) { types.push( "mouseenter" + namespaces, "mouseleave" + namespaces ); continue; } preType = type; if ( liveMap[ type ] ) { types.push( liveMap[ type ] + namespaces ); type = type + namespaces; } else { type = (liveMap[ type ] || type) + namespaces; } if ( name === "live" ) { // bind live handler for ( var j = 0, l = context.length; j < l; j++ ) { jQuery.event.add( context[j], "live." + liveConvert( type, selector ), { data: data, selector: selector, handler: fn, origType: type, origHandler: fn, preType: preType } ); } } else { // unbind live handler context.unbind( "live." + liveConvert( type, selector ), fn ); } } return this; }; }); function liveHandler( event ) { var stop, maxLevel, related, match, handleObj, elem, j, i, l, data, close, namespace, ret, elems = [], selectors = [], events = jQuery._data( this, "events" ); // Make sure we avoid non-left-click bubbling in Firefox (#3861) and disabled elements in IE (#6911) if ( event.liveFired === this || !events || !events.live || event.target.disabled || event.button && event.type === "click" ) { return; } if ( event.namespace ) { namespace = new RegExp("(^|\\.)" + event.namespace.split(".").join("\\.(?:.*\\.)?") + "(\\.|$)"); } event.liveFired = this; var live = events.live.slice(0); for ( j = 0; j < live.length; j++ ) { handleObj = live[j]; if ( handleObj.origType.replace( rnamespaces, "" ) === event.type ) { selectors.push( handleObj.selector ); } else { live.splice( j--, 1 ); } } match = jQuery( event.target ).closest( selectors, event.currentTarget ); for ( i = 0, l = match.length; i < l; i++ ) { close = match[i]; for ( j = 0; j < live.length; j++ ) { handleObj = live[j]; if ( close.selector === handleObj.selector && (!namespace || namespace.test( handleObj.namespace )) && !close.elem.disabled ) { elem = close.elem; related = null; // Those two events require additional checking if ( handleObj.preType === "mouseenter" || handleObj.preType === "mouseleave" ) { event.type = handleObj.preType; related = jQuery( event.relatedTarget ).closest( handleObj.selector )[0]; // Make sure not to accidentally match a child element with the same selector if ( related && jQuery.contains( elem, related ) ) { related = elem; } } if ( !related || related !== elem ) { elems.push({ elem: elem, handleObj: handleObj, level: close.level }); } } } } for ( i = 0, l = elems.length; i < l; i++ ) { match = elems[i]; if ( maxLevel && match.level > maxLevel ) { break; } event.currentTarget = match.elem; event.data = match.handleObj.data; event.handleObj = match.handleObj; ret = match.handleObj.origHandler.apply( match.elem, arguments ); if ( ret === false || event.isPropagationStopped() ) { maxLevel = match.level; if ( ret === false ) { stop = false; } if ( event.isImmediatePropagationStopped() ) { break; } } } return stop; } function liveConvert( type, selector ) { return (type && type !== "*" ? type + "." : "") + selector.replace(rperiod, "`").replace(rspaces, "&"); } jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " + "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " + "change select submit keydown keypress keyup error").split(" "), function( i, name ) { // Handle event binding jQuery.fn[ name ] = function( data, fn ) { if ( fn == null ) { fn = data; data = null; } return arguments.length > 0 ? this.bind( name, data, fn ) : this.trigger( name ); }; if ( jQuery.attrFn ) { jQuery.attrFn[ name ] = true; } }); /*! * Sizzle CSS Selector Engine * Copyright 2011, The Dojo Foundation * Released under the MIT, BSD, and GPL Licenses. * More information: http://sizzlejs.com/ */ (function(){ var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g, done = 0, toString = Object.prototype.toString, hasDuplicate = false, baseHasDuplicate = true, rBackslash = /\\/g, rNonWord = /\W/; // Here we check if the JavaScript engine is using some sort of // optimization where it does not always call our comparision // function. If that is the case, discard the hasDuplicate value. // Thus far that includes Google Chrome. [0, 0].sort(function() { baseHasDuplicate = false; return 0; }); var Sizzle = function( selector, context, results, seed ) { results = results || []; context = context || document; var origContext = context; if ( context.nodeType !== 1 && context.nodeType !== 9 ) { return []; } if ( !selector || typeof selector !== "string" ) { return results; } var m, set, checkSet, extra, ret, cur, pop, i, prune = true, contextXML = Sizzle.isXML( context ), parts = [], soFar = selector; // Reset the position of the chunker regexp (start from head) do { chunker.exec( "" ); m = chunker.exec( soFar ); if ( m ) { soFar = m[3]; parts.push( m[1] ); if ( m[2] ) { extra = m[3]; break; } } } while ( m ); if ( parts.length > 1 && origPOS.exec( selector ) ) { if ( parts.length === 2 && Expr.relative[ parts[0] ] ) { set = posProcess( parts[0] + parts[1], context ); } else { set = Expr.relative[ parts[0] ] ? [ context ] : Sizzle( parts.shift(), context ); while ( parts.length ) { selector = parts.shift(); if ( Expr.relative[ selector ] ) { selector += parts.shift(); } set = posProcess( selector, set ); } } } else { // Take a shortcut and set the context if the root selector is an ID // (but not if it'll be faster if the inner selector is an ID) if ( !seed && parts.length > 1 && context.nodeType === 9 && !contextXML && Expr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1]) ) { ret = Sizzle.find( parts.shift(), context, contextXML ); context = ret.expr ? Sizzle.filter( ret.expr, ret.set )[0] : ret.set[0]; } if ( context ) { ret = seed ? { expr: parts.pop(), set: makeArray(seed) } : Sizzle.find( parts.pop(), parts.length === 1 && (parts[0] === "~" || parts[0] === "+") && context.parentNode ? context.parentNode : context, contextXML ); set = ret.expr ? Sizzle.filter( ret.expr, ret.set ) : ret.set; if ( parts.length > 0 ) { checkSet = makeArray( set ); } else { prune = false; } while ( parts.length ) { cur = parts.pop(); pop = cur; if ( !Expr.relative[ cur ] ) { cur = ""; } else { pop = parts.pop(); } if ( pop == null ) { pop = context; } Expr.relative[ cur ]( checkSet, pop, contextXML ); } } else { checkSet = parts = []; } } if ( !checkSet ) { checkSet = set; } if ( !checkSet ) { Sizzle.error( cur || selector ); } if ( toString.call(checkSet) === "[object Array]" ) { if ( !prune ) { results.push.apply( results, checkSet ); } else if ( context && context.nodeType === 1 ) { for ( i = 0; checkSet[i] != null; i++ ) { if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && Sizzle.contains(context, checkSet[i])) ) { results.push( set[i] ); } } } else { for ( i = 0; checkSet[i] != null; i++ ) { if ( checkSet[i] && checkSet[i].nodeType === 1 ) { results.push( set[i] ); } } } } else { makeArray( checkSet, results ); } if ( extra ) { Sizzle( extra, origContext, results, seed ); Sizzle.uniqueSort( results ); } return results; }; Sizzle.uniqueSort = function( results ) { if ( sortOrder ) { hasDuplicate = baseHasDuplicate; results.sort( sortOrder ); if ( hasDuplicate ) { for ( var i = 1; i < results.length; i++ ) { if ( results[i] === results[ i - 1 ] ) { results.splice( i--, 1 ); } } } } return results; }; Sizzle.matches = function( expr, set ) { return Sizzle( expr, null, null, set ); }; Sizzle.matchesSelector = function( node, expr ) { return Sizzle( expr, null, null, [node] ).length > 0; }; Sizzle.find = function( expr, context, isXML ) { var set; if ( !expr ) { return []; } for ( var i = 0, l = Expr.order.length; i < l; i++ ) { var match, type = Expr.order[i]; if ( (match = Expr.leftMatch[ type ].exec( expr )) ) { var left = match[1]; match.splice( 1, 1 ); if ( left.substr( left.length - 1 ) !== "\\" ) { match[1] = (match[1] || "").replace( rBackslash, "" ); set = Expr.find[ type ]( match, context, isXML ); if ( set != null ) { expr = expr.replace( Expr.match[ type ], "" ); break; } } } } if ( !set ) { set = typeof context.getElementsByTagName !== "undefined" ? context.getElementsByTagName( "*" ) : []; } return { set: set, expr: expr }; }; Sizzle.filter = function( expr, set, inplace, not ) { var match, anyFound, old = expr, result = [], curLoop = set, isXMLFilter = set && set[0] && Sizzle.isXML( set[0] ); while ( expr && set.length ) { for ( var type in Expr.filter ) { if ( (match = Expr.leftMatch[ type ].exec( expr )) != null && match[2] ) { var found, item, filter = Expr.filter[ type ], left = match[1]; anyFound = false; match.splice(1,1); if ( left.substr( left.length - 1 ) === "\\" ) { continue; } if ( curLoop === result ) { result = []; } if ( Expr.preFilter[ type ] ) { match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter ); if ( !match ) { anyFound = found = true; } else if ( match === true ) { continue; } } if ( match ) { for ( var i = 0; (item = curLoop[i]) != null; i++ ) { if ( item ) { found = filter( item, match, i, curLoop ); var pass = not ^ !!found; if ( inplace && found != null ) { if ( pass ) { anyFound = true; } else { curLoop[i] = false; } } else if ( pass ) { result.push( item ); anyFound = true; } } } } if ( found !== undefined ) { if ( !inplace ) { curLoop = result; } expr = expr.replace( Expr.match[ type ], "" ); if ( !anyFound ) { return []; } break; } } } // Improper expression if ( expr === old ) { if ( anyFound == null ) { Sizzle.error( expr ); } else { break; } } old = expr; } return curLoop; }; Sizzle.error = function( msg ) { throw "Syntax error, unrecognized expression: " + msg; }; var Expr = Sizzle.selectors = { order: [ "ID", "NAME", "TAG" ], match: { ID: /#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/, CLASS: /\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/, NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF\-]|\\.)+)['"]*\]/, ATTR: /\[\s*((?:[\w\u00c0-\uFFFF\-]|\\.)+)\s*(?:(\S?=)\s*(?:(['"])(.*?)\3|(#?(?:[\w\u00c0-\uFFFF\-]|\\.)*)|)|)\s*\]/, TAG: /^((?:[\w\u00c0-\uFFFF\*\-]|\\.)+)/, CHILD: /:(only|nth|last|first)-child(?:\(\s*(even|odd|(?:[+\-]?\d+|(?:[+\-]?\d*)?n\s*(?:[+\-]\s*\d+)?))\s*\))?/, POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^\-]|$)/, PSEUDO: /:((?:[\w\u00c0-\uFFFF\-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/ }, leftMatch: {}, attrMap: { "class": "className", "for": "htmlFor" }, attrHandle: { href: function( elem ) { return elem.getAttribute( "href" ); }, type: function( elem ) { return elem.getAttribute( "type" ); } }, relative: { "+": function(checkSet, part){ var isPartStr = typeof part === "string", isTag = isPartStr && !rNonWord.test( part ), isPartStrNotTag = isPartStr && !isTag; if ( isTag ) { part = part.toLowerCase(); } for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) { if ( (elem = checkSet[i]) ) { while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {} checkSet[i] = isPartStrNotTag || elem && elem.nodeName.toLowerCase() === part ? elem || false : elem === part; } } if ( isPartStrNotTag ) { Sizzle.filter( part, checkSet, true ); } }, ">": function( checkSet, part ) { var elem, isPartStr = typeof part === "string", i = 0, l = checkSet.length; if ( isPartStr && !rNonWord.test( part ) ) { part = part.toLowerCase(); for ( ; i < l; i++ ) { elem = checkSet[i]; if ( elem ) { var parent = elem.parentNode; checkSet[i] = parent.nodeName.toLowerCase() === part ? parent : false; } } } else { for ( ; i < l; i++ ) { elem = checkSet[i]; if ( elem ) { checkSet[i] = isPartStr ? elem.parentNode : elem.parentNode === part; } } if ( isPartStr ) { Sizzle.filter( part, checkSet, true ); } } }, "": function(checkSet, part, isXML){ var nodeCheck, doneName = done++, checkFn = dirCheck; if ( typeof part === "string" && !rNonWord.test( part ) ) { part = part.toLowerCase(); nodeCheck = part; checkFn = dirNodeCheck; } checkFn( "parentNode", part, doneName, checkSet, nodeCheck, isXML ); }, "~": function( checkSet, part, isXML ) { var nodeCheck, doneName = done++, checkFn = dirCheck; if ( typeof part === "string" && !rNonWord.test( part ) ) { part = part.toLowerCase(); nodeCheck = part; checkFn = dirNodeCheck; } checkFn( "previousSibling", part, doneName, checkSet, nodeCheck, isXML ); } }, find: { ID: function( match, context, isXML ) { if ( typeof context.getElementById !== "undefined" && !isXML ) { var m = context.getElementById(match[1]); // Check parentNode to catch when Blackberry 4.6 returns // nodes that are no longer in the document #6963 return m && m.parentNode ? [m] : []; } }, NAME: function( match, context ) { if ( typeof context.getElementsByName !== "undefined" ) { var ret = [], results = context.getElementsByName( match[1] ); for ( var i = 0, l = results.length; i < l; i++ ) { if ( results[i].getAttribute("name") === match[1] ) { ret.push( results[i] ); } } return ret.length === 0 ? null : ret; } }, TAG: function( match, context ) { if ( typeof context.getElementsByTagName !== "undefined" ) { return context.getElementsByTagName( match[1] ); } } }, preFilter: { CLASS: function( match, curLoop, inplace, result, not, isXML ) { match = " " + match[1].replace( rBackslash, "" ) + " "; if ( isXML ) { return match; } for ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) { if ( elem ) { if ( not ^ (elem.className && (" " + elem.className + " ").replace(/[\t\n\r]/g, " ").indexOf(match) >= 0) ) { if ( !inplace ) { result.push( elem ); } } else if ( inplace ) { curLoop[i] = false; } } } return false; }, ID: function( match ) { return match[1].replace( rBackslash, "" ); }, TAG: function( match, curLoop ) { return match[1].replace( rBackslash, "" ).toLowerCase(); }, CHILD: function( match ) { if ( match[1] === "nth" ) { if ( !match[2] ) { Sizzle.error( match[0] ); } match[2] = match[2].replace(/^\+|\s*/g, ''); // parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6' var test = /(-?)(\d*)(?:n([+\-]?\d*))?/.exec( match[2] === "even" && "2n" || match[2] === "odd" && "2n+1" || !/\D/.test( match[2] ) && "0n+" + match[2] || match[2]); // calculate the numbers (first)n+(last) including if they are negative match[2] = (test[1] + (test[2] || 1)) - 0; match[3] = test[3] - 0; } else if ( match[2] ) { Sizzle.error( match[0] ); } // TODO: Move to normal caching system match[0] = done++; return match; }, ATTR: function( match, curLoop, inplace, result, not, isXML ) { var name = match[1] = match[1].replace( rBackslash, "" ); if ( !isXML && Expr.attrMap[name] ) { match[1] = Expr.attrMap[name]; } // Handle if an un-quoted value was used match[4] = ( match[4] || match[5] || "" ).replace( rBackslash, "" ); if ( match[2] === "~=" ) { match[4] = " " + match[4] + " "; } return match; }, PSEUDO: function( match, curLoop, inplace, result, not ) { if ( match[1] === "not" ) { // If we're dealing with a complex expression, or a simple one if ( ( chunker.exec(match[3]) || "" ).length > 1 || /^\w/.test(match[3]) ) { match[3] = Sizzle(match[3], null, null, curLoop); } else { var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not); if ( !inplace ) { result.push.apply( result, ret ); } return false; } } else if ( Expr.match.POS.test( match[0] ) || Expr.match.CHILD.test( match[0] ) ) { return true; } return match; }, POS: function( match ) { match.unshift( true ); return match; } }, filters: { enabled: function( elem ) { return elem.disabled === false && elem.type !== "hidden"; }, disabled: function( elem ) { return elem.disabled === true; }, checked: function( elem ) { return elem.checked === true; }, selected: function( elem ) { // Accessing this property makes selected-by-default // options in Safari work properly if ( elem.parentNode ) { elem.parentNode.selectedIndex; } return elem.selected === true; }, parent: function( elem ) { return !!elem.firstChild; }, empty: function( elem ) { return !elem.firstChild; }, has: function( elem, i, match ) { return !!Sizzle( match[3], elem ).length; }, header: function( elem ) { return (/h\d/i).test( elem.nodeName ); }, text: function( elem ) { var attr = elem.getAttribute( "type" ), type = elem.type; // IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc) // use getAttribute instead to test this case return elem.nodeName.toLowerCase() === "input" && "text" === type && ( attr === type || attr === null ); }, radio: function( elem ) { return elem.nodeName.toLowerCase() === "input" && "radio" === elem.type; }, checkbox: function( elem ) { return elem.nodeName.toLowerCase() === "input" && "checkbox" === elem.type; }, file: function( elem ) { return elem.nodeName.toLowerCase() === "input" && "file" === elem.type; }, password: function( elem ) { return elem.nodeName.toLowerCase() === "input" && "password" === elem.type; }, submit: function( elem ) { var name = elem.nodeName.toLowerCase(); return (name === "input" || name === "button") && "submit" === elem.type; }, image: function( elem ) { return elem.nodeName.toLowerCase() === "input" && "image" === elem.type; }, reset: function( elem ) { var name = elem.nodeName.toLowerCase(); return (name === "input" || name === "button") && "reset" === elem.type; }, button: function( elem ) { var name = elem.nodeName.toLowerCase(); return name === "input" && "button" === elem.type || name === "button"; }, input: function( elem ) { return (/input|select|textarea|button/i).test( elem.nodeName ); }, focus: function( elem ) { return elem === elem.ownerDocument.activeElement; } }, setFilters: { first: function( elem, i ) { return i === 0; }, last: function( elem, i, match, array ) { return i === array.length - 1; }, even: function( elem, i ) { return i % 2 === 0; }, odd: function( elem, i ) { return i % 2 === 1; }, lt: function( elem, i, match ) { return i < match[3] - 0; }, gt: function( elem, i, match ) { return i > match[3] - 0; }, nth: function( elem, i, match ) { return match[3] - 0 === i; }, eq: function( elem, i, match ) { return match[3] - 0 === i; } }, filter: { PSEUDO: function( elem, match, i, array ) { var name = match[1], filter = Expr.filters[ name ]; if ( filter ) { return filter( elem, i, match, array ); } else if ( name === "contains" ) { return (elem.textContent || elem.innerText || Sizzle.getText([ elem ]) || "").indexOf(match[3]) >= 0; } else if ( name === "not" ) { var not = match[3]; for ( var j = 0, l = not.length; j < l; j++ ) { if ( not[j] === elem ) { return false; } } return true; } else { Sizzle.error( name ); } }, CHILD: function( elem, match ) { var type = match[1], node = elem; switch ( type ) { case "only": case "first": while ( (node = node.previousSibling) ) { if ( node.nodeType === 1 ) { return false; } } if ( type === "first" ) { return true; } node = elem; case "last": while ( (node = node.nextSibling) ) { if ( node.nodeType === 1 ) { return false; } } return true; case "nth": var first = match[2], last = match[3]; if ( first === 1 && last === 0 ) { return true; } var doneName = match[0], parent = elem.parentNode; if ( parent && (parent.sizcache !== doneName || !elem.nodeIndex) ) { var count = 0; for ( node = parent.firstChild; node; node = node.nextSibling ) { if ( node.nodeType === 1 ) { node.nodeIndex = ++count; } } parent.sizcache = doneName; } var diff = elem.nodeIndex - last; if ( first === 0 ) { return diff === 0; } else { return ( diff % first === 0 && diff / first >= 0 ); } } }, ID: function( elem, match ) { return elem.nodeType === 1 && elem.getAttribute("id") === match; }, TAG: function( elem, match ) { return (match === "*" && elem.nodeType === 1) || elem.nodeName.toLowerCase() === match; }, CLASS: function( elem, match ) { return (" " + (elem.className || elem.getAttribute("class")) + " ") .indexOf( match ) > -1; }, ATTR: function( elem, match ) { var name = match[1], result = Expr.attrHandle[ name ] ? Expr.attrHandle[ name ]( elem ) : elem[ name ] != null ? elem[ name ] : elem.getAttribute( name ), value = result + "", type = match[2], check = match[4]; return result == null ? type === "!=" : type === "=" ? value === check : type === "*=" ? value.indexOf(check) >= 0 : type === "~=" ? (" " + value + " ").indexOf(check) >= 0 : !check ? value && result !== false : type === "!=" ? value !== check : type === "^=" ? value.indexOf(check) === 0 : type === "$=" ? value.substr(value.length - check.length) === check : type === "|=" ? value === check || value.substr(0, check.length + 1) === check + "-" : false; }, POS: function( elem, match, i, array ) { var name = match[2], filter = Expr.setFilters[ name ]; if ( filter ) { return filter( elem, i, match, array ); } } } }; var origPOS = Expr.match.POS, fescape = function(all, num){ return "\\" + (num - 0 + 1); }; for ( var type in Expr.match ) { Expr.match[ type ] = new RegExp( Expr.match[ type ].source + (/(?![^\[]*\])(?![^\(]*\))/.source) ); Expr.leftMatch[ type ] = new RegExp( /(^(?:.|\r|\n)*?)/.source + Expr.match[ type ].source.replace(/\\(\d+)/g, fescape) ); } var makeArray = function( array, results ) { array = Array.prototype.slice.call( array, 0 ); if ( results ) { results.push.apply( results, array ); return results; } return array; }; // Perform a simple check to determine if the browser is capable of // converting a NodeList to an array using builtin methods. // Also verifies that the returned array holds DOM nodes // (which is not the case in the Blackberry browser) try { Array.prototype.slice.call( document.documentElement.childNodes, 0 )[0].nodeType; // Provide a fallback method if it does not work } catch( e ) { makeArray = function( array, results ) { var i = 0, ret = results || []; if ( toString.call(array) === "[object Array]" ) { Array.prototype.push.apply( ret, array ); } else { if ( typeof array.length === "number" ) { for ( var l = array.length; i < l; i++ ) { ret.push( array[i] ); } } else { for ( ; array[i]; i++ ) { ret.push( array[i] ); } } } return ret; }; } var sortOrder, siblingCheck; if ( document.documentElement.compareDocumentPosition ) { sortOrder = function( a, b ) { if ( a === b ) { hasDuplicate = true; return 0; } if ( !a.compareDocumentPosition || !b.compareDocumentPosition ) { return a.compareDocumentPosition ? -1 : 1; } return a.compareDocumentPosition(b) & 4 ? -1 : 1; }; } else { sortOrder = function( a, b ) { // The nodes are identical, we can exit early if ( a === b ) { hasDuplicate = true; return 0; // Fallback to using sourceIndex (in IE) if it's available on both nodes } else if ( a.sourceIndex && b.sourceIndex ) { return a.sourceIndex - b.sourceIndex; } var al, bl, ap = [], bp = [], aup = a.parentNode, bup = b.parentNode, cur = aup; // If the nodes are siblings (or identical) we can do a quick check if ( aup === bup ) { return siblingCheck( a, b ); // If no parents were found then the nodes are disconnected } else if ( !aup ) { return -1; } else if ( !bup ) { return 1; } // Otherwise they're somewhere else in the tree so we need // to build up a full list of the parentNodes for comparison while ( cur ) { ap.unshift( cur ); cur = cur.parentNode; } cur = bup; while ( cur ) { bp.unshift( cur ); cur = cur.parentNode; } al = ap.length; bl = bp.length; // Start walking down the tree looking for a discrepancy for ( var i = 0; i < al && i < bl; i++ ) { if ( ap[i] !== bp[i] ) { return siblingCheck( ap[i], bp[i] ); } } // We ended someplace up the tree so do a sibling check return i === al ? siblingCheck( a, bp[i], -1 ) : siblingCheck( ap[i], b, 1 ); }; siblingCheck = function( a, b, ret ) { if ( a === b ) { return ret; } var cur = a.nextSibling; while ( cur ) { if ( cur === b ) { return -1; } cur = cur.nextSibling; } return 1; }; } // Utility function for retreiving the text value of an array of DOM nodes Sizzle.getText = function( elems ) { var ret = "", elem; for ( var i = 0; elems[i]; i++ ) { elem = elems[i]; // Get the text from text nodes and CDATA nodes if ( elem.nodeType === 3 || elem.nodeType === 4 ) { ret += elem.nodeValue; // Traverse everything else, except comment nodes } else if ( elem.nodeType !== 8 ) { ret += Sizzle.getText( elem.childNodes ); } } return ret; }; // Check to see if the browser returns elements by name when // querying by getElementById (and provide a workaround) (function(){ // We're going to inject a fake input element with a specified name var form = document.createElement("div"), id = "script" + (new Date()).getTime(), root = document.documentElement; form.innerHTML = ""; // Inject it into the root element, check its status, and remove it quickly root.insertBefore( form, root.firstChild ); // The workaround has to do additional checks after a getElementById // Which slows things down for other browsers (hence the branching) if ( document.getElementById( id ) ) { Expr.find.ID = function( match, context, isXML ) { if ( typeof context.getElementById !== "undefined" && !isXML ) { var m = context.getElementById(match[1]); return m ? m.id === match[1] || typeof m.getAttributeNode !== "undefined" && m.getAttributeNode("id").nodeValue === match[1] ? [m] : undefined : []; } }; Expr.filter.ID = function( elem, match ) { var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id"); return elem.nodeType === 1 && node && node.nodeValue === match; }; } root.removeChild( form ); // release memory in IE root = form = null; })(); (function(){ // Check to see if the browser returns only elements // when doing getElementsByTagName("*") // Create a fake element var div = document.createElement("div"); div.appendChild( document.createComment("") ); // Make sure no comments are found if ( div.getElementsByTagName("*").length > 0 ) { Expr.find.TAG = function( match, context ) { var results = context.getElementsByTagName( match[1] ); // Filter out possible comments if ( match[1] === "*" ) { var tmp = []; for ( var i = 0; results[i]; i++ ) { if ( results[i].nodeType === 1 ) { tmp.push( results[i] ); } } results = tmp; } return results; }; } // Check to see if an attribute returns normalized href attributes div.innerHTML = ""; if ( div.firstChild && typeof div.firstChild.getAttribute !== "undefined" && div.firstChild.getAttribute("href") !== "#" ) { Expr.attrHandle.href = function( elem ) { return elem.getAttribute( "href", 2 ); }; } // release memory in IE div = null; })(); if ( document.querySelectorAll ) { (function(){ var oldSizzle = Sizzle, div = document.createElement("div"), id = "__sizzle__"; div.innerHTML = "

"; // Safari can't handle uppercase or unicode characters when // in quirks mode. if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) { return; } Sizzle = function( query, context, extra, seed ) { context = context || document; // Only use querySelectorAll on non-XML documents // (ID selectors don't work in non-HTML documents) if ( !seed && !Sizzle.isXML(context) ) { // See if we find a selector to speed up var match = /^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec( query ); if ( match && (context.nodeType === 1 || context.nodeType === 9) ) { // Speed-up: Sizzle("TAG") if ( match[1] ) { return makeArray( context.getElementsByTagName( query ), extra ); // Speed-up: Sizzle(".CLASS") } else if ( match[2] && Expr.find.CLASS && context.getElementsByClassName ) { return makeArray( context.getElementsByClassName( match[2] ), extra ); } } if ( context.nodeType === 9 ) { // Speed-up: Sizzle("body") // The body element only exists once, optimize finding it if ( query === "body" && context.body ) { return makeArray( [ context.body ], extra ); // Speed-up: Sizzle("#ID") } else if ( match && match[3] ) { var elem = context.getElementById( match[3] ); // Check parentNode to catch when Blackberry 4.6 returns // nodes that are no longer in the document #6963 if ( elem && elem.parentNode ) { // Handle the case where IE and Opera return items // by name instead of ID if ( elem.id === match[3] ) { return makeArray( [ elem ], extra ); } } else { return makeArray( [], extra ); } } try { return makeArray( context.querySelectorAll(query), extra ); } catch(qsaError) {} // qSA works strangely on Element-rooted queries // We can work around this by specifying an extra ID on the root // and working up from there (Thanks to Andrew Dupont for the technique) // IE 8 doesn't work on object elements } else if ( context.nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) { var oldContext = context, old = context.getAttribute( "id" ), nid = old || id, hasParent = context.parentNode, relativeHierarchySelector = /^\s*[+~]/.test( query ); if ( !old ) { context.setAttribute( "id", nid ); } else { nid = nid.replace( /'/g, "\\$&" ); } if ( relativeHierarchySelector && hasParent ) { context = context.parentNode; } try { if ( !relativeHierarchySelector || hasParent ) { return makeArray( context.querySelectorAll( "[id='" + nid + "'] " + query ), extra ); } } catch(pseudoError) { } finally { if ( !old ) { oldContext.removeAttribute( "id" ); } } } } return oldSizzle(query, context, extra, seed); }; for ( var prop in oldSizzle ) { Sizzle[ prop ] = oldSizzle[ prop ]; } // release memory in IE div = null; })(); } (function(){ var html = document.documentElement, matches = html.matchesSelector || html.mozMatchesSelector || html.webkitMatchesSelector || html.msMatchesSelector; if ( matches ) { // Check to see if it's possible to do matchesSelector // on a disconnected node (IE 9 fails this) var disconnectedMatch = !matches.call( document.createElement( "div" ), "div" ), pseudoWorks = false; try { // This should fail with an exception // Gecko does not error, returns false instead matches.call( document.documentElement, "[test!='']:sizzle" ); } catch( pseudoError ) { pseudoWorks = true; } Sizzle.matchesSelector = function( node, expr ) { // Make sure that attribute selectors are quoted expr = expr.replace(/\=\s*([^'"\]]*)\s*\]/g, "='$1']"); if ( !Sizzle.isXML( node ) ) { try { if ( pseudoWorks || !Expr.match.PSEUDO.test( expr ) && !/!=/.test( expr ) ) { var ret = matches.call( node, expr ); // IE 9's matchesSelector returns false on disconnected nodes if ( ret || !disconnectedMatch || // As well, disconnected nodes are said to be in a document // fragment in IE 9, so check for that node.document && node.document.nodeType !== 11 ) { return ret; } } } catch(e) {} } return Sizzle(expr, null, null, [node]).length > 0; }; } })(); (function(){ var div = document.createElement("div"); div.innerHTML = "
"; // Opera can't find a second classname (in 9.6) // Also, make sure that getElementsByClassName actually exists if ( !div.getElementsByClassName || div.getElementsByClassName("e").length === 0 ) { return; } // Safari caches class attributes, doesn't catch changes (in 3.2) div.lastChild.className = "e"; if ( div.getElementsByClassName("e").length === 1 ) { return; } Expr.order.splice(1, 0, "CLASS"); Expr.find.CLASS = function( match, context, isXML ) { if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) { return context.getElementsByClassName(match[1]); } }; // release memory in IE div = null; })(); function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { for ( var i = 0, l = checkSet.length; i < l; i++ ) { var elem = checkSet[i]; if ( elem ) { var match = false; elem = elem[dir]; while ( elem ) { if ( elem.sizcache === doneName ) { match = checkSet[elem.sizset]; break; } if ( elem.nodeType === 1 && !isXML ){ elem.sizcache = doneName; elem.sizset = i; } if ( elem.nodeName.toLowerCase() === cur ) { match = elem; break; } elem = elem[dir]; } checkSet[i] = match; } } } function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { for ( var i = 0, l = checkSet.length; i < l; i++ ) { var elem = checkSet[i]; if ( elem ) { var match = false; elem = elem[dir]; while ( elem ) { if ( elem.sizcache === doneName ) { match = checkSet[elem.sizset]; break; } if ( elem.nodeType === 1 ) { if ( !isXML ) { elem.sizcache = doneName; elem.sizset = i; } if ( typeof cur !== "string" ) { if ( elem === cur ) { match = true; break; } } else if ( Sizzle.filter( cur, [elem] ).length > 0 ) { match = elem; break; } } elem = elem[dir]; } checkSet[i] = match; } } } if ( document.documentElement.contains ) { Sizzle.contains = function( a, b ) { return a !== b && (a.contains ? a.contains(b) : true); }; } else if ( document.documentElement.compareDocumentPosition ) { Sizzle.contains = function( a, b ) { return !!(a.compareDocumentPosition(b) & 16); }; } else { Sizzle.contains = function() { return false; }; } Sizzle.isXML = function( elem ) { // documentElement is verified for cases where it doesn't yet exist // (such as loading iframes in IE - #4833) var documentElement = (elem ? elem.ownerDocument || elem : 0).documentElement; return documentElement ? documentElement.nodeName !== "HTML" : false; }; var posProcess = function( selector, context ) { var match, tmpSet = [], later = "", root = context.nodeType ? [context] : context; // Position selectors must be done after the filter // And so must :not(positional) so we move all PSEUDOs to the end while ( (match = Expr.match.PSEUDO.exec( selector )) ) { later += match[0]; selector = selector.replace( Expr.match.PSEUDO, "" ); } selector = Expr.relative[selector] ? selector + "*" : selector; for ( var i = 0, l = root.length; i < l; i++ ) { Sizzle( selector, root[i], tmpSet ); } return Sizzle.filter( later, tmpSet ); }; // EXPOSE jQuery.find = Sizzle; jQuery.expr = Sizzle.selectors; jQuery.expr[":"] = jQuery.expr.filters; jQuery.unique = Sizzle.uniqueSort; jQuery.text = Sizzle.getText; jQuery.isXMLDoc = Sizzle.isXML; jQuery.contains = Sizzle.contains; })(); var runtil = /Until$/, rparentsprev = /^(?:parents|prevUntil|prevAll)/, // Note: This RegExp should be improved, or likely pulled from Sizzle rmultiselector = /,/, isSimple = /^.[^:#\[\.,]*$/, slice = Array.prototype.slice, POS = jQuery.expr.match.POS, // methods guaranteed to produce a unique set when starting from a unique set guaranteedUnique = { children: true, contents: true, next: true, prev: true }; jQuery.fn.extend({ find: function( selector ) { var self = this, i, l; if ( typeof selector !== "string" ) { return jQuery( selector ).filter(function() { for ( i = 0, l = self.length; i < l; i++ ) { if ( jQuery.contains( self[ i ], this ) ) { return true; } } }); } var ret = this.pushStack( "", "find", selector ), length, n, r; for ( i = 0, l = this.length; i < l; i++ ) { length = ret.length; jQuery.find( selector, this[i], ret ); if ( i > 0 ) { // Make sure that the results are unique for ( n = length; n < ret.length; n++ ) { for ( r = 0; r < length; r++ ) { if ( ret[r] === ret[n] ) { ret.splice(n--, 1); break; } } } } } return ret; }, has: function( target ) { var targets = jQuery( target ); return this.filter(function() { for ( var i = 0, l = targets.length; i < l; i++ ) { if ( jQuery.contains( this, targets[i] ) ) { return true; } } }); }, not: function( selector ) { return this.pushStack( winnow(this, selector, false), "not", selector); }, filter: function( selector ) { return this.pushStack( winnow(this, selector, true), "filter", selector ); }, is: function( selector ) { return !!selector && ( typeof selector === "string" ? jQuery.filter( selector, this ).length > 0 : this.filter( selector ).length > 0 ); }, closest: function( selectors, context ) { var ret = [], i, l, cur = this[0]; // Array if ( jQuery.isArray( selectors ) ) { var match, selector, matches = {}, level = 1; if ( cur && selectors.length ) { for ( i = 0, l = selectors.length; i < l; i++ ) { selector = selectors[i]; if ( !matches[ selector ] ) { matches[ selector ] = POS.test( selector ) ? jQuery( selector, context || this.context ) : selector; } } while ( cur && cur.ownerDocument && cur !== context ) { for ( selector in matches ) { match = matches[ selector ]; if ( match.jquery ? match.index( cur ) > -1 : jQuery( cur ).is( match ) ) { ret.push({ selector: selector, elem: cur, level: level }); } } cur = cur.parentNode; level++; } } return ret; } // String var pos = POS.test( selectors ) || typeof selectors !== "string" ? jQuery( selectors, context || this.context ) : 0; for ( i = 0, l = this.length; i < l; i++ ) { cur = this[i]; while ( cur ) { if ( pos ? pos.index(cur) > -1 : jQuery.find.matchesSelector(cur, selectors) ) { ret.push( cur ); break; } else { cur = cur.parentNode; if ( !cur || !cur.ownerDocument || cur === context || cur.nodeType === 11 ) { break; } } } } ret = ret.length > 1 ? jQuery.unique( ret ) : ret; return this.pushStack( ret, "closest", selectors ); }, // Determine the position of an element within // the matched set of elements index: function( elem ) { // No argument, return index in parent if ( !elem ) { return ( this[0] && this[0].parentNode ) ? this.prevAll().length : -1; } // index in selector if ( typeof elem === "string" ) { return jQuery.inArray( this[0], jQuery( elem ) ); } // Locate the position of the desired element return jQuery.inArray( // If it receives a jQuery object, the first element is used elem.jquery ? elem[0] : elem, this ); }, add: function( selector, context ) { var set = typeof selector === "string" ? jQuery( selector, context ) : jQuery.makeArray( selector && selector.nodeType ? [ selector ] : selector ), all = jQuery.merge( this.get(), set ); return this.pushStack( isDisconnected( set[0] ) || isDisconnected( all[0] ) ? all : jQuery.unique( all ) ); }, andSelf: function() { return this.add( this.prevObject ); } }); // A painfully simple check to see if an element is disconnected // from a document (should be improved, where feasible). function isDisconnected( node ) { return !node || !node.parentNode || node.parentNode.nodeType === 11; } jQuery.each({ parent: function( elem ) { var parent = elem.parentNode; return parent && parent.nodeType !== 11 ? parent : null; }, parents: function( elem ) { return jQuery.dir( elem, "parentNode" ); }, parentsUntil: function( elem, i, until ) { return jQuery.dir( elem, "parentNode", until ); }, next: function( elem ) { return jQuery.nth( elem, 2, "nextSibling" ); }, prev: function( elem ) { return jQuery.nth( elem, 2, "previousSibling" ); }, nextAll: function( elem ) { return jQuery.dir( elem, "nextSibling" ); }, prevAll: function( elem ) { return jQuery.dir( elem, "previousSibling" ); }, nextUntil: function( elem, i, until ) { return jQuery.dir( elem, "nextSibling", until ); }, prevUntil: function( elem, i, until ) { return jQuery.dir( elem, "previousSibling", until ); }, siblings: function( elem ) { return jQuery.sibling( elem.parentNode.firstChild, elem ); }, children: function( elem ) { return jQuery.sibling( elem.firstChild ); }, contents: function( elem ) { return jQuery.nodeName( elem, "iframe" ) ? elem.contentDocument || elem.contentWindow.document : jQuery.makeArray( elem.childNodes ); } }, function( name, fn ) { jQuery.fn[ name ] = function( until, selector ) { var ret = jQuery.map( this, fn, until ), // The variable 'args' was introduced in // https://github.com/jquery/jquery/commit/52a0238 // to work around a bug in Chrome 10 (Dev) and should be removed when the bug is fixed. // http://code.google.com/p/v8/issues/detail?id=1050 args = slice.call(arguments); if ( !runtil.test( name ) ) { selector = until; } if ( selector && typeof selector === "string" ) { ret = jQuery.filter( selector, ret ); } ret = this.length > 1 && !guaranteedUnique[ name ] ? jQuery.unique( ret ) : ret; if ( (this.length > 1 || rmultiselector.test( selector )) && rparentsprev.test( name ) ) { ret = ret.reverse(); } return this.pushStack( ret, name, args.join(",") ); }; }); jQuery.extend({ filter: function( expr, elems, not ) { if ( not ) { expr = ":not(" + expr + ")"; } return elems.length === 1 ? jQuery.find.matchesSelector(elems[0], expr) ? [ elems[0] ] : [] : jQuery.find.matches(expr, elems); }, dir: function( elem, dir, until ) { var matched = [], cur = elem[ dir ]; while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) { if ( cur.nodeType === 1 ) { matched.push( cur ); } cur = cur[dir]; } return matched; }, nth: function( cur, result, dir, elem ) { result = result || 1; var num = 0; for ( ; cur; cur = cur[dir] ) { if ( cur.nodeType === 1 && ++num === result ) { break; } } return cur; }, sibling: function( n, elem ) { var r = []; for ( ; n; n = n.nextSibling ) { if ( n.nodeType === 1 && n !== elem ) { r.push( n ); } } return r; } }); // Implement the identical functionality for filter and not function winnow( elements, qualifier, keep ) { // Can't pass null or undefined to indexOf in Firefox 4 // Set to 0 to skip string check qualifier = qualifier || 0; if ( jQuery.isFunction( qualifier ) ) { return jQuery.grep(elements, function( elem, i ) { var retVal = !!qualifier.call( elem, i, elem ); return retVal === keep; }); } else if ( qualifier.nodeType ) { return jQuery.grep(elements, function( elem, i ) { return (elem === qualifier) === keep; }); } else if ( typeof qualifier === "string" ) { var filtered = jQuery.grep(elements, function( elem ) { return elem.nodeType === 1; }); if ( isSimple.test( qualifier ) ) { return jQuery.filter(qualifier, filtered, !keep); } else { qualifier = jQuery.filter( qualifier, filtered ); } } return jQuery.grep(elements, function( elem, i ) { return (jQuery.inArray( elem, qualifier ) >= 0) === keep; }); } var rinlinejQuery = / jQuery\d+="(?:\d+|null)"/g, rleadingWhitespace = /^\s+/, rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig, rtagName = /<([\w:]+)/, rtbody = /", "" ], legend: [ 1, "
", "
" ], thead: [ 1, "", "
" ], tr: [ 2, "", "
" ], td: [ 3, "", "
" ], col: [ 2, "", "
" ], area: [ 1, "", "" ], _default: [ 0, "", "" ] }; wrapMap.optgroup = wrapMap.option; wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; wrapMap.th = wrapMap.td; // IE can't serialize and
run: cubes

Installation

The CoffeeScript compiler is itself written in CoffeeScript, using the Jison parser generator. The command-line version of coffee is available as a Node.js utility. The core compiler however, does not depend on Node, and can be run in any JavaScript environment, or in the browser (see "Try CoffeeScript", above).

To install, first make sure you have a working copy of the latest stable version of Node.js, and npm (the Node Package Manager). You can then install CoffeeScript with npm:

npm install -g coffee-script

(Leave off the -g if you don't wish to install globally.)

If you'd prefer to install the latest master version of CoffeeScript, you can clone the CoffeeScript source repository from GitHub, or download the source directly. To install the lastest master CoffeeScript compiler with npm:

npm install -g http://github.com/jashkenas/coffee-script/tarball/master

Or, if you want to install to /usr/local, and don't want to use npm to manage it, open the coffee-script directory and run:

sudo bin/cake install

Usage

Once installed, you should have access to the coffee command, which can execute scripts, compile .coffee files into .js, and provide an interactive REPL. The coffee command takes the following options:

-c, --compile Compile a .coffee script into a .js JavaScript file of the same name.
-i, --interactive Launch an interactive CoffeeScript session to try short snippets. Identical to calling coffee with no arguments.
-o, --output [DIR] Write out all compiled JavaScript files into the specified directory. Use in conjunction with --compile or --watch.
-j, --join [FILE] Before compiling, concatenate all scripts together in the order they were passed, and write them into the specified file. Useful for building large projects.
-w, --watch Watch files for changes, rerunning the specified command when any file is updated.
-p, --print Instead of writing out the JavaScript as a file, print it directly to stdout.
-l, --lint If the jsl (JavaScript Lint) command is installed, use it to check the compilation of a CoffeeScript file. (Handy in conjunction with
--watch)
-s, --stdio Pipe in CoffeeScript to STDIN and get back JavaScript over STDOUT. Good for use with processes written in other languages. An example:
cat src/cake.coffee | coffee -sc
-e, --eval Compile and print a little snippet of CoffeeScript directly from the command line. For example:
coffee -e "console.log num for num in [10..1]"
-r, --require Load a library before compiling or executing your script. Can be used to hook in to the compiler (to add Growl notifications, for example).
-b, --bare Compile the JavaScript without the top-level function safety wrapper.
-t, --tokens Instead of parsing the CoffeeScript, just lex it, and print out the token stream: [IDENTIFIER square] [ASSIGN =] [PARAM_START (] ...
-n, --nodes Instead of compiling the CoffeeScript, just lex and parse it, and print out the parse tree:
Expressions
  Assign
    Value "square"
    Code "x"
      Op *
        Value "x"
        Value "x"
--nodejs The node executable has some useful options you can set, such as
--debug, --debug-brk and --max-stack-size. Use this flag to forward options directly to Node.js.

Examples:

  • Compile a directory tree of .coffee files in src into a parallel tree of .js files in lib:
    coffee --compile --output lib/ src/
  • Watch a file for changes, and recompile it every time the file is saved:
    coffee --watch --compile experimental.coffee
  • Concatenate a list of files into a single script:
    coffee --join project.js --compile src/*.coffee
  • Print out the compiled JS from a one-liner:
    coffee -bpe "alert i for i in [0..10]"
  • All together now, watch and recompile an entire project as you work on it:
    coffee -o lib/ -cw src/
  • Start the CoffeeScript REPL (Ctrl-D to exit, Ctrl-Vfor multi-line):
    coffee

Language Reference

This reference is structured so that it can be read from top to bottom, if you like. Later sections use ideas and syntax previously introduced. Familiarity with JavaScript is assumed. In all of the following examples, the source CoffeeScript is provided on the left, and the direct compilation into JavaScript is on the right.

Many of the examples can be run (where it makes sense) by pressing the run button on the right, and can be loaded into the "Try CoffeeScript" console by pressing the load button on the left.

First, the basics: CoffeeScript uses significant whitespace to delimit blocks of code. You don't need to use semicolons ; to terminate expressions, ending the line will do just as well (although semicolons can still be used to fit multiple expressions onto a single line). Instead of using curly braces { } to surround blocks of code in functions, if-statements, switch, and try/catch, use indentation.

You don't need to use parentheses to invoke a function if you're passing arguments. The implicit call wraps forward to the end of the line or block expression.
console.log sys.inspect objectconsole.log(sys.inspect(object));

Functions Functions are defined by an optional list of parameters in parentheses, an arrow, and the function body. The empty function looks like this: ->

square = (x) -> x * x
cube   = (x) -> square(x) * x
var cube, square;

square = function(x) {
  return x * x;
};

cube = function(x) {
  return square(x) * x;
};
load
run: cube(5)

Functions may also have default values for arguments. Override the default value by passing a non-null argument.

fill = (container, liquid = "coffee") ->
  "Filling the #{container} with #{liquid}..."






var fill;

fill = function(container, liquid) {
  if (liquid == null) {
    liquid = "coffee";
  }
  return "Filling the " + container + " with " + liquid + "...";
};
load
run: fill("cup")

Objects and Arrays The CoffeeScript literals for objects and arrays look very similar to their JavaScript cousins. When each property is listed on its own line, the commas are optional. Objects may be created using indentation instead of explicit braces, similar to YAML.

song = ["do", "re", "mi", "fa", "so"]

singers = {Jagger: "Rock", Elvis: "Roll"}

bitlist = [
  1, 0, 1
  0, 0, 1
  1, 1, 0
]

kids =
  brother:
    name: "Max"
    age:  11
  sister:
    name: "Ida"
    age:  9


var bitlist, kids, singers, song;

song = ["do", "re", "mi", "fa", "so"];

singers = {
  Jagger: "Rock",
  Elvis: "Roll"
};

bitlist = [1, 0, 1, 0, 0, 1, 1, 1, 0];

kids = {
  brother: {
    name: "Max",
    age: 11
  },
  sister: {
    name: "Ida",
    age: 9
  }
};
load
run: song.join(" ... ")

In JavaScript, you can't use reserved words, like class, as properties of an object, without quoting them as strings. CoffeeScript notices reserved words used as keys in objects and quotes them for you, so you don't have to worry about it (say, when using jQuery).

$('.account').attr class: 'active'

log object.class


$('.account').attr({
  "class": 'active'
});

log(object["class"]);
load

Lexical Scoping and Variable Safety The CoffeeScript compiler takes care to make sure that all of your variables are properly declared within lexical scope — you never need to write var yourself.

outer = 1
changeNumbers = ->
  inner = -1
  outer = 10
inner = changeNumbers()
var changeNumbers, inner, outer;

outer = 1;

changeNumbers = function() {
  var inner;
  inner = -1;
  return outer = 10;
};

inner = changeNumbers();
load
run: inner

Notice how all of the variable declarations have been pushed up to the top of the closest scope, the first time they appear. outer is not redeclared within the inner function, because it's already in scope; inner within the function, on the other hand, should not be able to change the value of the external variable of the same name, and therefore has a declaration of its own.

This behavior is effectively identical to Ruby's scope for local variables. Because you don't have direct access to the var keyword, it's impossible to shadow an outer variable on purpose, you may only refer to it. So be careful that you're not reusing the name of an external variable accidentally, if you're writing a deeply nested function.

Although suppressed within this documentation for clarity, all CoffeeScript output is wrapped in an anonymous function: (function(){ ... })(); This safety wrapper, combined with the automatic generation of the var keyword, make it exceedingly difficult to pollute the global namespace by accident.

If you'd like to create top-level variables for other scripts to use, attach them as properties on window, or on the exports object in CommonJS. The existential operator (covered below), gives you a reliable way to figure out where to add them; if you're targeting both CommonJS and the browser: exports ? this

If, Else, Unless, and Conditional Assignment If/else statements can be written without the use of parentheses and curly brackets. As with functions and other block expressions, multi-line conditionals are delimited by indentation. There's also a handy postfix form, with the if or unless at the end.

CoffeeScript can compile if statements into JavaScript expressions, using the ternary operator when possible, and closure wrapping otherwise. There is no explicit ternary statement in CoffeeScript — you simply use a regular if statement on a single line.

mood = greatlyImproved if singing

if happy and knowsIt
  clapsHands()
  chaChaCha()
else
  showIt()

date = if friday then sue else jill



var date, mood;

if (singing) {
  mood = greatlyImproved;
}

if (happy && knowsIt) {
  clapsHands();
  chaChaCha();
} else {
  showIt();
}

date = friday ? sue : jill;
load

Splats... The JavaScript arguments object is a useful way to work with functions that accept variable numbers of arguments. CoffeeScript provides splats ..., both for function definition as well as invocation, making variable numbers of arguments a little bit more palatable.

gold = silver = rest = "unknown"

awardMedals = (first, second, others...) ->
  gold   = first
  silver = second
  rest   = others

contenders = [
  "Michael Phelps"
  "Liu Xiang"
  "Yao Ming"
  "Allyson Felix"
  "Shawn Johnson"
  "Roman Sebrle"
  "Guo Jingjing"
  "Tyson Gay"
  "Asafa Powell"
  "Usain Bolt"
]

awardMedals contenders...

alert "Gold: " + gold
alert "Silver: " + silver
alert "The Field: " + rest


var awardMedals, contenders, gold, rest, silver,
  __slice = [].slice;

gold = silver = rest = "unknown";

awardMedals = function() {
  var first, others, second;
  first = arguments[0], second = arguments[1], others = 3 <= arguments.length ? __slice.call(arguments, 2) : [];
  gold = first;
  silver = second;
  return rest = others;
};

contenders = ["Michael Phelps", "Liu Xiang", "Yao Ming", "Allyson Felix", "Shawn Johnson", "Roman Sebrle", "Guo Jingjing", "Tyson Gay", "Asafa Powell", "Usain Bolt"];

awardMedals.apply(null, contenders);

alert("Gold: " + gold);

alert("Silver: " + silver);

alert("The Field: " + rest);
load
run

Loops and Comprehensions Most of the loops you'll write in CoffeeScript will be comprehensions over arrays, objects, and ranges. Comprehensions replace (and compile into) for loops, with optional guard clauses and the value of the current array index. Unlike for loops, array comprehensions are expressions, and can be returned and assigned.

# Eat lunch.
eat food for food in ['toast', 'cheese', 'wine']

# Fine five course dining.
courses = ['greens', 'caviar', 'truffles', 'roast', 'cake']
menu i + 1, dish for dish, i in courses

# Health conscious meal.
foods = ['broccoli', 'spinach', 'chocolate']
eat food for food in foods when food isnt 'chocolate'
var courses, dish, food, foods, i, _i, _j, _k, _len, _len1, _len2, _ref;

_ref = ['toast', 'cheese', 'wine'];
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
  food = _ref[_i];
  eat(food);
}

courses = ['greens', 'caviar', 'truffles', 'roast', 'cake'];

for (i = _j = 0, _len1 = courses.length; _j < _len1; i = ++_j) {
  dish = courses[i];
  menu(i + 1, dish);
}

foods = ['broccoli', 'spinach', 'chocolate'];

for (_k = 0, _len2 = foods.length; _k < _len2; _k++) {
  food = foods[_k];
  if (food !== 'chocolate') {
    eat(food);
  }
}
load

Comprehensions should be able to handle most places where you otherwise would use a loop, each/forEach, map, or select/filter, for example: shortNames = (name for name in list when name.length < 5)
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.

countdown = (num for num in [10..1])

var countdown, num;

countdown = (function() {
  var _i, _results;
  _results = [];
  for (num = _i = 10; _i >= 1; num = --_i) {
    _results.push(num);
  }
  return _results;
})();
load
run: countdown

Note how because we are assigning the value of the comprehensions to a variable in the example above, CoffeeScript is collecting the result of each iteration into an array. Sometimes functions end with loops that are intended to run only for their side-effects. Be careful that you're not accidentally returning the results of the comprehension in these cases, by adding a meaningful return value — like true — or null, to the bottom of your function.

To step through a range comprehension in fixed-size chunks, use by, for example:
evens = (x for x in [0..10] by 2)

Comprehensions can also be used to iterate over the keys and values in an object. Use of to signal comprehension over the properties of an object instead of the values in an array.

yearsOld = max: 10, ida: 9, tim: 11

ages = for child, age of yearsOld
  "#{child} is #{age}"
var age, ages, child, yearsOld;

yearsOld = {
  max: 10,
  ida: 9,
  tim: 11
};

ages = (function() {
  var _results;
  _results = [];
  for (child in yearsOld) {
    age = yearsOld[child];
    _results.push("" + child + " is " + age);
  }
  return _results;
})();
load
run: ages.join(", ")

If you would like to iterate over just the keys that are defined on the object itself, by adding a hasOwnProperty check to avoid properties that may be inherited from the prototype, use
for own key, value of object

The only low-level loop that CoffeeScript provides is the while loop. The main difference from JavaScript is that the while loop can be used as an expression, returning an array containing the result of each iteration through the loop.

# Econ 101
if this.studyingEconomics
  buy()  while supply > demand
  sell() until supply > demand

# Nursery Rhyme
num = 6
lyrics = while num -= 1
  "#{num} little monkeys, jumping on the bed.
    One fell out and bumped his head."
var lyrics, num;

if (this.studyingEconomics) {
  while (supply > demand) {
    buy();
  }
  while (!(supply > demand)) {
    sell();
  }
}

num = 6;

lyrics = (function() {
  var _results;
  _results = [];
  while (num -= 1) {
    _results.push("" + num + " little monkeys, jumping on the bed.    One fell out and bumped his head.");
  }
  return _results;
})();
load
run: lyrics.join("\n")

For readability, the until keyword is equivalent to while not, and the loop keyword is equivalent to while true.

When using a JavaScript loop to generate functions, it's common to insert a closure wrapper in order to ensure that loop variables are closed over, and all the generated functions don't just share the final values. CoffeeScript provides the do keyword, which immediately invokes a passed function, forwarding any arguments.

for filename in list
  do (filename) ->
    fs.readFile filename, (err, contents) ->
      compile filename, contents.toString()
var filename, _fn, _i, _len;

_fn = function(filename) {
  return fs.readFile(filename, function(err, contents) {
    return compile(filename, contents.toString());
  });
};
for (_i = 0, _len = list.length; _i < _len; _i++) {
  filename = list[_i];
  _fn(filename);
}
load

Array Slicing and Splicing with Ranges Ranges can also be used to extract slices of arrays. With two dots (3..6), the range is inclusive (3, 4, 5, 6); with three dots (3...6), the range excludes the end (3, 4, 5). Slices indices have useful defaults. An omitted first index defaults to zero and an omitted second index defaults to the size of the array.

numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9]

start   = numbers[0..2]

middle  = numbers[3...6]

end     = numbers[6..]

copy    = numbers[..]
var copy, end, middle, numbers, start;

numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9];

start = numbers.slice(0, 3);

middle = numbers.slice(3, 6);

end = numbers.slice(6);

copy = numbers.slice(0);
load
run: middle

The same syntax can be used with assignment to replace a segment of an array with new values, splicing it.

numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

numbers[3..6] = [-3, -4, -5, -6]



 
var numbers, _ref;

numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];

[].splice.apply(numbers, [3, 4].concat(_ref = [-3, -4, -5, -6])), _ref;
load
run: numbers

Note that JavaScript strings are immutable, and can't be spliced.

Everything is an Expression (at least, as much as possible) You might have noticed how even though we don't add return statements to CoffeeScript functions, they nonetheless return their final value. The CoffeeScript compiler tries to make sure that all statements in the language can be used as expressions. Watch how the return gets pushed down into each possible branch of execution in the function below.

grade = (student) ->
  if student.excellentWork
    "A+"
  else if student.okayStuff
    if student.triedHard then "B" else "B-"
  else
    "C"

eldest = if 24 > 21 then "Liz" else "Ike"
var eldest, grade;

grade = function(student) {
  if (student.excellentWork) {
    return "A+";
  } else if (student.okayStuff) {
    if (student.triedHard) {
      return "B";
    } else {
      return "B-";
    }
  } else {
    return "C";
  }
};

eldest = 24 > 21 ? "Liz" : "Ike";
load
run: eldest

Even though functions will always return their final value, it's both possible and encouraged to return early from a function body writing out the explicit return (return value), when you know that you're done.

Because variable declarations occur at the top of scope, assignment can be used within expressions, even for variables that haven't been seen before:

six = (one = 1) + (two = 2) + (three = 3)


var one, six, three, two;

six = (one = 1) + (two = 2) + (three = 3);
load
run: six

Things that would otherwise be statements in JavaScript, when used as part of an expression in CoffeeScript, are converted into expressions by wrapping them in a closure. This lets you do useful things, like assign the result of a comprehension to a variable:

# The first ten global properties.

globals = (name for name of window)[0...10]
var globals, name;

globals = ((function() {
  var _results;
  _results = [];
  for (name in window) {
    _results.push(name);
  }
  return _results;
})()).slice(0, 10);
load
run: globals

As well as silly things, like passing a try/catch statement directly into a function call:

alert(
  try
    nonexistent / undefined
  catch error
    "And the error is ... #{error}"
)

alert((function() {
  try {
    return nonexistent / void 0;
  } catch (error) {
    return "And the error is ... " + error;
  }
})());
load
run

There are a handful of statements in JavaScript that can't be meaningfully converted into expressions, namely break, continue, and return. If you make use of them within a block of code, CoffeeScript won't try to perform the conversion.

Operators and Aliases Because the == operator frequently causes undesirable coercion, is intransitive, and has a different meaning than in other languages, CoffeeScript compiles == into ===, and != into !==. In addition, is compiles into ===, and isnt into !==.

You can use not as an alias for !.

For logic, and compiles to &&, and or into ||.

Instead of a newline or semicolon, then can be used to separate conditions from expressions, in while, if/else, and switch/when statements.

As in YAML, on and yes are the same as boolean true, while off and no are boolean false.

unless can be used as the inverse of if.

As a shortcut for this.property, you can use @property.

You can use in to test for array presence, and of to test for JavaScript object-key presence.

All together now:

CoffeeScriptJavaScript
is===
isnt!==
not!
and&&
or||
true, yes, ontrue
false, no, offfalse
@, thisthis
ofin
inno JS equivalent
launch() if ignition is on

volume = 10 if band isnt SpinalTap

letTheWildRumpusBegin() unless answer is no

if car.speed < limit then accelerate()

winner = yes if pick in [47, 92, 13]

print inspect "My name is #{@name}"
var volume, winner;

if (ignition === true) {
  launch();
}

if (band !== SpinalTap) {
  volume = 10;
}

if (answer !== false) {
  letTheWildRumpusBegin();
}

if (car.speed < limit) {
  accelerate();
}

if (pick === 47 || pick === 92 || pick === 13) {
  winner = true;
}

print(inspect("My name is " + this.name));
load

The Existential Operator It's a little difficult to check for the existence of a variable in JavaScript. if (variable) ... comes close, but fails for zero, the empty string, and false. CoffeeScript's existential operator ? returns true unless a variable is null or undefined, which makes it analogous to Ruby's nil?

It can also be used for safer conditional assignment than ||= provides, for cases where you may be handling numbers or strings.

solipsism = true if mind? and not world?

speed = 0
speed ?= 15

footprints = yeti ? "bear"






 
var footprints, solipsism, speed;

if ((typeof mind !== "undefined" && mind !== null) && !(typeof world !== "undefined" && world !== null)) {
  solipsism = true;
}

speed = 0;

if (speed == null) {
  speed = 15;
}

footprints = typeof yeti !== "undefined" && yeti !== null ? yeti : "bear";
load
run: footprints

The accessor variant of the existential operator ?. can be used to soak up null references in a chain of properties. Use it instead of the dot accessor . in cases where the base value may be null or undefined. If all of the properties exist then you'll get the expected result, if the chain is broken, undefined is returned instead of the TypeError that would be raised otherwise.

zip = lottery.drawWinner?().address?.zipcode
var zip, _ref;

zip = typeof lottery.drawWinner === "function" ? (_ref = lottery.drawWinner().address) != null ? _ref.zipcode : void 0 : void 0;
load

Soaking up nulls is similar to Ruby's andand gem, and to the safe navigation operator in Groovy.

Classes, Inheritance, and Super JavaScript's prototypal inheritance has always been a bit of a brain-bender, with a whole family tree of libraries that provide a cleaner syntax for classical inheritance on top of JavaScript's prototypes: Base2, Prototype.js, JS.Class, etc. The libraries provide syntactic sugar, but the built-in inheritance would be completely usable if it weren't for a couple of small exceptions: it's awkward to call super (the prototype object's implementation of the current function), and it's awkward to correctly set the prototype chain.

Instead of repetitively attaching functions to a prototype, CoffeeScript provides a basic class structure that allows you to name your class, set the superclass, assign prototypal properties, and define the constructor, in a single assignable expression.

Constructor functions are named, to better support helpful stack traces. In the first class in the example below, this.constructor.name is "Animal".

class Animal
  constructor: (@name) ->

  move: (meters) ->
    alert @name + " moved #{meters}m."

class Snake extends Animal
  move: ->
    alert "Slithering..."
    super 5

class Horse extends Animal
  move: ->
    alert "Galloping..."
    super 45

sam = new Snake "Sammy the Python"
tom = new Horse "Tommy the Palomino"

sam.move()
tom.move()




var Animal, Horse, Snake, sam, tom,
  __hasProp = {}.hasOwnProperty,
  __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };

Animal = (function() {

  function Animal(name) {
    this.name = name;
  }

  Animal.prototype.move = function(meters) {
    return alert(this.name + (" moved " + meters + "m."));
  };

  return Animal;

})();

Snake = (function(_super) {

  __extends(Snake, _super);

  function Snake() {
    return Snake.__super__.constructor.apply(this, arguments);
  }

  Snake.prototype.move = function() {
    alert("Slithering...");
    return Snake.__super__.move.call(this, 5);
  };

  return Snake;

})(Animal);

Horse = (function(_super) {

  __extends(Horse, _super);

  function Horse() {
    return Horse.__super__.constructor.apply(this, arguments);
  }

  Horse.prototype.move = function() {
    alert("Galloping...");
    return Horse.__super__.move.call(this, 45);
  };

  return Horse;

})(Animal);

sam = new Snake("Sammy the Python");

tom = new Horse("Tommy the Palomino");

sam.move();

tom.move();
load
run

If structuring your prototypes classically isn't your cup of tea, CoffeeScript provides a couple of lower-level conveniences. The extends operator helps with proper prototype setup, and can be used to create an inheritance chain between any pair of constructor functions; :: gives you quick access to an object's prototype; and super() is converted into a call against the immediate ancestor's method of the same name.

String::dasherize = ->
  this.replace /_/g, "-"

String.prototype.dasherize = function() {
  return this.replace(/_/g, "-");
};
load
run: "one_two".dasherize()

Finally, class definitions are blocks of executable code, which make for interesting metaprogramming possibilities. Because in the context of a class definition, this is the class object itself (the constructor function), you can assign static properties by using
@property: value, and call functions defined in parent classes: @attr 'title', type: 'text'

Destructuring Assignment To make extracting values from complex arrays and objects more convenient, CoffeeScript implements ECMAScript Harmony's proposed destructuring assignment syntax. When you assign an array or object literal to a value, CoffeeScript breaks up and matches both sides against each other, assigning the values on the right to the variables on the left. In the simplest case, it can be used for parallel assignment:

theBait   = 1000
theSwitch = 0

[theBait, theSwitch] = [theSwitch, theBait]




 
var theBait, theSwitch, _ref;

theBait = 1000;

theSwitch = 0;

_ref = [theSwitch, theBait], theBait = _ref[0], theSwitch = _ref[1];
load
run: theBait

But it's also helpful for dealing with functions that return multiple values.

weatherReport = (location) ->
  # Make an Ajax request to fetch the weather...
  [location, 72, "Mostly Sunny"]

[city, temp, forecast] = weatherReport "Berkeley, CA"




var city, forecast, temp, weatherReport, _ref;

weatherReport = function(location) {
  return [location, 72, "Mostly Sunny"];
};

_ref = weatherReport("Berkeley, CA"), city = _ref[0], temp = _ref[1], forecast = _ref[2];
load
run: forecast

Destructuring assignment can be used with any depth of array and object nesting, to help pull out deeply nested properties.

futurists =
  sculptor: "Umberto Boccioni"
  painter:  "Vladimir Burliuk"
  poet:
    name:   "F.T. Marinetti"
    address: [
      "Via Roma 42R"
      "Bellagio, Italy 22021"
    ]

{poet: {name, address: [street, city]}} = futurists



var city, futurists, name, street, _ref, _ref1;

futurists = {
  sculptor: "Umberto Boccioni",
  painter: "Vladimir Burliuk",
  poet: {
    name: "F.T. Marinetti",
    address: ["Via Roma 42R", "Bellagio, Italy 22021"]
  }
};

_ref = futurists.poet, name = _ref.name, (_ref1 = _ref.address, street = _ref1[0], city = _ref1[1]);
load
run: name + " — " + street

Destructuring assignment can even be combined with splats.

tag = "<impossible>"

[open, contents..., close] = tag.split("")






var close, contents, open, tag, _i, _ref,
  __slice = [].slice;

tag = "<impossible>";

_ref = tag.split(""), open = _ref[0], contents = 3 <= _ref.length ? __slice.call(_ref, 1, _i = _ref.length - 1) : (_i = 1, []), close = _ref[_i++];
load
run: contents.join("")

Function binding In JavaScript, the this keyword is dynamically scoped to mean the object that the current function is attached to. If you pass a function as a callback or attach it to a different object, the original value of this will be lost. If you're not familiar with this behavior, this Digital Web article gives a good overview of the quirks.

The fat arrow => can be used to both define a function, and to bind it to the current value of this, right on the spot. This is helpful when using callback-based libraries like Prototype or jQuery, for creating iterator functions to pass to each, or event-handler functions to use with bind. Functions created with the fat arrow are able to access properties of the this where they're defined.

Account = (customer, cart) ->
  @customer = customer
  @cart = cart

  $('.shopping_cart').bind 'click', (event) =>
    @customer.purchase @cart
var Account;

Account = function(customer, cart) {
  var _this = this;
  this.customer = customer;
  this.cart = cart;
  return $('.shopping_cart').bind('click', function(event) {
    return _this.customer.purchase(_this.cart);
  });
};
load

If we had used -> in the callback above, @customer would have referred to the undefined "customer" property of the DOM element, and trying to call purchase() on it would have raised an exception.

When used in a class definition, methods declared with the fat arrow will be automatically bound to each instance of the class when the instance is constructed.

Embedded JavaScript Hopefully, you'll never need to use it, but if you ever need to intersperse snippets of JavaScript within your CoffeeScript, you can use backticks to pass it straight through.

hi = `function() {
  return [document.title, "Hello JavaScript"].join(": ");
}`



var hi;

hi = function() {
  return [document.title, "Hello JavaScript"].join(": ");
};
load
run: hi()

Switch/When/Else Switch statements in JavaScript are a bit awkward. You need to remember to break at the end of every case statement to avoid accidentally falling through to the default case. CoffeeScript prevents accidental fall-through, and can convert the switch into a returnable, assignable expression. The format is: switch condition, when clauses, else the default case.

As in Ruby, switch statements in CoffeeScript can take multiple values for each when clause. If any of the values match, the clause runs.

switch day
  when "Mon" then go work
  when "Tue" then go relax
  when "Thu" then go iceFishing
  when "Fri", "Sat"
    if day is bingoDay
      go bingo
      go dancing
  when "Sun" then go church
  else go work
switch (day) {
  case "Mon":
    go(work);
    break;
  case "Tue":
    go(relax);
    break;
  case "Thu":
    go(iceFishing);
    break;
  case "Fri":
  case "Sat":
    if (day === bingoDay) {
      go(bingo);
      go(dancing);
    }
    break;
  case "Sun":
    go(church);
    break;
  default:
    go(work);
}
load

Try/Catch/Finally Try/catch statements are just about the same as JavaScript (although they work as expressions).

try
  allHellBreaksLoose()
  catsAndDogsLivingTogether()
catch error
  print error
finally
  cleanUp()

try {
  allHellBreaksLoose();
  catsAndDogsLivingTogether();
} catch (error) {
  print(error);
} finally {
  cleanUp();
}
load

Chained Comparisons CoffeeScript borrows chained comparisons from Python — making it easy to test if a value falls within a certain range.

cholesterol = 127

healthy = 200 > cholesterol > 60


var cholesterol, healthy;

cholesterol = 127;

healthy = (200 > cholesterol && cholesterol > 60);
load
run: healthy

String Interpolation, Block Strings, and Block Comments Ruby-style string interpolation is included in CoffeeScript. Double-quoted strings allow for interpolated values, using #{ ... }, and single-quoted strings are literal.

author = "Wittgenstein"
quote  = "A picture is a fact. -- #{ author }"

sentence = "#{ 22 / 7 } is a decent approximation of π"





var author, quote, sentence;

author = "Wittgenstein";

quote = "A picture is a fact. -- " + author;

sentence = "" + (22 / 7) + " is a decent approximation of π";
load
run: sentence

Multiline strings are allowed in CoffeeScript.

mobyDick = "Call me Ishmael. Some years ago --
 never mind how long precisely -- having little
 or no money in my purse, and nothing particular
 to interest me on shore, I thought I would sail
 about a little and see the watery part of the
 world..."


var mobyDick;

mobyDick = "Call me Ishmael. Some years ago -- never mind how long precisely -- having little or no money in my purse, and nothing particular to interest me on shore, I thought I would sail about a little and see the watery part of the world...";
load
run: mobyDick

Block strings can be used to hold formatted or indentation-sensitive text (or, if you just don't feel like escaping quotes and apostrophes). The indentation level that begins the block is maintained throughout, so you can keep it all aligned with the body of your code.

html = """
       <strong>
         cup of coffeescript
       </strong>
       """
       
var html;

html = "<strong>\n  cup of coffeescript\n</strong>";
load
run: html

Double-quoted block strings, like other double-quoted strings, allow interpolation.

Sometimes you'd like to pass a block comment through to the generated JavaScript. For example, when you need to embed a licensing header at the top of a file. Block comments, which mirror the syntax for block strings, are preserved in the generated code.

###
CoffeeScript Compiler v1.4.0
Released under the MIT License
###


/*
CoffeeScript Compiler v1.4.0
Released under the MIT License
*/


load

Block Regular Expressions Similar to block strings and comments, CoffeeScript supports block regexes — extended regular expressions that ignore internal whitespace and can contain comments and interpolation. Modeled after Perl's /x modifier, CoffeeSctipt's block regexes are delimited by /// and go a long way towards making complex regular expressions readable. To quote from the CoffeeScript source:

OPERATOR = /// ^ (
  ?: [-=]>             # function
   | [-+*/%<>&|^!?=]=  # compound assign / compare
   | >>>=?             # zero-fill right shift
   | ([-+:])\1         # doubles
   | ([&|<>])\2=?      # logic / shift
   | \?\.              # soak access
   | \.{2,3}           # range or splat
) ///


var OPERATOR;

OPERATOR = /^(?:[-=]>|[-+*\/%<>&|^!?=]=|>>>=?|([-+:])\1|([&|<>])\2=?|\?\.|\.{2,3})/;
load

Cake, and Cakefiles

CoffeeScript includes a (very) simple build system similar to Make and Rake. Naturally, it's called Cake, and is used for the tasks that build and test the CoffeeScript language itself. Tasks are defined in a file named Cakefile, and can be invoked by running cake [task] from within the directory. To print a list of all the tasks and options, just type cake.

Task definitions are written in CoffeeScript, so you can put arbitrary code in your Cakefile. Define a task with a name, a long description, and the function to invoke when the task is run. If your task takes a command-line option, you can define the option with short and long flags, and it will be made available in the options object. Here's a task that uses the Node.js API to rebuild CoffeeScript's parser:

fs = require 'fs'

option '-o', '--output [DIR]', 'directory for compiled code'

task 'build:parser', 'rebuild the Jison parser', (options) ->
  require 'jison'
  code = require('./lib/grammar').parser.generate()
  dir  = options.output or 'lib'
  fs.writeFile "#{dir}/parser.js", code
var fs;

fs = require('fs');

option('-o', '--output [DIR]', 'directory for compiled code');

task('build:parser', 'rebuild the Jison parser', function(options) {
  var code, dir;
  require('jison');
  code = require('./lib/grammar').parser.generate();
  dir = options.output || 'lib';
  return fs.writeFile("" + dir + "/parser.js", code);
});
load

If you need to invoke one task before another — for example, running build before test, you can use the invoke function: invoke 'build'. Cake tasks are a minimal way to expose your CoffeeScript functions to the command line, so don't expect any fanciness built-in. If you need dependencies, or async callbacks, it's best to put them in your code itself — not the cake task.

"text/coffeescript" Script Tags

While it's not recommended for serious use, CoffeeScripts may be included directly within the browser using <script type="text/coffeescript"> tags. The source includes a compressed and minified version of the compiler (Download current version here, 39k when gzipped) as extras/coffee-script.js. Include this file on a page with inline CoffeeScript tags, and it will compile and evaluate them in order.

In fact, the little bit of glue script that runs "Try CoffeeScript" above, as well as the jQuery for the menu, is implemented in just this way. View source and look at the bottom of the page to see the example. Including the script also gives you access to CoffeeScript.compile() so you can pop open Firebug and try compiling some strings.

The usual caveats about CoffeeScript apply — your inline scripts will run within a closure wrapper, so if you want to expose global variables or functions, attach them to the window object.

Books

There are a number of excellent resources to help you get started with CoffeeScript, some of which are freely available online.

Screencasts

  • A Sip of CoffeeScript is a Code School Course which combines 6 screencasts with in-browser coding to make learning fun. The first level is free to try out.
  • Meet CoffeeScript is a 75-minute long screencast by PeepCode. Highly memorable for its animations which demonstrate transforming CoffeeScript into the equivalent JS.
  • If you're looking for less of a time commitment, RailsCasts' CoffeeScript Basics should have you covered, hitting all of the important notes about CoffeeScript in 11 minutes.

Examples

The best list of open-source CoffeeScript examples can be found on GitHub. But just to throw out few more:

  • github's Hubot, a friendly IRC robot that can perform any number of useful and useless tasks.
  • sstephenson's Pow, a zero-configuration Rack server, with comprehensive annotated source.
  • frank06's riak-js, a Node.js client for Riak, with support for HTTP and Protocol Buffers.
  • technoweenie's Coffee-Resque, a port of Resque for Node.js.
  • assaf's Zombie.js, a headless, full-stack, faux-browser testing library for Node.js.
  • jashkenas' Underscore.coffee, a port of the Underscore.js library of helper functions.
  • stephank's Orona, a remake of the Bolo tank game for modern browsers.
  • josh's nack, a Node.js-powered Rack server.

Resources

  • Source Code
    Use bin/coffee to test your changes,
    bin/cake test to run the test suite,
    bin/cake build to rebuild the CoffeeScript compiler, and
    bin/cake build:parser to regenerate the Jison parser if you're working on the grammar.

    git checkout lib && bin/cake build:full is a good command to run when you're working on the core language. It'll refresh the lib directory (in case you broke something), build your altered compiler, use that to rebuild itself (a good sanity test) and then run all of the tests. If they pass, there's a good chance you've made a successful change.
  • CoffeeScript Issues
    Bug reports, feature proposals, and ideas for changes to the language belong here.
  • CoffeeScript Google Group
    If you'd like to ask a question, the mailing list is a good place to get help.
  • The CoffeeScript Wiki
    If you've ever learned a neat CoffeeScript tip or trick, or ran into a gotcha — share it on the wiki. The wiki also serves as a directory of handy text editor extensions, web framework plugins, and general CoffeeScript build tools.
  • The FAQ
    Perhaps your CoffeeScript-related question has been asked before. Check the FAQ first.
  • High-Rez Logo
    The CoffeeScript logo is available in Illustrator, EPS and PSD formats, for use in presentations.

Web Chat (IRC)

Quick help and advice can usually be found in the CoffeeScript IRC room. Join #coffeescript on irc.freenode.net, or click the button below to open a webchat session on this page.

Change Log

1.4.0 Oct 23, 2012

  • The CoffeeScript compiler now strips Microsoft's UTF-8 BOM if it exists, allowing you to compile BOM-borked source files.
  • Fix Node/compiler deprecation warnings by removing registerExtension, and moving from path.exists to fs.exists.
  • Small tweaks to splat compilation, backticks, slicing, and the error for duplicate keys in object literals.

1.3.3 May 15, 2012

  • Due to the new semantics of JavaScript's strict mode, CoffeeScript no longer guarantees that constructor functions have names in all runtimes. See #2052 for discussion.
  • Inside of a nested function inside of an instance method, it's now possible to call super more reliably (walks recursively up).
  • Named loop variables no longer have different scoping heuristics than other local variables. (Reverts #643)
  • Fix for splats nested within the LHS of destructuring assignment.
  • Corrections to our compile time strict mode forbidding of octal literals.

1.3.1 April 10, 2012

  • CoffeeScript now enforces all of JavaScript's Strict Mode early syntax errors at compile time. This includes old-style octal literals, duplicate property names in object literals, duplicate parameters in a function definition, deleting naked variables, setting the value of eval or arguments, and more. See a full discussion at #1547.
  • The REPL now has a handy new multi-line mode for entering large blocks of code. It's useful when copy-and-pasting examples into the REPL. Enter multi-line mode with Ctrl-V. You may also now pipe input directly into the REPL.
  • CoffeeScript now prints a Generated by CoffeeScript VERSION header at the top of each compiled file.
  • Conditional assignment of previously undefined variables a or= b is now considered a syntax error.
  • A tweak to the semantics of do, which can now be used to more easily simulate a namespace: do (x = 1, y = 2) -> ...
  • Loop indices are now mutable within a loop iteration, and immutable between them.
  • Both endpoints of a slice are now allowed to be omitted for consistency, effectively creating a shallow copy of the list.
  • Additional tweaks and improvments to coffee --watch under Node's "new" file watching API. Watch will now beep by default if you introduce a syntax error into a watched script. We also now ignore hidden directories by default when watching recursively.

1.2.0 Dec. 18, 2011

  • Multiple improvements to coffee --watch and --join. You may now use both together, as well as add and remove files and directories within a --watch'd folder.
  • The throw statement can now be used as part of an expression.
  • Block comments at the top of the file will now appear outside of the safety closure wrapper.
  • Fixed a number of minor 1.1.3 regressions having to do with trailing operators and unfinished lines, and a more major 1.1.3 regression that caused bound functions within bound class functions to have the incorrect this.

1.1.3 Nov. 8, 2011

  • Ahh, whitespace. CoffeeScript's compiled JS now tries to space things out and keep it readable, as you can see in the examples on this page.
  • You can now call super in class level methods in class bodies, and bound class methods now preserve their correct context.
  • JavaScript has always supported octal numbers 010 is 8, and hexadecimal numbers 0xf is 15, but CoffeeScript now also supports binary numbers: 0b10 is 2.
  • The CoffeeScript module has been nested under a subdirectory to make it easier to require individual components separately, without having to use npm. For example, after adding the CoffeeScript folder to your path: require('coffee-script/lexer')
  • There's a new "link" feature in Try CoffeeScript on this webpage. Use it to get a shareable permalink for your example script.
  • The coffee --watch feature now only works on Node.js 0.6.0 and higher, but now also works properly on Windows.
  • Lots of small bug fixes from @michaelficarra, @geraldalewis, @satyr, and @trevorburnham.

1.1.2 August 4, 2011 Fixes for block comment formatting, ?= compilation, implicit calls against control structures, implicit invocation of a try/catch block, variadic arguments leaking from local scope, line numbers in syntax errors following heregexes, property access on parenthesized number literals, bound class methods and super with reserved names, a REPL overhaul, consecutive compiled semicolons, block comments in implicitly called objects, and a Chrome bug.

1.1.1 May 10, 2011 Bugfix release for classes with external constructor functions, see issue #1182.

1.1.0 May 1, 2011 When running via the coffee executable, process.argv and friends now report coffee instead of node. Better compatibility with Node.js 0.4.x module lookup changes. The output in the REPL is now colorized, like Node's is. Giving your concatenated CoffeeScripts a name when using --join is now mandatory. Fix for lexing compound division /= as a regex accidentally. All text/coffeescript tags should now execute in the order they're included. Fixed an issue with extended subclasses using external constructor functions. Fixed an edge-case infinite loop in addImplicitParentheses. Fixed exponential slowdown with long chains of function calls. Globals no longer leak into the CoffeeScript REPL. Splatted parameters are declared local to the function.

1.0.1 Jan 31, 2011 Fixed a lexer bug with Unicode identifiers. Updated REPL for compatibility with Node.js 0.3.7. Fixed requiring relative paths in the REPL. Trailing return and return undefined are now optimized away. Stopped requiring the core Node.js "util" module for back-compatibility with Node.js 0.2.5. Fixed a case where a conditional return would cause fallthrough in a switch statement. Optimized empty objects in destructuring assignment.

1.0.0 Dec 24, 2010 CoffeeScript loops no longer try to preserve block scope when functions are being generated within the loop body. Instead, you can use the do keyword to create a convenient closure wrapper. Added a --nodejs flag for passing through options directly to the node executable. Better behavior around the use of pure statements within expressions. Fixed inclusive slicing through -1, for all browsers, and splicing with arbitrary expressions as endpoints.

0.9.6 Dec 6, 2010 The REPL now properly formats stacktraces, and stays alive through asynchronous exceptions. Using --watch now prints timestamps as files are compiled. Fixed some accidentally-leaking variables within plucked closure-loops. Constructors now maintain their declaration location within a class body. Dynamic object keys were removed. Nested classes are now supported. Fixes execution context for naked splatted functions. Bugfix for inversion of chained comparisons. Chained class instantiation now works properly with splats.

0.9.5 Nov 21, 2010 0.9.5 should be considered the first release candidate for CoffeeScript 1.0. There have been a large number of internal changes since the previous release, many contributed from satyr's Coco dialect of CoffeeScript. Heregexes (extended regexes) were added. Functions can now have default arguments. Class bodies are now executable code. Improved syntax errors for invalid CoffeeScript. undefined now works like null, and cannot be assigned a new value. There was a precedence change with respect to single-line comprehensions: result = i for i in list
used to parse as result = (i for i in list) by default ... it now parses as
(result = i) for i in list.

0.9.4 Sep 21, 2010 CoffeeScript now uses appropriately-named temporary variables, and recycles their references after use. Added require.extensions support for Node.js 0.3. Loading CoffeeScript in the browser now adds just a single CoffeeScript object to global scope. Fixes for implicit object and block comment edge cases.

0.9.3 Sep 16, 2010 CoffeeScript switch statements now compile into JS switch statements — they previously compiled into if/else chains for JavaScript 1.3 compatibility. Soaking a function invocation is now supported. Users of the RubyMine editor should now be able to use --watch mode.

0.9.2 Aug 23, 2010 Specifying the start and end of a range literal is now optional, eg. array[3..]. You can now say a not instanceof b. Fixed important bugs with nested significant and non-significant indentation (Issue #637). Added a --require flag that allows you to hook into the coffee command. Added a custom jsl.conf file for our preferred JavaScriptLint setup. Sped up Jison grammar compilation time by flattening rules for operations. Block comments can now be used with JavaScript-minifier-friendly syntax. Added JavaScript's compound assignment bitwise operators. Bugfixes to implicit object literals with leading number and string keys, as the subject of implicit calls, and as part of compound assignment.

0.9.1 Aug 11, 2010 Bugfix release for 0.9.1. Greatly improves the handling of mixed implicit objects, implicit function calls, and implicit indentation. String and regex interpolation is now strictly #{ ... } (Ruby style). The compiler now takes a --require flag, which specifies scripts to run before compilation.

0.9.0 Aug 4, 2010 The CoffeeScript 0.9 series is considered to be a release candidate for 1.0; let's give her a shakedown cruise. 0.9.0 introduces a massive backwards-incompatible change: Assignment now uses =, and object literals use :, as in JavaScript. This allows us to have implicit object literals, and YAML-style object definitions. Half assignments are removed, in favor of +=, or=, and friends. Interpolation now uses a hash mark # instead of the dollar sign $ — because dollar signs may be part of a valid JS identifier. Downwards range comprehensions are now safe again, and are optimized to straight for loops when created with integer endpoints. A fast, unguarded form of object comprehension was added: for all key, value of object. Mentioning the super keyword with no arguments now forwards all arguments passed to the function, as in Ruby. If you extend class B from parent class A, if A has an extended method defined, it will be called, passing in B — this enables static inheritance, among other things. Cleaner output for functions bound with the fat arrow. @variables can now be used in parameter lists, with the parameter being automatically set as a property on the object — useful in constructors and setter functions. Constructor functions can now take splats.

0.7.2 Jul 12, 2010 Quick bugfix (right after 0.7.1) for a problem that prevented coffee command-line options from being parsed in some circumstances.

0.7.1 Jul 11, 2010 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.

0.7.0 Jun 28, 2010 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 by -1 if you'd like to iterate downward. Reporting of syntax errors is greatly improved from the previous release. Running coffee with no arguments now launches the REPL, with Readline support. The <- bind operator has been removed from CoffeeScript. The loop keyword was added, which is equivalent to a while true loop. Comprehensions that contain closures will now close over their variables, like the semantics of a forEach. You can now use bound function in class definitions (bound to the instance). For consistency, a in b is now an array presence check, and a of b is an object-key check. Comments are no longer passed through to the generated JavaScript.

0.6.2 May 15, 2010 The coffee 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: {name, length}: func. Pattern matching is now allowed within comprehension variables. unless is now allowed in block form. until loops were added, as the inverse of while loops. switch statements are now allowed without switch object clauses. Compatible with Node.js v0.1.95.

0.6.1 Apr 12, 2010 Upgraded CoffeeScript for compatibility with the new Node.js v0.1.90 series.

0.6.0 Apr 3, 2010 Trailing commas are now allowed, a-la Python. Static properties may be assigned directly within class definitions, using @property notation.

0.5.6 Mar 23, 2010 Interpolation can now be used within regular expressions and heredocs, as well as strings. Added the <- bind operator. Allowing assignment to half-expressions instead of special ||=-style operators. The arguments object is no longer automatically converted into an array. After requiring coffee-script, Node.js can now directly load .coffee files, thanks to registerExtension. Multiple splats can now be used in function calls, arrays, and pattern matching.

0.5.5 Mar 8, 2010 String interpolation, contributed by Stan Angeloff. Since --run has been the default since 0.5.3, updating --stdio and --eval to run by default, pass --compile as well if you'd like to print the result.

0.5.4 Mar 3, 2010 Bugfix that corrects the Node.js global constants __filename and __dirname. Tweaks for more flexible parsing of nested function literals and improperly-indented comments. Updates for the latest Node.js API.

0.5.3 Feb 27, 2010 CoffeeScript now has a syntax for defining classes. Many of the core components (Nodes, Lexer, Rewriter, Scope, Optparse) are using them. Cakefiles can use optparse.coffee to define options for tasks. --run is now the default flag for the coffee command, use --compile to save JavaScripts. Bugfix for an ambiguity between RegExp literals and chained divisions.

0.5.2 Feb 25, 2010 Added a compressed version of the compiler for inclusion in web pages as
extras/coffee-script.js. It'll automatically run any script tags with type text/coffeescript for you. Added a --stdio option to the coffee command, for piped-in compiles.

0.5.1 Feb 24, 2010 Improvements to null soaking with the existential operator, including soaks on indexed properties. Added conditions to while loops, so you can use them as filters with when, in the same manner as comprehensions.

0.5.0 Feb 21, 2010 CoffeeScript 0.5.0 is a major release, While there are no language changes, the Ruby compiler has been removed in favor of a self-hosting compiler written in pure CoffeeScript.

0.3.2 Feb 8, 2010 @property is now a shorthand for this.property.
Switched the default JavaScript engine from Narwhal to Node.js. Pass the --narwhal flag if you'd like to continue using it.

0.3.0 Jan 26, 2010 CoffeeScript 0.3 includes major syntax changes:
The function symbol was changed to ->, and the bound function symbol is now =>.
Parameter lists in function definitions must now be wrapped in parentheses.
Added property soaking, with the ?. operator.
Made parentheses optional, when invoking functions with arguments.
Removed the obsolete block literal syntax.

0.2.6 Jan 17, 2010 Added Python-style chained comparisons, the conditional existence operator ?=, and some examples from Beautiful Code. Bugfixes relating to statement-to-expression conversion, arguments-to-array conversion, and the TextMate syntax highlighter.

0.2.5 Jan 13, 2010 The conditions in switch statements can now take multiple values at once — If any of them are true, the case will run. Added the long arrow ==>, which defines and immediately binds a function to this. While loops can now be used as expressions, in the same way that comprehensions can. Splats can be used within pattern matches to soak up the rest of an array.

0.2.4 Jan 12, 2010 Added ECMAScript Harmony style destructuring assignment, for dealing with extracting values from nested arrays and objects. Added indentation-sensitive heredocs for nicely formatted strings or chunks of code.

0.2.3 Jan 11, 2010 Axed the unsatisfactory ino keyword, replacing it with of for object comprehensions. They now look like: for prop, value of object.

0.2.2 Jan 10, 2010 When performing a comprehension over an object, use ino, instead of in, which helps us generate smaller, more efficient code at compile time.
Added :: as a shorthand for saying .prototype.
The "splat" symbol has been changed from a prefix asterisk *, to a postfix ellipsis ...
Added JavaScript's in operator, empty return statements, and empty while loops.
Constructor functions that start with capital letters now include a safety check to make sure that the new instance of the object is returned.
The extends keyword now functions identically to goog.inherits in Google's Closure Library.

0.2.1 Jan 5, 2010 Arguments objects are now converted into real arrays when referenced.

0.2.0 Jan 5, 2010 Major release. Significant whitespace. Better statement-to-expression conversion. Splats. Splice literals. Object comprehensions. Blocks. The existential operator. Many thanks to all the folks who posted issues, with special thanks to Liam O'Connor-Davis for whitespace and expression help.

0.1.6 Dec 27, 2009 Bugfix for running coffee --interactive and --run from outside of the CoffeeScript directory. Bugfix for nested function/if-statements.

0.1.5 Dec 26, 2009 Array slice literals and array comprehensions can now both take Ruby-style ranges to specify the start and end. JavaScript variable declaration is now pushed up to the top of the scope, making all assignment statements into expressions. You can use \ to escape newlines. The coffee-script command is now called coffee.

0.1.4 Dec 25, 2009 The official CoffeeScript extension is now .coffee instead of .cs, which properly belongs to C#. Due to popular demand, you can now also use = to assign. Unlike JavaScript, = can also be used within object literals, interchangeably with :. Made a grammatical fix for chained function calls like func(1)(2)(3)(4). Inheritance and super no longer use __proto__, so they should be IE-compatible now.

0.1.3 Dec 25, 2009 The coffee command now includes --interactive, which launches an interactive CoffeeScript session, and --run, which directly compiles and executes a script. Both options depend on a working installation of Narwhal. The aint keyword has been replaced by isnt, which goes together a little smoother with is. Quoted strings are now allowed as identifiers within object literals: eg. {"5+5": 10}. All assignment operators now use a colon: +:, -:, *:, etc.

0.1.2 Dec 24, 2009 Fixed a bug with calling super() through more than one level of inheritance, with the re-addition of the extends keyword. Added experimental Narwhal support (as a Tusk package), contributed by Tom Robinson, including bin/cs as a CoffeeScript REPL and interpreter. New --no-wrap option to suppress the safety function wrapper.

0.1.1 Dec 24, 2009 Added instanceof and typeof as operators.

0.1.0 Dec 24, 2009 Initial CoffeeScript release.

coffee-script-1.4.0/lib/000077500000000000000000000000001204160075300150115ustar00rootroot00000000000000coffee-script-1.4.0/lib/coffee-script/000077500000000000000000000000001204160075300175425ustar00rootroot00000000000000coffee-script-1.4.0/lib/coffee-script/browser.js000066400000000000000000000044721204160075300215720ustar00rootroot00000000000000// Generated by CoffeeScript 1.4.0 (function() { var CoffeeScript, runScripts; CoffeeScript = require('./coffee-script'); CoffeeScript.require = require; CoffeeScript["eval"] = function(code, options) { var _ref; if (options == null) { options = {}; } if ((_ref = options.bare) == null) { options.bare = true; } return eval(CoffeeScript.compile(code, options)); }; CoffeeScript.run = function(code, options) { if (options == null) { options = {}; } options.bare = true; return Function(CoffeeScript.compile(code, options))(); }; if (typeof window === "undefined" || window === null) { return; } CoffeeScript.load = function(url, callback) { var xhr; xhr = window.ActiveXObject ? new window.ActiveXObject('Microsoft.XMLHTTP') : new XMLHttpRequest(); xhr.open('GET', url, true); if ('overrideMimeType' in xhr) { xhr.overrideMimeType('text/plain'); } xhr.onreadystatechange = function() { var _ref; if (xhr.readyState === 4) { if ((_ref = xhr.status) === 0 || _ref === 200) { CoffeeScript.run(xhr.responseText); } else { throw new Error("Could not load " + url); } if (callback) { return callback(); } } }; return xhr.send(null); }; runScripts = function() { var coffees, execute, index, length, s, scripts; scripts = document.getElementsByTagName('script'); coffees = (function() { var _i, _len, _results; _results = []; for (_i = 0, _len = scripts.length; _i < _len; _i++) { s = scripts[_i]; if (s.type === 'text/coffeescript') { _results.push(s); } } return _results; })(); index = 0; length = coffees.length; (execute = function() { var script; script = coffees[index++]; if ((script != null ? script.type : void 0) === 'text/coffeescript') { if (script.src) { return CoffeeScript.load(script.src, execute); } else { CoffeeScript.run(script.innerHTML); return execute(); } } })(); return null; }; if (window.addEventListener) { addEventListener('DOMContentLoaded', runScripts, false); } else { attachEvent('onload', runScripts); } }).call(this); coffee-script-1.4.0/lib/coffee-script/cake.js000066400000000000000000000057231204160075300210120ustar00rootroot00000000000000// Generated by CoffeeScript 1.4.0 (function() { var CoffeeScript, cakefileDirectory, existsSync, fatalError, fs, helpers, missingTask, oparse, options, optparse, path, printTasks, switches, tasks; fs = require('fs'); path = require('path'); helpers = require('./helpers'); optparse = require('./optparse'); CoffeeScript = require('./coffee-script'); existsSync = fs.existsSync || path.existsSync; tasks = {}; options = {}; switches = []; oparse = null; helpers.extend(global, { task: function(name, description, action) { var _ref; if (!action) { _ref = [description, action], action = _ref[0], description = _ref[1]; } return tasks[name] = { name: name, description: description, action: action }; }, option: function(letter, flag, description) { return switches.push([letter, flag, description]); }, invoke: function(name) { if (!tasks[name]) { missingTask(name); } return tasks[name].action(options); } }); exports.run = function() { var arg, args, _i, _len, _ref, _results; global.__originalDirname = fs.realpathSync('.'); process.chdir(cakefileDirectory(__originalDirname)); args = process.argv.slice(2); CoffeeScript.run(fs.readFileSync('Cakefile').toString(), { filename: 'Cakefile' }); oparse = new optparse.OptionParser(switches); if (!args.length) { return printTasks(); } try { options = oparse.parse(args); } catch (e) { return fatalError("" + e); } _ref = options["arguments"]; _results = []; for (_i = 0, _len = _ref.length; _i < _len; _i++) { arg = _ref[_i]; _results.push(invoke(arg)); } return _results; }; printTasks = function() { var cakefilePath, desc, name, relative, spaces, task; relative = path.relative || path.resolve; cakefilePath = path.join(relative(__originalDirname, process.cwd()), 'Cakefile'); console.log("" + cakefilePath + " defines the following tasks:\n"); for (name in tasks) { task = tasks[name]; spaces = 20 - name.length; spaces = spaces > 0 ? Array(spaces + 1).join(' ') : ''; desc = task.description ? "# " + task.description : ''; console.log("cake " + name + spaces + " " + desc); } if (switches.length) { return console.log(oparse.help()); } }; fatalError = function(message) { console.error(message + '\n'); console.log('To see a list of all tasks/options, run "cake"'); return process.exit(1); }; missingTask = function(task) { return fatalError("No such task: " + task); }; cakefileDirectory = function(dir) { var parent; if (existsSync(path.join(dir, 'Cakefile'))) { return dir; } parent = path.normalize(path.join(dir, '..')); if (parent !== dir) { return cakefileDirectory(parent); } throw new Error("Cakefile not found in " + (process.cwd())); }; }).call(this); coffee-script-1.4.0/lib/coffee-script/coffee-script.js000066400000000000000000000114041204160075300226310ustar00rootroot00000000000000// Generated by CoffeeScript 1.4.0 (function() { var Lexer, RESERVED, compile, fs, lexer, parser, path, stripBOM, vm, _ref, __hasProp = {}.hasOwnProperty; fs = require('fs'); path = require('path'); _ref = require('./lexer'), Lexer = _ref.Lexer, RESERVED = _ref.RESERVED; parser = require('./parser').parser; vm = require('vm'); stripBOM = function(content) { if (content.charCodeAt(0) === 0xFEFF) { return content.substring(1); } else { return content; } }; if (require.extensions) { require.extensions['.coffee'] = function(module, filename) { var content; content = compile(stripBOM(fs.readFileSync(filename, 'utf8')), { filename: filename }); return module._compile(content, filename); }; } exports.VERSION = '1.4.0'; exports.RESERVED = RESERVED; exports.helpers = require('./helpers'); exports.compile = compile = function(code, options) { var header, js, merge; if (options == null) { options = {}; } merge = exports.helpers.merge; try { js = (parser.parse(lexer.tokenize(code))).compile(options); if (!options.header) { return js; } } catch (err) { if (options.filename) { err.message = "In " + options.filename + ", " + err.message; } throw err; } header = "Generated by CoffeeScript " + this.VERSION; return "// " + header + "\n" + js; }; exports.tokens = function(code, options) { return lexer.tokenize(code, options); }; exports.nodes = function(source, options) { if (typeof source === 'string') { return parser.parse(lexer.tokenize(source, options)); } else { return parser.parse(source); } }; exports.run = function(code, options) { var mainModule; if (options == null) { options = {}; } mainModule = require.main; mainModule.filename = process.argv[1] = options.filename ? fs.realpathSync(options.filename) : '.'; mainModule.moduleCache && (mainModule.moduleCache = {}); mainModule.paths = require('module')._nodeModulePaths(path.dirname(fs.realpathSync(options.filename))); if (path.extname(mainModule.filename) !== '.coffee' || require.extensions) { return mainModule._compile(compile(code, options), mainModule.filename); } else { return mainModule._compile(code, mainModule.filename); } }; exports["eval"] = function(code, options) { var Module, Script, js, k, o, r, sandbox, v, _i, _len, _module, _ref1, _ref2, _require; if (options == null) { options = {}; } if (!(code = code.trim())) { return; } Script = vm.Script; if (Script) { if (options.sandbox != null) { if (options.sandbox instanceof Script.createContext().constructor) { sandbox = options.sandbox; } else { sandbox = Script.createContext(); _ref1 = options.sandbox; for (k in _ref1) { if (!__hasProp.call(_ref1, k)) continue; v = _ref1[k]; sandbox[k] = v; } } sandbox.global = sandbox.root = sandbox.GLOBAL = sandbox; } else { sandbox = global; } sandbox.__filename = options.filename || 'eval'; sandbox.__dirname = path.dirname(sandbox.__filename); if (!(sandbox !== global || sandbox.module || sandbox.require)) { Module = require('module'); sandbox.module = _module = new Module(options.modulename || 'eval'); sandbox.require = _require = function(path) { return Module._load(path, _module, true); }; _module.filename = sandbox.__filename; _ref2 = Object.getOwnPropertyNames(require); for (_i = 0, _len = _ref2.length; _i < _len; _i++) { r = _ref2[_i]; if (r !== 'paths') { _require[r] = require[r]; } } _require.paths = _module.paths = Module._nodeModulePaths(process.cwd()); _require.resolve = function(request) { return Module._resolveFilename(request, _module); }; } } o = {}; for (k in options) { if (!__hasProp.call(options, k)) continue; v = options[k]; o[k] = v; } o.bare = true; js = compile(code, o); if (sandbox === global) { return vm.runInThisContext(js); } else { return vm.runInContext(js, sandbox); } }; lexer = new Lexer; parser.lexer = { lex: function() { var tag, _ref1; _ref1 = this.tokens[this.pos++] || [''], tag = _ref1[0], this.yytext = _ref1[1], this.yylineno = _ref1[2]; return tag; }, setInput: function(tokens) { this.tokens = tokens; return this.pos = 0; }, upcomingInput: function() { return ""; } }; parser.yy = require('./nodes'); }).call(this); coffee-script-1.4.0/lib/coffee-script/command.js000066400000000000000000000361761204160075300215330ustar00rootroot00000000000000// Generated by CoffeeScript 1.4.0 (function() { var BANNER, CoffeeScript, EventEmitter, SWITCHES, compileJoin, compileOptions, compilePath, compileScript, compileStdio, exec, exists, forkNode, fs, helpers, hidden, joinTimeout, lint, loadRequires, notSources, optionParser, optparse, opts, outputPath, parseOptions, path, printLine, printTokens, printWarn, removeSource, sourceCode, sources, spawn, timeLog, unwatchDir, usage, version, wait, watch, watchDir, watchers, writeJs, _ref; fs = require('fs'); path = require('path'); helpers = require('./helpers'); optparse = require('./optparse'); CoffeeScript = require('./coffee-script'); _ref = require('child_process'), spawn = _ref.spawn, exec = _ref.exec; EventEmitter = require('events').EventEmitter; exists = fs.exists || path.exists; helpers.extend(CoffeeScript, new EventEmitter); printLine = function(line) { return process.stdout.write(line + '\n'); }; printWarn = function(line) { return process.stderr.write(line + '\n'); }; hidden = function(file) { return /^\.|~$/.test(file); }; BANNER = 'Usage: coffee [options] path/to/script.coffee -- [args]\n\nIf called without options, `coffee` will run your script.'; SWITCHES = [['-b', '--bare', 'compile without a top-level function wrapper'], ['-c', '--compile', 'compile to JavaScript and save as .js files'], ['-e', '--eval', 'pass a string from the command line as input'], ['-h', '--help', 'display this help message'], ['-i', '--interactive', 'run an interactive CoffeeScript REPL'], ['-j', '--join [FILE]', 'concatenate the source CoffeeScript before compiling'], ['-l', '--lint', 'pipe the compiled JavaScript through JavaScript Lint'], ['-n', '--nodes', 'print out the parse tree that the parser produces'], ['--nodejs [ARGS]', 'pass options directly to the "node" binary'], ['-o', '--output [DIR]', 'set the output directory for compiled JavaScript'], ['-p', '--print', 'print out the compiled JavaScript'], ['-r', '--require [FILE*]', 'require a library before executing your script'], ['-s', '--stdio', 'listen for and compile scripts over stdio'], ['-t', '--tokens', 'print out the tokens that the lexer/rewriter produce'], ['-v', '--version', 'display the version number'], ['-w', '--watch', 'watch scripts for changes and rerun commands']]; opts = {}; sources = []; sourceCode = []; notSources = {}; watchers = {}; optionParser = null; exports.run = function() { var literals, source, _i, _len, _results; parseOptions(); if (opts.nodejs) { return forkNode(); } if (opts.help) { return usage(); } if (opts.version) { return version(); } if (opts.require) { loadRequires(); } if (opts.interactive) { return require('./repl'); } if (opts.watch && !fs.watch) { return printWarn("The --watch feature depends on Node v0.6.0+. You are running " + process.version + "."); } if (opts.stdio) { return compileStdio(); } if (opts["eval"]) { return compileScript(null, sources[0]); } if (!sources.length) { return require('./repl'); } literals = opts.run ? sources.splice(1) : []; process.argv = process.argv.slice(0, 2).concat(literals); process.argv[0] = 'coffee'; process.execPath = require.main.filename; _results = []; for (_i = 0, _len = sources.length; _i < _len; _i++) { source = sources[_i]; _results.push(compilePath(source, true, path.normalize(source))); } return _results; }; compilePath = function(source, topLevel, base) { return fs.stat(source, function(err, stats) { if (err && err.code !== 'ENOENT') { throw err; } if ((err != null ? err.code : void 0) === 'ENOENT') { if (topLevel && source.slice(-7) !== '.coffee') { source = sources[sources.indexOf(source)] = "" + source + ".coffee"; return compilePath(source, topLevel, base); } if (topLevel) { console.error("File not found: " + source); process.exit(1); } return; } if (stats.isDirectory()) { if (opts.watch) { watchDir(source, base); } return fs.readdir(source, function(err, files) { var file, index, _ref1, _ref2; if (err && err.code !== 'ENOENT') { throw err; } if ((err != null ? err.code : void 0) === 'ENOENT') { return; } index = sources.indexOf(source); files = files.filter(function(file) { return !hidden(file); }); [].splice.apply(sources, [index, index - index + 1].concat(_ref1 = (function() { var _i, _len, _results; _results = []; for (_i = 0, _len = files.length; _i < _len; _i++) { file = files[_i]; _results.push(path.join(source, file)); } return _results; })())), _ref1; [].splice.apply(sourceCode, [index, index - index + 1].concat(_ref2 = files.map(function() { return null; }))), _ref2; return files.forEach(function(file) { return compilePath(path.join(source, file), false, base); }); }); } else if (topLevel || path.extname(source) === '.coffee') { if (opts.watch) { watch(source, base); } return fs.readFile(source, function(err, code) { if (err && err.code !== 'ENOENT') { throw err; } if ((err != null ? err.code : void 0) === 'ENOENT') { return; } return compileScript(source, code.toString(), base); }); } else { notSources[source] = true; return removeSource(source, base); } }); }; compileScript = function(file, input, base) { var o, options, t, task; o = opts; options = compileOptions(file); try { t = task = { file: file, input: input, options: options }; CoffeeScript.emit('compile', task); if (o.tokens) { return printTokens(CoffeeScript.tokens(t.input)); } else if (o.nodes) { return printLine(CoffeeScript.nodes(t.input).toString().trim()); } else if (o.run) { return CoffeeScript.run(t.input, t.options); } else if (o.join && t.file !== o.join) { sourceCode[sources.indexOf(t.file)] = t.input; return compileJoin(); } else { t.output = CoffeeScript.compile(t.input, t.options); CoffeeScript.emit('success', task); if (o.print) { return printLine(t.output.trim()); } else if (o.compile) { return writeJs(t.file, t.output, base); } else if (o.lint) { return lint(t.file, t.output); } } } catch (err) { CoffeeScript.emit('failure', err, task); if (CoffeeScript.listeners('failure').length) { return; } if (o.watch) { return printLine(err.message + '\x07'); } printWarn(err instanceof Error && err.stack || ("ERROR: " + err)); return process.exit(1); } }; compileStdio = function() { var code, stdin; code = ''; stdin = process.openStdin(); stdin.on('data', function(buffer) { if (buffer) { return code += buffer.toString(); } }); return stdin.on('end', function() { return compileScript(null, code); }); }; joinTimeout = null; compileJoin = function() { if (!opts.join) { return; } if (!sourceCode.some(function(code) { return code === null; })) { clearTimeout(joinTimeout); return joinTimeout = wait(100, function() { return compileScript(opts.join, sourceCode.join('\n'), opts.join); }); } }; loadRequires = function() { var realFilename, req, _i, _len, _ref1; realFilename = module.filename; module.filename = '.'; _ref1 = opts.require; for (_i = 0, _len = _ref1.length; _i < _len; _i++) { req = _ref1[_i]; require(req); } return module.filename = realFilename; }; watch = function(source, base) { var compile, compileTimeout, prevStats, rewatch, watchErr, watcher; prevStats = null; compileTimeout = null; watchErr = function(e) { if (e.code === 'ENOENT') { if (sources.indexOf(source) === -1) { return; } try { rewatch(); return compile(); } catch (e) { removeSource(source, base, true); return compileJoin(); } } else { throw e; } }; compile = function() { clearTimeout(compileTimeout); return compileTimeout = wait(25, function() { return fs.stat(source, function(err, stats) { if (err) { return watchErr(err); } if (prevStats && stats.size === prevStats.size && stats.mtime.getTime() === prevStats.mtime.getTime()) { return rewatch(); } prevStats = stats; return fs.readFile(source, function(err, code) { if (err) { return watchErr(err); } compileScript(source, code.toString(), base); return rewatch(); }); }); }); }; try { watcher = fs.watch(source, compile); } catch (e) { watchErr(e); } return rewatch = function() { if (watcher != null) { watcher.close(); } return watcher = fs.watch(source, compile); }; }; watchDir = function(source, base) { var readdirTimeout, watcher; readdirTimeout = null; try { return watcher = fs.watch(source, function() { clearTimeout(readdirTimeout); return readdirTimeout = wait(25, function() { return fs.readdir(source, function(err, files) { var file, _i, _len, _results; if (err) { if (err.code !== 'ENOENT') { throw err; } watcher.close(); return unwatchDir(source, base); } _results = []; for (_i = 0, _len = files.length; _i < _len; _i++) { file = files[_i]; if (!(!hidden(file) && !notSources[file])) { continue; } file = path.join(source, file); if (sources.some(function(s) { return s.indexOf(file) >= 0; })) { continue; } sources.push(file); sourceCode.push(null); _results.push(compilePath(file, false, base)); } return _results; }); }); }); } catch (e) { if (e.code !== 'ENOENT') { throw e; } } }; unwatchDir = function(source, base) { var file, prevSources, toRemove, _i, _len; prevSources = sources.slice(0); toRemove = (function() { var _i, _len, _results; _results = []; for (_i = 0, _len = sources.length; _i < _len; _i++) { file = sources[_i]; if (file.indexOf(source) >= 0) { _results.push(file); } } return _results; })(); for (_i = 0, _len = toRemove.length; _i < _len; _i++) { file = toRemove[_i]; removeSource(file, base, true); } if (!sources.some(function(s, i) { return prevSources[i] !== s; })) { return; } return compileJoin(); }; removeSource = function(source, base, removeJs) { var index, jsPath; index = sources.indexOf(source); sources.splice(index, 1); sourceCode.splice(index, 1); if (removeJs && !opts.join) { jsPath = outputPath(source, base); return exists(jsPath, function(itExists) { if (itExists) { return fs.unlink(jsPath, function(err) { if (err && err.code !== 'ENOENT') { throw err; } return timeLog("removed " + source); }); } }); } }; outputPath = function(source, base) { var baseDir, dir, filename, srcDir; filename = path.basename(source, path.extname(source)) + '.js'; srcDir = path.dirname(source); baseDir = base === '.' ? srcDir : srcDir.substring(base.length); dir = opts.output ? path.join(opts.output, baseDir) : srcDir; return path.join(dir, filename); }; writeJs = function(source, js, base) { var compile, jsDir, jsPath; jsPath = outputPath(source, base); jsDir = path.dirname(jsPath); compile = function() { if (js.length <= 0) { js = ' '; } return fs.writeFile(jsPath, js, function(err) { if (err) { return printLine(err.message); } else if (opts.compile && opts.watch) { return timeLog("compiled " + source); } }); }; return exists(jsDir, function(itExists) { if (itExists) { return compile(); } else { return exec("mkdir -p " + jsDir, compile); } }); }; wait = function(milliseconds, func) { return setTimeout(func, milliseconds); }; timeLog = function(message) { return console.log("" + ((new Date).toLocaleTimeString()) + " - " + message); }; lint = function(file, js) { var conf, jsl, printIt; printIt = function(buffer) { return printLine(file + ':\t' + buffer.toString().trim()); }; conf = __dirname + '/../../extras/jsl.conf'; jsl = spawn('jsl', ['-nologo', '-stdin', '-conf', conf]); jsl.stdout.on('data', printIt); jsl.stderr.on('data', printIt); jsl.stdin.write(js); return jsl.stdin.end(); }; printTokens = function(tokens) { var strings, tag, token, value; strings = (function() { var _i, _len, _ref1, _results; _results = []; for (_i = 0, _len = tokens.length; _i < _len; _i++) { token = tokens[_i]; _ref1 = [token[0], token[1].toString().replace(/\n/, '\\n')], tag = _ref1[0], value = _ref1[1]; _results.push("[" + tag + " " + value + "]"); } return _results; })(); return printLine(strings.join(' ')); }; parseOptions = function() { var i, o, source, _i, _len; optionParser = new optparse.OptionParser(SWITCHES, BANNER); o = opts = optionParser.parse(process.argv.slice(2)); o.compile || (o.compile = !!o.output); o.run = !(o.compile || o.print || o.lint); o.print = !!(o.print || (o["eval"] || o.stdio && o.compile)); sources = o["arguments"]; for (i = _i = 0, _len = sources.length; _i < _len; i = ++_i) { source = sources[i]; sourceCode[i] = null; } }; compileOptions = function(filename) { return { filename: filename, bare: opts.bare, header: opts.compile }; }; forkNode = function() { var args, nodeArgs; nodeArgs = opts.nodejs.split(/\s+/); args = process.argv.slice(1); args.splice(args.indexOf('--nodejs'), 2); return spawn(process.execPath, nodeArgs.concat(args), { cwd: process.cwd(), env: process.env, customFds: [0, 1, 2] }); }; usage = function() { return printLine((new optparse.OptionParser(SWITCHES, BANNER)).help()); }; version = function() { return printLine("CoffeeScript version " + CoffeeScript.VERSION); }; }).call(this); coffee-script-1.4.0/lib/coffee-script/grammar.js000066400000000000000000000435371204160075300215420ustar00rootroot00000000000000// Generated by CoffeeScript 1.4.0 (function() { var Parser, alt, alternatives, grammar, name, o, operators, token, tokens, unwrap; Parser = require('jison').Parser; unwrap = /^function\s*\(\)\s*\{\s*return\s*([\s\S]*);\s*\}/; o = function(patternString, action, options) { var match; patternString = patternString.replace(/\s{2,}/g, ' '); if (!action) { return [patternString, '$$ = $1;', options]; } action = (match = unwrap.exec(action)) ? match[1] : "(" + action + "())"; action = action.replace(/\bnew /g, '$&yy.'); action = action.replace(/\b(?:Block\.wrap|extend)\b/g, 'yy.$&'); return [patternString, "$$ = " + action + ";", options]; }; grammar = { Root: [ o('', function() { return new Block; }), o('Body'), o('Block TERMINATOR') ], Body: [ o('Line', function() { return Block.wrap([$1]); }), o('Body TERMINATOR Line', function() { return $1.push($3); }), o('Body TERMINATOR') ], Line: [o('Expression'), o('Statement')], Statement: [ o('Return'), o('Comment'), o('STATEMENT', function() { return new Literal($1); }) ], Expression: [o('Value'), o('Invocation'), o('Code'), o('Operation'), o('Assign'), o('If'), o('Try'), o('While'), o('For'), o('Switch'), o('Class'), o('Throw')], Block: [ o('INDENT OUTDENT', function() { return new Block; }), o('INDENT Body OUTDENT', function() { return $2; }) ], Identifier: [ o('IDENTIFIER', function() { return new Literal($1); }) ], AlphaNumeric: [ o('NUMBER', function() { return new Literal($1); }), o('STRING', function() { return new Literal($1); }) ], Literal: [ o('AlphaNumeric'), o('JS', function() { return new Literal($1); }), o('REGEX', function() { return new Literal($1); }), o('DEBUGGER', function() { return new Literal($1); }), o('UNDEFINED', function() { return new Undefined; }), o('NULL', function() { return new Null; }), o('BOOL', function() { return new Bool($1); }) ], Assign: [ o('Assignable = Expression', function() { return new Assign($1, $3); }), o('Assignable = TERMINATOR Expression', function() { return new Assign($1, $4); }), o('Assignable = INDENT Expression OUTDENT', function() { return new Assign($1, $4); }) ], AssignObj: [ o('ObjAssignable', function() { return new Value($1); }), o('ObjAssignable : Expression', function() { return new Assign(new Value($1), $3, 'object'); }), o('ObjAssignable :\ INDENT Expression OUTDENT', function() { return new Assign(new Value($1), $4, 'object'); }), o('Comment') ], ObjAssignable: [o('Identifier'), o('AlphaNumeric'), o('ThisProperty')], Return: [ o('RETURN Expression', function() { return new Return($2); }), o('RETURN', function() { return new Return; }) ], Comment: [ o('HERECOMMENT', function() { return new Comment($1); }) ], Code: [ o('PARAM_START ParamList PARAM_END FuncGlyph Block', function() { return new Code($2, $5, $4); }), o('FuncGlyph Block', function() { return new Code([], $2, $1); }) ], FuncGlyph: [ o('->', function() { return 'func'; }), o('=>', function() { return 'boundfunc'; }) ], OptComma: [o(''), o(',')], ParamList: [ o('', function() { return []; }), o('Param', function() { return [$1]; }), o('ParamList , Param', function() { return $1.concat($3); }), o('ParamList OptComma TERMINATOR Param', function() { return $1.concat($4); }), o('ParamList OptComma INDENT ParamList OptComma OUTDENT', function() { return $1.concat($4); }) ], Param: [ o('ParamVar', function() { return new Param($1); }), o('ParamVar ...', function() { return new Param($1, null, true); }), o('ParamVar = Expression', function() { return new Param($1, $3); }) ], ParamVar: [o('Identifier'), o('ThisProperty'), o('Array'), o('Object')], Splat: [ o('Expression ...', function() { return new Splat($1); }) ], SimpleAssignable: [ o('Identifier', function() { return new Value($1); }), o('Value Accessor', function() { return $1.add($2); }), o('Invocation Accessor', function() { return new Value($1, [].concat($2)); }), o('ThisProperty') ], Assignable: [ o('SimpleAssignable'), o('Array', function() { return new Value($1); }), o('Object', function() { return new Value($1); }) ], Value: [ o('Assignable'), o('Literal', function() { return new Value($1); }), o('Parenthetical', function() { return new Value($1); }), o('Range', function() { return new Value($1); }), o('This') ], Accessor: [ o('. Identifier', function() { return new Access($2); }), o('?. Identifier', function() { return new Access($2, 'soak'); }), o(':: Identifier', function() { return [new Access(new Literal('prototype')), new Access($2)]; }), o('::', function() { return new Access(new Literal('prototype')); }), o('Index') ], Index: [ o('INDEX_START IndexValue INDEX_END', function() { return $2; }), o('INDEX_SOAK Index', function() { return extend($2, { soak: true }); }) ], IndexValue: [ o('Expression', function() { return new Index($1); }), o('Slice', function() { return new Slice($1); }) ], Object: [ o('{ AssignList OptComma }', function() { return new Obj($2, $1.generated); }) ], AssignList: [ o('', function() { return []; }), o('AssignObj', function() { return [$1]; }), o('AssignList , AssignObj', function() { return $1.concat($3); }), o('AssignList OptComma TERMINATOR AssignObj', function() { return $1.concat($4); }), o('AssignList OptComma INDENT AssignList OptComma OUTDENT', function() { return $1.concat($4); }) ], Class: [ o('CLASS', function() { return new Class; }), o('CLASS Block', function() { return new Class(null, null, $2); }), o('CLASS EXTENDS Expression', function() { return new Class(null, $3); }), o('CLASS EXTENDS Expression Block', function() { return new Class(null, $3, $4); }), o('CLASS SimpleAssignable', function() { return new Class($2); }), o('CLASS SimpleAssignable Block', function() { return new Class($2, null, $3); }), o('CLASS SimpleAssignable EXTENDS Expression', function() { return new Class($2, $4); }), o('CLASS SimpleAssignable EXTENDS Expression Block', function() { return new Class($2, $4, $5); }) ], Invocation: [ o('Value OptFuncExist Arguments', function() { return new Call($1, $3, $2); }), o('Invocation OptFuncExist Arguments', function() { return new Call($1, $3, $2); }), o('SUPER', function() { return new Call('super', [new Splat(new Literal('arguments'))]); }), o('SUPER Arguments', function() { return new Call('super', $2); }) ], OptFuncExist: [ o('', function() { return false; }), o('FUNC_EXIST', function() { return true; }) ], Arguments: [ o('CALL_START CALL_END', function() { return []; }), o('CALL_START ArgList OptComma CALL_END', function() { return $2; }) ], This: [ o('THIS', function() { return new Value(new Literal('this')); }), o('@', function() { return new Value(new Literal('this')); }) ], ThisProperty: [ o('@ Identifier', function() { return new Value(new Literal('this'), [new Access($2)], 'this'); }) ], Array: [ o('[ ]', function() { return new Arr([]); }), o('[ ArgList OptComma ]', function() { return new Arr($2); }) ], RangeDots: [ o('..', function() { return 'inclusive'; }), o('...', function() { return 'exclusive'; }) ], Range: [ o('[ Expression RangeDots Expression ]', function() { return new Range($2, $4, $3); }) ], Slice: [ o('Expression RangeDots Expression', function() { return new Range($1, $3, $2); }), o('Expression RangeDots', function() { return new Range($1, null, $2); }), o('RangeDots Expression', function() { return new Range(null, $2, $1); }), o('RangeDots', function() { return new Range(null, null, $1); }) ], ArgList: [ o('Arg', function() { return [$1]; }), o('ArgList , Arg', function() { return $1.concat($3); }), o('ArgList OptComma TERMINATOR Arg', function() { return $1.concat($4); }), o('INDENT ArgList OptComma OUTDENT', function() { return $2; }), o('ArgList OptComma INDENT ArgList OptComma OUTDENT', function() { return $1.concat($4); }) ], Arg: [o('Expression'), o('Splat')], SimpleArgs: [ o('Expression'), o('SimpleArgs , Expression', function() { return [].concat($1, $3); }) ], Try: [ o('TRY Block', function() { return new Try($2); }), o('TRY Block Catch', function() { return new Try($2, $3[0], $3[1]); }), o('TRY Block FINALLY Block', function() { return new Try($2, null, null, $4); }), o('TRY Block Catch FINALLY Block', function() { return new Try($2, $3[0], $3[1], $5); }) ], Catch: [ o('CATCH Identifier Block', function() { return [$2, $3]; }) ], Throw: [ o('THROW Expression', function() { return new Throw($2); }) ], Parenthetical: [ o('( Body )', function() { return new Parens($2); }), o('( INDENT Body OUTDENT )', function() { return new Parens($3); }) ], WhileSource: [ o('WHILE Expression', function() { return new While($2); }), o('WHILE Expression WHEN Expression', function() { return new While($2, { guard: $4 }); }), o('UNTIL Expression', function() { return new While($2, { invert: true }); }), o('UNTIL Expression WHEN Expression', function() { return new While($2, { invert: true, guard: $4 }); }) ], While: [ o('WhileSource Block', function() { return $1.addBody($2); }), o('Statement WhileSource', function() { return $2.addBody(Block.wrap([$1])); }), o('Expression WhileSource', function() { return $2.addBody(Block.wrap([$1])); }), o('Loop', function() { return $1; }) ], Loop: [ o('LOOP Block', function() { return new While(new Literal('true')).addBody($2); }), o('LOOP Expression', function() { return new While(new Literal('true')).addBody(Block.wrap([$2])); }) ], For: [ o('Statement ForBody', function() { return new For($1, $2); }), o('Expression ForBody', function() { return new For($1, $2); }), o('ForBody Block', function() { return new For($2, $1); }) ], ForBody: [ o('FOR Range', function() { return { source: new Value($2) }; }), o('ForStart ForSource', function() { $2.own = $1.own; $2.name = $1[0]; $2.index = $1[1]; return $2; }) ], ForStart: [ o('FOR ForVariables', function() { return $2; }), o('FOR OWN ForVariables', function() { $3.own = true; return $3; }) ], ForValue: [ o('Identifier'), o('ThisProperty'), o('Array', function() { return new Value($1); }), o('Object', function() { return new Value($1); }) ], ForVariables: [ o('ForValue', function() { return [$1]; }), o('ForValue , ForValue', function() { return [$1, $3]; }) ], ForSource: [ o('FORIN Expression', function() { return { source: $2 }; }), o('FOROF Expression', function() { return { source: $2, object: true }; }), o('FORIN Expression WHEN Expression', function() { return { source: $2, guard: $4 }; }), o('FOROF Expression WHEN Expression', function() { return { source: $2, guard: $4, object: true }; }), o('FORIN Expression BY Expression', function() { return { source: $2, step: $4 }; }), o('FORIN Expression WHEN Expression BY Expression', function() { return { source: $2, guard: $4, step: $6 }; }), o('FORIN Expression BY Expression WHEN Expression', function() { return { source: $2, step: $4, guard: $6 }; }) ], Switch: [ o('SWITCH Expression INDENT Whens OUTDENT', function() { return new Switch($2, $4); }), o('SWITCH Expression INDENT Whens ELSE Block OUTDENT', function() { return new Switch($2, $4, $6); }), o('SWITCH INDENT Whens OUTDENT', function() { return new Switch(null, $3); }), o('SWITCH INDENT Whens ELSE Block OUTDENT', function() { return new Switch(null, $3, $5); }) ], Whens: [ o('When'), o('Whens When', function() { return $1.concat($2); }) ], When: [ o('LEADING_WHEN SimpleArgs Block', function() { return [[$2, $3]]; }), o('LEADING_WHEN SimpleArgs Block TERMINATOR', function() { return [[$2, $3]]; }) ], IfBlock: [ o('IF Expression Block', function() { return new If($2, $3, { type: $1 }); }), o('IfBlock ELSE IF Expression Block', function() { return $1.addElse(new If($4, $5, { type: $3 })); }) ], If: [ o('IfBlock'), o('IfBlock ELSE Block', function() { return $1.addElse($3); }), o('Statement POST_IF Expression', function() { return new If($3, Block.wrap([$1]), { type: $2, statement: true }); }), o('Expression POST_IF Expression', function() { return new If($3, Block.wrap([$1]), { type: $2, statement: true }); }) ], Operation: [ o('UNARY Expression', function() { return new Op($1, $2); }), o('- Expression', (function() { return new Op('-', $2); }), { prec: 'UNARY' }), o('+ Expression', (function() { return new Op('+', $2); }), { prec: 'UNARY' }), o('-- SimpleAssignable', function() { return new Op('--', $2); }), o('++ SimpleAssignable', function() { return new Op('++', $2); }), o('SimpleAssignable --', function() { return new Op('--', $1, null, true); }), o('SimpleAssignable ++', function() { return new Op('++', $1, null, true); }), o('Expression ?', function() { return new Existence($1); }), o('Expression + Expression', function() { return new Op('+', $1, $3); }), o('Expression - Expression', function() { return new Op('-', $1, $3); }), o('Expression MATH Expression', function() { return new Op($2, $1, $3); }), o('Expression SHIFT Expression', function() { return new Op($2, $1, $3); }), o('Expression COMPARE Expression', function() { return new Op($2, $1, $3); }), o('Expression LOGIC Expression', function() { return new Op($2, $1, $3); }), o('Expression RELATION Expression', function() { if ($2.charAt(0) === '!') { return new Op($2.slice(1), $1, $3).invert(); } else { return new Op($2, $1, $3); } }), o('SimpleAssignable COMPOUND_ASSIGN\ Expression', function() { return new Assign($1, $3, $2); }), o('SimpleAssignable COMPOUND_ASSIGN\ INDENT Expression OUTDENT', function() { return new Assign($1, $4, $2); }), o('SimpleAssignable EXTENDS Expression', function() { return new Extends($1, $3); }) ] }; operators = [['left', '.', '?.', '::'], ['left', 'CALL_START', 'CALL_END'], ['nonassoc', '++', '--'], ['left', '?'], ['right', 'UNARY'], ['left', 'MATH'], ['left', '+', '-'], ['left', 'SHIFT'], ['left', 'RELATION'], ['left', 'COMPARE'], ['left', 'LOGIC'], ['nonassoc', 'INDENT', 'OUTDENT'], ['right', '=', ':', 'COMPOUND_ASSIGN', 'RETURN', 'THROW', 'EXTENDS'], ['right', 'FORIN', 'FOROF', 'BY', 'WHEN'], ['right', 'IF', 'ELSE', 'FOR', 'WHILE', 'UNTIL', 'LOOP', 'SUPER', 'CLASS'], ['right', 'POST_IF']]; tokens = []; for (name in grammar) { alternatives = grammar[name]; grammar[name] = (function() { var _i, _j, _len, _len1, _ref, _results; _results = []; for (_i = 0, _len = alternatives.length; _i < _len; _i++) { alt = alternatives[_i]; _ref = alt[0].split(' '); for (_j = 0, _len1 = _ref.length; _j < _len1; _j++) { token = _ref[_j]; if (!grammar[token]) { tokens.push(token); } } if (name === 'Root') { alt[1] = "return " + alt[1]; } _results.push(alt); } return _results; })(); } exports.parser = new Parser({ tokens: tokens.join(' '), bnf: grammar, operators: operators.reverse(), startSymbol: 'Root' }); }).call(this); coffee-script-1.4.0/lib/coffee-script/helpers.js000066400000000000000000000037341204160075300215510ustar00rootroot00000000000000// Generated by CoffeeScript 1.4.0 (function() { var extend, flatten, _ref; exports.starts = function(string, literal, start) { return literal === string.substr(start, literal.length); }; exports.ends = function(string, literal, back) { var len; len = literal.length; return literal === string.substr(string.length - len - (back || 0), len); }; exports.compact = function(array) { var item, _i, _len, _results; _results = []; for (_i = 0, _len = array.length; _i < _len; _i++) { item = array[_i]; if (item) { _results.push(item); } } return _results; }; exports.count = function(string, substr) { var num, pos; num = pos = 0; if (!substr.length) { return 1 / 0; } while (pos = 1 + string.indexOf(substr, pos)) { num++; } return num; }; exports.merge = function(options, overrides) { return extend(extend({}, options), overrides); }; extend = exports.extend = function(object, properties) { var key, val; for (key in properties) { val = properties[key]; object[key] = val; } return object; }; exports.flatten = flatten = function(array) { var element, flattened, _i, _len; flattened = []; for (_i = 0, _len = array.length; _i < _len; _i++) { element = array[_i]; if (element instanceof Array) { flattened = flattened.concat(flatten(element)); } else { flattened.push(element); } } return flattened; }; exports.del = function(obj, key) { var val; val = obj[key]; delete obj[key]; return val; }; exports.last = function(array, back) { return array[array.length - (back || 0) - 1]; }; exports.some = (_ref = Array.prototype.some) != null ? _ref : function(fn) { var e, _i, _len; for (_i = 0, _len = this.length; _i < _len; _i++) { e = this[_i]; if (fn(e)) { return true; } } return false; }; }).call(this); coffee-script-1.4.0/lib/coffee-script/index.js000066400000000000000000000003041204160075300212040ustar00rootroot00000000000000// Generated by CoffeeScript 1.4.0 (function() { var key, val, _ref; _ref = require('./coffee-script'); for (key in _ref) { val = _ref[key]; exports[key] = val; } }).call(this); coffee-script-1.4.0/lib/coffee-script/lexer.js000066400000000000000000000616351204160075300212320ustar00rootroot00000000000000// Generated by CoffeeScript 1.4.0 (function() { var BOOL, CALLABLE, CODE, COFFEE_ALIASES, COFFEE_ALIAS_MAP, COFFEE_KEYWORDS, COMMENT, COMPARE, COMPOUND_ASSIGN, HEREDOC, HEREDOC_ILLEGAL, HEREDOC_INDENT, HEREGEX, HEREGEX_OMIT, IDENTIFIER, INDEXABLE, INVERSES, JSTOKEN, JS_FORBIDDEN, JS_KEYWORDS, LINE_BREAK, LINE_CONTINUER, LOGIC, Lexer, MATH, MULTILINER, MULTI_DENT, NOT_REGEX, NOT_SPACED_REGEX, NUMBER, OPERATOR, REGEX, RELATION, RESERVED, Rewriter, SHIFT, SIMPLESTR, STRICT_PROSCRIBED, TRAILING_SPACES, UNARY, WHITESPACE, compact, count, key, last, starts, _ref, _ref1, __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }; _ref = require('./rewriter'), Rewriter = _ref.Rewriter, INVERSES = _ref.INVERSES; _ref1 = require('./helpers'), count = _ref1.count, starts = _ref1.starts, compact = _ref1.compact, last = _ref1.last; exports.Lexer = Lexer = (function() { function Lexer() {} Lexer.prototype.tokenize = function(code, opts) { var i, tag; if (opts == null) { opts = {}; } if (WHITESPACE.test(code)) { code = "\n" + code; } code = code.replace(/\r/g, '').replace(TRAILING_SPACES, ''); this.code = code; this.line = opts.line || 0; this.indent = 0; this.indebt = 0; this.outdebt = 0; this.indents = []; this.ends = []; this.tokens = []; i = 0; while (this.chunk = code.slice(i)) { i += this.identifierToken() || this.commentToken() || this.whitespaceToken() || this.lineToken() || this.heredocToken() || this.stringToken() || this.numberToken() || this.regexToken() || this.jsToken() || this.literalToken(); } this.closeIndentation(); if (tag = this.ends.pop()) { this.error("missing " + tag); } if (opts.rewrite === false) { return this.tokens; } return (new Rewriter).rewrite(this.tokens); }; Lexer.prototype.identifierToken = function() { var colon, forcedIdentifier, id, input, match, prev, tag, _ref2, _ref3; if (!(match = IDENTIFIER.exec(this.chunk))) { return 0; } input = match[0], id = match[1], colon = match[2]; if (id === 'own' && this.tag() === 'FOR') { this.token('OWN', id); return id.length; } forcedIdentifier = colon || (prev = last(this.tokens)) && (((_ref2 = prev[0]) === '.' || _ref2 === '?.' || _ref2 === '::') || !prev.spaced && prev[0] === '@'); tag = 'IDENTIFIER'; if (!forcedIdentifier && (__indexOf.call(JS_KEYWORDS, id) >= 0 || __indexOf.call(COFFEE_KEYWORDS, id) >= 0)) { tag = id.toUpperCase(); if (tag === 'WHEN' && (_ref3 = this.tag(), __indexOf.call(LINE_BREAK, _ref3) >= 0)) { tag = 'LEADING_WHEN'; } else if (tag === 'FOR') { this.seenFor = true; } else if (tag === 'UNLESS') { tag = 'IF'; } else if (__indexOf.call(UNARY, tag) >= 0) { tag = 'UNARY'; } else if (__indexOf.call(RELATION, tag) >= 0) { if (tag !== 'INSTANCEOF' && this.seenFor) { tag = 'FOR' + tag; this.seenFor = false; } else { tag = 'RELATION'; if (this.value() === '!') { this.tokens.pop(); id = '!' + id; } } } } if (__indexOf.call(JS_FORBIDDEN, id) >= 0) { if (forcedIdentifier) { tag = 'IDENTIFIER'; id = new String(id); id.reserved = true; } else if (__indexOf.call(RESERVED, id) >= 0) { this.error("reserved word \"" + id + "\""); } } if (!forcedIdentifier) { if (__indexOf.call(COFFEE_ALIASES, id) >= 0) { id = COFFEE_ALIAS_MAP[id]; } tag = (function() { switch (id) { case '!': return 'UNARY'; case '==': case '!=': return 'COMPARE'; case '&&': case '||': return 'LOGIC'; case 'true': case 'false': return 'BOOL'; case 'break': case 'continue': return 'STATEMENT'; default: return tag; } })(); } this.token(tag, id); if (colon) { this.token(':', ':'); } return input.length; }; Lexer.prototype.numberToken = function() { var binaryLiteral, lexedLength, match, number, octalLiteral; if (!(match = NUMBER.exec(this.chunk))) { return 0; } number = match[0]; if (/^0[BOX]/.test(number)) { this.error("radix prefix '" + number + "' must be lowercase"); } else if (/E/.test(number) && !/^0x/.test(number)) { this.error("exponential notation '" + number + "' must be indicated with a lowercase 'e'"); } else if (/^0\d*[89]/.test(number)) { this.error("decimal literal '" + number + "' must not be prefixed with '0'"); } else if (/^0\d+/.test(number)) { this.error("octal literal '" + number + "' must be prefixed with '0o'"); } lexedLength = number.length; if (octalLiteral = /^0o([0-7]+)/.exec(number)) { number = '0x' + (parseInt(octalLiteral[1], 8)).toString(16); } if (binaryLiteral = /^0b([01]+)/.exec(number)) { number = '0x' + (parseInt(binaryLiteral[1], 2)).toString(16); } this.token('NUMBER', number); return lexedLength; }; Lexer.prototype.stringToken = function() { var match, octalEsc, string; switch (this.chunk.charAt(0)) { case "'": if (!(match = SIMPLESTR.exec(this.chunk))) { return 0; } this.token('STRING', (string = match[0]).replace(MULTILINER, '\\\n')); break; case '"': if (!(string = this.balancedString(this.chunk, '"'))) { return 0; } if (0 < string.indexOf('#{', 1)) { this.interpolateString(string.slice(1, -1)); } else { this.token('STRING', this.escapeLines(string)); } break; default: return 0; } if (octalEsc = /^(?:\\.|[^\\])*\\(?:0[0-7]|[1-7])/.test(string)) { this.error("octal escape sequences " + string + " are not allowed"); } this.line += count(string, '\n'); return string.length; }; Lexer.prototype.heredocToken = function() { var doc, heredoc, match, quote; if (!(match = HEREDOC.exec(this.chunk))) { return 0; } heredoc = match[0]; quote = heredoc.charAt(0); doc = this.sanitizeHeredoc(match[2], { quote: quote, indent: null }); if (quote === '"' && 0 <= doc.indexOf('#{')) { this.interpolateString(doc, { heredoc: true }); } else { this.token('STRING', this.makeString(doc, quote, true)); } this.line += count(heredoc, '\n'); return heredoc.length; }; Lexer.prototype.commentToken = function() { var comment, here, match; if (!(match = this.chunk.match(COMMENT))) { return 0; } comment = match[0], here = match[1]; if (here) { this.token('HERECOMMENT', this.sanitizeHeredoc(here, { herecomment: true, indent: Array(this.indent + 1).join(' ') })); } this.line += count(comment, '\n'); return comment.length; }; Lexer.prototype.jsToken = function() { var match, script; if (!(this.chunk.charAt(0) === '`' && (match = JSTOKEN.exec(this.chunk)))) { return 0; } this.token('JS', (script = match[0]).slice(1, -1)); this.line += count(script, '\n'); return script.length; }; Lexer.prototype.regexToken = function() { var flags, length, match, prev, regex, _ref2, _ref3; if (this.chunk.charAt(0) !== '/') { return 0; } if (match = HEREGEX.exec(this.chunk)) { length = this.heregexToken(match); this.line += count(match[0], '\n'); return length; } prev = last(this.tokens); if (prev && (_ref2 = prev[0], __indexOf.call((prev.spaced ? NOT_REGEX : NOT_SPACED_REGEX), _ref2) >= 0)) { return 0; } if (!(match = REGEX.exec(this.chunk))) { return 0; } _ref3 = match, match = _ref3[0], regex = _ref3[1], flags = _ref3[2]; if (regex.slice(0, 2) === '/*') { this.error('regular expressions cannot begin with `*`'); } if (regex === '//') { regex = '/(?:)/'; } this.token('REGEX', "" + regex + flags); return match.length; }; Lexer.prototype.heregexToken = function(match) { var body, flags, heregex, re, tag, tokens, value, _i, _len, _ref2, _ref3, _ref4, _ref5; heregex = match[0], body = match[1], flags = match[2]; if (0 > body.indexOf('#{')) { re = body.replace(HEREGEX_OMIT, '').replace(/\//g, '\\/'); if (re.match(/^\*/)) { this.error('regular expressions cannot begin with `*`'); } this.token('REGEX', "/" + (re || '(?:)') + "/" + flags); return heregex.length; } this.token('IDENTIFIER', 'RegExp'); this.tokens.push(['CALL_START', '(']); tokens = []; _ref2 = this.interpolateString(body, { regex: true }); for (_i = 0, _len = _ref2.length; _i < _len; _i++) { _ref3 = _ref2[_i], tag = _ref3[0], value = _ref3[1]; if (tag === 'TOKENS') { tokens.push.apply(tokens, value); } else { if (!(value = value.replace(HEREGEX_OMIT, ''))) { continue; } value = value.replace(/\\/g, '\\\\'); tokens.push(['STRING', this.makeString(value, '"', true)]); } tokens.push(['+', '+']); } tokens.pop(); if (((_ref4 = tokens[0]) != null ? _ref4[0] : void 0) !== 'STRING') { this.tokens.push(['STRING', '""'], ['+', '+']); } (_ref5 = this.tokens).push.apply(_ref5, tokens); if (flags) { this.tokens.push([',', ','], ['STRING', '"' + flags + '"']); } this.token(')', ')'); return heregex.length; }; Lexer.prototype.lineToken = function() { var diff, indent, match, noNewlines, size; if (!(match = MULTI_DENT.exec(this.chunk))) { return 0; } indent = match[0]; this.line += count(indent, '\n'); this.seenFor = false; size = indent.length - 1 - indent.lastIndexOf('\n'); noNewlines = this.unfinished(); if (size - this.indebt === this.indent) { if (noNewlines) { this.suppressNewlines(); } else { this.newlineToken(); } return indent.length; } if (size > this.indent) { if (noNewlines) { this.indebt = size - this.indent; this.suppressNewlines(); return indent.length; } diff = size - this.indent + this.outdebt; this.token('INDENT', diff); this.indents.push(diff); this.ends.push('OUTDENT'); this.outdebt = this.indebt = 0; } else { this.indebt = 0; this.outdentToken(this.indent - size, noNewlines); } this.indent = size; return indent.length; }; Lexer.prototype.outdentToken = function(moveOut, noNewlines) { var dent, len; while (moveOut > 0) { len = this.indents.length - 1; if (this.indents[len] === void 0) { moveOut = 0; } else if (this.indents[len] === this.outdebt) { moveOut -= this.outdebt; this.outdebt = 0; } else if (this.indents[len] < this.outdebt) { this.outdebt -= this.indents[len]; moveOut -= this.indents[len]; } else { dent = this.indents.pop() - this.outdebt; moveOut -= dent; this.outdebt = 0; this.pair('OUTDENT'); this.token('OUTDENT', dent); } } if (dent) { this.outdebt -= moveOut; } while (this.value() === ';') { this.tokens.pop(); } if (!(this.tag() === 'TERMINATOR' || noNewlines)) { this.token('TERMINATOR', '\n'); } return this; }; Lexer.prototype.whitespaceToken = function() { var match, nline, prev; if (!((match = WHITESPACE.exec(this.chunk)) || (nline = this.chunk.charAt(0) === '\n'))) { return 0; } prev = last(this.tokens); if (prev) { prev[match ? 'spaced' : 'newLine'] = true; } if (match) { return match[0].length; } else { return 0; } }; Lexer.prototype.newlineToken = function() { while (this.value() === ';') { this.tokens.pop(); } if (this.tag() !== 'TERMINATOR') { this.token('TERMINATOR', '\n'); } return this; }; Lexer.prototype.suppressNewlines = function() { if (this.value() === '\\') { this.tokens.pop(); } return this; }; Lexer.prototype.literalToken = function() { var match, prev, tag, value, _ref2, _ref3, _ref4, _ref5; if (match = OPERATOR.exec(this.chunk)) { value = match[0]; if (CODE.test(value)) { this.tagParameters(); } } else { value = this.chunk.charAt(0); } tag = value; prev = last(this.tokens); if (value === '=' && prev) { if (!prev[1].reserved && (_ref2 = prev[1], __indexOf.call(JS_FORBIDDEN, _ref2) >= 0)) { this.error("reserved word \"" + (this.value()) + "\" can't be assigned"); } if ((_ref3 = prev[1]) === '||' || _ref3 === '&&') { prev[0] = 'COMPOUND_ASSIGN'; prev[1] += '='; return value.length; } } if (value === ';') { this.seenFor = false; tag = 'TERMINATOR'; } else if (__indexOf.call(MATH, value) >= 0) { tag = 'MATH'; } else if (__indexOf.call(COMPARE, value) >= 0) { tag = 'COMPARE'; } else if (__indexOf.call(COMPOUND_ASSIGN, value) >= 0) { tag = 'COMPOUND_ASSIGN'; } else if (__indexOf.call(UNARY, value) >= 0) { tag = 'UNARY'; } else if (__indexOf.call(SHIFT, value) >= 0) { tag = 'SHIFT'; } else if (__indexOf.call(LOGIC, value) >= 0 || value === '?' && (prev != null ? prev.spaced : void 0)) { tag = 'LOGIC'; } else if (prev && !prev.spaced) { if (value === '(' && (_ref4 = prev[0], __indexOf.call(CALLABLE, _ref4) >= 0)) { if (prev[0] === '?') { prev[0] = 'FUNC_EXIST'; } tag = 'CALL_START'; } else if (value === '[' && (_ref5 = prev[0], __indexOf.call(INDEXABLE, _ref5) >= 0)) { tag = 'INDEX_START'; switch (prev[0]) { case '?': prev[0] = 'INDEX_SOAK'; } } } switch (value) { case '(': case '{': case '[': this.ends.push(INVERSES[value]); break; case ')': case '}': case ']': this.pair(value); } this.token(tag, value); return value.length; }; Lexer.prototype.sanitizeHeredoc = function(doc, options) { var attempt, herecomment, indent, match, _ref2; indent = options.indent, herecomment = options.herecomment; if (herecomment) { if (HEREDOC_ILLEGAL.test(doc)) { this.error("block comment cannot contain \"*/\", starting"); } if (doc.indexOf('\n') <= 0) { return doc; } } else { while (match = HEREDOC_INDENT.exec(doc)) { attempt = match[1]; if (indent === null || (0 < (_ref2 = attempt.length) && _ref2 < indent.length)) { indent = attempt; } } } if (indent) { doc = doc.replace(RegExp("\\n" + indent, "g"), '\n'); } if (!herecomment) { doc = doc.replace(/^\n/, ''); } return doc; }; Lexer.prototype.tagParameters = function() { var i, stack, tok, tokens; if (this.tag() !== ')') { return this; } stack = []; tokens = this.tokens; i = tokens.length; tokens[--i][0] = 'PARAM_END'; while (tok = tokens[--i]) { switch (tok[0]) { case ')': stack.push(tok); break; case '(': case 'CALL_START': if (stack.length) { stack.pop(); } else if (tok[0] === '(') { tok[0] = 'PARAM_START'; return this; } else { return this; } } } return this; }; Lexer.prototype.closeIndentation = function() { return this.outdentToken(this.indent); }; Lexer.prototype.balancedString = function(str, end) { var continueCount, i, letter, match, prev, stack, _i, _ref2; continueCount = 0; stack = [end]; for (i = _i = 1, _ref2 = str.length; 1 <= _ref2 ? _i < _ref2 : _i > _ref2; i = 1 <= _ref2 ? ++_i : --_i) { if (continueCount) { --continueCount; continue; } switch (letter = str.charAt(i)) { case '\\': ++continueCount; continue; case end: stack.pop(); if (!stack.length) { return str.slice(0, +i + 1 || 9e9); } end = stack[stack.length - 1]; continue; } if (end === '}' && (letter === '"' || letter === "'")) { stack.push(end = letter); } else if (end === '}' && letter === '/' && (match = HEREGEX.exec(str.slice(i)) || REGEX.exec(str.slice(i)))) { continueCount += match[0].length - 1; } else if (end === '}' && letter === '{') { stack.push(end = '}'); } else if (end === '"' && prev === '#' && letter === '{') { stack.push(end = '}'); } prev = letter; } return this.error("missing " + (stack.pop()) + ", starting"); }; Lexer.prototype.interpolateString = function(str, options) { var expr, heredoc, i, inner, interpolated, len, letter, nested, pi, regex, tag, tokens, value, _i, _len, _ref2, _ref3, _ref4; if (options == null) { options = {}; } heredoc = options.heredoc, regex = options.regex; tokens = []; pi = 0; i = -1; while (letter = str.charAt(i += 1)) { if (letter === '\\') { i += 1; continue; } if (!(letter === '#' && str.charAt(i + 1) === '{' && (expr = this.balancedString(str.slice(i + 1), '}')))) { continue; } if (pi < i) { tokens.push(['NEOSTRING', str.slice(pi, i)]); } inner = expr.slice(1, -1); if (inner.length) { nested = new Lexer().tokenize(inner, { line: this.line, rewrite: false }); nested.pop(); if (((_ref2 = nested[0]) != null ? _ref2[0] : void 0) === 'TERMINATOR') { nested.shift(); } if (len = nested.length) { if (len > 1) { nested.unshift(['(', '(', this.line]); nested.push([')', ')', this.line]); } tokens.push(['TOKENS', nested]); } } i += expr.length; pi = i + 1; } if ((i > pi && pi < str.length)) { tokens.push(['NEOSTRING', str.slice(pi)]); } if (regex) { return tokens; } if (!tokens.length) { return this.token('STRING', '""'); } if (tokens[0][0] !== 'NEOSTRING') { tokens.unshift(['', '']); } if (interpolated = tokens.length > 1) { this.token('(', '('); } for (i = _i = 0, _len = tokens.length; _i < _len; i = ++_i) { _ref3 = tokens[i], tag = _ref3[0], value = _ref3[1]; if (i) { this.token('+', '+'); } if (tag === 'TOKENS') { (_ref4 = this.tokens).push.apply(_ref4, value); } else { this.token('STRING', this.makeString(value, '"', heredoc)); } } if (interpolated) { this.token(')', ')'); } return tokens; }; Lexer.prototype.pair = function(tag) { var size, wanted; if (tag !== (wanted = last(this.ends))) { if ('OUTDENT' !== wanted) { this.error("unmatched " + tag); } this.indent -= size = last(this.indents); this.outdentToken(size, true); return this.pair(tag); } return this.ends.pop(); }; Lexer.prototype.token = function(tag, value) { return this.tokens.push([tag, value, this.line]); }; Lexer.prototype.tag = function(index, tag) { var tok; return (tok = last(this.tokens, index)) && (tag ? tok[0] = tag : tok[0]); }; Lexer.prototype.value = function(index, val) { var tok; return (tok = last(this.tokens, index)) && (val ? tok[1] = val : tok[1]); }; Lexer.prototype.unfinished = function() { var _ref2; return LINE_CONTINUER.test(this.chunk) || ((_ref2 = this.tag()) === '\\' || _ref2 === '.' || _ref2 === '?.' || _ref2 === 'UNARY' || _ref2 === 'MATH' || _ref2 === '+' || _ref2 === '-' || _ref2 === 'SHIFT' || _ref2 === 'RELATION' || _ref2 === 'COMPARE' || _ref2 === 'LOGIC' || _ref2 === 'THROW' || _ref2 === 'EXTENDS'); }; Lexer.prototype.escapeLines = function(str, heredoc) { return str.replace(MULTILINER, heredoc ? '\\n' : ''); }; Lexer.prototype.makeString = function(body, quote, heredoc) { if (!body) { return quote + quote; } body = body.replace(/\\([\s\S])/g, function(match, contents) { if (contents === '\n' || contents === quote) { return contents; } else { return match; } }); body = body.replace(RegExp("" + quote, "g"), '\\$&'); return quote + this.escapeLines(body, heredoc) + quote; }; Lexer.prototype.error = function(message) { throw SyntaxError("" + message + " on line " + (this.line + 1)); }; return Lexer; })(); JS_KEYWORDS = ['true', 'false', 'null', 'this', 'new', 'delete', 'typeof', 'in', 'instanceof', 'return', 'throw', 'break', 'continue', 'debugger', 'if', 'else', 'switch', 'for', 'while', 'do', 'try', 'catch', 'finally', 'class', 'extends', 'super']; COFFEE_KEYWORDS = ['undefined', 'then', 'unless', 'until', 'loop', 'of', 'by', 'when']; COFFEE_ALIAS_MAP = { and: '&&', or: '||', is: '==', isnt: '!=', not: '!', yes: 'true', no: 'false', on: 'true', off: 'false' }; COFFEE_ALIASES = (function() { var _results; _results = []; for (key in COFFEE_ALIAS_MAP) { _results.push(key); } return _results; })(); COFFEE_KEYWORDS = COFFEE_KEYWORDS.concat(COFFEE_ALIASES); RESERVED = ['case', 'default', 'function', 'var', 'void', 'with', 'const', 'let', 'enum', 'export', 'import', 'native', '__hasProp', '__extends', '__slice', '__bind', '__indexOf', 'implements', 'interface', 'package', 'private', 'protected', 'public', 'static', 'yield']; STRICT_PROSCRIBED = ['arguments', 'eval']; JS_FORBIDDEN = JS_KEYWORDS.concat(RESERVED).concat(STRICT_PROSCRIBED); exports.RESERVED = RESERVED.concat(JS_KEYWORDS).concat(COFFEE_KEYWORDS).concat(STRICT_PROSCRIBED); exports.STRICT_PROSCRIBED = STRICT_PROSCRIBED; IDENTIFIER = /^([$A-Za-z_\x7f-\uffff][$\w\x7f-\uffff]*)([^\n\S]*:(?!:))?/; NUMBER = /^0b[01]+|^0o[0-7]+|^0x[\da-f]+|^\d*\.?\d+(?:e[+-]?\d+)?/i; HEREDOC = /^("""|''')([\s\S]*?)(?:\n[^\n\S]*)?\1/; OPERATOR = /^(?:[-=]>|[-+*\/%<>&|^!?=]=|>>>=?|([-+:])\1|([&|<>])\2=?|\?\.|\.{2,3})/; WHITESPACE = /^[^\n\S]+/; COMMENT = /^###([^#][\s\S]*?)(?:###[^\n\S]*|(?:###)?$)|^(?:\s*#(?!##[^#]).*)+/; CODE = /^[-=]>/; MULTI_DENT = /^(?:\n[^\n\S]*)+/; SIMPLESTR = /^'[^\\']*(?:\\.[^\\']*)*'/; JSTOKEN = /^`[^\\`]*(?:\\.[^\\`]*)*`/; REGEX = /^(\/(?![\s=])[^[\/\n\\]*(?:(?:\\[\s\S]|\[[^\]\n\\]*(?:\\[\s\S][^\]\n\\]*)*])[^[\/\n\\]*)*\/)([imgy]{0,4})(?!\w)/; HEREGEX = /^\/{3}([\s\S]+?)\/{3}([imgy]{0,4})(?!\w)/; HEREGEX_OMIT = /\s+(?:#.*)?/g; MULTILINER = /\n/g; HEREDOC_INDENT = /\n+([^\n\S]*)/g; HEREDOC_ILLEGAL = /\*\//; LINE_CONTINUER = /^\s*(?:,|\??\.(?![.\d])|::)/; TRAILING_SPACES = /\s+$/; COMPOUND_ASSIGN = ['-=', '+=', '/=', '*=', '%=', '||=', '&&=', '?=', '<<=', '>>=', '>>>=', '&=', '^=', '|=']; UNARY = ['!', '~', 'NEW', 'TYPEOF', 'DELETE', 'DO']; LOGIC = ['&&', '||', '&', '|', '^']; SHIFT = ['<<', '>>', '>>>']; COMPARE = ['==', '!=', '<', '>', '<=', '>=']; MATH = ['*', '/', '%']; RELATION = ['IN', 'OF', 'INSTANCEOF']; BOOL = ['TRUE', 'FALSE']; NOT_REGEX = ['NUMBER', 'REGEX', 'BOOL', 'NULL', 'UNDEFINED', '++', '--', ']']; NOT_SPACED_REGEX = NOT_REGEX.concat(')', '}', 'THIS', 'IDENTIFIER', 'STRING'); CALLABLE = ['IDENTIFIER', 'STRING', 'REGEX', ')', ']', '}', '?', '::', '@', 'THIS', 'SUPER']; INDEXABLE = CALLABLE.concat('NUMBER', 'BOOL', 'NULL', 'UNDEFINED'); LINE_BREAK = ['INDENT', 'OUTDENT', 'TERMINATOR']; }).call(this); coffee-script-1.4.0/lib/coffee-script/nodes.js000066400000000000000000002631561204160075300212250ustar00rootroot00000000000000// Generated by CoffeeScript 1.4.0 (function() { var Access, Arr, Assign, Base, Block, Call, Class, Closure, Code, Comment, Existence, Extends, For, IDENTIFIER, IDENTIFIER_STR, IS_STRING, If, In, Index, LEVEL_ACCESS, LEVEL_COND, LEVEL_LIST, LEVEL_OP, LEVEL_PAREN, LEVEL_TOP, Literal, METHOD_DEF, NEGATE, NO, Obj, Op, Param, Parens, RESERVED, Range, Return, SIMPLENUM, STRICT_PROSCRIBED, Scope, Slice, Splat, Switch, TAB, THIS, Throw, Try, UTILITIES, Value, While, YES, compact, del, ends, extend, flatten, last, merge, multident, some, starts, unfoldSoak, utility, _ref, _ref1, __hasProp = {}.hasOwnProperty, __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }; Scope = require('./scope').Scope; _ref = require('./lexer'), RESERVED = _ref.RESERVED, STRICT_PROSCRIBED = _ref.STRICT_PROSCRIBED; _ref1 = require('./helpers'), compact = _ref1.compact, flatten = _ref1.flatten, extend = _ref1.extend, merge = _ref1.merge, del = _ref1.del, starts = _ref1.starts, ends = _ref1.ends, last = _ref1.last, some = _ref1.some; exports.extend = extend; YES = function() { return true; }; NO = function() { return false; }; THIS = function() { return this; }; NEGATE = function() { this.negated = !this.negated; return this; }; exports.Base = Base = (function() { function Base() {} Base.prototype.compile = function(o, lvl) { var node; o = extend({}, o); if (lvl) { o.level = lvl; } node = this.unfoldSoak(o) || this; node.tab = o.indent; if (o.level === LEVEL_TOP || !node.isStatement(o)) { return node.compileNode(o); } else { return node.compileClosure(o); } }; Base.prototype.compileClosure = function(o) { if (this.jumps()) { throw SyntaxError('cannot use a pure statement in an expression.'); } o.sharedScope = true; return Closure.wrap(this).compileNode(o); }; Base.prototype.cache = function(o, level, reused) { var ref, sub; if (!this.isComplex()) { ref = level ? this.compile(o, level) : this; return [ref, ref]; } else { ref = new Literal(reused || o.scope.freeVariable('ref')); sub = new Assign(ref, this); if (level) { return [sub.compile(o, level), ref.value]; } else { return [sub, ref]; } } }; Base.prototype.compileLoopReference = function(o, name) { var src, tmp; src = tmp = this.compile(o, LEVEL_LIST); if (!((-Infinity < +src && +src < Infinity) || IDENTIFIER.test(src) && o.scope.check(src, true))) { src = "" + (tmp = o.scope.freeVariable(name)) + " = " + src; } return [src, tmp]; }; Base.prototype.makeReturn = function(res) { var me; me = this.unwrapAll(); if (res) { return new Call(new Literal("" + res + ".push"), [me]); } else { return new Return(me); } }; Base.prototype.contains = function(pred) { var contains; contains = false; this.traverseChildren(false, function(node) { if (pred(node)) { contains = true; return false; } }); return contains; }; Base.prototype.containsType = function(type) { return this instanceof type || this.contains(function(node) { return node instanceof type; }); }; Base.prototype.lastNonComment = function(list) { var i; i = list.length; while (i--) { if (!(list[i] instanceof Comment)) { return list[i]; } } return null; }; Base.prototype.toString = function(idt, name) { var tree; if (idt == null) { idt = ''; } if (name == null) { name = this.constructor.name; } tree = '\n' + idt + name; if (this.soak) { tree += '?'; } this.eachChild(function(node) { return tree += node.toString(idt + TAB); }); return tree; }; Base.prototype.eachChild = function(func) { var attr, child, _i, _j, _len, _len1, _ref2, _ref3; if (!this.children) { return this; } _ref2 = this.children; for (_i = 0, _len = _ref2.length; _i < _len; _i++) { attr = _ref2[_i]; if (this[attr]) { _ref3 = flatten([this[attr]]); for (_j = 0, _len1 = _ref3.length; _j < _len1; _j++) { child = _ref3[_j]; if (func(child) === false) { return this; } } } } return this; }; Base.prototype.traverseChildren = function(crossScope, func) { return this.eachChild(function(child) { if (func(child) === false) { return false; } return child.traverseChildren(crossScope, func); }); }; Base.prototype.invert = function() { return new Op('!', this); }; Base.prototype.unwrapAll = function() { var node; node = this; while (node !== (node = node.unwrap())) { continue; } return node; }; Base.prototype.children = []; Base.prototype.isStatement = NO; Base.prototype.jumps = NO; Base.prototype.isComplex = YES; Base.prototype.isChainable = NO; Base.prototype.isAssignable = NO; Base.prototype.unwrap = THIS; Base.prototype.unfoldSoak = NO; Base.prototype.assigns = NO; return Base; })(); exports.Block = Block = (function(_super) { __extends(Block, _super); function Block(nodes) { this.expressions = compact(flatten(nodes || [])); } Block.prototype.children = ['expressions']; Block.prototype.push = function(node) { this.expressions.push(node); return this; }; Block.prototype.pop = function() { return this.expressions.pop(); }; Block.prototype.unshift = function(node) { this.expressions.unshift(node); return this; }; Block.prototype.unwrap = function() { if (this.expressions.length === 1) { return this.expressions[0]; } else { return this; } }; Block.prototype.isEmpty = function() { return !this.expressions.length; }; Block.prototype.isStatement = function(o) { var exp, _i, _len, _ref2; _ref2 = this.expressions; for (_i = 0, _len = _ref2.length; _i < _len; _i++) { exp = _ref2[_i]; if (exp.isStatement(o)) { return true; } } return false; }; Block.prototype.jumps = function(o) { var exp, _i, _len, _ref2; _ref2 = this.expressions; for (_i = 0, _len = _ref2.length; _i < _len; _i++) { exp = _ref2[_i]; if (exp.jumps(o)) { return exp; } } }; Block.prototype.makeReturn = function(res) { var expr, len; len = this.expressions.length; while (len--) { expr = this.expressions[len]; if (!(expr instanceof Comment)) { this.expressions[len] = expr.makeReturn(res); if (expr instanceof Return && !expr.expression) { this.expressions.splice(len, 1); } break; } } return this; }; Block.prototype.compile = function(o, level) { if (o == null) { o = {}; } if (o.scope) { return Block.__super__.compile.call(this, o, level); } else { return this.compileRoot(o); } }; Block.prototype.compileNode = function(o) { var code, codes, node, top, _i, _len, _ref2; this.tab = o.indent; top = o.level === LEVEL_TOP; codes = []; _ref2 = this.expressions; for (_i = 0, _len = _ref2.length; _i < _len; _i++) { node = _ref2[_i]; node = node.unwrapAll(); node = node.unfoldSoak(o) || node; if (node instanceof Block) { codes.push(node.compileNode(o)); } else if (top) { node.front = true; code = node.compile(o); if (!node.isStatement(o)) { code = "" + this.tab + code + ";"; if (node instanceof Literal) { code = "" + code + "\n"; } } codes.push(code); } else { codes.push(node.compile(o, LEVEL_LIST)); } } if (top) { if (this.spaced) { return "\n" + (codes.join('\n\n')) + "\n"; } else { return codes.join('\n'); } } code = codes.join(', ') || 'void 0'; if (codes.length > 1 && o.level >= LEVEL_LIST) { return "(" + code + ")"; } else { return code; } }; Block.prototype.compileRoot = function(o) { var code, exp, i, prelude, preludeExps, rest; o.indent = o.bare ? '' : TAB; o.scope = new Scope(null, this, null); o.level = LEVEL_TOP; this.spaced = true; prelude = ""; if (!o.bare) { preludeExps = (function() { var _i, _len, _ref2, _results; _ref2 = this.expressions; _results = []; for (i = _i = 0, _len = _ref2.length; _i < _len; i = ++_i) { exp = _ref2[i]; if (!(exp.unwrap() instanceof Comment)) { break; } _results.push(exp); } return _results; }).call(this); rest = this.expressions.slice(preludeExps.length); this.expressions = preludeExps; if (preludeExps.length) { prelude = "" + (this.compileNode(merge(o, { indent: '' }))) + "\n"; } this.expressions = rest; } code = this.compileWithDeclarations(o); if (o.bare) { return code; } return "" + prelude + "(function() {\n" + code + "\n}).call(this);\n"; }; Block.prototype.compileWithDeclarations = function(o) { var assigns, code, declars, exp, i, post, rest, scope, spaced, _i, _len, _ref2, _ref3, _ref4; code = post = ''; _ref2 = this.expressions; for (i = _i = 0, _len = _ref2.length; _i < _len; i = ++_i) { exp = _ref2[i]; exp = exp.unwrap(); if (!(exp instanceof Comment || exp instanceof Literal)) { break; } } o = merge(o, { level: LEVEL_TOP }); if (i) { rest = this.expressions.splice(i, 9e9); _ref3 = [this.spaced, false], spaced = _ref3[0], this.spaced = _ref3[1]; _ref4 = [this.compileNode(o), spaced], code = _ref4[0], this.spaced = _ref4[1]; this.expressions = rest; } post = this.compileNode(o); scope = o.scope; if (scope.expressions === this) { declars = o.scope.hasDeclarations(); assigns = scope.hasAssignments; if (declars || assigns) { if (i) { code += '\n'; } code += "" + this.tab + "var "; if (declars) { code += scope.declaredVariables().join(', '); } if (assigns) { if (declars) { code += ",\n" + (this.tab + TAB); } code += scope.assignedVariables().join(",\n" + (this.tab + TAB)); } code += ';\n'; } } return code + post; }; Block.wrap = function(nodes) { if (nodes.length === 1 && nodes[0] instanceof Block) { return nodes[0]; } return new Block(nodes); }; return Block; })(Base); exports.Literal = Literal = (function(_super) { __extends(Literal, _super); function Literal(value) { this.value = value; } Literal.prototype.makeReturn = function() { if (this.isStatement()) { return this; } else { return Literal.__super__.makeReturn.apply(this, arguments); } }; Literal.prototype.isAssignable = function() { return IDENTIFIER.test(this.value); }; Literal.prototype.isStatement = function() { var _ref2; return (_ref2 = this.value) === 'break' || _ref2 === 'continue' || _ref2 === 'debugger'; }; Literal.prototype.isComplex = NO; Literal.prototype.assigns = function(name) { return name === this.value; }; Literal.prototype.jumps = function(o) { if (this.value === 'break' && !((o != null ? o.loop : void 0) || (o != null ? o.block : void 0))) { return this; } if (this.value === 'continue' && !(o != null ? o.loop : void 0)) { return this; } }; Literal.prototype.compileNode = function(o) { var code, _ref2; code = this.value === 'this' ? ((_ref2 = o.scope.method) != null ? _ref2.bound : void 0) ? o.scope.method.context : this.value : this.value.reserved ? "\"" + this.value + "\"" : this.value; if (this.isStatement()) { return "" + this.tab + code + ";"; } else { return code; } }; Literal.prototype.toString = function() { return ' "' + this.value + '"'; }; return Literal; })(Base); exports.Undefined = (function(_super) { __extends(Undefined, _super); function Undefined() { return Undefined.__super__.constructor.apply(this, arguments); } Undefined.prototype.isAssignable = NO; Undefined.prototype.isComplex = NO; Undefined.prototype.compileNode = function(o) { if (o.level >= LEVEL_ACCESS) { return '(void 0)'; } else { return 'void 0'; } }; return Undefined; })(Base); exports.Null = (function(_super) { __extends(Null, _super); function Null() { return Null.__super__.constructor.apply(this, arguments); } Null.prototype.isAssignable = NO; Null.prototype.isComplex = NO; Null.prototype.compileNode = function() { return "null"; }; return Null; })(Base); exports.Bool = (function(_super) { __extends(Bool, _super); Bool.prototype.isAssignable = NO; Bool.prototype.isComplex = NO; Bool.prototype.compileNode = function() { return this.val; }; function Bool(val) { this.val = val; } return Bool; })(Base); exports.Return = Return = (function(_super) { __extends(Return, _super); function Return(expr) { if (expr && !expr.unwrap().isUndefined) { this.expression = expr; } } Return.prototype.children = ['expression']; Return.prototype.isStatement = YES; Return.prototype.makeReturn = THIS; Return.prototype.jumps = THIS; Return.prototype.compile = function(o, level) { var expr, _ref2; expr = (_ref2 = this.expression) != null ? _ref2.makeReturn() : void 0; if (expr && !(expr instanceof Return)) { return expr.compile(o, level); } else { return Return.__super__.compile.call(this, o, level); } }; Return.prototype.compileNode = function(o) { return this.tab + ("return" + [this.expression ? " " + (this.expression.compile(o, LEVEL_PAREN)) : void 0] + ";"); }; return Return; })(Base); exports.Value = Value = (function(_super) { __extends(Value, _super); function Value(base, props, tag) { if (!props && base instanceof Value) { return base; } this.base = base; this.properties = props || []; if (tag) { this[tag] = true; } return this; } Value.prototype.children = ['base', 'properties']; Value.prototype.add = function(props) { this.properties = this.properties.concat(props); return this; }; Value.prototype.hasProperties = function() { return !!this.properties.length; }; Value.prototype.isArray = function() { return !this.properties.length && this.base instanceof Arr; }; Value.prototype.isComplex = function() { return this.hasProperties() || this.base.isComplex(); }; Value.prototype.isAssignable = function() { return this.hasProperties() || this.base.isAssignable(); }; Value.prototype.isSimpleNumber = function() { return this.base instanceof Literal && SIMPLENUM.test(this.base.value); }; Value.prototype.isString = function() { return this.base instanceof Literal && IS_STRING.test(this.base.value); }; Value.prototype.isAtomic = function() { var node, _i, _len, _ref2; _ref2 = this.properties.concat(this.base); for (_i = 0, _len = _ref2.length; _i < _len; _i++) { node = _ref2[_i]; if (node.soak || node instanceof Call) { return false; } } return true; }; Value.prototype.isStatement = function(o) { return !this.properties.length && this.base.isStatement(o); }; Value.prototype.assigns = function(name) { return !this.properties.length && this.base.assigns(name); }; Value.prototype.jumps = function(o) { return !this.properties.length && this.base.jumps(o); }; Value.prototype.isObject = function(onlyGenerated) { if (this.properties.length) { return false; } return (this.base instanceof Obj) && (!onlyGenerated || this.base.generated); }; Value.prototype.isSplice = function() { return last(this.properties) instanceof Slice; }; Value.prototype.unwrap = function() { if (this.properties.length) { return this; } else { return this.base; } }; Value.prototype.cacheReference = function(o) { var base, bref, name, nref; name = last(this.properties); if (this.properties.length < 2 && !this.base.isComplex() && !(name != null ? name.isComplex() : void 0)) { return [this, this]; } base = new Value(this.base, this.properties.slice(0, -1)); if (base.isComplex()) { bref = new Literal(o.scope.freeVariable('base')); base = new Value(new Parens(new Assign(bref, base))); } if (!name) { return [base, bref]; } if (name.isComplex()) { nref = new Literal(o.scope.freeVariable('name')); name = new Index(new Assign(nref, name.index)); nref = new Index(nref); } return [base.add(name), new Value(bref || base.base, [nref || name])]; }; Value.prototype.compileNode = function(o) { var code, prop, props, _i, _len; this.base.front = this.front; props = this.properties; code = this.base.compile(o, props.length ? LEVEL_ACCESS : null); if ((this.base instanceof Parens || props.length) && SIMPLENUM.test(code)) { code = "" + code + "."; } for (_i = 0, _len = props.length; _i < _len; _i++) { prop = props[_i]; code += prop.compile(o); } return code; }; Value.prototype.unfoldSoak = function(o) { var result, _this = this; if (this.unfoldedSoak != null) { return this.unfoldedSoak; } result = (function() { var fst, i, ifn, prop, ref, snd, _i, _len, _ref2; if (ifn = _this.base.unfoldSoak(o)) { Array.prototype.push.apply(ifn.body.properties, _this.properties); return ifn; } _ref2 = _this.properties; for (i = _i = 0, _len = _ref2.length; _i < _len; i = ++_i) { prop = _ref2[i]; if (!prop.soak) { continue; } prop.soak = false; fst = new Value(_this.base, _this.properties.slice(0, i)); snd = new Value(_this.base, _this.properties.slice(i)); if (fst.isComplex()) { ref = new Literal(o.scope.freeVariable('ref')); fst = new Parens(new Assign(ref, fst)); snd.base = ref; } return new If(new Existence(fst), snd, { soak: true }); } return null; })(); return this.unfoldedSoak = result || false; }; return Value; })(Base); exports.Comment = Comment = (function(_super) { __extends(Comment, _super); function Comment(comment) { this.comment = comment; } Comment.prototype.isStatement = YES; Comment.prototype.makeReturn = THIS; Comment.prototype.compileNode = function(o, level) { var code; code = '/*' + multident(this.comment, this.tab) + ("\n" + this.tab + "*/\n"); if ((level || o.level) === LEVEL_TOP) { code = o.indent + code; } return code; }; return Comment; })(Base); exports.Call = Call = (function(_super) { __extends(Call, _super); function Call(variable, args, soak) { this.args = args != null ? args : []; this.soak = soak; this.isNew = false; this.isSuper = variable === 'super'; this.variable = this.isSuper ? null : variable; } Call.prototype.children = ['variable', 'args']; Call.prototype.newInstance = function() { var base, _ref2; base = ((_ref2 = this.variable) != null ? _ref2.base : void 0) || this.variable; if (base instanceof Call && !base.isNew) { base.newInstance(); } else { this.isNew = true; } return this; }; Call.prototype.superReference = function(o) { var accesses, method, name; method = o.scope.namedMethod(); if (!method) { throw SyntaxError('cannot call super outside of a function.'); } name = method.name; if (name == null) { throw SyntaxError('cannot call super on an anonymous function.'); } if (method.klass) { accesses = [new Access(new Literal('__super__'))]; if (method["static"]) { accesses.push(new Access(new Literal('constructor'))); } accesses.push(new Access(new Literal(name))); return (new Value(new Literal(method.klass), accesses)).compile(o); } else { return "" + name + ".__super__.constructor"; } }; Call.prototype.superThis = function(o) { var method; method = o.scope.method; return (method && !method.klass && method.context) || "this"; }; Call.prototype.unfoldSoak = function(o) { var call, ifn, left, list, rite, _i, _len, _ref2, _ref3; if (this.soak) { if (this.variable) { if (ifn = unfoldSoak(o, this, 'variable')) { return ifn; } _ref2 = new Value(this.variable).cacheReference(o), left = _ref2[0], rite = _ref2[1]; } else { left = new Literal(this.superReference(o)); rite = new Value(left); } rite = new Call(rite, this.args); rite.isNew = this.isNew; left = new Literal("typeof " + (left.compile(o)) + " === \"function\""); return new If(left, new Value(rite), { soak: true }); } call = this; list = []; while (true) { if (call.variable instanceof Call) { list.push(call); call = call.variable; continue; } if (!(call.variable instanceof Value)) { break; } list.push(call); if (!((call = call.variable.base) instanceof Call)) { break; } } _ref3 = list.reverse(); for (_i = 0, _len = _ref3.length; _i < _len; _i++) { call = _ref3[_i]; if (ifn) { if (call.variable instanceof Call) { call.variable = ifn; } else { call.variable.base = ifn; } } ifn = unfoldSoak(o, call, 'variable'); } return ifn; }; Call.prototype.filterImplicitObjects = function(list) { var node, nodes, obj, prop, properties, _i, _j, _len, _len1, _ref2; nodes = []; for (_i = 0, _len = list.length; _i < _len; _i++) { node = list[_i]; if (!((typeof node.isObject === "function" ? node.isObject() : void 0) && node.base.generated)) { nodes.push(node); continue; } obj = null; _ref2 = node.base.properties; for (_j = 0, _len1 = _ref2.length; _j < _len1; _j++) { prop = _ref2[_j]; if (prop instanceof Assign || prop instanceof Comment) { if (!obj) { nodes.push(obj = new Obj(properties = [], true)); } properties.push(prop); } else { nodes.push(prop); obj = null; } } } return nodes; }; Call.prototype.compileNode = function(o) { var arg, args, code, _ref2; if ((_ref2 = this.variable) != null) { _ref2.front = this.front; } if (code = Splat.compileSplattedArray(o, this.args, true)) { return this.compileSplat(o, code); } args = this.filterImplicitObjects(this.args); args = ((function() { var _i, _len, _results; _results = []; for (_i = 0, _len = args.length; _i < _len; _i++) { arg = args[_i]; _results.push(arg.compile(o, LEVEL_LIST)); } return _results; })()).join(', '); if (this.isSuper) { return this.superReference(o) + (".call(" + (this.superThis(o)) + (args && ', ' + args) + ")"); } else { return (this.isNew ? 'new ' : '') + this.variable.compile(o, LEVEL_ACCESS) + ("(" + args + ")"); } }; Call.prototype.compileSuper = function(args, o) { return "" + (this.superReference(o)) + ".call(" + (this.superThis(o)) + (args.length ? ', ' : '') + args + ")"; }; Call.prototype.compileSplat = function(o, splatArgs) { var base, fun, idt, name, ref; if (this.isSuper) { return "" + (this.superReference(o)) + ".apply(" + (this.superThis(o)) + ", " + splatArgs + ")"; } if (this.isNew) { idt = this.tab + TAB; return "(function(func, args, ctor) {\n" + idt + "ctor.prototype = func.prototype;\n" + idt + "var child = new ctor, result = func.apply(child, args);\n" + idt + "return Object(result) === result ? result : child;\n" + this.tab + "})(" + (this.variable.compile(o, LEVEL_LIST)) + ", " + splatArgs + ", function(){})"; } base = new Value(this.variable); if ((name = base.properties.pop()) && base.isComplex()) { ref = o.scope.freeVariable('ref'); fun = "(" + ref + " = " + (base.compile(o, LEVEL_LIST)) + ")" + (name.compile(o)); } else { fun = base.compile(o, LEVEL_ACCESS); if (SIMPLENUM.test(fun)) { fun = "(" + fun + ")"; } if (name) { ref = fun; fun += name.compile(o); } else { ref = 'null'; } } return "" + fun + ".apply(" + ref + ", " + splatArgs + ")"; }; return Call; })(Base); exports.Extends = Extends = (function(_super) { __extends(Extends, _super); function Extends(child, parent) { this.child = child; this.parent = parent; } Extends.prototype.children = ['child', 'parent']; Extends.prototype.compile = function(o) { return new Call(new Value(new Literal(utility('extends'))), [this.child, this.parent]).compile(o); }; return Extends; })(Base); exports.Access = Access = (function(_super) { __extends(Access, _super); function Access(name, tag) { this.name = name; this.name.asKey = true; this.soak = tag === 'soak'; } Access.prototype.children = ['name']; Access.prototype.compile = function(o) { var name; name = this.name.compile(o); if (IDENTIFIER.test(name)) { return "." + name; } else { return "[" + name + "]"; } }; Access.prototype.isComplex = NO; return Access; })(Base); exports.Index = Index = (function(_super) { __extends(Index, _super); function Index(index) { this.index = index; } Index.prototype.children = ['index']; Index.prototype.compile = function(o) { return "[" + (this.index.compile(o, LEVEL_PAREN)) + "]"; }; Index.prototype.isComplex = function() { return this.index.isComplex(); }; return Index; })(Base); exports.Range = Range = (function(_super) { __extends(Range, _super); Range.prototype.children = ['from', 'to']; function Range(from, to, tag) { this.from = from; this.to = to; this.exclusive = tag === 'exclusive'; this.equals = this.exclusive ? '' : '='; } Range.prototype.compileVariables = function(o) { var step, _ref2, _ref3, _ref4, _ref5; o = merge(o, { top: true }); _ref2 = this.from.cache(o, LEVEL_LIST), this.fromC = _ref2[0], this.fromVar = _ref2[1]; _ref3 = this.to.cache(o, LEVEL_LIST), this.toC = _ref3[0], this.toVar = _ref3[1]; if (step = del(o, 'step')) { _ref4 = step.cache(o, LEVEL_LIST), this.step = _ref4[0], this.stepVar = _ref4[1]; } _ref5 = [this.fromVar.match(SIMPLENUM), this.toVar.match(SIMPLENUM)], this.fromNum = _ref5[0], this.toNum = _ref5[1]; if (this.stepVar) { return this.stepNum = this.stepVar.match(SIMPLENUM); } }; Range.prototype.compileNode = function(o) { var cond, condPart, from, gt, idx, idxName, known, lt, namedIndex, stepPart, to, varPart, _ref2, _ref3; if (!this.fromVar) { this.compileVariables(o); } if (!o.index) { return this.compileArray(o); } known = this.fromNum && this.toNum; idx = del(o, 'index'); idxName = del(o, 'name'); namedIndex = idxName && idxName !== idx; varPart = "" + idx + " = " + this.fromC; if (this.toC !== this.toVar) { varPart += ", " + this.toC; } if (this.step !== this.stepVar) { varPart += ", " + this.step; } _ref2 = ["" + idx + " <" + this.equals, "" + idx + " >" + this.equals], lt = _ref2[0], gt = _ref2[1]; condPart = this.stepNum ? +this.stepNum > 0 ? "" + lt + " " + this.toVar : "" + gt + " " + this.toVar : known ? ((_ref3 = [+this.fromNum, +this.toNum], from = _ref3[0], to = _ref3[1], _ref3), from <= to ? "" + lt + " " + to : "" + gt + " " + to) : (cond = "" + this.fromVar + " <= " + this.toVar, "" + cond + " ? " + lt + " " + this.toVar + " : " + gt + " " + this.toVar); stepPart = this.stepVar ? "" + idx + " += " + this.stepVar : known ? namedIndex ? from <= to ? "++" + idx : "--" + idx : from <= to ? "" + idx + "++" : "" + idx + "--" : namedIndex ? "" + cond + " ? ++" + idx + " : --" + idx : "" + cond + " ? " + idx + "++ : " + idx + "--"; if (namedIndex) { varPart = "" + idxName + " = " + varPart; } if (namedIndex) { stepPart = "" + idxName + " = " + stepPart; } return "" + varPart + "; " + condPart + "; " + stepPart; }; Range.prototype.compileArray = function(o) { var args, body, cond, hasArgs, i, idt, post, pre, range, result, vars, _i, _ref2, _ref3, _results; if (this.fromNum && this.toNum && Math.abs(this.fromNum - this.toNum) <= 20) { range = (function() { _results = []; for (var _i = _ref2 = +this.fromNum, _ref3 = +this.toNum; _ref2 <= _ref3 ? _i <= _ref3 : _i >= _ref3; _ref2 <= _ref3 ? _i++ : _i--){ _results.push(_i); } return _results; }).apply(this); if (this.exclusive) { range.pop(); } return "[" + (range.join(', ')) + "]"; } idt = this.tab + TAB; i = o.scope.freeVariable('i'); result = o.scope.freeVariable('results'); pre = "\n" + idt + result + " = [];"; if (this.fromNum && this.toNum) { o.index = i; body = this.compileNode(o); } else { vars = ("" + i + " = " + this.fromC) + (this.toC !== this.toVar ? ", " + this.toC : ''); cond = "" + this.fromVar + " <= " + this.toVar; body = "var " + vars + "; " + cond + " ? " + i + " <" + this.equals + " " + this.toVar + " : " + i + " >" + this.equals + " " + this.toVar + "; " + cond + " ? " + i + "++ : " + i + "--"; } post = "{ " + result + ".push(" + i + "); }\n" + idt + "return " + result + ";\n" + o.indent; hasArgs = function(node) { return node != null ? node.contains(function(n) { return n instanceof Literal && n.value === 'arguments' && !n.asKey; }) : void 0; }; if (hasArgs(this.from) || hasArgs(this.to)) { args = ', arguments'; } return "(function() {" + pre + "\n" + idt + "for (" + body + ")" + post + "}).apply(this" + (args != null ? args : '') + ")"; }; return Range; })(Base); exports.Slice = Slice = (function(_super) { __extends(Slice, _super); Slice.prototype.children = ['range']; function Slice(range) { this.range = range; Slice.__super__.constructor.call(this); } Slice.prototype.compileNode = function(o) { var compiled, from, fromStr, to, toStr, _ref2; _ref2 = this.range, to = _ref2.to, from = _ref2.from; fromStr = from && from.compile(o, LEVEL_PAREN) || '0'; compiled = to && to.compile(o, LEVEL_PAREN); if (to && !(!this.range.exclusive && +compiled === -1)) { toStr = ', ' + (this.range.exclusive ? compiled : SIMPLENUM.test(compiled) ? "" + (+compiled + 1) : (compiled = to.compile(o, LEVEL_ACCESS), "+" + compiled + " + 1 || 9e9")); } return ".slice(" + fromStr + (toStr || '') + ")"; }; return Slice; })(Base); exports.Obj = Obj = (function(_super) { __extends(Obj, _super); function Obj(props, generated) { this.generated = generated != null ? generated : false; this.objects = this.properties = props || []; } Obj.prototype.children = ['properties']; Obj.prototype.compileNode = function(o) { var i, idt, indent, join, lastNoncom, node, obj, prop, props, _i, _len; props = this.properties; if (!props.length) { return (this.front ? '({})' : '{}'); } if (this.generated) { for (_i = 0, _len = props.length; _i < _len; _i++) { node = props[_i]; if (node instanceof Value) { throw new Error('cannot have an implicit value in an implicit object'); } } } idt = o.indent += TAB; lastNoncom = this.lastNonComment(this.properties); props = (function() { var _j, _len1, _results; _results = []; for (i = _j = 0, _len1 = props.length; _j < _len1; i = ++_j) { prop = props[i]; join = i === props.length - 1 ? '' : prop === lastNoncom || prop instanceof Comment ? '\n' : ',\n'; indent = prop instanceof Comment ? '' : idt; if (prop instanceof Value && prop["this"]) { prop = new Assign(prop.properties[0].name, prop, 'object'); } if (!(prop instanceof Comment)) { if (!(prop instanceof Assign)) { prop = new Assign(prop, prop, 'object'); } (prop.variable.base || prop.variable).asKey = true; } _results.push(indent + prop.compile(o, LEVEL_TOP) + join); } return _results; })(); props = props.join(''); obj = "{" + (props && '\n' + props + '\n' + this.tab) + "}"; if (this.front) { return "(" + obj + ")"; } else { return obj; } }; Obj.prototype.assigns = function(name) { var prop, _i, _len, _ref2; _ref2 = this.properties; for (_i = 0, _len = _ref2.length; _i < _len; _i++) { prop = _ref2[_i]; if (prop.assigns(name)) { return true; } } return false; }; return Obj; })(Base); exports.Arr = Arr = (function(_super) { __extends(Arr, _super); function Arr(objs) { this.objects = objs || []; } Arr.prototype.children = ['objects']; Arr.prototype.filterImplicitObjects = Call.prototype.filterImplicitObjects; Arr.prototype.compileNode = function(o) { var code, obj, objs; if (!this.objects.length) { return '[]'; } o.indent += TAB; objs = this.filterImplicitObjects(this.objects); if (code = Splat.compileSplattedArray(o, objs)) { return code; } code = ((function() { var _i, _len, _results; _results = []; for (_i = 0, _len = objs.length; _i < _len; _i++) { obj = objs[_i]; _results.push(obj.compile(o, LEVEL_LIST)); } return _results; })()).join(', '); if (code.indexOf('\n') >= 0) { return "[\n" + o.indent + code + "\n" + this.tab + "]"; } else { return "[" + code + "]"; } }; Arr.prototype.assigns = function(name) { var obj, _i, _len, _ref2; _ref2 = this.objects; for (_i = 0, _len = _ref2.length; _i < _len; _i++) { obj = _ref2[_i]; if (obj.assigns(name)) { return true; } } return false; }; return Arr; })(Base); exports.Class = Class = (function(_super) { __extends(Class, _super); function Class(variable, parent, body) { this.variable = variable; this.parent = parent; this.body = body != null ? body : new Block; this.boundFuncs = []; this.body.classBody = true; } Class.prototype.children = ['variable', 'parent', 'body']; Class.prototype.determineName = function() { var decl, tail; if (!this.variable) { return null; } decl = (tail = last(this.variable.properties)) ? tail instanceof Access && tail.name.value : this.variable.base.value; if (__indexOf.call(STRICT_PROSCRIBED, decl) >= 0) { throw SyntaxError("variable name may not be " + decl); } return decl && (decl = IDENTIFIER.test(decl) && decl); }; Class.prototype.setContext = function(name) { return this.body.traverseChildren(false, function(node) { if (node.classBody) { return false; } if (node instanceof Literal && node.value === 'this') { return node.value = name; } else if (node instanceof Code) { node.klass = name; if (node.bound) { return node.context = name; } } }); }; Class.prototype.addBoundFunctions = function(o) { var bvar, lhs, _i, _len, _ref2, _results; if (this.boundFuncs.length) { _ref2 = this.boundFuncs; _results = []; for (_i = 0, _len = _ref2.length; _i < _len; _i++) { bvar = _ref2[_i]; lhs = (new Value(new Literal("this"), [new Access(bvar)])).compile(o); _results.push(this.ctor.body.unshift(new Literal("" + lhs + " = " + (utility('bind')) + "(" + lhs + ", this)"))); } return _results; } }; Class.prototype.addProperties = function(node, name, o) { var assign, base, exprs, func, props; props = node.base.properties.slice(0); exprs = (function() { var _results; _results = []; while (assign = props.shift()) { if (assign instanceof Assign) { base = assign.variable.base; delete assign.context; func = assign.value; if (base.value === 'constructor') { if (this.ctor) { throw new Error('cannot define more than one constructor in a class'); } if (func.bound) { throw new Error('cannot define a constructor as a bound function'); } if (func instanceof Code) { assign = this.ctor = func; } else { this.externalCtor = o.scope.freeVariable('class'); assign = new Assign(new Literal(this.externalCtor), func); } } else { if (assign.variable["this"]) { func["static"] = true; if (func.bound) { func.context = name; } } else { assign.variable = new Value(new Literal(name), [new Access(new Literal('prototype')), new Access(base)]); if (func instanceof Code && func.bound) { this.boundFuncs.push(base); func.bound = false; } } } } _results.push(assign); } return _results; }).call(this); return compact(exprs); }; Class.prototype.walkBody = function(name, o) { var _this = this; return this.traverseChildren(false, function(child) { var exps, i, node, _i, _len, _ref2; if (child instanceof Class) { return false; } if (child instanceof Block) { _ref2 = exps = child.expressions; for (i = _i = 0, _len = _ref2.length; _i < _len; i = ++_i) { node = _ref2[i]; if (node instanceof Value && node.isObject(true)) { exps[i] = _this.addProperties(node, name, o); } } return child.expressions = exps = flatten(exps); } }); }; Class.prototype.hoistDirectivePrologue = function() { var expressions, index, node; index = 0; expressions = this.body.expressions; while ((node = expressions[index]) && node instanceof Comment || node instanceof Value && node.isString()) { ++index; } return this.directives = expressions.splice(0, index); }; Class.prototype.ensureConstructor = function(name) { if (!this.ctor) { this.ctor = new Code; if (this.parent) { this.ctor.body.push(new Literal("" + name + ".__super__.constructor.apply(this, arguments)")); } if (this.externalCtor) { this.ctor.body.push(new Literal("" + this.externalCtor + ".apply(this, arguments)")); } this.ctor.body.makeReturn(); this.body.expressions.unshift(this.ctor); } this.ctor.ctor = this.ctor.name = name; this.ctor.klass = null; return this.ctor.noReturn = true; }; Class.prototype.compileNode = function(o) { var call, decl, klass, lname, name, params, _ref2; decl = this.determineName(); name = decl || '_Class'; if (name.reserved) { name = "_" + name; } lname = new Literal(name); this.hoistDirectivePrologue(); this.setContext(name); this.walkBody(name, o); this.ensureConstructor(name); this.body.spaced = true; if (!(this.ctor instanceof Code)) { this.body.expressions.unshift(this.ctor); } this.body.expressions.push(lname); (_ref2 = this.body.expressions).unshift.apply(_ref2, this.directives); this.addBoundFunctions(o); call = Closure.wrap(this.body); if (this.parent) { this.superClass = new Literal(o.scope.freeVariable('super', false)); this.body.expressions.unshift(new Extends(lname, this.superClass)); call.args.push(this.parent); params = call.variable.params || call.variable.base.params; params.push(new Param(this.superClass)); } klass = new Parens(call, true); if (this.variable) { klass = new Assign(this.variable, klass); } return klass.compile(o); }; return Class; })(Base); exports.Assign = Assign = (function(_super) { __extends(Assign, _super); function Assign(variable, value, context, options) { var forbidden, name, _ref2; this.variable = variable; this.value = value; this.context = context; this.param = options && options.param; this.subpattern = options && options.subpattern; forbidden = (_ref2 = (name = this.variable.unwrapAll().value), __indexOf.call(STRICT_PROSCRIBED, _ref2) >= 0); if (forbidden && this.context !== 'object') { throw SyntaxError("variable name may not be \"" + name + "\""); } } Assign.prototype.children = ['variable', 'value']; Assign.prototype.isStatement = function(o) { return (o != null ? o.level : void 0) === LEVEL_TOP && (this.context != null) && __indexOf.call(this.context, "?") >= 0; }; Assign.prototype.assigns = function(name) { return this[this.context === 'object' ? 'value' : 'variable'].assigns(name); }; Assign.prototype.unfoldSoak = function(o) { return unfoldSoak(o, this, 'variable'); }; Assign.prototype.compileNode = function(o) { var isValue, match, name, val, varBase, _ref2, _ref3, _ref4, _ref5; if (isValue = this.variable instanceof Value) { if (this.variable.isArray() || this.variable.isObject()) { return this.compilePatternMatch(o); } if (this.variable.isSplice()) { return this.compileSplice(o); } if ((_ref2 = this.context) === '||=' || _ref2 === '&&=' || _ref2 === '?=') { return this.compileConditional(o); } } name = this.variable.compile(o, LEVEL_LIST); if (!this.context) { if (!(varBase = this.variable.unwrapAll()).isAssignable()) { throw SyntaxError("\"" + (this.variable.compile(o)) + "\" cannot be assigned."); } if (!(typeof varBase.hasProperties === "function" ? varBase.hasProperties() : void 0)) { if (this.param) { o.scope.add(name, 'var'); } else { o.scope.find(name); } } } if (this.value instanceof Code && (match = METHOD_DEF.exec(name))) { if (match[1]) { this.value.klass = match[1]; } this.value.name = (_ref3 = (_ref4 = (_ref5 = match[2]) != null ? _ref5 : match[3]) != null ? _ref4 : match[4]) != null ? _ref3 : match[5]; } val = this.value.compile(o, LEVEL_LIST); if (this.context === 'object') { return "" + name + ": " + val; } val = name + (" " + (this.context || '=') + " ") + val; if (o.level <= LEVEL_LIST) { return val; } else { return "(" + val + ")"; } }; Assign.prototype.compilePatternMatch = function(o) { var acc, assigns, code, i, idx, isObject, ivar, name, obj, objects, olen, ref, rest, splat, top, val, value, vvar, _i, _len, _ref2, _ref3, _ref4, _ref5, _ref6, _ref7, _ref8; top = o.level === LEVEL_TOP; value = this.value; objects = this.variable.base.objects; if (!(olen = objects.length)) { code = value.compile(o); if (o.level >= LEVEL_OP) { return "(" + code + ")"; } else { return code; } } isObject = this.variable.isObject(); if (top && olen === 1 && !((obj = objects[0]) instanceof Splat)) { if (obj instanceof Assign) { _ref2 = obj, (_ref3 = _ref2.variable, idx = _ref3.base), obj = _ref2.value; } else { if (obj.base instanceof Parens) { _ref4 = new Value(obj.unwrapAll()).cacheReference(o), obj = _ref4[0], idx = _ref4[1]; } else { idx = isObject ? obj["this"] ? obj.properties[0].name : obj : new Literal(0); } } acc = IDENTIFIER.test(idx.unwrap().value || 0); value = new Value(value); value.properties.push(new (acc ? Access : Index)(idx)); if (_ref5 = obj.unwrap().value, __indexOf.call(RESERVED, _ref5) >= 0) { throw new SyntaxError("assignment to a reserved word: " + (obj.compile(o)) + " = " + (value.compile(o))); } return new Assign(obj, value, null, { param: this.param }).compile(o, LEVEL_TOP); } vvar = value.compile(o, LEVEL_LIST); assigns = []; splat = false; if (!IDENTIFIER.test(vvar) || this.variable.assigns(vvar)) { assigns.push("" + (ref = o.scope.freeVariable('ref')) + " = " + vvar); vvar = ref; } for (i = _i = 0, _len = objects.length; _i < _len; i = ++_i) { obj = objects[i]; idx = i; if (isObject) { if (obj instanceof Assign) { _ref6 = obj, (_ref7 = _ref6.variable, idx = _ref7.base), obj = _ref6.value; } else { if (obj.base instanceof Parens) { _ref8 = new Value(obj.unwrapAll()).cacheReference(o), obj = _ref8[0], idx = _ref8[1]; } else { idx = obj["this"] ? obj.properties[0].name : obj; } } } if (!splat && obj instanceof Splat) { name = obj.name.unwrap().value; obj = obj.unwrap(); val = "" + olen + " <= " + vvar + ".length ? " + (utility('slice')) + ".call(" + vvar + ", " + i; if (rest = olen - i - 1) { ivar = o.scope.freeVariable('i'); val += ", " + ivar + " = " + vvar + ".length - " + rest + ") : (" + ivar + " = " + i + ", [])"; } else { val += ") : []"; } val = new Literal(val); splat = "" + ivar + "++"; } else { name = obj.unwrap().value; if (obj instanceof Splat) { obj = obj.name.compile(o); throw new SyntaxError("multiple splats are disallowed in an assignment: " + obj + "..."); } if (typeof idx === 'number') { idx = new Literal(splat || idx); acc = false; } else { acc = isObject && IDENTIFIER.test(idx.unwrap().value || 0); } val = new Value(new Literal(vvar), [new (acc ? Access : Index)(idx)]); } if ((name != null) && __indexOf.call(RESERVED, name) >= 0) { throw new SyntaxError("assignment to a reserved word: " + (obj.compile(o)) + " = " + (val.compile(o))); } assigns.push(new Assign(obj, val, null, { param: this.param, subpattern: true }).compile(o, LEVEL_LIST)); } if (!(top || this.subpattern)) { assigns.push(vvar); } code = assigns.join(', '); if (o.level < LEVEL_LIST) { return code; } else { return "(" + code + ")"; } }; Assign.prototype.compileConditional = function(o) { var left, right, _ref2; _ref2 = this.variable.cacheReference(o), left = _ref2[0], right = _ref2[1]; if (!left.properties.length && left.base instanceof Literal && left.base.value !== "this" && !o.scope.check(left.base.value)) { throw new Error("the variable \"" + left.base.value + "\" can't be assigned with " + this.context + " because it has not been defined."); } if (__indexOf.call(this.context, "?") >= 0) { o.isExistentialEquals = true; } return new Op(this.context.slice(0, -1), left, new Assign(right, this.value, '=')).compile(o); }; Assign.prototype.compileSplice = function(o) { var code, exclusive, from, fromDecl, fromRef, name, to, valDef, valRef, _ref2, _ref3, _ref4; _ref2 = this.variable.properties.pop().range, from = _ref2.from, to = _ref2.to, exclusive = _ref2.exclusive; name = this.variable.compile(o); _ref3 = (from != null ? from.cache(o, LEVEL_OP) : void 0) || ['0', '0'], fromDecl = _ref3[0], fromRef = _ref3[1]; if (to) { if ((from != null ? from.isSimpleNumber() : void 0) && to.isSimpleNumber()) { to = +to.compile(o) - +fromRef; if (!exclusive) { to += 1; } } else { to = to.compile(o, LEVEL_ACCESS) + ' - ' + fromRef; if (!exclusive) { to += ' + 1'; } } } else { to = "9e9"; } _ref4 = this.value.cache(o, LEVEL_LIST), valDef = _ref4[0], valRef = _ref4[1]; code = "[].splice.apply(" + name + ", [" + fromDecl + ", " + to + "].concat(" + valDef + ")), " + valRef; if (o.level > LEVEL_TOP) { return "(" + code + ")"; } else { return code; } }; return Assign; })(Base); exports.Code = Code = (function(_super) { __extends(Code, _super); function Code(params, body, tag) { this.params = params || []; this.body = body || new Block; this.bound = tag === 'boundfunc'; if (this.bound) { this.context = '_this'; } } Code.prototype.children = ['params', 'body']; Code.prototype.isStatement = function() { return !!this.ctor; }; Code.prototype.jumps = NO; Code.prototype.compileNode = function(o) { var code, exprs, i, idt, lit, name, p, param, params, ref, splats, uniqs, val, wasEmpty, _i, _j, _k, _l, _len, _len1, _len2, _len3, _len4, _len5, _m, _n, _ref2, _ref3, _ref4, _ref5, _ref6, _ref7, _ref8; o.scope = new Scope(o.scope, this.body, this); o.scope.shared = del(o, 'sharedScope'); o.indent += TAB; delete o.bare; delete o.isExistentialEquals; params = []; exprs = []; _ref2 = this.paramNames(); for (_i = 0, _len = _ref2.length; _i < _len; _i++) { name = _ref2[_i]; if (!o.scope.check(name)) { o.scope.parameter(name); } } _ref3 = this.params; for (_j = 0, _len1 = _ref3.length; _j < _len1; _j++) { param = _ref3[_j]; if (!param.splat) { continue; } _ref4 = this.params; for (_k = 0, _len2 = _ref4.length; _k < _len2; _k++) { p = _ref4[_k].name; if (p["this"]) { p = p.properties[0].name; } if (p.value) { o.scope.add(p.value, 'var', true); } } splats = new Assign(new Value(new Arr((function() { var _l, _len3, _ref5, _results; _ref5 = this.params; _results = []; for (_l = 0, _len3 = _ref5.length; _l < _len3; _l++) { p = _ref5[_l]; _results.push(p.asReference(o)); } return _results; }).call(this))), new Value(new Literal('arguments'))); break; } _ref5 = this.params; for (_l = 0, _len3 = _ref5.length; _l < _len3; _l++) { param = _ref5[_l]; if (param.isComplex()) { val = ref = param.asReference(o); if (param.value) { val = new Op('?', ref, param.value); } exprs.push(new Assign(new Value(param.name), val, '=', { param: true })); } else { ref = param; if (param.value) { lit = new Literal(ref.name.value + ' == null'); val = new Assign(new Value(param.name), param.value, '='); exprs.push(new If(lit, val)); } } if (!splats) { params.push(ref); } } wasEmpty = this.body.isEmpty(); if (splats) { exprs.unshift(splats); } if (exprs.length) { (_ref6 = this.body.expressions).unshift.apply(_ref6, exprs); } for (i = _m = 0, _len4 = params.length; _m < _len4; i = ++_m) { p = params[i]; o.scope.parameter(params[i] = p.compile(o)); } uniqs = []; _ref7 = this.paramNames(); for (_n = 0, _len5 = _ref7.length; _n < _len5; _n++) { name = _ref7[_n]; if (__indexOf.call(uniqs, name) >= 0) { throw SyntaxError("multiple parameters named '" + name + "'"); } uniqs.push(name); } if (!(wasEmpty || this.noReturn)) { this.body.makeReturn(); } if (this.bound) { if ((_ref8 = o.scope.parent.method) != null ? _ref8.bound : void 0) { this.bound = this.context = o.scope.parent.method.context; } else if (!this["static"]) { o.scope.parent.assign('_this', 'this'); } } idt = o.indent; code = 'function'; if (this.ctor) { code += ' ' + this.name; } code += '(' + params.join(', ') + ') {'; if (!this.body.isEmpty()) { code += "\n" + (this.body.compileWithDeclarations(o)) + "\n" + this.tab; } code += '}'; if (this.ctor) { return this.tab + code; } if (this.front || (o.level >= LEVEL_ACCESS)) { return "(" + code + ")"; } else { return code; } }; Code.prototype.paramNames = function() { var names, param, _i, _len, _ref2; names = []; _ref2 = this.params; for (_i = 0, _len = _ref2.length; _i < _len; _i++) { param = _ref2[_i]; names.push.apply(names, param.names()); } return names; }; Code.prototype.traverseChildren = function(crossScope, func) { if (crossScope) { return Code.__super__.traverseChildren.call(this, crossScope, func); } }; return Code; })(Base); exports.Param = Param = (function(_super) { __extends(Param, _super); function Param(name, value, splat) { var _ref2; this.name = name; this.value = value; this.splat = splat; if (_ref2 = (name = this.name.unwrapAll().value), __indexOf.call(STRICT_PROSCRIBED, _ref2) >= 0) { throw SyntaxError("parameter name \"" + name + "\" is not allowed"); } } Param.prototype.children = ['name', 'value']; Param.prototype.compile = function(o) { return this.name.compile(o, LEVEL_LIST); }; Param.prototype.asReference = function(o) { var node; if (this.reference) { return this.reference; } node = this.name; if (node["this"]) { node = node.properties[0].name; if (node.value.reserved) { node = new Literal(o.scope.freeVariable(node.value)); } } else if (node.isComplex()) { node = new Literal(o.scope.freeVariable('arg')); } node = new Value(node); if (this.splat) { node = new Splat(node); } return this.reference = node; }; Param.prototype.isComplex = function() { return this.name.isComplex(); }; Param.prototype.names = function(name) { var atParam, names, obj, _i, _len, _ref2; if (name == null) { name = this.name; } atParam = function(obj) { var value; value = obj.properties[0].name.value; if (value.reserved) { return []; } else { return [value]; } }; if (name instanceof Literal) { return [name.value]; } if (name instanceof Value) { return atParam(name); } names = []; _ref2 = name.objects; for (_i = 0, _len = _ref2.length; _i < _len; _i++) { obj = _ref2[_i]; if (obj instanceof Assign) { names.push(obj.value.unwrap().value); } else if (obj instanceof Splat) { names.push(obj.name.unwrap().value); } else if (obj instanceof Value) { if (obj.isArray() || obj.isObject()) { names.push.apply(names, this.names(obj.base)); } else if (obj["this"]) { names.push.apply(names, atParam(obj)); } else { names.push(obj.base.value); } } else { throw SyntaxError("illegal parameter " + (obj.compile())); } } return names; }; return Param; })(Base); exports.Splat = Splat = (function(_super) { __extends(Splat, _super); Splat.prototype.children = ['name']; Splat.prototype.isAssignable = YES; function Splat(name) { this.name = name.compile ? name : new Literal(name); } Splat.prototype.assigns = function(name) { return this.name.assigns(name); }; Splat.prototype.compile = function(o) { if (this.index != null) { return this.compileParam(o); } else { return this.name.compile(o); } }; Splat.prototype.unwrap = function() { return this.name; }; Splat.compileSplattedArray = function(o, list, apply) { var args, base, code, i, index, node, _i, _len; index = -1; while ((node = list[++index]) && !(node instanceof Splat)) { continue; } if (index >= list.length) { return ''; } if (list.length === 1) { code = list[0].compile(o, LEVEL_LIST); if (apply) { return code; } return "" + (utility('slice')) + ".call(" + code + ")"; } args = list.slice(index); for (i = _i = 0, _len = args.length; _i < _len; i = ++_i) { node = args[i]; code = node.compile(o, LEVEL_LIST); args[i] = node instanceof Splat ? "" + (utility('slice')) + ".call(" + code + ")" : "[" + code + "]"; } if (index === 0) { return args[0] + (".concat(" + (args.slice(1).join(', ')) + ")"); } base = (function() { var _j, _len1, _ref2, _results; _ref2 = list.slice(0, index); _results = []; for (_j = 0, _len1 = _ref2.length; _j < _len1; _j++) { node = _ref2[_j]; _results.push(node.compile(o, LEVEL_LIST)); } return _results; })(); return "[" + (base.join(', ')) + "].concat(" + (args.join(', ')) + ")"; }; return Splat; })(Base); exports.While = While = (function(_super) { __extends(While, _super); function While(condition, options) { this.condition = (options != null ? options.invert : void 0) ? condition.invert() : condition; this.guard = options != null ? options.guard : void 0; } While.prototype.children = ['condition', 'guard', 'body']; While.prototype.isStatement = YES; While.prototype.makeReturn = function(res) { if (res) { return While.__super__.makeReturn.apply(this, arguments); } else { this.returns = !this.jumps({ loop: true }); return this; } }; While.prototype.addBody = function(body) { this.body = body; return this; }; While.prototype.jumps = function() { var expressions, node, _i, _len; expressions = this.body.expressions; if (!expressions.length) { return false; } for (_i = 0, _len = expressions.length; _i < _len; _i++) { node = expressions[_i]; if (node.jumps({ loop: true })) { return node; } } return false; }; While.prototype.compileNode = function(o) { var body, code, rvar, set; o.indent += TAB; set = ''; body = this.body; if (body.isEmpty()) { body = ''; } else { if (this.returns) { body.makeReturn(rvar = o.scope.freeVariable('results')); set = "" + this.tab + rvar + " = [];\n"; } if (this.guard) { if (body.expressions.length > 1) { body.expressions.unshift(new If((new Parens(this.guard)).invert(), new Literal("continue"))); } else { if (this.guard) { body = Block.wrap([new If(this.guard, body)]); } } } body = "\n" + (body.compile(o, LEVEL_TOP)) + "\n" + this.tab; } code = set + this.tab + ("while (" + (this.condition.compile(o, LEVEL_PAREN)) + ") {" + body + "}"); if (this.returns) { code += "\n" + this.tab + "return " + rvar + ";"; } return code; }; return While; })(Base); exports.Op = Op = (function(_super) { var CONVERSIONS, INVERSIONS; __extends(Op, _super); function Op(op, first, second, flip) { if (op === 'in') { return new In(first, second); } if (op === 'do') { return this.generateDo(first); } if (op === 'new') { if (first instanceof Call && !first["do"] && !first.isNew) { return first.newInstance(); } if (first instanceof Code && first.bound || first["do"]) { first = new Parens(first); } } this.operator = CONVERSIONS[op] || op; this.first = first; this.second = second; this.flip = !!flip; return this; } CONVERSIONS = { '==': '===', '!=': '!==', 'of': 'in' }; INVERSIONS = { '!==': '===', '===': '!==' }; Op.prototype.children = ['first', 'second']; Op.prototype.isSimpleNumber = NO; Op.prototype.isUnary = function() { return !this.second; }; Op.prototype.isComplex = function() { var _ref2; return !(this.isUnary() && ((_ref2 = this.operator) === '+' || _ref2 === '-')) || this.first.isComplex(); }; Op.prototype.isChainable = function() { var _ref2; return (_ref2 = this.operator) === '<' || _ref2 === '>' || _ref2 === '>=' || _ref2 === '<=' || _ref2 === '===' || _ref2 === '!=='; }; Op.prototype.invert = function() { var allInvertable, curr, fst, op, _ref2; if (this.isChainable() && this.first.isChainable()) { allInvertable = true; curr = this; while (curr && curr.operator) { allInvertable && (allInvertable = curr.operator in INVERSIONS); curr = curr.first; } if (!allInvertable) { return new Parens(this).invert(); } curr = this; while (curr && curr.operator) { curr.invert = !curr.invert; curr.operator = INVERSIONS[curr.operator]; curr = curr.first; } return this; } else if (op = INVERSIONS[this.operator]) { this.operator = op; if (this.first.unwrap() instanceof Op) { this.first.invert(); } return this; } else if (this.second) { return new Parens(this).invert(); } else if (this.operator === '!' && (fst = this.first.unwrap()) instanceof Op && ((_ref2 = fst.operator) === '!' || _ref2 === 'in' || _ref2 === 'instanceof')) { return fst; } else { return new Op('!', this); } }; Op.prototype.unfoldSoak = function(o) { var _ref2; return ((_ref2 = this.operator) === '++' || _ref2 === '--' || _ref2 === 'delete') && unfoldSoak(o, this, 'first'); }; Op.prototype.generateDo = function(exp) { var call, func, param, passedParams, ref, _i, _len, _ref2; passedParams = []; func = exp instanceof Assign && (ref = exp.value.unwrap()) instanceof Code ? ref : exp; _ref2 = func.params || []; for (_i = 0, _len = _ref2.length; _i < _len; _i++) { param = _ref2[_i]; if (param.value) { passedParams.push(param.value); delete param.value; } else { passedParams.push(param); } } call = new Call(exp, passedParams); call["do"] = true; return call; }; Op.prototype.compileNode = function(o) { var code, isChain, _ref2, _ref3; isChain = this.isChainable() && this.first.isChainable(); if (!isChain) { this.first.front = this.front; } if (this.operator === 'delete' && o.scope.check(this.first.unwrapAll().value)) { throw SyntaxError('delete operand may not be argument or var'); } if (((_ref2 = this.operator) === '--' || _ref2 === '++') && (_ref3 = this.first.unwrapAll().value, __indexOf.call(STRICT_PROSCRIBED, _ref3) >= 0)) { throw SyntaxError('prefix increment/decrement may not have eval or arguments operand'); } if (this.isUnary()) { return this.compileUnary(o); } if (isChain) { return this.compileChain(o); } if (this.operator === '?') { return this.compileExistence(o); } code = this.first.compile(o, LEVEL_OP) + ' ' + this.operator + ' ' + this.second.compile(o, LEVEL_OP); if (o.level <= LEVEL_OP) { return code; } else { return "(" + code + ")"; } }; Op.prototype.compileChain = function(o) { var code, fst, shared, _ref2; _ref2 = this.first.second.cache(o), this.first.second = _ref2[0], shared = _ref2[1]; fst = this.first.compile(o, LEVEL_OP); code = "" + fst + " " + (this.invert ? '&&' : '||') + " " + (shared.compile(o)) + " " + this.operator + " " + (this.second.compile(o, LEVEL_OP)); return "(" + code + ")"; }; Op.prototype.compileExistence = function(o) { var fst, ref; if (this.first.isComplex()) { ref = new Literal(o.scope.freeVariable('ref')); fst = new Parens(new Assign(ref, this.first)); } else { fst = this.first; ref = fst; } return new If(new Existence(fst), ref, { type: 'if' }).addElse(this.second).compile(o); }; Op.prototype.compileUnary = function(o) { var op, parts, plusMinus; if (o.level >= LEVEL_ACCESS) { return (new Parens(this)).compile(o); } parts = [op = this.operator]; plusMinus = op === '+' || op === '-'; if ((op === 'new' || op === 'typeof' || op === 'delete') || plusMinus && this.first instanceof Op && this.first.operator === op) { parts.push(' '); } if ((plusMinus && this.first instanceof Op) || (op === 'new' && this.first.isStatement(o))) { this.first = new Parens(this.first); } parts.push(this.first.compile(o, LEVEL_OP)); if (this.flip) { parts.reverse(); } return parts.join(''); }; Op.prototype.toString = function(idt) { return Op.__super__.toString.call(this, idt, this.constructor.name + ' ' + this.operator); }; return Op; })(Base); exports.In = In = (function(_super) { __extends(In, _super); function In(object, array) { this.object = object; this.array = array; } In.prototype.children = ['object', 'array']; In.prototype.invert = NEGATE; In.prototype.compileNode = function(o) { var hasSplat, obj, _i, _len, _ref2; if (this.array instanceof Value && this.array.isArray()) { _ref2 = this.array.base.objects; for (_i = 0, _len = _ref2.length; _i < _len; _i++) { obj = _ref2[_i]; if (!(obj instanceof Splat)) { continue; } hasSplat = true; break; } if (!hasSplat) { return this.compileOrTest(o); } } return this.compileLoopTest(o); }; In.prototype.compileOrTest = function(o) { var cmp, cnj, i, item, ref, sub, tests, _ref2, _ref3; if (this.array.base.objects.length === 0) { return "" + (!!this.negated); } _ref2 = this.object.cache(o, LEVEL_OP), sub = _ref2[0], ref = _ref2[1]; _ref3 = this.negated ? [' !== ', ' && '] : [' === ', ' || '], cmp = _ref3[0], cnj = _ref3[1]; tests = (function() { var _i, _len, _ref4, _results; _ref4 = this.array.base.objects; _results = []; for (i = _i = 0, _len = _ref4.length; _i < _len; i = ++_i) { item = _ref4[i]; _results.push((i ? ref : sub) + cmp + item.compile(o, LEVEL_ACCESS)); } return _results; }).call(this); tests = tests.join(cnj); if (o.level < LEVEL_OP) { return tests; } else { return "(" + tests + ")"; } }; In.prototype.compileLoopTest = function(o) { var code, ref, sub, _ref2; _ref2 = this.object.cache(o, LEVEL_LIST), sub = _ref2[0], ref = _ref2[1]; code = utility('indexOf') + (".call(" + (this.array.compile(o, LEVEL_LIST)) + ", " + ref + ") ") + (this.negated ? '< 0' : '>= 0'); if (sub === ref) { return code; } code = sub + ', ' + code; if (o.level < LEVEL_LIST) { return code; } else { return "(" + code + ")"; } }; In.prototype.toString = function(idt) { return In.__super__.toString.call(this, idt, this.constructor.name + (this.negated ? '!' : '')); }; return In; })(Base); exports.Try = Try = (function(_super) { __extends(Try, _super); function Try(attempt, error, recovery, ensure) { this.attempt = attempt; this.error = error; this.recovery = recovery; this.ensure = ensure; } Try.prototype.children = ['attempt', 'recovery', 'ensure']; Try.prototype.isStatement = YES; Try.prototype.jumps = function(o) { var _ref2; return this.attempt.jumps(o) || ((_ref2 = this.recovery) != null ? _ref2.jumps(o) : void 0); }; Try.prototype.makeReturn = function(res) { if (this.attempt) { this.attempt = this.attempt.makeReturn(res); } if (this.recovery) { this.recovery = this.recovery.makeReturn(res); } return this; }; Try.prototype.compileNode = function(o) { var catchPart, ensurePart, errorPart, tryPart; o.indent += TAB; errorPart = this.error ? " (" + (this.error.compile(o)) + ") " : ' '; tryPart = this.attempt.compile(o, LEVEL_TOP); catchPart = (function() { var _ref2; if (this.recovery) { if (_ref2 = this.error.value, __indexOf.call(STRICT_PROSCRIBED, _ref2) >= 0) { throw SyntaxError("catch variable may not be \"" + this.error.value + "\""); } if (!o.scope.check(this.error.value)) { o.scope.add(this.error.value, 'param'); } return " catch" + errorPart + "{\n" + (this.recovery.compile(o, LEVEL_TOP)) + "\n" + this.tab + "}"; } else if (!(this.ensure || this.recovery)) { return ' catch (_error) {}'; } }).call(this); ensurePart = this.ensure ? " finally {\n" + (this.ensure.compile(o, LEVEL_TOP)) + "\n" + this.tab + "}" : ''; return "" + this.tab + "try {\n" + tryPart + "\n" + this.tab + "}" + (catchPart || '') + ensurePart; }; return Try; })(Base); exports.Throw = Throw = (function(_super) { __extends(Throw, _super); function Throw(expression) { this.expression = expression; } Throw.prototype.children = ['expression']; Throw.prototype.isStatement = YES; Throw.prototype.jumps = NO; Throw.prototype.makeReturn = THIS; Throw.prototype.compileNode = function(o) { return this.tab + ("throw " + (this.expression.compile(o)) + ";"); }; return Throw; })(Base); exports.Existence = Existence = (function(_super) { __extends(Existence, _super); function Existence(expression) { this.expression = expression; } Existence.prototype.children = ['expression']; Existence.prototype.invert = NEGATE; Existence.prototype.compileNode = function(o) { var cmp, cnj, code, _ref2; this.expression.front = this.front; code = this.expression.compile(o, LEVEL_OP); if (IDENTIFIER.test(code) && !o.scope.check(code)) { _ref2 = this.negated ? ['===', '||'] : ['!==', '&&'], cmp = _ref2[0], cnj = _ref2[1]; code = "typeof " + code + " " + cmp + " \"undefined\" " + cnj + " " + code + " " + cmp + " null"; } else { code = "" + code + " " + (this.negated ? '==' : '!=') + " null"; } if (o.level <= LEVEL_COND) { return code; } else { return "(" + code + ")"; } }; return Existence; })(Base); exports.Parens = Parens = (function(_super) { __extends(Parens, _super); function Parens(body) { this.body = body; } Parens.prototype.children = ['body']; Parens.prototype.unwrap = function() { return this.body; }; Parens.prototype.isComplex = function() { return this.body.isComplex(); }; Parens.prototype.compileNode = function(o) { var bare, code, expr; expr = this.body.unwrap(); if (expr instanceof Value && expr.isAtomic()) { expr.front = this.front; return expr.compile(o); } code = expr.compile(o, LEVEL_PAREN); bare = o.level < LEVEL_OP && (expr instanceof Op || expr instanceof Call || (expr instanceof For && expr.returns)); if (bare) { return code; } else { return "(" + code + ")"; } }; return Parens; })(Base); exports.For = For = (function(_super) { __extends(For, _super); function For(body, source) { var _ref2; this.source = source.source, this.guard = source.guard, this.step = source.step, this.name = source.name, this.index = source.index; this.body = Block.wrap([body]); this.own = !!source.own; this.object = !!source.object; if (this.object) { _ref2 = [this.index, this.name], this.name = _ref2[0], this.index = _ref2[1]; } if (this.index instanceof Value) { throw SyntaxError('index cannot be a pattern matching expression'); } this.range = this.source instanceof Value && this.source.base instanceof Range && !this.source.properties.length; this.pattern = this.name instanceof Value; if (this.range && this.index) { throw SyntaxError('indexes do not apply to range loops'); } if (this.range && this.pattern) { throw SyntaxError('cannot pattern match over range loops'); } this.returns = false; } For.prototype.children = ['body', 'source', 'guard', 'step']; For.prototype.compileNode = function(o) { var body, defPart, forPart, forVarPart, guardPart, idt1, index, ivar, kvar, kvarAssign, lastJumps, lvar, name, namePart, ref, resultPart, returnResult, rvar, scope, source, stepPart, stepvar, svar, varPart, _ref2; body = Block.wrap([this.body]); lastJumps = (_ref2 = last(body.expressions)) != null ? _ref2.jumps() : void 0; if (lastJumps && lastJumps instanceof Return) { this.returns = false; } source = this.range ? this.source.base : this.source; scope = o.scope; name = this.name && this.name.compile(o, LEVEL_LIST); index = this.index && this.index.compile(o, LEVEL_LIST); if (name && !this.pattern) { scope.find(name); } if (index) { scope.find(index); } if (this.returns) { rvar = scope.freeVariable('results'); } ivar = (this.object && index) || scope.freeVariable('i'); kvar = (this.range && name) || index || ivar; kvarAssign = kvar !== ivar ? "" + kvar + " = " : ""; if (this.step && !this.range) { stepvar = scope.freeVariable("step"); } if (this.pattern) { name = ivar; } varPart = ''; guardPart = ''; defPart = ''; idt1 = this.tab + TAB; if (this.range) { forPart = source.compile(merge(o, { index: ivar, name: name, step: this.step })); } else { svar = this.source.compile(o, LEVEL_LIST); if ((name || this.own) && !IDENTIFIER.test(svar)) { defPart = "" + this.tab + (ref = scope.freeVariable('ref')) + " = " + svar + ";\n"; svar = ref; } if (name && !this.pattern) { namePart = "" + name + " = " + svar + "[" + kvar + "]"; } if (!this.object) { lvar = scope.freeVariable('len'); forVarPart = "" + kvarAssign + ivar + " = 0, " + lvar + " = " + svar + ".length"; if (this.step) { forVarPart += ", " + stepvar + " = " + (this.step.compile(o, LEVEL_OP)); } stepPart = "" + kvarAssign + (this.step ? "" + ivar + " += " + stepvar : (kvar !== ivar ? "++" + ivar : "" + ivar + "++")); forPart = "" + forVarPart + "; " + ivar + " < " + lvar + "; " + stepPart; } } if (this.returns) { resultPart = "" + this.tab + rvar + " = [];\n"; returnResult = "\n" + this.tab + "return " + rvar + ";"; body.makeReturn(rvar); } if (this.guard) { if (body.expressions.length > 1) { body.expressions.unshift(new If((new Parens(this.guard)).invert(), new Literal("continue"))); } else { if (this.guard) { body = Block.wrap([new If(this.guard, body)]); } } } if (this.pattern) { body.expressions.unshift(new Assign(this.name, new Literal("" + svar + "[" + kvar + "]"))); } defPart += this.pluckDirectCall(o, body); if (namePart) { varPart = "\n" + idt1 + namePart + ";"; } if (this.object) { forPart = "" + kvar + " in " + svar; if (this.own) { guardPart = "\n" + idt1 + "if (!" + (utility('hasProp')) + ".call(" + svar + ", " + kvar + ")) continue;"; } } body = body.compile(merge(o, { indent: idt1 }), LEVEL_TOP); if (body) { body = '\n' + body + '\n'; } return "" + defPart + (resultPart || '') + this.tab + "for (" + forPart + ") {" + guardPart + varPart + body + this.tab + "}" + (returnResult || ''); }; For.prototype.pluckDirectCall = function(o, body) { var base, defs, expr, fn, idx, ref, val, _i, _len, _ref2, _ref3, _ref4, _ref5, _ref6, _ref7; defs = ''; _ref2 = body.expressions; for (idx = _i = 0, _len = _ref2.length; _i < _len; idx = ++_i) { expr = _ref2[idx]; expr = expr.unwrapAll(); if (!(expr instanceof Call)) { continue; } val = expr.variable.unwrapAll(); if (!((val instanceof Code) || (val instanceof Value && ((_ref3 = val.base) != null ? _ref3.unwrapAll() : void 0) instanceof Code && val.properties.length === 1 && ((_ref4 = (_ref5 = val.properties[0].name) != null ? _ref5.value : void 0) === 'call' || _ref4 === 'apply')))) { continue; } fn = ((_ref6 = val.base) != null ? _ref6.unwrapAll() : void 0) || val; ref = new Literal(o.scope.freeVariable('fn')); base = new Value(ref); if (val.base) { _ref7 = [base, val], val.base = _ref7[0], base = _ref7[1]; } body.expressions[idx] = new Call(base, expr.args); defs += this.tab + new Assign(ref, fn).compile(o, LEVEL_TOP) + ';\n'; } return defs; }; return For; })(While); exports.Switch = Switch = (function(_super) { __extends(Switch, _super); function Switch(subject, cases, otherwise) { this.subject = subject; this.cases = cases; this.otherwise = otherwise; } Switch.prototype.children = ['subject', 'cases', 'otherwise']; Switch.prototype.isStatement = YES; Switch.prototype.jumps = function(o) { var block, conds, _i, _len, _ref2, _ref3, _ref4; if (o == null) { o = { block: true }; } _ref2 = this.cases; for (_i = 0, _len = _ref2.length; _i < _len; _i++) { _ref3 = _ref2[_i], conds = _ref3[0], block = _ref3[1]; if (block.jumps(o)) { return block; } } return (_ref4 = this.otherwise) != null ? _ref4.jumps(o) : void 0; }; Switch.prototype.makeReturn = function(res) { var pair, _i, _len, _ref2, _ref3; _ref2 = this.cases; for (_i = 0, _len = _ref2.length; _i < _len; _i++) { pair = _ref2[_i]; pair[1].makeReturn(res); } if (res) { this.otherwise || (this.otherwise = new Block([new Literal('void 0')])); } if ((_ref3 = this.otherwise) != null) { _ref3.makeReturn(res); } return this; }; Switch.prototype.compileNode = function(o) { var block, body, code, cond, conditions, expr, i, idt1, idt2, _i, _j, _len, _len1, _ref2, _ref3, _ref4, _ref5; idt1 = o.indent + TAB; idt2 = o.indent = idt1 + TAB; code = this.tab + ("switch (" + (((_ref2 = this.subject) != null ? _ref2.compile(o, LEVEL_PAREN) : void 0) || false) + ") {\n"); _ref3 = this.cases; for (i = _i = 0, _len = _ref3.length; _i < _len; i = ++_i) { _ref4 = _ref3[i], conditions = _ref4[0], block = _ref4[1]; _ref5 = flatten([conditions]); for (_j = 0, _len1 = _ref5.length; _j < _len1; _j++) { cond = _ref5[_j]; if (!this.subject) { cond = cond.invert(); } code += idt1 + ("case " + (cond.compile(o, LEVEL_PAREN)) + ":\n"); } if (body = block.compile(o, LEVEL_TOP)) { code += body + '\n'; } if (i === this.cases.length - 1 && !this.otherwise) { break; } expr = this.lastNonComment(block.expressions); if (expr instanceof Return || (expr instanceof Literal && expr.jumps() && expr.value !== 'debugger')) { continue; } code += idt2 + 'break;\n'; } if (this.otherwise && this.otherwise.expressions.length) { code += idt1 + ("default:\n" + (this.otherwise.compile(o, LEVEL_TOP)) + "\n"); } return code + this.tab + '}'; }; return Switch; })(Base); exports.If = If = (function(_super) { __extends(If, _super); function If(condition, body, options) { this.body = body; if (options == null) { options = {}; } this.condition = options.type === 'unless' ? condition.invert() : condition; this.elseBody = null; this.isChain = false; this.soak = options.soak; } If.prototype.children = ['condition', 'body', 'elseBody']; If.prototype.bodyNode = function() { var _ref2; return (_ref2 = this.body) != null ? _ref2.unwrap() : void 0; }; If.prototype.elseBodyNode = function() { var _ref2; return (_ref2 = this.elseBody) != null ? _ref2.unwrap() : void 0; }; If.prototype.addElse = function(elseBody) { if (this.isChain) { this.elseBodyNode().addElse(elseBody); } else { this.isChain = elseBody instanceof If; this.elseBody = this.ensureBlock(elseBody); } return this; }; If.prototype.isStatement = function(o) { var _ref2; return (o != null ? o.level : void 0) === LEVEL_TOP || this.bodyNode().isStatement(o) || ((_ref2 = this.elseBodyNode()) != null ? _ref2.isStatement(o) : void 0); }; If.prototype.jumps = function(o) { var _ref2; return this.body.jumps(o) || ((_ref2 = this.elseBody) != null ? _ref2.jumps(o) : void 0); }; If.prototype.compileNode = function(o) { if (this.isStatement(o)) { return this.compileStatement(o); } else { return this.compileExpression(o); } }; If.prototype.makeReturn = function(res) { if (res) { this.elseBody || (this.elseBody = new Block([new Literal('void 0')])); } this.body && (this.body = new Block([this.body.makeReturn(res)])); this.elseBody && (this.elseBody = new Block([this.elseBody.makeReturn(res)])); return this; }; If.prototype.ensureBlock = function(node) { if (node instanceof Block) { return node; } else { return new Block([node]); } }; If.prototype.compileStatement = function(o) { var body, child, cond, exeq, ifPart; child = del(o, 'chainChild'); exeq = del(o, 'isExistentialEquals'); if (exeq) { return new If(this.condition.invert(), this.elseBodyNode(), { type: 'if' }).compile(o); } cond = this.condition.compile(o, LEVEL_PAREN); o.indent += TAB; body = this.ensureBlock(this.body); ifPart = "if (" + cond + ") {\n" + (body.compile(o)) + "\n" + this.tab + "}"; if (!child) { ifPart = this.tab + ifPart; } if (!this.elseBody) { return ifPart; } return ifPart + ' else ' + (this.isChain ? (o.indent = this.tab, o.chainChild = true, this.elseBody.unwrap().compile(o, LEVEL_TOP)) : "{\n" + (this.elseBody.compile(o, LEVEL_TOP)) + "\n" + this.tab + "}"); }; If.prototype.compileExpression = function(o) { var alt, body, code, cond; cond = this.condition.compile(o, LEVEL_COND); body = this.bodyNode().compile(o, LEVEL_LIST); alt = this.elseBodyNode() ? this.elseBodyNode().compile(o, LEVEL_LIST) : 'void 0'; code = "" + cond + " ? " + body + " : " + alt; if (o.level >= LEVEL_COND) { return "(" + code + ")"; } else { return code; } }; If.prototype.unfoldSoak = function() { return this.soak && this; }; return If; })(Base); Closure = { wrap: function(expressions, statement, noReturn) { var args, call, func, mentionsArgs, meth; if (expressions.jumps()) { return expressions; } func = new Code([], Block.wrap([expressions])); args = []; if ((mentionsArgs = expressions.contains(this.literalArgs)) || expressions.contains(this.literalThis)) { meth = new Literal(mentionsArgs ? 'apply' : 'call'); args = [new Literal('this')]; if (mentionsArgs) { args.push(new Literal('arguments')); } func = new Value(func, [new Access(meth)]); } func.noReturn = noReturn; call = new Call(func, args); if (statement) { return Block.wrap([call]); } else { return call; } }, literalArgs: function(node) { return node instanceof Literal && node.value === 'arguments' && !node.asKey; }, literalThis: function(node) { return (node instanceof Literal && node.value === 'this' && !node.asKey) || (node instanceof Code && node.bound) || (node instanceof Call && node.isSuper); } }; unfoldSoak = function(o, parent, name) { var ifn; if (!(ifn = parent[name].unfoldSoak(o))) { return; } parent[name] = ifn.body; ifn.body = new Value(parent); return ifn; }; UTILITIES = { "extends": function() { return "function(child, parent) { for (var key in parent) { if (" + (utility('hasProp')) + ".call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }"; }, bind: function() { return 'function(fn, me){ return function(){ return fn.apply(me, arguments); }; }'; }, indexOf: function() { return "[].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }"; }, hasProp: function() { return '{}.hasOwnProperty'; }, slice: function() { return '[].slice'; } }; LEVEL_TOP = 1; LEVEL_PAREN = 2; LEVEL_LIST = 3; LEVEL_COND = 4; LEVEL_OP = 5; LEVEL_ACCESS = 6; TAB = ' '; IDENTIFIER_STR = "[$A-Za-z_\\x7f-\\uffff][$\\w\\x7f-\\uffff]*"; IDENTIFIER = RegExp("^" + IDENTIFIER_STR + "$"); SIMPLENUM = /^[+-]?\d+$/; METHOD_DEF = RegExp("^(?:(" + IDENTIFIER_STR + ")\\.prototype(?:\\.(" + IDENTIFIER_STR + ")|\\[(\"(?:[^\\\\\"\\r\\n]|\\\\.)*\"|'(?:[^\\\\'\\r\\n]|\\\\.)*')\\]|\\[(0x[\\da-fA-F]+|\\d*\\.?\\d+(?:[eE][+-]?\\d+)?)\\]))|(" + IDENTIFIER_STR + ")$"); IS_STRING = /^['"]/; utility = function(name) { var ref; ref = "__" + name; Scope.root.assign(ref, UTILITIES[name]()); return ref; }; multident = function(code, tab) { code = code.replace(/\n/g, '$&' + tab); return code.replace(/\s+$/, ''); }; }).call(this); coffee-script-1.4.0/lib/coffee-script/optparse.js000066400000000000000000000100041204160075300217300ustar00rootroot00000000000000// Generated by CoffeeScript 1.4.0 (function() { var LONG_FLAG, MULTI_FLAG, OPTIONAL, OptionParser, SHORT_FLAG, buildRule, buildRules, normalizeArguments; exports.OptionParser = OptionParser = (function() { function OptionParser(rules, banner) { this.banner = banner; this.rules = buildRules(rules); } OptionParser.prototype.parse = function(args) { var arg, i, isOption, matchedRule, options, originalArgs, pos, rule, seenNonOptionArg, skippingArgument, value, _i, _j, _len, _len1, _ref; options = { "arguments": [] }; skippingArgument = false; originalArgs = args; args = normalizeArguments(args); for (i = _i = 0, _len = args.length; _i < _len; i = ++_i) { arg = args[i]; if (skippingArgument) { skippingArgument = false; continue; } if (arg === '--') { pos = originalArgs.indexOf('--'); options["arguments"] = options["arguments"].concat(originalArgs.slice(pos + 1)); break; } isOption = !!(arg.match(LONG_FLAG) || arg.match(SHORT_FLAG)); seenNonOptionArg = options["arguments"].length > 0; if (!seenNonOptionArg) { matchedRule = false; _ref = this.rules; for (_j = 0, _len1 = _ref.length; _j < _len1; _j++) { rule = _ref[_j]; if (rule.shortFlag === arg || rule.longFlag === arg) { value = true; if (rule.hasArgument) { skippingArgument = true; value = args[i + 1]; } options[rule.name] = rule.isList ? (options[rule.name] || []).concat(value) : value; matchedRule = true; break; } } if (isOption && !matchedRule) { throw new Error("unrecognized option: " + arg); } } if (seenNonOptionArg || !isOption) { options["arguments"].push(arg); } } return options; }; OptionParser.prototype.help = function() { var letPart, lines, rule, spaces, _i, _len, _ref; lines = []; if (this.banner) { lines.unshift("" + this.banner + "\n"); } _ref = this.rules; for (_i = 0, _len = _ref.length; _i < _len; _i++) { rule = _ref[_i]; spaces = 15 - rule.longFlag.length; spaces = spaces > 0 ? Array(spaces + 1).join(' ') : ''; letPart = rule.shortFlag ? rule.shortFlag + ', ' : ' '; lines.push(' ' + letPart + rule.longFlag + spaces + rule.description); } return "\n" + (lines.join('\n')) + "\n"; }; return OptionParser; })(); LONG_FLAG = /^(--\w[\w\-]*)/; SHORT_FLAG = /^(-\w)$/; MULTI_FLAG = /^-(\w{2,})/; OPTIONAL = /\[(\w+(\*?))\]/; buildRules = function(rules) { var tuple, _i, _len, _results; _results = []; for (_i = 0, _len = rules.length; _i < _len; _i++) { tuple = rules[_i]; if (tuple.length < 3) { tuple.unshift(null); } _results.push(buildRule.apply(null, tuple)); } return _results; }; buildRule = function(shortFlag, longFlag, description, options) { var match; if (options == null) { options = {}; } match = longFlag.match(OPTIONAL); longFlag = longFlag.match(LONG_FLAG)[1]; return { name: longFlag.substr(2), shortFlag: shortFlag, longFlag: longFlag, description: description, hasArgument: !!(match && match[1]), isList: !!(match && match[2]) }; }; normalizeArguments = function(args) { var arg, l, match, result, _i, _j, _len, _len1, _ref; args = args.slice(0); result = []; for (_i = 0, _len = args.length; _i < _len; _i++) { arg = args[_i]; if (match = arg.match(MULTI_FLAG)) { _ref = match[1].split(''); for (_j = 0, _len1 = _ref.length; _j < _len1; _j++) { l = _ref[_j]; result.push('-' + l); } } else { result.push(arg); } } return result; }; }).call(this); coffee-script-1.4.0/lib/coffee-script/parser.js000077500000000000000000003276741204160075300214220ustar00rootroot00000000000000/* Jison generated parser */ var parser = (function(){ var parser = {trace: function trace() { }, yy: {}, symbols_: {"error":2,"Root":3,"Body":4,"Block":5,"TERMINATOR":6,"Line":7,"Expression":8,"Statement":9,"Return":10,"Comment":11,"STATEMENT":12,"Value":13,"Invocation":14,"Code":15,"Operation":16,"Assign":17,"If":18,"Try":19,"While":20,"For":21,"Switch":22,"Class":23,"Throw":24,"INDENT":25,"OUTDENT":26,"Identifier":27,"IDENTIFIER":28,"AlphaNumeric":29,"NUMBER":30,"STRING":31,"Literal":32,"JS":33,"REGEX":34,"DEBUGGER":35,"UNDEFINED":36,"NULL":37,"BOOL":38,"Assignable":39,"=":40,"AssignObj":41,"ObjAssignable":42,":":43,"ThisProperty":44,"RETURN":45,"HERECOMMENT":46,"PARAM_START":47,"ParamList":48,"PARAM_END":49,"FuncGlyph":50,"->":51,"=>":52,"OptComma":53,",":54,"Param":55,"ParamVar":56,"...":57,"Array":58,"Object":59,"Splat":60,"SimpleAssignable":61,"Accessor":62,"Parenthetical":63,"Range":64,"This":65,".":66,"?.":67,"::":68,"Index":69,"INDEX_START":70,"IndexValue":71,"INDEX_END":72,"INDEX_SOAK":73,"Slice":74,"{":75,"AssignList":76,"}":77,"CLASS":78,"EXTENDS":79,"OptFuncExist":80,"Arguments":81,"SUPER":82,"FUNC_EXIST":83,"CALL_START":84,"CALL_END":85,"ArgList":86,"THIS":87,"@":88,"[":89,"]":90,"RangeDots":91,"..":92,"Arg":93,"SimpleArgs":94,"TRY":95,"Catch":96,"FINALLY":97,"CATCH":98,"THROW":99,"(":100,")":101,"WhileSource":102,"WHILE":103,"WHEN":104,"UNTIL":105,"Loop":106,"LOOP":107,"ForBody":108,"FOR":109,"ForStart":110,"ForSource":111,"ForVariables":112,"OWN":113,"ForValue":114,"FORIN":115,"FOROF":116,"BY":117,"SWITCH":118,"Whens":119,"ELSE":120,"When":121,"LEADING_WHEN":122,"IfBlock":123,"IF":124,"POST_IF":125,"UNARY":126,"-":127,"+":128,"--":129,"++":130,"?":131,"MATH":132,"SHIFT":133,"COMPARE":134,"LOGIC":135,"RELATION":136,"COMPOUND_ASSIGN":137,"$accept":0,"$end":1}, terminals_: {2:"error",6:"TERMINATOR",12:"STATEMENT",25:"INDENT",26:"OUTDENT",28:"IDENTIFIER",30:"NUMBER",31:"STRING",33:"JS",34:"REGEX",35:"DEBUGGER",36:"UNDEFINED",37:"NULL",38:"BOOL",40:"=",43:":",45:"RETURN",46:"HERECOMMENT",47:"PARAM_START",49:"PARAM_END",51:"->",52:"=>",54:",",57:"...",66:".",67:"?.",68:"::",70:"INDEX_START",72:"INDEX_END",73:"INDEX_SOAK",75:"{",77:"}",78:"CLASS",79:"EXTENDS",82:"SUPER",83:"FUNC_EXIST",84:"CALL_START",85:"CALL_END",87:"THIS",88:"@",89:"[",90:"]",92:"..",95:"TRY",97:"FINALLY",98:"CATCH",99:"THROW",100:"(",101:")",103:"WHILE",104:"WHEN",105:"UNTIL",107:"LOOP",109:"FOR",113:"OWN",115:"FORIN",116:"FOROF",117:"BY",118:"SWITCH",120:"ELSE",122:"LEADING_WHEN",124:"IF",125:"POST_IF",126:"UNARY",127:"-",128:"+",129:"--",130:"++",131:"?",132:"MATH",133:"SHIFT",134:"COMPARE",135:"LOGIC",136:"RELATION",137:"COMPOUND_ASSIGN"}, productions_: [0,[3,0],[3,1],[3,2],[4,1],[4,3],[4,2],[7,1],[7,1],[9,1],[9,1],[9,1],[8,1],[8,1],[8,1],[8,1],[8,1],[8,1],[8,1],[8,1],[8,1],[8,1],[8,1],[8,1],[5,2],[5,3],[27,1],[29,1],[29,1],[32,1],[32,1],[32,1],[32,1],[32,1],[32,1],[32,1],[17,3],[17,4],[17,5],[41,1],[41,3],[41,5],[41,1],[42,1],[42,1],[42,1],[10,2],[10,1],[11,1],[15,5],[15,2],[50,1],[50,1],[53,0],[53,1],[48,0],[48,1],[48,3],[48,4],[48,6],[55,1],[55,2],[55,3],[56,1],[56,1],[56,1],[56,1],[60,2],[61,1],[61,2],[61,2],[61,1],[39,1],[39,1],[39,1],[13,1],[13,1],[13,1],[13,1],[13,1],[62,2],[62,2],[62,2],[62,1],[62,1],[69,3],[69,2],[71,1],[71,1],[59,4],[76,0],[76,1],[76,3],[76,4],[76,6],[23,1],[23,2],[23,3],[23,4],[23,2],[23,3],[23,4],[23,5],[14,3],[14,3],[14,1],[14,2],[80,0],[80,1],[81,2],[81,4],[65,1],[65,1],[44,2],[58,2],[58,4],[91,1],[91,1],[64,5],[74,3],[74,2],[74,2],[74,1],[86,1],[86,3],[86,4],[86,4],[86,6],[93,1],[93,1],[94,1],[94,3],[19,2],[19,3],[19,4],[19,5],[96,3],[24,2],[63,3],[63,5],[102,2],[102,4],[102,2],[102,4],[20,2],[20,2],[20,2],[20,1],[106,2],[106,2],[21,2],[21,2],[21,2],[108,2],[108,2],[110,2],[110,3],[114,1],[114,1],[114,1],[114,1],[112,1],[112,3],[111,2],[111,2],[111,4],[111,4],[111,4],[111,6],[111,6],[22,5],[22,7],[22,4],[22,6],[119,1],[119,2],[121,3],[121,4],[123,3],[123,5],[18,1],[18,3],[18,3],[18,3],[16,2],[16,2],[16,2],[16,2],[16,2],[16,2],[16,2],[16,2],[16,3],[16,3],[16,3],[16,3],[16,3],[16,3],[16,3],[16,3],[16,5],[16,3]], performAction: function anonymous(yytext,yyleng,yylineno,yy,yystate,$$,_$) { var $0 = $$.length - 1; switch (yystate) { case 1:return this.$ = new yy.Block; break; case 2:return this.$ = $$[$0]; break; case 3:return this.$ = $$[$0-1]; break; case 4:this.$ = yy.Block.wrap([$$[$0]]); break; case 5:this.$ = $$[$0-2].push($$[$0]); break; case 6:this.$ = $$[$0-1]; break; case 7:this.$ = $$[$0]; break; case 8:this.$ = $$[$0]; break; case 9:this.$ = $$[$0]; break; case 10:this.$ = $$[$0]; break; case 11:this.$ = new yy.Literal($$[$0]); break; case 12:this.$ = $$[$0]; break; case 13:this.$ = $$[$0]; break; case 14:this.$ = $$[$0]; break; case 15:this.$ = $$[$0]; break; case 16:this.$ = $$[$0]; break; case 17:this.$ = $$[$0]; break; case 18:this.$ = $$[$0]; break; case 19:this.$ = $$[$0]; break; case 20:this.$ = $$[$0]; break; case 21:this.$ = $$[$0]; break; case 22:this.$ = $$[$0]; break; case 23:this.$ = $$[$0]; break; case 24:this.$ = new yy.Block; break; case 25:this.$ = $$[$0-1]; break; case 26:this.$ = new yy.Literal($$[$0]); break; case 27:this.$ = new yy.Literal($$[$0]); break; case 28:this.$ = new yy.Literal($$[$0]); break; case 29:this.$ = $$[$0]; break; case 30:this.$ = new yy.Literal($$[$0]); break; case 31:this.$ = new yy.Literal($$[$0]); break; case 32:this.$ = new yy.Literal($$[$0]); break; case 33:this.$ = new yy.Undefined; break; case 34:this.$ = new yy.Null; break; case 35:this.$ = new yy.Bool($$[$0]); break; case 36:this.$ = new yy.Assign($$[$0-2], $$[$0]); break; case 37:this.$ = new yy.Assign($$[$0-3], $$[$0]); break; case 38:this.$ = new yy.Assign($$[$0-4], $$[$0-1]); break; case 39:this.$ = new yy.Value($$[$0]); break; case 40:this.$ = new yy.Assign(new yy.Value($$[$0-2]), $$[$0], 'object'); break; case 41:this.$ = new yy.Assign(new yy.Value($$[$0-4]), $$[$0-1], 'object'); break; case 42:this.$ = $$[$0]; break; case 43:this.$ = $$[$0]; break; case 44:this.$ = $$[$0]; break; case 45:this.$ = $$[$0]; break; case 46:this.$ = new yy.Return($$[$0]); break; case 47:this.$ = new yy.Return; break; case 48:this.$ = new yy.Comment($$[$0]); break; case 49:this.$ = new yy.Code($$[$0-3], $$[$0], $$[$0-1]); break; case 50:this.$ = new yy.Code([], $$[$0], $$[$0-1]); break; case 51:this.$ = 'func'; break; case 52:this.$ = 'boundfunc'; break; case 53:this.$ = $$[$0]; break; case 54:this.$ = $$[$0]; break; case 55:this.$ = []; break; case 56:this.$ = [$$[$0]]; break; case 57:this.$ = $$[$0-2].concat($$[$0]); break; case 58:this.$ = $$[$0-3].concat($$[$0]); break; case 59:this.$ = $$[$0-5].concat($$[$0-2]); break; case 60:this.$ = new yy.Param($$[$0]); break; case 61:this.$ = new yy.Param($$[$0-1], null, true); break; case 62:this.$ = new yy.Param($$[$0-2], $$[$0]); break; case 63:this.$ = $$[$0]; break; case 64:this.$ = $$[$0]; break; case 65:this.$ = $$[$0]; break; case 66:this.$ = $$[$0]; break; case 67:this.$ = new yy.Splat($$[$0-1]); break; case 68:this.$ = new yy.Value($$[$0]); break; case 69:this.$ = $$[$0-1].add($$[$0]); break; case 70:this.$ = new yy.Value($$[$0-1], [].concat($$[$0])); break; case 71:this.$ = $$[$0]; break; case 72:this.$ = $$[$0]; break; case 73:this.$ = new yy.Value($$[$0]); break; case 74:this.$ = new yy.Value($$[$0]); break; case 75:this.$ = $$[$0]; break; case 76:this.$ = new yy.Value($$[$0]); break; case 77:this.$ = new yy.Value($$[$0]); break; case 78:this.$ = new yy.Value($$[$0]); break; case 79:this.$ = $$[$0]; break; case 80:this.$ = new yy.Access($$[$0]); break; case 81:this.$ = new yy.Access($$[$0], 'soak'); break; case 82:this.$ = [new yy.Access(new yy.Literal('prototype')), new yy.Access($$[$0])]; break; case 83:this.$ = new yy.Access(new yy.Literal('prototype')); break; case 84:this.$ = $$[$0]; break; case 85:this.$ = $$[$0-1]; break; case 86:this.$ = yy.extend($$[$0], { soak: true }); break; case 87:this.$ = new yy.Index($$[$0]); break; case 88:this.$ = new yy.Slice($$[$0]); break; case 89:this.$ = new yy.Obj($$[$0-2], $$[$0-3].generated); break; case 90:this.$ = []; break; case 91:this.$ = [$$[$0]]; break; case 92:this.$ = $$[$0-2].concat($$[$0]); break; case 93:this.$ = $$[$0-3].concat($$[$0]); break; case 94:this.$ = $$[$0-5].concat($$[$0-2]); break; case 95:this.$ = new yy.Class; break; case 96:this.$ = new yy.Class(null, null, $$[$0]); break; case 97:this.$ = new yy.Class(null, $$[$0]); break; case 98:this.$ = new yy.Class(null, $$[$0-1], $$[$0]); break; case 99:this.$ = new yy.Class($$[$0]); break; case 100:this.$ = new yy.Class($$[$0-1], null, $$[$0]); break; case 101:this.$ = new yy.Class($$[$0-2], $$[$0]); break; case 102:this.$ = new yy.Class($$[$0-3], $$[$0-1], $$[$0]); break; case 103:this.$ = new yy.Call($$[$0-2], $$[$0], $$[$0-1]); break; case 104:this.$ = new yy.Call($$[$0-2], $$[$0], $$[$0-1]); break; case 105:this.$ = new yy.Call('super', [new yy.Splat(new yy.Literal('arguments'))]); break; case 106:this.$ = new yy.Call('super', $$[$0]); break; case 107:this.$ = false; break; case 108:this.$ = true; break; case 109:this.$ = []; break; case 110:this.$ = $$[$0-2]; break; case 111:this.$ = new yy.Value(new yy.Literal('this')); break; case 112:this.$ = new yy.Value(new yy.Literal('this')); break; case 113:this.$ = new yy.Value(new yy.Literal('this'), [new yy.Access($$[$0])], 'this'); break; case 114:this.$ = new yy.Arr([]); break; case 115:this.$ = new yy.Arr($$[$0-2]); break; case 116:this.$ = 'inclusive'; break; case 117:this.$ = 'exclusive'; break; case 118:this.$ = new yy.Range($$[$0-3], $$[$0-1], $$[$0-2]); break; case 119:this.$ = new yy.Range($$[$0-2], $$[$0], $$[$0-1]); break; case 120:this.$ = new yy.Range($$[$0-1], null, $$[$0]); break; case 121:this.$ = new yy.Range(null, $$[$0], $$[$0-1]); break; case 122:this.$ = new yy.Range(null, null, $$[$0]); break; case 123:this.$ = [$$[$0]]; break; case 124:this.$ = $$[$0-2].concat($$[$0]); break; case 125:this.$ = $$[$0-3].concat($$[$0]); break; case 126:this.$ = $$[$0-2]; break; case 127:this.$ = $$[$0-5].concat($$[$0-2]); break; case 128:this.$ = $$[$0]; break; case 129:this.$ = $$[$0]; break; case 130:this.$ = $$[$0]; break; case 131:this.$ = [].concat($$[$0-2], $$[$0]); break; case 132:this.$ = new yy.Try($$[$0]); break; case 133:this.$ = new yy.Try($$[$0-1], $$[$0][0], $$[$0][1]); break; case 134:this.$ = new yy.Try($$[$0-2], null, null, $$[$0]); break; case 135:this.$ = new yy.Try($$[$0-3], $$[$0-2][0], $$[$0-2][1], $$[$0]); break; case 136:this.$ = [$$[$0-1], $$[$0]]; break; case 137:this.$ = new yy.Throw($$[$0]); break; case 138:this.$ = new yy.Parens($$[$0-1]); break; case 139:this.$ = new yy.Parens($$[$0-2]); break; case 140:this.$ = new yy.While($$[$0]); break; case 141:this.$ = new yy.While($$[$0-2], { guard: $$[$0] }); break; case 142:this.$ = new yy.While($$[$0], { invert: true }); break; case 143:this.$ = new yy.While($$[$0-2], { invert: true, guard: $$[$0] }); break; case 144:this.$ = $$[$0-1].addBody($$[$0]); break; case 145:this.$ = $$[$0].addBody(yy.Block.wrap([$$[$0-1]])); break; case 146:this.$ = $$[$0].addBody(yy.Block.wrap([$$[$0-1]])); break; case 147:this.$ = $$[$0]; break; case 148:this.$ = new yy.While(new yy.Literal('true')).addBody($$[$0]); break; case 149:this.$ = new yy.While(new yy.Literal('true')).addBody(yy.Block.wrap([$$[$0]])); break; case 150:this.$ = new yy.For($$[$0-1], $$[$0]); break; case 151:this.$ = new yy.For($$[$0-1], $$[$0]); break; case 152:this.$ = new yy.For($$[$0], $$[$0-1]); break; case 153:this.$ = { source: new yy.Value($$[$0]) }; break; case 154:this.$ = (function () { $$[$0].own = $$[$0-1].own; $$[$0].name = $$[$0-1][0]; $$[$0].index = $$[$0-1][1]; return $$[$0]; }()); break; case 155:this.$ = $$[$0]; break; case 156:this.$ = (function () { $$[$0].own = true; return $$[$0]; }()); break; case 157:this.$ = $$[$0]; break; case 158:this.$ = $$[$0]; break; case 159:this.$ = new yy.Value($$[$0]); break; case 160:this.$ = new yy.Value($$[$0]); break; case 161:this.$ = [$$[$0]]; break; case 162:this.$ = [$$[$0-2], $$[$0]]; break; case 163:this.$ = { source: $$[$0] }; break; case 164:this.$ = { source: $$[$0], object: true }; break; case 165:this.$ = { source: $$[$0-2], guard: $$[$0] }; break; case 166:this.$ = { source: $$[$0-2], guard: $$[$0], object: true }; break; case 167:this.$ = { source: $$[$0-2], step: $$[$0] }; break; case 168:this.$ = { source: $$[$0-4], guard: $$[$0-2], step: $$[$0] }; break; case 169:this.$ = { source: $$[$0-4], step: $$[$0-2], guard: $$[$0] }; break; case 170:this.$ = new yy.Switch($$[$0-3], $$[$0-1]); break; case 171:this.$ = new yy.Switch($$[$0-5], $$[$0-3], $$[$0-1]); break; case 172:this.$ = new yy.Switch(null, $$[$0-1]); break; case 173:this.$ = new yy.Switch(null, $$[$0-3], $$[$0-1]); break; case 174:this.$ = $$[$0]; break; case 175:this.$ = $$[$0-1].concat($$[$0]); break; case 176:this.$ = [[$$[$0-1], $$[$0]]]; break; case 177:this.$ = [[$$[$0-2], $$[$0-1]]]; break; case 178:this.$ = new yy.If($$[$0-1], $$[$0], { type: $$[$0-2] }); break; case 179:this.$ = $$[$0-4].addElse(new yy.If($$[$0-1], $$[$0], { type: $$[$0-2] })); break; case 180:this.$ = $$[$0]; break; case 181:this.$ = $$[$0-2].addElse($$[$0]); break; case 182:this.$ = new yy.If($$[$0], yy.Block.wrap([$$[$0-2]]), { type: $$[$0-1], statement: true }); break; case 183:this.$ = new yy.If($$[$0], yy.Block.wrap([$$[$0-2]]), { type: $$[$0-1], statement: true }); break; case 184:this.$ = new yy.Op($$[$0-1], $$[$0]); break; case 185:this.$ = new yy.Op('-', $$[$0]); break; case 186:this.$ = new yy.Op('+', $$[$0]); break; case 187:this.$ = new yy.Op('--', $$[$0]); break; case 188:this.$ = new yy.Op('++', $$[$0]); break; case 189:this.$ = new yy.Op('--', $$[$0-1], null, true); break; case 190:this.$ = new yy.Op('++', $$[$0-1], null, true); break; case 191:this.$ = new yy.Existence($$[$0-1]); break; case 192:this.$ = new yy.Op('+', $$[$0-2], $$[$0]); break; case 193:this.$ = new yy.Op('-', $$[$0-2], $$[$0]); break; case 194:this.$ = new yy.Op($$[$0-1], $$[$0-2], $$[$0]); break; case 195:this.$ = new yy.Op($$[$0-1], $$[$0-2], $$[$0]); break; case 196:this.$ = new yy.Op($$[$0-1], $$[$0-2], $$[$0]); break; case 197:this.$ = new yy.Op($$[$0-1], $$[$0-2], $$[$0]); break; case 198:this.$ = (function () { if ($$[$0-1].charAt(0) === '!') { return new yy.Op($$[$0-1].slice(1), $$[$0-2], $$[$0]).invert(); } else { return new yy.Op($$[$0-1], $$[$0-2], $$[$0]); } }()); break; case 199:this.$ = new yy.Assign($$[$0-2], $$[$0], $$[$0-1]); break; case 200:this.$ = new yy.Assign($$[$0-4], $$[$0-1], $$[$0-3]); break; case 201:this.$ = new yy.Extends($$[$0-2], $$[$0]); break; } }, table: [{1:[2,1],3:1,4:2,5:3,7:4,8:6,9:7,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,25:[1,5],27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{1:[3]},{1:[2,2],6:[1,74]},{6:[1,75]},{1:[2,4],6:[2,4],26:[2,4],101:[2,4]},{4:77,7:4,8:6,9:7,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,26:[1,76],27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{1:[2,7],6:[2,7],26:[2,7],101:[2,7],102:87,103:[1,65],105:[1,66],108:88,109:[1,68],110:69,125:[1,86],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{1:[2,8],6:[2,8],26:[2,8],101:[2,8],102:90,103:[1,65],105:[1,66],108:91,109:[1,68],110:69,125:[1,89]},{1:[2,12],6:[2,12],25:[2,12],26:[2,12],49:[2,12],54:[2,12],57:[2,12],62:93,66:[1,95],67:[1,96],68:[1,97],69:98,70:[1,99],72:[2,12],73:[1,100],77:[2,12],80:92,83:[1,94],84:[2,107],85:[2,12],90:[2,12],92:[2,12],101:[2,12],103:[2,12],104:[2,12],105:[2,12],109:[2,12],117:[2,12],125:[2,12],127:[2,12],128:[2,12],131:[2,12],132:[2,12],133:[2,12],134:[2,12],135:[2,12],136:[2,12]},{1:[2,13],6:[2,13],25:[2,13],26:[2,13],49:[2,13],54:[2,13],57:[2,13],62:102,66:[1,95],67:[1,96],68:[1,97],69:98,70:[1,99],72:[2,13],73:[1,100],77:[2,13],80:101,83:[1,94],84:[2,107],85:[2,13],90:[2,13],92:[2,13],101:[2,13],103:[2,13],104:[2,13],105:[2,13],109:[2,13],117:[2,13],125:[2,13],127:[2,13],128:[2,13],131:[2,13],132:[2,13],133:[2,13],134:[2,13],135:[2,13],136:[2,13]},{1:[2,14],6:[2,14],25:[2,14],26:[2,14],49:[2,14],54:[2,14],57:[2,14],72:[2,14],77:[2,14],85:[2,14],90:[2,14],92:[2,14],101:[2,14],103:[2,14],104:[2,14],105:[2,14],109:[2,14],117:[2,14],125:[2,14],127:[2,14],128:[2,14],131:[2,14],132:[2,14],133:[2,14],134:[2,14],135:[2,14],136:[2,14]},{1:[2,15],6:[2,15],25:[2,15],26:[2,15],49:[2,15],54:[2,15],57:[2,15],72:[2,15],77:[2,15],85:[2,15],90:[2,15],92:[2,15],101:[2,15],103:[2,15],104:[2,15],105:[2,15],109:[2,15],117:[2,15],125:[2,15],127:[2,15],128:[2,15],131:[2,15],132:[2,15],133:[2,15],134:[2,15],135:[2,15],136:[2,15]},{1:[2,16],6:[2,16],25:[2,16],26:[2,16],49:[2,16],54:[2,16],57:[2,16],72:[2,16],77:[2,16],85:[2,16],90:[2,16],92:[2,16],101:[2,16],103:[2,16],104:[2,16],105:[2,16],109:[2,16],117:[2,16],125:[2,16],127:[2,16],128:[2,16],131:[2,16],132:[2,16],133:[2,16],134:[2,16],135:[2,16],136:[2,16]},{1:[2,17],6:[2,17],25:[2,17],26:[2,17],49:[2,17],54:[2,17],57:[2,17],72:[2,17],77:[2,17],85:[2,17],90:[2,17],92:[2,17],101:[2,17],103:[2,17],104:[2,17],105:[2,17],109:[2,17],117:[2,17],125:[2,17],127:[2,17],128:[2,17],131:[2,17],132:[2,17],133:[2,17],134:[2,17],135:[2,17],136:[2,17]},{1:[2,18],6:[2,18],25:[2,18],26:[2,18],49:[2,18],54:[2,18],57:[2,18],72:[2,18],77:[2,18],85:[2,18],90:[2,18],92:[2,18],101:[2,18],103:[2,18],104:[2,18],105:[2,18],109:[2,18],117:[2,18],125:[2,18],127:[2,18],128:[2,18],131:[2,18],132:[2,18],133:[2,18],134:[2,18],135:[2,18],136:[2,18]},{1:[2,19],6:[2,19],25:[2,19],26:[2,19],49:[2,19],54:[2,19],57:[2,19],72:[2,19],77:[2,19],85:[2,19],90:[2,19],92:[2,19],101:[2,19],103:[2,19],104:[2,19],105:[2,19],109:[2,19],117:[2,19],125:[2,19],127:[2,19],128:[2,19],131:[2,19],132:[2,19],133:[2,19],134:[2,19],135:[2,19],136:[2,19]},{1:[2,20],6:[2,20],25:[2,20],26:[2,20],49:[2,20],54:[2,20],57:[2,20],72:[2,20],77:[2,20],85:[2,20],90:[2,20],92:[2,20],101:[2,20],103:[2,20],104:[2,20],105:[2,20],109:[2,20],117:[2,20],125:[2,20],127:[2,20],128:[2,20],131:[2,20],132:[2,20],133:[2,20],134:[2,20],135:[2,20],136:[2,20]},{1:[2,21],6:[2,21],25:[2,21],26:[2,21],49:[2,21],54:[2,21],57:[2,21],72:[2,21],77:[2,21],85:[2,21],90:[2,21],92:[2,21],101:[2,21],103:[2,21],104:[2,21],105:[2,21],109:[2,21],117:[2,21],125:[2,21],127:[2,21],128:[2,21],131:[2,21],132:[2,21],133:[2,21],134:[2,21],135:[2,21],136:[2,21]},{1:[2,22],6:[2,22],25:[2,22],26:[2,22],49:[2,22],54:[2,22],57:[2,22],72:[2,22],77:[2,22],85:[2,22],90:[2,22],92:[2,22],101:[2,22],103:[2,22],104:[2,22],105:[2,22],109:[2,22],117:[2,22],125:[2,22],127:[2,22],128:[2,22],131:[2,22],132:[2,22],133:[2,22],134:[2,22],135:[2,22],136:[2,22]},{1:[2,23],6:[2,23],25:[2,23],26:[2,23],49:[2,23],54:[2,23],57:[2,23],72:[2,23],77:[2,23],85:[2,23],90:[2,23],92:[2,23],101:[2,23],103:[2,23],104:[2,23],105:[2,23],109:[2,23],117:[2,23],125:[2,23],127:[2,23],128:[2,23],131:[2,23],132:[2,23],133:[2,23],134:[2,23],135:[2,23],136:[2,23]},{1:[2,9],6:[2,9],26:[2,9],101:[2,9],103:[2,9],105:[2,9],109:[2,9],125:[2,9]},{1:[2,10],6:[2,10],26:[2,10],101:[2,10],103:[2,10],105:[2,10],109:[2,10],125:[2,10]},{1:[2,11],6:[2,11],26:[2,11],101:[2,11],103:[2,11],105:[2,11],109:[2,11],125:[2,11]},{1:[2,75],6:[2,75],25:[2,75],26:[2,75],40:[1,103],49:[2,75],54:[2,75],57:[2,75],66:[2,75],67:[2,75],68:[2,75],70:[2,75],72:[2,75],73:[2,75],77:[2,75],83:[2,75],84:[2,75],85:[2,75],90:[2,75],92:[2,75],101:[2,75],103:[2,75],104:[2,75],105:[2,75],109:[2,75],117:[2,75],125:[2,75],127:[2,75],128:[2,75],131:[2,75],132:[2,75],133:[2,75],134:[2,75],135:[2,75],136:[2,75]},{1:[2,76],6:[2,76],25:[2,76],26:[2,76],49:[2,76],54:[2,76],57:[2,76],66:[2,76],67:[2,76],68:[2,76],70:[2,76],72:[2,76],73:[2,76],77:[2,76],83:[2,76],84:[2,76],85:[2,76],90:[2,76],92:[2,76],101:[2,76],103:[2,76],104:[2,76],105:[2,76],109:[2,76],117:[2,76],125:[2,76],127:[2,76],128:[2,76],131:[2,76],132:[2,76],133:[2,76],134:[2,76],135:[2,76],136:[2,76]},{1:[2,77],6:[2,77],25:[2,77],26:[2,77],49:[2,77],54:[2,77],57:[2,77],66:[2,77],67:[2,77],68:[2,77],70:[2,77],72:[2,77],73:[2,77],77:[2,77],83:[2,77],84:[2,77],85:[2,77],90:[2,77],92:[2,77],101:[2,77],103:[2,77],104:[2,77],105:[2,77],109:[2,77],117:[2,77],125:[2,77],127:[2,77],128:[2,77],131:[2,77],132:[2,77],133:[2,77],134:[2,77],135:[2,77],136:[2,77]},{1:[2,78],6:[2,78],25:[2,78],26:[2,78],49:[2,78],54:[2,78],57:[2,78],66:[2,78],67:[2,78],68:[2,78],70:[2,78],72:[2,78],73:[2,78],77:[2,78],83:[2,78],84:[2,78],85:[2,78],90:[2,78],92:[2,78],101:[2,78],103:[2,78],104:[2,78],105:[2,78],109:[2,78],117:[2,78],125:[2,78],127:[2,78],128:[2,78],131:[2,78],132:[2,78],133:[2,78],134:[2,78],135:[2,78],136:[2,78]},{1:[2,79],6:[2,79],25:[2,79],26:[2,79],49:[2,79],54:[2,79],57:[2,79],66:[2,79],67:[2,79],68:[2,79],70:[2,79],72:[2,79],73:[2,79],77:[2,79],83:[2,79],84:[2,79],85:[2,79],90:[2,79],92:[2,79],101:[2,79],103:[2,79],104:[2,79],105:[2,79],109:[2,79],117:[2,79],125:[2,79],127:[2,79],128:[2,79],131:[2,79],132:[2,79],133:[2,79],134:[2,79],135:[2,79],136:[2,79]},{1:[2,105],6:[2,105],25:[2,105],26:[2,105],49:[2,105],54:[2,105],57:[2,105],66:[2,105],67:[2,105],68:[2,105],70:[2,105],72:[2,105],73:[2,105],77:[2,105],81:104,83:[2,105],84:[1,105],85:[2,105],90:[2,105],92:[2,105],101:[2,105],103:[2,105],104:[2,105],105:[2,105],109:[2,105],117:[2,105],125:[2,105],127:[2,105],128:[2,105],131:[2,105],132:[2,105],133:[2,105],134:[2,105],135:[2,105],136:[2,105]},{6:[2,55],25:[2,55],27:109,28:[1,73],44:110,48:106,49:[2,55],54:[2,55],55:107,56:108,58:111,59:112,75:[1,70],88:[1,113],89:[1,114]},{5:115,25:[1,5]},{8:116,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{8:118,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{8:119,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{13:121,14:122,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:123,44:63,58:47,59:48,61:120,63:25,64:26,65:27,75:[1,70],82:[1,28],87:[1,58],88:[1,59],89:[1,57],100:[1,56]},{13:121,14:122,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:123,44:63,58:47,59:48,61:124,63:25,64:26,65:27,75:[1,70],82:[1,28],87:[1,58],88:[1,59],89:[1,57],100:[1,56]},{1:[2,72],6:[2,72],25:[2,72],26:[2,72],40:[2,72],49:[2,72],54:[2,72],57:[2,72],66:[2,72],67:[2,72],68:[2,72],70:[2,72],72:[2,72],73:[2,72],77:[2,72],79:[1,128],83:[2,72],84:[2,72],85:[2,72],90:[2,72],92:[2,72],101:[2,72],103:[2,72],104:[2,72],105:[2,72],109:[2,72],117:[2,72],125:[2,72],127:[2,72],128:[2,72],129:[1,125],130:[1,126],131:[2,72],132:[2,72],133:[2,72],134:[2,72],135:[2,72],136:[2,72],137:[1,127]},{1:[2,180],6:[2,180],25:[2,180],26:[2,180],49:[2,180],54:[2,180],57:[2,180],72:[2,180],77:[2,180],85:[2,180],90:[2,180],92:[2,180],101:[2,180],103:[2,180],104:[2,180],105:[2,180],109:[2,180],117:[2,180],120:[1,129],125:[2,180],127:[2,180],128:[2,180],131:[2,180],132:[2,180],133:[2,180],134:[2,180],135:[2,180],136:[2,180]},{5:130,25:[1,5]},{5:131,25:[1,5]},{1:[2,147],6:[2,147],25:[2,147],26:[2,147],49:[2,147],54:[2,147],57:[2,147],72:[2,147],77:[2,147],85:[2,147],90:[2,147],92:[2,147],101:[2,147],103:[2,147],104:[2,147],105:[2,147],109:[2,147],117:[2,147],125:[2,147],127:[2,147],128:[2,147],131:[2,147],132:[2,147],133:[2,147],134:[2,147],135:[2,147],136:[2,147]},{5:132,25:[1,5]},{8:133,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,25:[1,134],27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{1:[2,95],5:135,6:[2,95],13:121,14:122,25:[1,5],26:[2,95],27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:123,44:63,49:[2,95],54:[2,95],57:[2,95],58:47,59:48,61:137,63:25,64:26,65:27,72:[2,95],75:[1,70],77:[2,95],79:[1,136],82:[1,28],85:[2,95],87:[1,58],88:[1,59],89:[1,57],90:[2,95],92:[2,95],100:[1,56],101:[2,95],103:[2,95],104:[2,95],105:[2,95],109:[2,95],117:[2,95],125:[2,95],127:[2,95],128:[2,95],131:[2,95],132:[2,95],133:[2,95],134:[2,95],135:[2,95],136:[2,95]},{8:138,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{1:[2,47],6:[2,47],8:139,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,26:[2,47],27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],101:[2,47],102:39,103:[2,47],105:[2,47],106:40,107:[1,67],108:41,109:[2,47],110:69,118:[1,42],123:37,124:[1,64],125:[2,47],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{1:[2,48],6:[2,48],25:[2,48],26:[2,48],54:[2,48],77:[2,48],101:[2,48],103:[2,48],105:[2,48],109:[2,48],125:[2,48]},{1:[2,73],6:[2,73],25:[2,73],26:[2,73],40:[2,73],49:[2,73],54:[2,73],57:[2,73],66:[2,73],67:[2,73],68:[2,73],70:[2,73],72:[2,73],73:[2,73],77:[2,73],83:[2,73],84:[2,73],85:[2,73],90:[2,73],92:[2,73],101:[2,73],103:[2,73],104:[2,73],105:[2,73],109:[2,73],117:[2,73],125:[2,73],127:[2,73],128:[2,73],131:[2,73],132:[2,73],133:[2,73],134:[2,73],135:[2,73],136:[2,73]},{1:[2,74],6:[2,74],25:[2,74],26:[2,74],40:[2,74],49:[2,74],54:[2,74],57:[2,74],66:[2,74],67:[2,74],68:[2,74],70:[2,74],72:[2,74],73:[2,74],77:[2,74],83:[2,74],84:[2,74],85:[2,74],90:[2,74],92:[2,74],101:[2,74],103:[2,74],104:[2,74],105:[2,74],109:[2,74],117:[2,74],125:[2,74],127:[2,74],128:[2,74],131:[2,74],132:[2,74],133:[2,74],134:[2,74],135:[2,74],136:[2,74]},{1:[2,29],6:[2,29],25:[2,29],26:[2,29],49:[2,29],54:[2,29],57:[2,29],66:[2,29],67:[2,29],68:[2,29],70:[2,29],72:[2,29],73:[2,29],77:[2,29],83:[2,29],84:[2,29],85:[2,29],90:[2,29],92:[2,29],101:[2,29],103:[2,29],104:[2,29],105:[2,29],109:[2,29],117:[2,29],125:[2,29],127:[2,29],128:[2,29],131:[2,29],132:[2,29],133:[2,29],134:[2,29],135:[2,29],136:[2,29]},{1:[2,30],6:[2,30],25:[2,30],26:[2,30],49:[2,30],54:[2,30],57:[2,30],66:[2,30],67:[2,30],68:[2,30],70:[2,30],72:[2,30],73:[2,30],77:[2,30],83:[2,30],84:[2,30],85:[2,30],90:[2,30],92:[2,30],101:[2,30],103:[2,30],104:[2,30],105:[2,30],109:[2,30],117:[2,30],125:[2,30],127:[2,30],128:[2,30],131:[2,30],132:[2,30],133:[2,30],134:[2,30],135:[2,30],136:[2,30]},{1:[2,31],6:[2,31],25:[2,31],26:[2,31],49:[2,31],54:[2,31],57:[2,31],66:[2,31],67:[2,31],68:[2,31],70:[2,31],72:[2,31],73:[2,31],77:[2,31],83:[2,31],84:[2,31],85:[2,31],90:[2,31],92:[2,31],101:[2,31],103:[2,31],104:[2,31],105:[2,31],109:[2,31],117:[2,31],125:[2,31],127:[2,31],128:[2,31],131:[2,31],132:[2,31],133:[2,31],134:[2,31],135:[2,31],136:[2,31]},{1:[2,32],6:[2,32],25:[2,32],26:[2,32],49:[2,32],54:[2,32],57:[2,32],66:[2,32],67:[2,32],68:[2,32],70:[2,32],72:[2,32],73:[2,32],77:[2,32],83:[2,32],84:[2,32],85:[2,32],90:[2,32],92:[2,32],101:[2,32],103:[2,32],104:[2,32],105:[2,32],109:[2,32],117:[2,32],125:[2,32],127:[2,32],128:[2,32],131:[2,32],132:[2,32],133:[2,32],134:[2,32],135:[2,32],136:[2,32]},{1:[2,33],6:[2,33],25:[2,33],26:[2,33],49:[2,33],54:[2,33],57:[2,33],66:[2,33],67:[2,33],68:[2,33],70:[2,33],72:[2,33],73:[2,33],77:[2,33],83:[2,33],84:[2,33],85:[2,33],90:[2,33],92:[2,33],101:[2,33],103:[2,33],104:[2,33],105:[2,33],109:[2,33],117:[2,33],125:[2,33],127:[2,33],128:[2,33],131:[2,33],132:[2,33],133:[2,33],134:[2,33],135:[2,33],136:[2,33]},{1:[2,34],6:[2,34],25:[2,34],26:[2,34],49:[2,34],54:[2,34],57:[2,34],66:[2,34],67:[2,34],68:[2,34],70:[2,34],72:[2,34],73:[2,34],77:[2,34],83:[2,34],84:[2,34],85:[2,34],90:[2,34],92:[2,34],101:[2,34],103:[2,34],104:[2,34],105:[2,34],109:[2,34],117:[2,34],125:[2,34],127:[2,34],128:[2,34],131:[2,34],132:[2,34],133:[2,34],134:[2,34],135:[2,34],136:[2,34]},{1:[2,35],6:[2,35],25:[2,35],26:[2,35],49:[2,35],54:[2,35],57:[2,35],66:[2,35],67:[2,35],68:[2,35],70:[2,35],72:[2,35],73:[2,35],77:[2,35],83:[2,35],84:[2,35],85:[2,35],90:[2,35],92:[2,35],101:[2,35],103:[2,35],104:[2,35],105:[2,35],109:[2,35],117:[2,35],125:[2,35],127:[2,35],128:[2,35],131:[2,35],132:[2,35],133:[2,35],134:[2,35],135:[2,35],136:[2,35]},{4:140,7:4,8:6,9:7,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,25:[1,141],27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{8:142,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,25:[1,146],27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,60:147,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],86:144,87:[1,58],88:[1,59],89:[1,57],90:[1,143],93:145,95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{1:[2,111],6:[2,111],25:[2,111],26:[2,111],49:[2,111],54:[2,111],57:[2,111],66:[2,111],67:[2,111],68:[2,111],70:[2,111],72:[2,111],73:[2,111],77:[2,111],83:[2,111],84:[2,111],85:[2,111],90:[2,111],92:[2,111],101:[2,111],103:[2,111],104:[2,111],105:[2,111],109:[2,111],117:[2,111],125:[2,111],127:[2,111],128:[2,111],131:[2,111],132:[2,111],133:[2,111],134:[2,111],135:[2,111],136:[2,111]},{1:[2,112],6:[2,112],25:[2,112],26:[2,112],27:148,28:[1,73],49:[2,112],54:[2,112],57:[2,112],66:[2,112],67:[2,112],68:[2,112],70:[2,112],72:[2,112],73:[2,112],77:[2,112],83:[2,112],84:[2,112],85:[2,112],90:[2,112],92:[2,112],101:[2,112],103:[2,112],104:[2,112],105:[2,112],109:[2,112],117:[2,112],125:[2,112],127:[2,112],128:[2,112],131:[2,112],132:[2,112],133:[2,112],134:[2,112],135:[2,112],136:[2,112]},{25:[2,51]},{25:[2,52]},{1:[2,68],6:[2,68],25:[2,68],26:[2,68],40:[2,68],49:[2,68],54:[2,68],57:[2,68],66:[2,68],67:[2,68],68:[2,68],70:[2,68],72:[2,68],73:[2,68],77:[2,68],79:[2,68],83:[2,68],84:[2,68],85:[2,68],90:[2,68],92:[2,68],101:[2,68],103:[2,68],104:[2,68],105:[2,68],109:[2,68],117:[2,68],125:[2,68],127:[2,68],128:[2,68],129:[2,68],130:[2,68],131:[2,68],132:[2,68],133:[2,68],134:[2,68],135:[2,68],136:[2,68],137:[2,68]},{1:[2,71],6:[2,71],25:[2,71],26:[2,71],40:[2,71],49:[2,71],54:[2,71],57:[2,71],66:[2,71],67:[2,71],68:[2,71],70:[2,71],72:[2,71],73:[2,71],77:[2,71],79:[2,71],83:[2,71],84:[2,71],85:[2,71],90:[2,71],92:[2,71],101:[2,71],103:[2,71],104:[2,71],105:[2,71],109:[2,71],117:[2,71],125:[2,71],127:[2,71],128:[2,71],129:[2,71],130:[2,71],131:[2,71],132:[2,71],133:[2,71],134:[2,71],135:[2,71],136:[2,71],137:[2,71]},{8:149,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{8:150,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{8:151,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{5:152,8:153,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,25:[1,5],27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{27:158,28:[1,73],44:159,58:160,59:161,64:154,75:[1,70],88:[1,113],89:[1,57],112:155,113:[1,156],114:157},{111:162,115:[1,163],116:[1,164]},{6:[2,90],11:168,25:[2,90],27:169,28:[1,73],29:170,30:[1,71],31:[1,72],41:166,42:167,44:171,46:[1,46],54:[2,90],76:165,77:[2,90],88:[1,113]},{1:[2,27],6:[2,27],25:[2,27],26:[2,27],43:[2,27],49:[2,27],54:[2,27],57:[2,27],66:[2,27],67:[2,27],68:[2,27],70:[2,27],72:[2,27],73:[2,27],77:[2,27],83:[2,27],84:[2,27],85:[2,27],90:[2,27],92:[2,27],101:[2,27],103:[2,27],104:[2,27],105:[2,27],109:[2,27],117:[2,27],125:[2,27],127:[2,27],128:[2,27],131:[2,27],132:[2,27],133:[2,27],134:[2,27],135:[2,27],136:[2,27]},{1:[2,28],6:[2,28],25:[2,28],26:[2,28],43:[2,28],49:[2,28],54:[2,28],57:[2,28],66:[2,28],67:[2,28],68:[2,28],70:[2,28],72:[2,28],73:[2,28],77:[2,28],83:[2,28],84:[2,28],85:[2,28],90:[2,28],92:[2,28],101:[2,28],103:[2,28],104:[2,28],105:[2,28],109:[2,28],117:[2,28],125:[2,28],127:[2,28],128:[2,28],131:[2,28],132:[2,28],133:[2,28],134:[2,28],135:[2,28],136:[2,28]},{1:[2,26],6:[2,26],25:[2,26],26:[2,26],40:[2,26],43:[2,26],49:[2,26],54:[2,26],57:[2,26],66:[2,26],67:[2,26],68:[2,26],70:[2,26],72:[2,26],73:[2,26],77:[2,26],79:[2,26],83:[2,26],84:[2,26],85:[2,26],90:[2,26],92:[2,26],101:[2,26],103:[2,26],104:[2,26],105:[2,26],109:[2,26],115:[2,26],116:[2,26],117:[2,26],125:[2,26],127:[2,26],128:[2,26],129:[2,26],130:[2,26],131:[2,26],132:[2,26],133:[2,26],134:[2,26],135:[2,26],136:[2,26],137:[2,26]},{1:[2,6],6:[2,6],7:172,8:6,9:7,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,26:[2,6],27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],101:[2,6],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{1:[2,3]},{1:[2,24],6:[2,24],25:[2,24],26:[2,24],49:[2,24],54:[2,24],57:[2,24],72:[2,24],77:[2,24],85:[2,24],90:[2,24],92:[2,24],97:[2,24],98:[2,24],101:[2,24],103:[2,24],104:[2,24],105:[2,24],109:[2,24],117:[2,24],120:[2,24],122:[2,24],125:[2,24],127:[2,24],128:[2,24],131:[2,24],132:[2,24],133:[2,24],134:[2,24],135:[2,24],136:[2,24]},{6:[1,74],26:[1,173]},{1:[2,191],6:[2,191],25:[2,191],26:[2,191],49:[2,191],54:[2,191],57:[2,191],72:[2,191],77:[2,191],85:[2,191],90:[2,191],92:[2,191],101:[2,191],103:[2,191],104:[2,191],105:[2,191],109:[2,191],117:[2,191],125:[2,191],127:[2,191],128:[2,191],131:[2,191],132:[2,191],133:[2,191],134:[2,191],135:[2,191],136:[2,191]},{8:174,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{8:175,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{8:176,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{8:177,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{8:178,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{8:179,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{8:180,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{8:181,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{1:[2,146],6:[2,146],25:[2,146],26:[2,146],49:[2,146],54:[2,146],57:[2,146],72:[2,146],77:[2,146],85:[2,146],90:[2,146],92:[2,146],101:[2,146],103:[2,146],104:[2,146],105:[2,146],109:[2,146],117:[2,146],125:[2,146],127:[2,146],128:[2,146],131:[2,146],132:[2,146],133:[2,146],134:[2,146],135:[2,146],136:[2,146]},{1:[2,151],6:[2,151],25:[2,151],26:[2,151],49:[2,151],54:[2,151],57:[2,151],72:[2,151],77:[2,151],85:[2,151],90:[2,151],92:[2,151],101:[2,151],103:[2,151],104:[2,151],105:[2,151],109:[2,151],117:[2,151],125:[2,151],127:[2,151],128:[2,151],131:[2,151],132:[2,151],133:[2,151],134:[2,151],135:[2,151],136:[2,151]},{8:182,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{1:[2,145],6:[2,145],25:[2,145],26:[2,145],49:[2,145],54:[2,145],57:[2,145],72:[2,145],77:[2,145],85:[2,145],90:[2,145],92:[2,145],101:[2,145],103:[2,145],104:[2,145],105:[2,145],109:[2,145],117:[2,145],125:[2,145],127:[2,145],128:[2,145],131:[2,145],132:[2,145],133:[2,145],134:[2,145],135:[2,145],136:[2,145]},{1:[2,150],6:[2,150],25:[2,150],26:[2,150],49:[2,150],54:[2,150],57:[2,150],72:[2,150],77:[2,150],85:[2,150],90:[2,150],92:[2,150],101:[2,150],103:[2,150],104:[2,150],105:[2,150],109:[2,150],117:[2,150],125:[2,150],127:[2,150],128:[2,150],131:[2,150],132:[2,150],133:[2,150],134:[2,150],135:[2,150],136:[2,150]},{81:183,84:[1,105]},{1:[2,69],6:[2,69],25:[2,69],26:[2,69],40:[2,69],49:[2,69],54:[2,69],57:[2,69],66:[2,69],67:[2,69],68:[2,69],70:[2,69],72:[2,69],73:[2,69],77:[2,69],79:[2,69],83:[2,69],84:[2,69],85:[2,69],90:[2,69],92:[2,69],101:[2,69],103:[2,69],104:[2,69],105:[2,69],109:[2,69],117:[2,69],125:[2,69],127:[2,69],128:[2,69],129:[2,69],130:[2,69],131:[2,69],132:[2,69],133:[2,69],134:[2,69],135:[2,69],136:[2,69],137:[2,69]},{84:[2,108]},{27:184,28:[1,73]},{27:185,28:[1,73]},{1:[2,83],6:[2,83],25:[2,83],26:[2,83],27:186,28:[1,73],40:[2,83],49:[2,83],54:[2,83],57:[2,83],66:[2,83],67:[2,83],68:[2,83],70:[2,83],72:[2,83],73:[2,83],77:[2,83],79:[2,83],83:[2,83],84:[2,83],85:[2,83],90:[2,83],92:[2,83],101:[2,83],103:[2,83],104:[2,83],105:[2,83],109:[2,83],117:[2,83],125:[2,83],127:[2,83],128:[2,83],129:[2,83],130:[2,83],131:[2,83],132:[2,83],133:[2,83],134:[2,83],135:[2,83],136:[2,83],137:[2,83]},{1:[2,84],6:[2,84],25:[2,84],26:[2,84],40:[2,84],49:[2,84],54:[2,84],57:[2,84],66:[2,84],67:[2,84],68:[2,84],70:[2,84],72:[2,84],73:[2,84],77:[2,84],79:[2,84],83:[2,84],84:[2,84],85:[2,84],90:[2,84],92:[2,84],101:[2,84],103:[2,84],104:[2,84],105:[2,84],109:[2,84],117:[2,84],125:[2,84],127:[2,84],128:[2,84],129:[2,84],130:[2,84],131:[2,84],132:[2,84],133:[2,84],134:[2,84],135:[2,84],136:[2,84],137:[2,84]},{8:188,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],57:[1,192],58:47,59:48,61:36,63:25,64:26,65:27,71:187,74:189,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],91:190,92:[1,191],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{69:193,70:[1,99],73:[1,100]},{81:194,84:[1,105]},{1:[2,70],6:[2,70],25:[2,70],26:[2,70],40:[2,70],49:[2,70],54:[2,70],57:[2,70],66:[2,70],67:[2,70],68:[2,70],70:[2,70],72:[2,70],73:[2,70],77:[2,70],79:[2,70],83:[2,70],84:[2,70],85:[2,70],90:[2,70],92:[2,70],101:[2,70],103:[2,70],104:[2,70],105:[2,70],109:[2,70],117:[2,70],125:[2,70],127:[2,70],128:[2,70],129:[2,70],130:[2,70],131:[2,70],132:[2,70],133:[2,70],134:[2,70],135:[2,70],136:[2,70],137:[2,70]},{6:[1,196],8:195,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,25:[1,197],27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{1:[2,106],6:[2,106],25:[2,106],26:[2,106],49:[2,106],54:[2,106],57:[2,106],66:[2,106],67:[2,106],68:[2,106],70:[2,106],72:[2,106],73:[2,106],77:[2,106],83:[2,106],84:[2,106],85:[2,106],90:[2,106],92:[2,106],101:[2,106],103:[2,106],104:[2,106],105:[2,106],109:[2,106],117:[2,106],125:[2,106],127:[2,106],128:[2,106],131:[2,106],132:[2,106],133:[2,106],134:[2,106],135:[2,106],136:[2,106]},{8:200,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,25:[1,146],27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,60:147,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],85:[1,198],86:199,87:[1,58],88:[1,59],89:[1,57],93:145,95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{6:[2,53],25:[2,53],49:[1,201],53:203,54:[1,202]},{6:[2,56],25:[2,56],26:[2,56],49:[2,56],54:[2,56]},{6:[2,60],25:[2,60],26:[2,60],40:[1,205],49:[2,60],54:[2,60],57:[1,204]},{6:[2,63],25:[2,63],26:[2,63],40:[2,63],49:[2,63],54:[2,63],57:[2,63]},{6:[2,64],25:[2,64],26:[2,64],40:[2,64],49:[2,64],54:[2,64],57:[2,64]},{6:[2,65],25:[2,65],26:[2,65],40:[2,65],49:[2,65],54:[2,65],57:[2,65]},{6:[2,66],25:[2,66],26:[2,66],40:[2,66],49:[2,66],54:[2,66],57:[2,66]},{27:148,28:[1,73]},{8:200,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,25:[1,146],27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,60:147,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],86:144,87:[1,58],88:[1,59],89:[1,57],90:[1,143],93:145,95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{1:[2,50],6:[2,50],25:[2,50],26:[2,50],49:[2,50],54:[2,50],57:[2,50],72:[2,50],77:[2,50],85:[2,50],90:[2,50],92:[2,50],101:[2,50],103:[2,50],104:[2,50],105:[2,50],109:[2,50],117:[2,50],125:[2,50],127:[2,50],128:[2,50],131:[2,50],132:[2,50],133:[2,50],134:[2,50],135:[2,50],136:[2,50]},{1:[2,184],6:[2,184],25:[2,184],26:[2,184],49:[2,184],54:[2,184],57:[2,184],72:[2,184],77:[2,184],85:[2,184],90:[2,184],92:[2,184],101:[2,184],102:87,103:[2,184],104:[2,184],105:[2,184],108:88,109:[2,184],110:69,117:[2,184],125:[2,184],127:[2,184],128:[2,184],131:[1,78],132:[2,184],133:[2,184],134:[2,184],135:[2,184],136:[2,184]},{102:90,103:[1,65],105:[1,66],108:91,109:[1,68],110:69,125:[1,89]},{1:[2,185],6:[2,185],25:[2,185],26:[2,185],49:[2,185],54:[2,185],57:[2,185],72:[2,185],77:[2,185],85:[2,185],90:[2,185],92:[2,185],101:[2,185],102:87,103:[2,185],104:[2,185],105:[2,185],108:88,109:[2,185],110:69,117:[2,185],125:[2,185],127:[2,185],128:[2,185],131:[1,78],132:[2,185],133:[2,185],134:[2,185],135:[2,185],136:[2,185]},{1:[2,186],6:[2,186],25:[2,186],26:[2,186],49:[2,186],54:[2,186],57:[2,186],72:[2,186],77:[2,186],85:[2,186],90:[2,186],92:[2,186],101:[2,186],102:87,103:[2,186],104:[2,186],105:[2,186],108:88,109:[2,186],110:69,117:[2,186],125:[2,186],127:[2,186],128:[2,186],131:[1,78],132:[2,186],133:[2,186],134:[2,186],135:[2,186],136:[2,186]},{1:[2,187],6:[2,187],25:[2,187],26:[2,187],49:[2,187],54:[2,187],57:[2,187],66:[2,72],67:[2,72],68:[2,72],70:[2,72],72:[2,187],73:[2,72],77:[2,187],83:[2,72],84:[2,72],85:[2,187],90:[2,187],92:[2,187],101:[2,187],103:[2,187],104:[2,187],105:[2,187],109:[2,187],117:[2,187],125:[2,187],127:[2,187],128:[2,187],131:[2,187],132:[2,187],133:[2,187],134:[2,187],135:[2,187],136:[2,187]},{62:93,66:[1,95],67:[1,96],68:[1,97],69:98,70:[1,99],73:[1,100],80:92,83:[1,94],84:[2,107]},{62:102,66:[1,95],67:[1,96],68:[1,97],69:98,70:[1,99],73:[1,100],80:101,83:[1,94],84:[2,107]},{66:[2,75],67:[2,75],68:[2,75],70:[2,75],73:[2,75],83:[2,75],84:[2,75]},{1:[2,188],6:[2,188],25:[2,188],26:[2,188],49:[2,188],54:[2,188],57:[2,188],66:[2,72],67:[2,72],68:[2,72],70:[2,72],72:[2,188],73:[2,72],77:[2,188],83:[2,72],84:[2,72],85:[2,188],90:[2,188],92:[2,188],101:[2,188],103:[2,188],104:[2,188],105:[2,188],109:[2,188],117:[2,188],125:[2,188],127:[2,188],128:[2,188],131:[2,188],132:[2,188],133:[2,188],134:[2,188],135:[2,188],136:[2,188]},{1:[2,189],6:[2,189],25:[2,189],26:[2,189],49:[2,189],54:[2,189],57:[2,189],72:[2,189],77:[2,189],85:[2,189],90:[2,189],92:[2,189],101:[2,189],103:[2,189],104:[2,189],105:[2,189],109:[2,189],117:[2,189],125:[2,189],127:[2,189],128:[2,189],131:[2,189],132:[2,189],133:[2,189],134:[2,189],135:[2,189],136:[2,189]},{1:[2,190],6:[2,190],25:[2,190],26:[2,190],49:[2,190],54:[2,190],57:[2,190],72:[2,190],77:[2,190],85:[2,190],90:[2,190],92:[2,190],101:[2,190],103:[2,190],104:[2,190],105:[2,190],109:[2,190],117:[2,190],125:[2,190],127:[2,190],128:[2,190],131:[2,190],132:[2,190],133:[2,190],134:[2,190],135:[2,190],136:[2,190]},{8:206,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,25:[1,207],27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{8:208,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{5:209,25:[1,5],124:[1,210]},{1:[2,132],6:[2,132],25:[2,132],26:[2,132],49:[2,132],54:[2,132],57:[2,132],72:[2,132],77:[2,132],85:[2,132],90:[2,132],92:[2,132],96:211,97:[1,212],98:[1,213],101:[2,132],103:[2,132],104:[2,132],105:[2,132],109:[2,132],117:[2,132],125:[2,132],127:[2,132],128:[2,132],131:[2,132],132:[2,132],133:[2,132],134:[2,132],135:[2,132],136:[2,132]},{1:[2,144],6:[2,144],25:[2,144],26:[2,144],49:[2,144],54:[2,144],57:[2,144],72:[2,144],77:[2,144],85:[2,144],90:[2,144],92:[2,144],101:[2,144],103:[2,144],104:[2,144],105:[2,144],109:[2,144],117:[2,144],125:[2,144],127:[2,144],128:[2,144],131:[2,144],132:[2,144],133:[2,144],134:[2,144],135:[2,144],136:[2,144]},{1:[2,152],6:[2,152],25:[2,152],26:[2,152],49:[2,152],54:[2,152],57:[2,152],72:[2,152],77:[2,152],85:[2,152],90:[2,152],92:[2,152],101:[2,152],103:[2,152],104:[2,152],105:[2,152],109:[2,152],117:[2,152],125:[2,152],127:[2,152],128:[2,152],131:[2,152],132:[2,152],133:[2,152],134:[2,152],135:[2,152],136:[2,152]},{25:[1,214],102:87,103:[1,65],105:[1,66],108:88,109:[1,68],110:69,125:[1,86],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{119:215,121:216,122:[1,217]},{1:[2,96],6:[2,96],25:[2,96],26:[2,96],49:[2,96],54:[2,96],57:[2,96],72:[2,96],77:[2,96],85:[2,96],90:[2,96],92:[2,96],101:[2,96],103:[2,96],104:[2,96],105:[2,96],109:[2,96],117:[2,96],125:[2,96],127:[2,96],128:[2,96],131:[2,96],132:[2,96],133:[2,96],134:[2,96],135:[2,96],136:[2,96]},{8:218,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{1:[2,99],5:219,6:[2,99],25:[1,5],26:[2,99],49:[2,99],54:[2,99],57:[2,99],66:[2,72],67:[2,72],68:[2,72],70:[2,72],72:[2,99],73:[2,72],77:[2,99],79:[1,220],83:[2,72],84:[2,72],85:[2,99],90:[2,99],92:[2,99],101:[2,99],103:[2,99],104:[2,99],105:[2,99],109:[2,99],117:[2,99],125:[2,99],127:[2,99],128:[2,99],131:[2,99],132:[2,99],133:[2,99],134:[2,99],135:[2,99],136:[2,99]},{1:[2,137],6:[2,137],25:[2,137],26:[2,137],49:[2,137],54:[2,137],57:[2,137],72:[2,137],77:[2,137],85:[2,137],90:[2,137],92:[2,137],101:[2,137],102:87,103:[2,137],104:[2,137],105:[2,137],108:88,109:[2,137],110:69,117:[2,137],125:[2,137],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{1:[2,46],6:[2,46],26:[2,46],101:[2,46],102:87,103:[2,46],105:[2,46],108:88,109:[2,46],110:69,125:[2,46],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{6:[1,74],101:[1,221]},{4:222,7:4,8:6,9:7,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{6:[2,128],25:[2,128],54:[2,128],57:[1,224],90:[2,128],91:223,92:[1,191],102:87,103:[1,65],105:[1,66],108:88,109:[1,68],110:69,125:[1,86],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{1:[2,114],6:[2,114],25:[2,114],26:[2,114],40:[2,114],49:[2,114],54:[2,114],57:[2,114],66:[2,114],67:[2,114],68:[2,114],70:[2,114],72:[2,114],73:[2,114],77:[2,114],83:[2,114],84:[2,114],85:[2,114],90:[2,114],92:[2,114],101:[2,114],103:[2,114],104:[2,114],105:[2,114],109:[2,114],115:[2,114],116:[2,114],117:[2,114],125:[2,114],127:[2,114],128:[2,114],131:[2,114],132:[2,114],133:[2,114],134:[2,114],135:[2,114],136:[2,114]},{6:[2,53],25:[2,53],53:225,54:[1,226],90:[2,53]},{6:[2,123],25:[2,123],26:[2,123],54:[2,123],85:[2,123],90:[2,123]},{8:200,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,25:[1,146],27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,60:147,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],86:227,87:[1,58],88:[1,59],89:[1,57],93:145,95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{6:[2,129],25:[2,129],26:[2,129],54:[2,129],85:[2,129],90:[2,129]},{1:[2,113],6:[2,113],25:[2,113],26:[2,113],40:[2,113],43:[2,113],49:[2,113],54:[2,113],57:[2,113],66:[2,113],67:[2,113],68:[2,113],70:[2,113],72:[2,113],73:[2,113],77:[2,113],79:[2,113],83:[2,113],84:[2,113],85:[2,113],90:[2,113],92:[2,113],101:[2,113],103:[2,113],104:[2,113],105:[2,113],109:[2,113],115:[2,113],116:[2,113],117:[2,113],125:[2,113],127:[2,113],128:[2,113],129:[2,113],130:[2,113],131:[2,113],132:[2,113],133:[2,113],134:[2,113],135:[2,113],136:[2,113],137:[2,113]},{5:228,25:[1,5],102:87,103:[1,65],105:[1,66],108:88,109:[1,68],110:69,125:[1,86],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{1:[2,140],6:[2,140],25:[2,140],26:[2,140],49:[2,140],54:[2,140],57:[2,140],72:[2,140],77:[2,140],85:[2,140],90:[2,140],92:[2,140],101:[2,140],102:87,103:[1,65],104:[1,229],105:[1,66],108:88,109:[1,68],110:69,117:[2,140],125:[2,140],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{1:[2,142],6:[2,142],25:[2,142],26:[2,142],49:[2,142],54:[2,142],57:[2,142],72:[2,142],77:[2,142],85:[2,142],90:[2,142],92:[2,142],101:[2,142],102:87,103:[1,65],104:[1,230],105:[1,66],108:88,109:[1,68],110:69,117:[2,142],125:[2,142],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{1:[2,148],6:[2,148],25:[2,148],26:[2,148],49:[2,148],54:[2,148],57:[2,148],72:[2,148],77:[2,148],85:[2,148],90:[2,148],92:[2,148],101:[2,148],103:[2,148],104:[2,148],105:[2,148],109:[2,148],117:[2,148],125:[2,148],127:[2,148],128:[2,148],131:[2,148],132:[2,148],133:[2,148],134:[2,148],135:[2,148],136:[2,148]},{1:[2,149],6:[2,149],25:[2,149],26:[2,149],49:[2,149],54:[2,149],57:[2,149],72:[2,149],77:[2,149],85:[2,149],90:[2,149],92:[2,149],101:[2,149],102:87,103:[1,65],104:[2,149],105:[1,66],108:88,109:[1,68],110:69,117:[2,149],125:[2,149],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{1:[2,153],6:[2,153],25:[2,153],26:[2,153],49:[2,153],54:[2,153],57:[2,153],72:[2,153],77:[2,153],85:[2,153],90:[2,153],92:[2,153],101:[2,153],103:[2,153],104:[2,153],105:[2,153],109:[2,153],117:[2,153],125:[2,153],127:[2,153],128:[2,153],131:[2,153],132:[2,153],133:[2,153],134:[2,153],135:[2,153],136:[2,153]},{115:[2,155],116:[2,155]},{27:158,28:[1,73],44:159,58:160,59:161,75:[1,70],88:[1,113],89:[1,114],112:231,114:157},{54:[1,232],115:[2,161],116:[2,161]},{54:[2,157],115:[2,157],116:[2,157]},{54:[2,158],115:[2,158],116:[2,158]},{54:[2,159],115:[2,159],116:[2,159]},{54:[2,160],115:[2,160],116:[2,160]},{1:[2,154],6:[2,154],25:[2,154],26:[2,154],49:[2,154],54:[2,154],57:[2,154],72:[2,154],77:[2,154],85:[2,154],90:[2,154],92:[2,154],101:[2,154],103:[2,154],104:[2,154],105:[2,154],109:[2,154],117:[2,154],125:[2,154],127:[2,154],128:[2,154],131:[2,154],132:[2,154],133:[2,154],134:[2,154],135:[2,154],136:[2,154]},{8:233,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{8:234,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{6:[2,53],25:[2,53],53:235,54:[1,236],77:[2,53]},{6:[2,91],25:[2,91],26:[2,91],54:[2,91],77:[2,91]},{6:[2,39],25:[2,39],26:[2,39],43:[1,237],54:[2,39],77:[2,39]},{6:[2,42],25:[2,42],26:[2,42],54:[2,42],77:[2,42]},{6:[2,43],25:[2,43],26:[2,43],43:[2,43],54:[2,43],77:[2,43]},{6:[2,44],25:[2,44],26:[2,44],43:[2,44],54:[2,44],77:[2,44]},{6:[2,45],25:[2,45],26:[2,45],43:[2,45],54:[2,45],77:[2,45]},{1:[2,5],6:[2,5],26:[2,5],101:[2,5]},{1:[2,25],6:[2,25],25:[2,25],26:[2,25],49:[2,25],54:[2,25],57:[2,25],72:[2,25],77:[2,25],85:[2,25],90:[2,25],92:[2,25],97:[2,25],98:[2,25],101:[2,25],103:[2,25],104:[2,25],105:[2,25],109:[2,25],117:[2,25],120:[2,25],122:[2,25],125:[2,25],127:[2,25],128:[2,25],131:[2,25],132:[2,25],133:[2,25],134:[2,25],135:[2,25],136:[2,25]},{1:[2,192],6:[2,192],25:[2,192],26:[2,192],49:[2,192],54:[2,192],57:[2,192],72:[2,192],77:[2,192],85:[2,192],90:[2,192],92:[2,192],101:[2,192],102:87,103:[2,192],104:[2,192],105:[2,192],108:88,109:[2,192],110:69,117:[2,192],125:[2,192],127:[2,192],128:[2,192],131:[1,78],132:[1,81],133:[2,192],134:[2,192],135:[2,192],136:[2,192]},{1:[2,193],6:[2,193],25:[2,193],26:[2,193],49:[2,193],54:[2,193],57:[2,193],72:[2,193],77:[2,193],85:[2,193],90:[2,193],92:[2,193],101:[2,193],102:87,103:[2,193],104:[2,193],105:[2,193],108:88,109:[2,193],110:69,117:[2,193],125:[2,193],127:[2,193],128:[2,193],131:[1,78],132:[1,81],133:[2,193],134:[2,193],135:[2,193],136:[2,193]},{1:[2,194],6:[2,194],25:[2,194],26:[2,194],49:[2,194],54:[2,194],57:[2,194],72:[2,194],77:[2,194],85:[2,194],90:[2,194],92:[2,194],101:[2,194],102:87,103:[2,194],104:[2,194],105:[2,194],108:88,109:[2,194],110:69,117:[2,194],125:[2,194],127:[2,194],128:[2,194],131:[1,78],132:[2,194],133:[2,194],134:[2,194],135:[2,194],136:[2,194]},{1:[2,195],6:[2,195],25:[2,195],26:[2,195],49:[2,195],54:[2,195],57:[2,195],72:[2,195],77:[2,195],85:[2,195],90:[2,195],92:[2,195],101:[2,195],102:87,103:[2,195],104:[2,195],105:[2,195],108:88,109:[2,195],110:69,117:[2,195],125:[2,195],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[2,195],134:[2,195],135:[2,195],136:[2,195]},{1:[2,196],6:[2,196],25:[2,196],26:[2,196],49:[2,196],54:[2,196],57:[2,196],72:[2,196],77:[2,196],85:[2,196],90:[2,196],92:[2,196],101:[2,196],102:87,103:[2,196],104:[2,196],105:[2,196],108:88,109:[2,196],110:69,117:[2,196],125:[2,196],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[2,196],135:[2,196],136:[1,85]},{1:[2,197],6:[2,197],25:[2,197],26:[2,197],49:[2,197],54:[2,197],57:[2,197],72:[2,197],77:[2,197],85:[2,197],90:[2,197],92:[2,197],101:[2,197],102:87,103:[2,197],104:[2,197],105:[2,197],108:88,109:[2,197],110:69,117:[2,197],125:[2,197],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[2,197],136:[1,85]},{1:[2,198],6:[2,198],25:[2,198],26:[2,198],49:[2,198],54:[2,198],57:[2,198],72:[2,198],77:[2,198],85:[2,198],90:[2,198],92:[2,198],101:[2,198],102:87,103:[2,198],104:[2,198],105:[2,198],108:88,109:[2,198],110:69,117:[2,198],125:[2,198],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[2,198],135:[2,198],136:[2,198]},{1:[2,183],6:[2,183],25:[2,183],26:[2,183],49:[2,183],54:[2,183],57:[2,183],72:[2,183],77:[2,183],85:[2,183],90:[2,183],92:[2,183],101:[2,183],102:87,103:[1,65],104:[2,183],105:[1,66],108:88,109:[1,68],110:69,117:[2,183],125:[1,86],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{1:[2,182],6:[2,182],25:[2,182],26:[2,182],49:[2,182],54:[2,182],57:[2,182],72:[2,182],77:[2,182],85:[2,182],90:[2,182],92:[2,182],101:[2,182],102:87,103:[1,65],104:[2,182],105:[1,66],108:88,109:[1,68],110:69,117:[2,182],125:[1,86],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{1:[2,103],6:[2,103],25:[2,103],26:[2,103],49:[2,103],54:[2,103],57:[2,103],66:[2,103],67:[2,103],68:[2,103],70:[2,103],72:[2,103],73:[2,103],77:[2,103],83:[2,103],84:[2,103],85:[2,103],90:[2,103],92:[2,103],101:[2,103],103:[2,103],104:[2,103],105:[2,103],109:[2,103],117:[2,103],125:[2,103],127:[2,103],128:[2,103],131:[2,103],132:[2,103],133:[2,103],134:[2,103],135:[2,103],136:[2,103]},{1:[2,80],6:[2,80],25:[2,80],26:[2,80],40:[2,80],49:[2,80],54:[2,80],57:[2,80],66:[2,80],67:[2,80],68:[2,80],70:[2,80],72:[2,80],73:[2,80],77:[2,80],79:[2,80],83:[2,80],84:[2,80],85:[2,80],90:[2,80],92:[2,80],101:[2,80],103:[2,80],104:[2,80],105:[2,80],109:[2,80],117:[2,80],125:[2,80],127:[2,80],128:[2,80],129:[2,80],130:[2,80],131:[2,80],132:[2,80],133:[2,80],134:[2,80],135:[2,80],136:[2,80],137:[2,80]},{1:[2,81],6:[2,81],25:[2,81],26:[2,81],40:[2,81],49:[2,81],54:[2,81],57:[2,81],66:[2,81],67:[2,81],68:[2,81],70:[2,81],72:[2,81],73:[2,81],77:[2,81],79:[2,81],83:[2,81],84:[2,81],85:[2,81],90:[2,81],92:[2,81],101:[2,81],103:[2,81],104:[2,81],105:[2,81],109:[2,81],117:[2,81],125:[2,81],127:[2,81],128:[2,81],129:[2,81],130:[2,81],131:[2,81],132:[2,81],133:[2,81],134:[2,81],135:[2,81],136:[2,81],137:[2,81]},{1:[2,82],6:[2,82],25:[2,82],26:[2,82],40:[2,82],49:[2,82],54:[2,82],57:[2,82],66:[2,82],67:[2,82],68:[2,82],70:[2,82],72:[2,82],73:[2,82],77:[2,82],79:[2,82],83:[2,82],84:[2,82],85:[2,82],90:[2,82],92:[2,82],101:[2,82],103:[2,82],104:[2,82],105:[2,82],109:[2,82],117:[2,82],125:[2,82],127:[2,82],128:[2,82],129:[2,82],130:[2,82],131:[2,82],132:[2,82],133:[2,82],134:[2,82],135:[2,82],136:[2,82],137:[2,82]},{72:[1,238]},{57:[1,192],72:[2,87],91:239,92:[1,191],102:87,103:[1,65],105:[1,66],108:88,109:[1,68],110:69,125:[1,86],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{72:[2,88]},{8:240,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,72:[2,122],75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{12:[2,116],28:[2,116],30:[2,116],31:[2,116],33:[2,116],34:[2,116],35:[2,116],36:[2,116],37:[2,116],38:[2,116],45:[2,116],46:[2,116],47:[2,116],51:[2,116],52:[2,116],72:[2,116],75:[2,116],78:[2,116],82:[2,116],87:[2,116],88:[2,116],89:[2,116],95:[2,116],99:[2,116],100:[2,116],103:[2,116],105:[2,116],107:[2,116],109:[2,116],118:[2,116],124:[2,116],126:[2,116],127:[2,116],128:[2,116],129:[2,116],130:[2,116]},{12:[2,117],28:[2,117],30:[2,117],31:[2,117],33:[2,117],34:[2,117],35:[2,117],36:[2,117],37:[2,117],38:[2,117],45:[2,117],46:[2,117],47:[2,117],51:[2,117],52:[2,117],72:[2,117],75:[2,117],78:[2,117],82:[2,117],87:[2,117],88:[2,117],89:[2,117],95:[2,117],99:[2,117],100:[2,117],103:[2,117],105:[2,117],107:[2,117],109:[2,117],118:[2,117],124:[2,117],126:[2,117],127:[2,117],128:[2,117],129:[2,117],130:[2,117]},{1:[2,86],6:[2,86],25:[2,86],26:[2,86],40:[2,86],49:[2,86],54:[2,86],57:[2,86],66:[2,86],67:[2,86],68:[2,86],70:[2,86],72:[2,86],73:[2,86],77:[2,86],79:[2,86],83:[2,86],84:[2,86],85:[2,86],90:[2,86],92:[2,86],101:[2,86],103:[2,86],104:[2,86],105:[2,86],109:[2,86],117:[2,86],125:[2,86],127:[2,86],128:[2,86],129:[2,86],130:[2,86],131:[2,86],132:[2,86],133:[2,86],134:[2,86],135:[2,86],136:[2,86],137:[2,86]},{1:[2,104],6:[2,104],25:[2,104],26:[2,104],49:[2,104],54:[2,104],57:[2,104],66:[2,104],67:[2,104],68:[2,104],70:[2,104],72:[2,104],73:[2,104],77:[2,104],83:[2,104],84:[2,104],85:[2,104],90:[2,104],92:[2,104],101:[2,104],103:[2,104],104:[2,104],105:[2,104],109:[2,104],117:[2,104],125:[2,104],127:[2,104],128:[2,104],131:[2,104],132:[2,104],133:[2,104],134:[2,104],135:[2,104],136:[2,104]},{1:[2,36],6:[2,36],25:[2,36],26:[2,36],49:[2,36],54:[2,36],57:[2,36],72:[2,36],77:[2,36],85:[2,36],90:[2,36],92:[2,36],101:[2,36],102:87,103:[2,36],104:[2,36],105:[2,36],108:88,109:[2,36],110:69,117:[2,36],125:[2,36],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{8:241,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{8:242,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{1:[2,109],6:[2,109],25:[2,109],26:[2,109],49:[2,109],54:[2,109],57:[2,109],66:[2,109],67:[2,109],68:[2,109],70:[2,109],72:[2,109],73:[2,109],77:[2,109],83:[2,109],84:[2,109],85:[2,109],90:[2,109],92:[2,109],101:[2,109],103:[2,109],104:[2,109],105:[2,109],109:[2,109],117:[2,109],125:[2,109],127:[2,109],128:[2,109],131:[2,109],132:[2,109],133:[2,109],134:[2,109],135:[2,109],136:[2,109]},{6:[2,53],25:[2,53],53:243,54:[1,226],85:[2,53]},{6:[2,128],25:[2,128],26:[2,128],54:[2,128],57:[1,244],85:[2,128],90:[2,128],102:87,103:[1,65],105:[1,66],108:88,109:[1,68],110:69,125:[1,86],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{50:245,51:[1,60],52:[1,61]},{6:[2,54],25:[2,54],26:[2,54],27:109,28:[1,73],44:110,55:246,56:108,58:111,59:112,75:[1,70],88:[1,113],89:[1,114]},{6:[1,247],25:[1,248]},{6:[2,61],25:[2,61],26:[2,61],49:[2,61],54:[2,61]},{8:249,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{1:[2,199],6:[2,199],25:[2,199],26:[2,199],49:[2,199],54:[2,199],57:[2,199],72:[2,199],77:[2,199],85:[2,199],90:[2,199],92:[2,199],101:[2,199],102:87,103:[2,199],104:[2,199],105:[2,199],108:88,109:[2,199],110:69,117:[2,199],125:[2,199],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{8:250,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{1:[2,201],6:[2,201],25:[2,201],26:[2,201],49:[2,201],54:[2,201],57:[2,201],72:[2,201],77:[2,201],85:[2,201],90:[2,201],92:[2,201],101:[2,201],102:87,103:[2,201],104:[2,201],105:[2,201],108:88,109:[2,201],110:69,117:[2,201],125:[2,201],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{1:[2,181],6:[2,181],25:[2,181],26:[2,181],49:[2,181],54:[2,181],57:[2,181],72:[2,181],77:[2,181],85:[2,181],90:[2,181],92:[2,181],101:[2,181],103:[2,181],104:[2,181],105:[2,181],109:[2,181],117:[2,181],125:[2,181],127:[2,181],128:[2,181],131:[2,181],132:[2,181],133:[2,181],134:[2,181],135:[2,181],136:[2,181]},{8:251,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{1:[2,133],6:[2,133],25:[2,133],26:[2,133],49:[2,133],54:[2,133],57:[2,133],72:[2,133],77:[2,133],85:[2,133],90:[2,133],92:[2,133],97:[1,252],101:[2,133],103:[2,133],104:[2,133],105:[2,133],109:[2,133],117:[2,133],125:[2,133],127:[2,133],128:[2,133],131:[2,133],132:[2,133],133:[2,133],134:[2,133],135:[2,133],136:[2,133]},{5:253,25:[1,5]},{27:254,28:[1,73]},{119:255,121:216,122:[1,217]},{26:[1,256],120:[1,257],121:258,122:[1,217]},{26:[2,174],120:[2,174],122:[2,174]},{8:260,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],94:259,95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{1:[2,97],5:261,6:[2,97],25:[1,5],26:[2,97],49:[2,97],54:[2,97],57:[2,97],72:[2,97],77:[2,97],85:[2,97],90:[2,97],92:[2,97],101:[2,97],102:87,103:[1,65],104:[2,97],105:[1,66],108:88,109:[1,68],110:69,117:[2,97],125:[2,97],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{1:[2,100],6:[2,100],25:[2,100],26:[2,100],49:[2,100],54:[2,100],57:[2,100],72:[2,100],77:[2,100],85:[2,100],90:[2,100],92:[2,100],101:[2,100],103:[2,100],104:[2,100],105:[2,100],109:[2,100],117:[2,100],125:[2,100],127:[2,100],128:[2,100],131:[2,100],132:[2,100],133:[2,100],134:[2,100],135:[2,100],136:[2,100]},{8:262,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{1:[2,138],6:[2,138],25:[2,138],26:[2,138],49:[2,138],54:[2,138],57:[2,138],66:[2,138],67:[2,138],68:[2,138],70:[2,138],72:[2,138],73:[2,138],77:[2,138],83:[2,138],84:[2,138],85:[2,138],90:[2,138],92:[2,138],101:[2,138],103:[2,138],104:[2,138],105:[2,138],109:[2,138],117:[2,138],125:[2,138],127:[2,138],128:[2,138],131:[2,138],132:[2,138],133:[2,138],134:[2,138],135:[2,138],136:[2,138]},{6:[1,74],26:[1,263]},{8:264,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{6:[2,67],12:[2,117],25:[2,67],28:[2,117],30:[2,117],31:[2,117],33:[2,117],34:[2,117],35:[2,117],36:[2,117],37:[2,117],38:[2,117],45:[2,117],46:[2,117],47:[2,117],51:[2,117],52:[2,117],54:[2,67],75:[2,117],78:[2,117],82:[2,117],87:[2,117],88:[2,117],89:[2,117],90:[2,67],95:[2,117],99:[2,117],100:[2,117],103:[2,117],105:[2,117],107:[2,117],109:[2,117],118:[2,117],124:[2,117],126:[2,117],127:[2,117],128:[2,117],129:[2,117],130:[2,117]},{6:[1,266],25:[1,267],90:[1,265]},{6:[2,54],8:200,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,25:[2,54],26:[2,54],27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,60:147,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],85:[2,54],87:[1,58],88:[1,59],89:[1,57],90:[2,54],93:268,95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{6:[2,53],25:[2,53],26:[2,53],53:269,54:[1,226]},{1:[2,178],6:[2,178],25:[2,178],26:[2,178],49:[2,178],54:[2,178],57:[2,178],72:[2,178],77:[2,178],85:[2,178],90:[2,178],92:[2,178],101:[2,178],103:[2,178],104:[2,178],105:[2,178],109:[2,178],117:[2,178],120:[2,178],125:[2,178],127:[2,178],128:[2,178],131:[2,178],132:[2,178],133:[2,178],134:[2,178],135:[2,178],136:[2,178]},{8:270,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{8:271,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{115:[2,156],116:[2,156]},{27:158,28:[1,73],44:159,58:160,59:161,75:[1,70],88:[1,113],89:[1,114],114:272},{1:[2,163],6:[2,163],25:[2,163],26:[2,163],49:[2,163],54:[2,163],57:[2,163],72:[2,163],77:[2,163],85:[2,163],90:[2,163],92:[2,163],101:[2,163],102:87,103:[2,163],104:[1,273],105:[2,163],108:88,109:[2,163],110:69,117:[1,274],125:[2,163],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{1:[2,164],6:[2,164],25:[2,164],26:[2,164],49:[2,164],54:[2,164],57:[2,164],72:[2,164],77:[2,164],85:[2,164],90:[2,164],92:[2,164],101:[2,164],102:87,103:[2,164],104:[1,275],105:[2,164],108:88,109:[2,164],110:69,117:[2,164],125:[2,164],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{6:[1,277],25:[1,278],77:[1,276]},{6:[2,54],11:168,25:[2,54],26:[2,54],27:169,28:[1,73],29:170,30:[1,71],31:[1,72],41:279,42:167,44:171,46:[1,46],77:[2,54],88:[1,113]},{8:280,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,25:[1,281],27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{1:[2,85],6:[2,85],25:[2,85],26:[2,85],40:[2,85],49:[2,85],54:[2,85],57:[2,85],66:[2,85],67:[2,85],68:[2,85],70:[2,85],72:[2,85],73:[2,85],77:[2,85],79:[2,85],83:[2,85],84:[2,85],85:[2,85],90:[2,85],92:[2,85],101:[2,85],103:[2,85],104:[2,85],105:[2,85],109:[2,85],117:[2,85],125:[2,85],127:[2,85],128:[2,85],129:[2,85],130:[2,85],131:[2,85],132:[2,85],133:[2,85],134:[2,85],135:[2,85],136:[2,85],137:[2,85]},{8:282,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,72:[2,120],75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{72:[2,121],102:87,103:[1,65],105:[1,66],108:88,109:[1,68],110:69,125:[1,86],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{1:[2,37],6:[2,37],25:[2,37],26:[2,37],49:[2,37],54:[2,37],57:[2,37],72:[2,37],77:[2,37],85:[2,37],90:[2,37],92:[2,37],101:[2,37],102:87,103:[2,37],104:[2,37],105:[2,37],108:88,109:[2,37],110:69,117:[2,37],125:[2,37],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{26:[1,283],102:87,103:[1,65],105:[1,66],108:88,109:[1,68],110:69,125:[1,86],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{6:[1,266],25:[1,267],85:[1,284]},{6:[2,67],25:[2,67],26:[2,67],54:[2,67],85:[2,67],90:[2,67]},{5:285,25:[1,5]},{6:[2,57],25:[2,57],26:[2,57],49:[2,57],54:[2,57]},{27:109,28:[1,73],44:110,55:286,56:108,58:111,59:112,75:[1,70],88:[1,113],89:[1,114]},{6:[2,55],25:[2,55],26:[2,55],27:109,28:[1,73],44:110,48:287,54:[2,55],55:107,56:108,58:111,59:112,75:[1,70],88:[1,113],89:[1,114]},{6:[2,62],25:[2,62],26:[2,62],49:[2,62],54:[2,62],102:87,103:[1,65],105:[1,66],108:88,109:[1,68],110:69,125:[1,86],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{26:[1,288],102:87,103:[1,65],105:[1,66],108:88,109:[1,68],110:69,125:[1,86],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{5:289,25:[1,5],102:87,103:[1,65],105:[1,66],108:88,109:[1,68],110:69,125:[1,86],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{5:290,25:[1,5]},{1:[2,134],6:[2,134],25:[2,134],26:[2,134],49:[2,134],54:[2,134],57:[2,134],72:[2,134],77:[2,134],85:[2,134],90:[2,134],92:[2,134],101:[2,134],103:[2,134],104:[2,134],105:[2,134],109:[2,134],117:[2,134],125:[2,134],127:[2,134],128:[2,134],131:[2,134],132:[2,134],133:[2,134],134:[2,134],135:[2,134],136:[2,134]},{5:291,25:[1,5]},{26:[1,292],120:[1,293],121:258,122:[1,217]},{1:[2,172],6:[2,172],25:[2,172],26:[2,172],49:[2,172],54:[2,172],57:[2,172],72:[2,172],77:[2,172],85:[2,172],90:[2,172],92:[2,172],101:[2,172],103:[2,172],104:[2,172],105:[2,172],109:[2,172],117:[2,172],125:[2,172],127:[2,172],128:[2,172],131:[2,172],132:[2,172],133:[2,172],134:[2,172],135:[2,172],136:[2,172]},{5:294,25:[1,5]},{26:[2,175],120:[2,175],122:[2,175]},{5:295,25:[1,5],54:[1,296]},{25:[2,130],54:[2,130],102:87,103:[1,65],105:[1,66],108:88,109:[1,68],110:69,125:[1,86],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{1:[2,98],6:[2,98],25:[2,98],26:[2,98],49:[2,98],54:[2,98],57:[2,98],72:[2,98],77:[2,98],85:[2,98],90:[2,98],92:[2,98],101:[2,98],103:[2,98],104:[2,98],105:[2,98],109:[2,98],117:[2,98],125:[2,98],127:[2,98],128:[2,98],131:[2,98],132:[2,98],133:[2,98],134:[2,98],135:[2,98],136:[2,98]},{1:[2,101],5:297,6:[2,101],25:[1,5],26:[2,101],49:[2,101],54:[2,101],57:[2,101],72:[2,101],77:[2,101],85:[2,101],90:[2,101],92:[2,101],101:[2,101],102:87,103:[1,65],104:[2,101],105:[1,66],108:88,109:[1,68],110:69,117:[2,101],125:[2,101],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{101:[1,298]},{90:[1,299],102:87,103:[1,65],105:[1,66],108:88,109:[1,68],110:69,125:[1,86],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{1:[2,115],6:[2,115],25:[2,115],26:[2,115],40:[2,115],49:[2,115],54:[2,115],57:[2,115],66:[2,115],67:[2,115],68:[2,115],70:[2,115],72:[2,115],73:[2,115],77:[2,115],83:[2,115],84:[2,115],85:[2,115],90:[2,115],92:[2,115],101:[2,115],103:[2,115],104:[2,115],105:[2,115],109:[2,115],115:[2,115],116:[2,115],117:[2,115],125:[2,115],127:[2,115],128:[2,115],131:[2,115],132:[2,115],133:[2,115],134:[2,115],135:[2,115],136:[2,115]},{8:200,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,60:147,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],93:300,95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{8:200,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,25:[1,146],27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,60:147,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],86:301,87:[1,58],88:[1,59],89:[1,57],93:145,95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{6:[2,124],25:[2,124],26:[2,124],54:[2,124],85:[2,124],90:[2,124]},{6:[1,266],25:[1,267],26:[1,302]},{1:[2,141],6:[2,141],25:[2,141],26:[2,141],49:[2,141],54:[2,141],57:[2,141],72:[2,141],77:[2,141],85:[2,141],90:[2,141],92:[2,141],101:[2,141],102:87,103:[1,65],104:[2,141],105:[1,66],108:88,109:[1,68],110:69,117:[2,141],125:[2,141],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{1:[2,143],6:[2,143],25:[2,143],26:[2,143],49:[2,143],54:[2,143],57:[2,143],72:[2,143],77:[2,143],85:[2,143],90:[2,143],92:[2,143],101:[2,143],102:87,103:[1,65],104:[2,143],105:[1,66],108:88,109:[1,68],110:69,117:[2,143],125:[2,143],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{115:[2,162],116:[2,162]},{8:303,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{8:304,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{8:305,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{1:[2,89],6:[2,89],25:[2,89],26:[2,89],40:[2,89],49:[2,89],54:[2,89],57:[2,89],66:[2,89],67:[2,89],68:[2,89],70:[2,89],72:[2,89],73:[2,89],77:[2,89],83:[2,89],84:[2,89],85:[2,89],90:[2,89],92:[2,89],101:[2,89],103:[2,89],104:[2,89],105:[2,89],109:[2,89],115:[2,89],116:[2,89],117:[2,89],125:[2,89],127:[2,89],128:[2,89],131:[2,89],132:[2,89],133:[2,89],134:[2,89],135:[2,89],136:[2,89]},{11:168,27:169,28:[1,73],29:170,30:[1,71],31:[1,72],41:306,42:167,44:171,46:[1,46],88:[1,113]},{6:[2,90],11:168,25:[2,90],26:[2,90],27:169,28:[1,73],29:170,30:[1,71],31:[1,72],41:166,42:167,44:171,46:[1,46],54:[2,90],76:307,88:[1,113]},{6:[2,92],25:[2,92],26:[2,92],54:[2,92],77:[2,92]},{6:[2,40],25:[2,40],26:[2,40],54:[2,40],77:[2,40],102:87,103:[1,65],105:[1,66],108:88,109:[1,68],110:69,125:[1,86],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{8:308,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{72:[2,119],102:87,103:[1,65],105:[1,66],108:88,109:[1,68],110:69,125:[1,86],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{1:[2,38],6:[2,38],25:[2,38],26:[2,38],49:[2,38],54:[2,38],57:[2,38],72:[2,38],77:[2,38],85:[2,38],90:[2,38],92:[2,38],101:[2,38],103:[2,38],104:[2,38],105:[2,38],109:[2,38],117:[2,38],125:[2,38],127:[2,38],128:[2,38],131:[2,38],132:[2,38],133:[2,38],134:[2,38],135:[2,38],136:[2,38]},{1:[2,110],6:[2,110],25:[2,110],26:[2,110],49:[2,110],54:[2,110],57:[2,110],66:[2,110],67:[2,110],68:[2,110],70:[2,110],72:[2,110],73:[2,110],77:[2,110],83:[2,110],84:[2,110],85:[2,110],90:[2,110],92:[2,110],101:[2,110],103:[2,110],104:[2,110],105:[2,110],109:[2,110],117:[2,110],125:[2,110],127:[2,110],128:[2,110],131:[2,110],132:[2,110],133:[2,110],134:[2,110],135:[2,110],136:[2,110]},{1:[2,49],6:[2,49],25:[2,49],26:[2,49],49:[2,49],54:[2,49],57:[2,49],72:[2,49],77:[2,49],85:[2,49],90:[2,49],92:[2,49],101:[2,49],103:[2,49],104:[2,49],105:[2,49],109:[2,49],117:[2,49],125:[2,49],127:[2,49],128:[2,49],131:[2,49],132:[2,49],133:[2,49],134:[2,49],135:[2,49],136:[2,49]},{6:[2,58],25:[2,58],26:[2,58],49:[2,58],54:[2,58]},{6:[2,53],25:[2,53],26:[2,53],53:309,54:[1,202]},{1:[2,200],6:[2,200],25:[2,200],26:[2,200],49:[2,200],54:[2,200],57:[2,200],72:[2,200],77:[2,200],85:[2,200],90:[2,200],92:[2,200],101:[2,200],103:[2,200],104:[2,200],105:[2,200],109:[2,200],117:[2,200],125:[2,200],127:[2,200],128:[2,200],131:[2,200],132:[2,200],133:[2,200],134:[2,200],135:[2,200],136:[2,200]},{1:[2,179],6:[2,179],25:[2,179],26:[2,179],49:[2,179],54:[2,179],57:[2,179],72:[2,179],77:[2,179],85:[2,179],90:[2,179],92:[2,179],101:[2,179],103:[2,179],104:[2,179],105:[2,179],109:[2,179],117:[2,179],120:[2,179],125:[2,179],127:[2,179],128:[2,179],131:[2,179],132:[2,179],133:[2,179],134:[2,179],135:[2,179],136:[2,179]},{1:[2,135],6:[2,135],25:[2,135],26:[2,135],49:[2,135],54:[2,135],57:[2,135],72:[2,135],77:[2,135],85:[2,135],90:[2,135],92:[2,135],101:[2,135],103:[2,135],104:[2,135],105:[2,135],109:[2,135],117:[2,135],125:[2,135],127:[2,135],128:[2,135],131:[2,135],132:[2,135],133:[2,135],134:[2,135],135:[2,135],136:[2,135]},{1:[2,136],6:[2,136],25:[2,136],26:[2,136],49:[2,136],54:[2,136],57:[2,136],72:[2,136],77:[2,136],85:[2,136],90:[2,136],92:[2,136],97:[2,136],101:[2,136],103:[2,136],104:[2,136],105:[2,136],109:[2,136],117:[2,136],125:[2,136],127:[2,136],128:[2,136],131:[2,136],132:[2,136],133:[2,136],134:[2,136],135:[2,136],136:[2,136]},{1:[2,170],6:[2,170],25:[2,170],26:[2,170],49:[2,170],54:[2,170],57:[2,170],72:[2,170],77:[2,170],85:[2,170],90:[2,170],92:[2,170],101:[2,170],103:[2,170],104:[2,170],105:[2,170],109:[2,170],117:[2,170],125:[2,170],127:[2,170],128:[2,170],131:[2,170],132:[2,170],133:[2,170],134:[2,170],135:[2,170],136:[2,170]},{5:310,25:[1,5]},{26:[1,311]},{6:[1,312],26:[2,176],120:[2,176],122:[2,176]},{8:313,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{1:[2,102],6:[2,102],25:[2,102],26:[2,102],49:[2,102],54:[2,102],57:[2,102],72:[2,102],77:[2,102],85:[2,102],90:[2,102],92:[2,102],101:[2,102],103:[2,102],104:[2,102],105:[2,102],109:[2,102],117:[2,102],125:[2,102],127:[2,102],128:[2,102],131:[2,102],132:[2,102],133:[2,102],134:[2,102],135:[2,102],136:[2,102]},{1:[2,139],6:[2,139],25:[2,139],26:[2,139],49:[2,139],54:[2,139],57:[2,139],66:[2,139],67:[2,139],68:[2,139],70:[2,139],72:[2,139],73:[2,139],77:[2,139],83:[2,139],84:[2,139],85:[2,139],90:[2,139],92:[2,139],101:[2,139],103:[2,139],104:[2,139],105:[2,139],109:[2,139],117:[2,139],125:[2,139],127:[2,139],128:[2,139],131:[2,139],132:[2,139],133:[2,139],134:[2,139],135:[2,139],136:[2,139]},{1:[2,118],6:[2,118],25:[2,118],26:[2,118],49:[2,118],54:[2,118],57:[2,118],66:[2,118],67:[2,118],68:[2,118],70:[2,118],72:[2,118],73:[2,118],77:[2,118],83:[2,118],84:[2,118],85:[2,118],90:[2,118],92:[2,118],101:[2,118],103:[2,118],104:[2,118],105:[2,118],109:[2,118],117:[2,118],125:[2,118],127:[2,118],128:[2,118],131:[2,118],132:[2,118],133:[2,118],134:[2,118],135:[2,118],136:[2,118]},{6:[2,125],25:[2,125],26:[2,125],54:[2,125],85:[2,125],90:[2,125]},{6:[2,53],25:[2,53],26:[2,53],53:314,54:[1,226]},{6:[2,126],25:[2,126],26:[2,126],54:[2,126],85:[2,126],90:[2,126]},{1:[2,165],6:[2,165],25:[2,165],26:[2,165],49:[2,165],54:[2,165],57:[2,165],72:[2,165],77:[2,165],85:[2,165],90:[2,165],92:[2,165],101:[2,165],102:87,103:[2,165],104:[2,165],105:[2,165],108:88,109:[2,165],110:69,117:[1,315],125:[2,165],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{1:[2,167],6:[2,167],25:[2,167],26:[2,167],49:[2,167],54:[2,167],57:[2,167],72:[2,167],77:[2,167],85:[2,167],90:[2,167],92:[2,167],101:[2,167],102:87,103:[2,167],104:[1,316],105:[2,167],108:88,109:[2,167],110:69,117:[2,167],125:[2,167],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{1:[2,166],6:[2,166],25:[2,166],26:[2,166],49:[2,166],54:[2,166],57:[2,166],72:[2,166],77:[2,166],85:[2,166],90:[2,166],92:[2,166],101:[2,166],102:87,103:[2,166],104:[2,166],105:[2,166],108:88,109:[2,166],110:69,117:[2,166],125:[2,166],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{6:[2,93],25:[2,93],26:[2,93],54:[2,93],77:[2,93]},{6:[2,53],25:[2,53],26:[2,53],53:317,54:[1,236]},{26:[1,318],102:87,103:[1,65],105:[1,66],108:88,109:[1,68],110:69,125:[1,86],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{6:[1,247],25:[1,248],26:[1,319]},{26:[1,320]},{1:[2,173],6:[2,173],25:[2,173],26:[2,173],49:[2,173],54:[2,173],57:[2,173],72:[2,173],77:[2,173],85:[2,173],90:[2,173],92:[2,173],101:[2,173],103:[2,173],104:[2,173],105:[2,173],109:[2,173],117:[2,173],125:[2,173],127:[2,173],128:[2,173],131:[2,173],132:[2,173],133:[2,173],134:[2,173],135:[2,173],136:[2,173]},{26:[2,177],120:[2,177],122:[2,177]},{25:[2,131],54:[2,131],102:87,103:[1,65],105:[1,66],108:88,109:[1,68],110:69,125:[1,86],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{6:[1,266],25:[1,267],26:[1,321]},{8:322,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{8:323,9:117,10:20,11:21,12:[1,22],13:8,14:9,15:10,16:11,17:12,18:13,19:14,20:15,21:16,22:17,23:18,24:19,27:62,28:[1,73],29:49,30:[1,71],31:[1,72],32:24,33:[1,50],34:[1,51],35:[1,52],36:[1,53],37:[1,54],38:[1,55],39:23,44:63,45:[1,45],46:[1,46],47:[1,29],50:30,51:[1,60],52:[1,61],58:47,59:48,61:36,63:25,64:26,65:27,75:[1,70],78:[1,43],82:[1,28],87:[1,58],88:[1,59],89:[1,57],95:[1,38],99:[1,44],100:[1,56],102:39,103:[1,65],105:[1,66],106:40,107:[1,67],108:41,109:[1,68],110:69,118:[1,42],123:37,124:[1,64],126:[1,31],127:[1,32],128:[1,33],129:[1,34],130:[1,35]},{6:[1,277],25:[1,278],26:[1,324]},{6:[2,41],25:[2,41],26:[2,41],54:[2,41],77:[2,41]},{6:[2,59],25:[2,59],26:[2,59],49:[2,59],54:[2,59]},{1:[2,171],6:[2,171],25:[2,171],26:[2,171],49:[2,171],54:[2,171],57:[2,171],72:[2,171],77:[2,171],85:[2,171],90:[2,171],92:[2,171],101:[2,171],103:[2,171],104:[2,171],105:[2,171],109:[2,171],117:[2,171],125:[2,171],127:[2,171],128:[2,171],131:[2,171],132:[2,171],133:[2,171],134:[2,171],135:[2,171],136:[2,171]},{6:[2,127],25:[2,127],26:[2,127],54:[2,127],85:[2,127],90:[2,127]},{1:[2,168],6:[2,168],25:[2,168],26:[2,168],49:[2,168],54:[2,168],57:[2,168],72:[2,168],77:[2,168],85:[2,168],90:[2,168],92:[2,168],101:[2,168],102:87,103:[2,168],104:[2,168],105:[2,168],108:88,109:[2,168],110:69,117:[2,168],125:[2,168],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{1:[2,169],6:[2,169],25:[2,169],26:[2,169],49:[2,169],54:[2,169],57:[2,169],72:[2,169],77:[2,169],85:[2,169],90:[2,169],92:[2,169],101:[2,169],102:87,103:[2,169],104:[2,169],105:[2,169],108:88,109:[2,169],110:69,117:[2,169],125:[2,169],127:[1,80],128:[1,79],131:[1,78],132:[1,81],133:[1,82],134:[1,83],135:[1,84],136:[1,85]},{6:[2,94],25:[2,94],26:[2,94],54:[2,94],77:[2,94]}], defaultActions: {60:[2,51],61:[2,52],75:[2,3],94:[2,108],189:[2,88]}, parseError: function parseError(str, hash) { throw new Error(str); }, parse: function parse(input) { var self = this, stack = [0], vstack = [null], // semantic value stack lstack = [], // location stack table = this.table, yytext = '', yylineno = 0, yyleng = 0, recovering = 0, TERROR = 2, EOF = 1; //this.reductionCount = this.shiftCount = 0; this.lexer.setInput(input); this.lexer.yy = this.yy; this.yy.lexer = this.lexer; if (typeof this.lexer.yylloc == 'undefined') this.lexer.yylloc = {}; var yyloc = this.lexer.yylloc; lstack.push(yyloc); if (typeof this.yy.parseError === 'function') this.parseError = this.yy.parseError; function popStack (n) { stack.length = stack.length - 2*n; vstack.length = vstack.length - n; lstack.length = lstack.length - n; } function lex() { var token; token = self.lexer.lex() || 1; // $end = 1 // if token isn't its numeric value, convert if (typeof token !== 'number') { token = self.symbols_[token] || token; } return token; } var symbol, preErrorSymbol, state, action, a, r, yyval={},p,len,newState, expected; while (true) { // retreive state number from top of stack state = stack[stack.length-1]; // use default actions if available if (this.defaultActions[state]) { action = this.defaultActions[state]; } else { if (symbol == null) symbol = lex(); // read action for current state and first input action = table[state] && table[state][symbol]; } // handle parse error _handle_error: if (typeof action === 'undefined' || !action.length || !action[0]) { if (!recovering) { // Report error expected = []; for (p in table[state]) if (this.terminals_[p] && p > 2) { expected.push("'"+this.terminals_[p]+"'"); } var errStr = ''; if (this.lexer.showPosition) { errStr = 'Parse error on line '+(yylineno+1)+":\n"+this.lexer.showPosition()+"\nExpecting "+expected.join(', ') + ", got '" + this.terminals_[symbol]+ "'"; } else { errStr = 'Parse error on line '+(yylineno+1)+": Unexpected " + (symbol == 1 /*EOF*/ ? "end of input" : ("'"+(this.terminals_[symbol] || symbol)+"'")); } this.parseError(errStr, {text: this.lexer.match, token: this.terminals_[symbol] || symbol, line: this.lexer.yylineno, loc: yyloc, expected: expected}); } // just recovered from another error if (recovering == 3) { if (symbol == EOF) { throw new Error(errStr || 'Parsing halted.'); } // discard current lookahead and grab another yyleng = this.lexer.yyleng; yytext = this.lexer.yytext; yylineno = this.lexer.yylineno; yyloc = this.lexer.yylloc; symbol = lex(); } // try to recover from error while (1) { // check for error recovery rule in this state if ((TERROR.toString()) in table[state]) { break; } if (state == 0) { throw new Error(errStr || 'Parsing halted.'); } popStack(1); state = stack[stack.length-1]; } preErrorSymbol = symbol; // save the lookahead token symbol = TERROR; // insert generic error symbol as new lookahead state = stack[stack.length-1]; action = table[state] && table[state][TERROR]; recovering = 3; // allow 3 real symbols to be shifted before reporting a new error } // this shouldn't happen, unless resolve defaults are off if (action[0] instanceof Array && action.length > 1) { throw new Error('Parse Error: multiple actions possible at state: '+state+', token: '+symbol); } switch (action[0]) { case 1: // shift //this.shiftCount++; stack.push(symbol); vstack.push(this.lexer.yytext); lstack.push(this.lexer.yylloc); stack.push(action[1]); // push state symbol = null; if (!preErrorSymbol) { // normal execution/no error yyleng = this.lexer.yyleng; yytext = this.lexer.yytext; yylineno = this.lexer.yylineno; yyloc = this.lexer.yylloc; if (recovering > 0) recovering--; } else { // error just occurred, resume old lookahead f/ before error symbol = preErrorSymbol; preErrorSymbol = null; } break; case 2: // reduce //this.reductionCount++; len = this.productions_[action[1]][1]; // perform semantic action yyval.$ = vstack[vstack.length-len]; // default to $$ = $1 // default location, uses first token for firsts, last for lasts yyval._$ = { first_line: lstack[lstack.length-(len||1)].first_line, last_line: lstack[lstack.length-1].last_line, first_column: lstack[lstack.length-(len||1)].first_column, last_column: lstack[lstack.length-1].last_column }; r = this.performAction.call(yyval, yytext, yyleng, yylineno, this.yy, action[1], vstack, lstack); if (typeof r !== 'undefined') { return r; } // pop off stack if (len) { stack = stack.slice(0,-1*len*2); vstack = vstack.slice(0, -1*len); lstack = lstack.slice(0, -1*len); } stack.push(this.productions_[action[1]][0]); // push nonterminal (reduce) vstack.push(yyval.$); lstack.push(yyval._$); // goto new state = table[STATE][NONTERMINAL] newState = table[stack[stack.length-2]][stack[stack.length-1]]; stack.push(newState); break; case 3: // accept return true; } } return true; }}; undefined return parser; })(); if (typeof require !== 'undefined' && typeof exports !== 'undefined') { exports.parser = parser; exports.parse = function () { return parser.parse.apply(parser, arguments); } exports.main = function commonjsMain(args) { if (!args[1]) throw new Error('Usage: '+args[0]+' FILE'); if (typeof process !== 'undefined') { var source = require('fs').readFileSync(require('path').join(process.cwd(), args[1]), "utf8"); } else { var cwd = require("file").path(require("file").cwd()); var source = cwd.join(args[1]).read({charset: "utf-8"}); } return exports.parser.parse(source); } if (typeof module !== 'undefined' && require.main === module) { exports.main(typeof process !== 'undefined' ? process.argv.slice(1) : require("system").args); } }coffee-script-1.4.0/lib/coffee-script/repl.js000066400000000000000000000165461204160075300210560ustar00rootroot00000000000000// Generated by CoffeeScript 1.4.0 (function() { var ACCESSOR, CoffeeScript, Module, REPL_PROMPT, REPL_PROMPT_CONTINUATION, REPL_PROMPT_MULTILINE, SIMPLEVAR, Script, autocomplete, backlog, completeAttribute, completeVariable, enableColours, error, getCompletions, inspect, multilineMode, pipedInput, readline, repl, run, stdin, stdout, __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }; stdin = process.openStdin(); stdout = process.stdout; CoffeeScript = require('./coffee-script'); readline = require('readline'); inspect = require('util').inspect; Script = require('vm').Script; Module = require('module'); REPL_PROMPT = 'coffee> '; REPL_PROMPT_MULTILINE = '------> '; REPL_PROMPT_CONTINUATION = '......> '; enableColours = false; if (process.platform !== 'win32') { enableColours = !process.env.NODE_DISABLE_COLORS; } error = function(err) { return stdout.write((err.stack || err.toString()) + '\n'); }; ACCESSOR = /\s*([\w\.]+)(?:\.(\w*))$/; SIMPLEVAR = /(\w+)$/i; autocomplete = function(text) { return completeAttribute(text) || completeVariable(text) || [[], text]; }; completeAttribute = function(text) { var all, candidates, completions, key, match, obj, prefix, _i, _len, _ref; if (match = text.match(ACCESSOR)) { all = match[0], obj = match[1], prefix = match[2]; try { obj = Script.runInThisContext(obj); } catch (e) { return; } if (obj == null) { return; } obj = Object(obj); candidates = Object.getOwnPropertyNames(obj); while (obj = Object.getPrototypeOf(obj)) { _ref = Object.getOwnPropertyNames(obj); for (_i = 0, _len = _ref.length; _i < _len; _i++) { key = _ref[_i]; if (__indexOf.call(candidates, key) < 0) { candidates.push(key); } } } completions = getCompletions(prefix, candidates); return [completions, prefix]; } }; completeVariable = function(text) { var candidates, completions, free, key, keywords, r, vars, _i, _len, _ref; free = (_ref = text.match(SIMPLEVAR)) != null ? _ref[1] : void 0; if (text === "") { free = ""; } if (free != null) { vars = Script.runInThisContext('Object.getOwnPropertyNames(Object(this))'); keywords = (function() { var _i, _len, _ref1, _results; _ref1 = CoffeeScript.RESERVED; _results = []; for (_i = 0, _len = _ref1.length; _i < _len; _i++) { r = _ref1[_i]; if (r.slice(0, 2) !== '__') { _results.push(r); } } return _results; })(); candidates = vars; for (_i = 0, _len = keywords.length; _i < _len; _i++) { key = keywords[_i]; if (__indexOf.call(candidates, key) < 0) { candidates.push(key); } } completions = getCompletions(free, candidates); return [completions, free]; } }; getCompletions = function(prefix, candidates) { var el, _i, _len, _results; _results = []; for (_i = 0, _len = candidates.length; _i < _len; _i++) { el = candidates[_i]; if (0 === el.indexOf(prefix)) { _results.push(el); } } return _results; }; process.on('uncaughtException', error); backlog = ''; run = function(buffer) { var code, returnValue, _; buffer = buffer.replace(/(^|[\r\n]+)(\s*)##?(?:[^#\r\n][^\r\n]*|)($|[\r\n])/, "$1$2$3"); buffer = buffer.replace(/[\r\n]+$/, ""); if (multilineMode) { backlog += "" + buffer + "\n"; repl.setPrompt(REPL_PROMPT_CONTINUATION); repl.prompt(); return; } if (!buffer.toString().trim() && !backlog) { repl.prompt(); return; } code = backlog += buffer; if (code[code.length - 1] === '\\') { backlog = "" + backlog.slice(0, -1) + "\n"; repl.setPrompt(REPL_PROMPT_CONTINUATION); repl.prompt(); return; } repl.setPrompt(REPL_PROMPT); backlog = ''; try { _ = global._; returnValue = CoffeeScript["eval"]("_=(" + code + "\n)", { filename: 'repl', modulename: 'repl' }); if (returnValue === void 0) { global._ = _; } repl.output.write("" + (inspect(returnValue, false, 2, enableColours)) + "\n"); } catch (err) { error(err); } return repl.prompt(); }; if (stdin.readable && stdin.isRaw) { pipedInput = ''; repl = { prompt: function() { return stdout.write(this._prompt); }, setPrompt: function(p) { return this._prompt = p; }, input: stdin, output: stdout, on: function() {} }; stdin.on('data', function(chunk) { var line, lines, _i, _len, _ref; pipedInput += chunk; if (!/\n/.test(pipedInput)) { return; } lines = pipedInput.split("\n"); pipedInput = lines[lines.length - 1]; _ref = lines.slice(0, -1); for (_i = 0, _len = _ref.length; _i < _len; _i++) { line = _ref[_i]; if (!(line)) { continue; } stdout.write("" + line + "\n"); run(line); } }); stdin.on('end', function() { var line, _i, _len, _ref; _ref = pipedInput.trim().split("\n"); for (_i = 0, _len = _ref.length; _i < _len; _i++) { line = _ref[_i]; if (!(line)) { continue; } stdout.write("" + line + "\n"); run(line); } stdout.write('\n'); return process.exit(0); }); } else { if (readline.createInterface.length < 3) { repl = readline.createInterface(stdin, autocomplete); stdin.on('data', function(buffer) { return repl.write(buffer); }); } else { repl = readline.createInterface(stdin, stdout, autocomplete); } } multilineMode = false; repl.input.on('keypress', function(char, key) { var cursorPos, newPrompt; if (!(key && key.ctrl && !key.meta && !key.shift && key.name === 'v')) { return; } cursorPos = repl.cursor; repl.output.cursorTo(0); repl.output.clearLine(1); multilineMode = !multilineMode; if (!multilineMode && backlog) { repl._line(); } backlog = ''; repl.setPrompt((newPrompt = multilineMode ? REPL_PROMPT_MULTILINE : REPL_PROMPT)); repl.prompt(); return repl.output.cursorTo(newPrompt.length + (repl.cursor = cursorPos)); }); repl.input.on('keypress', function(char, key) { if (!(multilineMode && repl.line)) { return; } if (!(key && key.ctrl && !key.meta && !key.shift && key.name === 'd')) { return; } multilineMode = false; return repl._line(); }); repl.on('attemptClose', function() { if (multilineMode) { multilineMode = false; repl.output.cursorTo(0); repl.output.clearLine(1); repl._onLine(repl.line); return; } if (backlog || repl.line) { backlog = ''; repl.historyIndex = -1; repl.setPrompt(REPL_PROMPT); repl.output.write('\n(^C again to quit)'); return repl._line((repl.line = '')); } else { return repl.close(); } }); repl.on('close', function() { repl.output.write('\n'); return repl.input.destroy(); }); repl.on('line', run); repl.setPrompt(REPL_PROMPT); repl.prompt(); }).call(this); coffee-script-1.4.0/lib/coffee-script/rewriter.js000066400000000000000000000316521204160075300217520ustar00rootroot00000000000000// Generated by CoffeeScript 1.4.0 (function() { var BALANCED_PAIRS, EXPRESSION_CLOSE, EXPRESSION_END, EXPRESSION_START, IMPLICIT_BLOCK, IMPLICIT_CALL, IMPLICIT_END, IMPLICIT_FUNC, IMPLICIT_UNSPACED_CALL, INVERSES, LINEBREAKS, SINGLE_CLOSERS, SINGLE_LINERS, left, rite, _i, _len, _ref, __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }, __slice = [].slice; exports.Rewriter = (function() { function Rewriter() {} Rewriter.prototype.rewrite = function(tokens) { this.tokens = tokens; this.removeLeadingNewlines(); this.removeMidExpressionNewlines(); this.closeOpenCalls(); this.closeOpenIndexes(); this.addImplicitIndentation(); this.tagPostfixConditionals(); this.addImplicitBraces(); this.addImplicitParentheses(); return this.tokens; }; Rewriter.prototype.scanTokens = function(block) { var i, token, tokens; tokens = this.tokens; i = 0; while (token = tokens[i]) { i += block.call(this, token, i, tokens); } return true; }; Rewriter.prototype.detectEnd = function(i, condition, action) { var levels, token, tokens, _ref, _ref1; tokens = this.tokens; levels = 0; while (token = tokens[i]) { if (levels === 0 && condition.call(this, token, i)) { return action.call(this, token, i); } if (!token || levels < 0) { return action.call(this, token, i - 1); } if (_ref = token[0], __indexOf.call(EXPRESSION_START, _ref) >= 0) { levels += 1; } else if (_ref1 = token[0], __indexOf.call(EXPRESSION_END, _ref1) >= 0) { levels -= 1; } i += 1; } return i - 1; }; Rewriter.prototype.removeLeadingNewlines = function() { var i, tag, _i, _len, _ref; _ref = this.tokens; for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) { tag = _ref[i][0]; if (tag !== 'TERMINATOR') { break; } } if (i) { return this.tokens.splice(0, i); } }; Rewriter.prototype.removeMidExpressionNewlines = function() { return this.scanTokens(function(token, i, tokens) { var _ref; if (!(token[0] === 'TERMINATOR' && (_ref = this.tag(i + 1), __indexOf.call(EXPRESSION_CLOSE, _ref) >= 0))) { return 1; } tokens.splice(i, 1); return 0; }); }; Rewriter.prototype.closeOpenCalls = function() { var action, condition; condition = function(token, i) { var _ref; return ((_ref = token[0]) === ')' || _ref === 'CALL_END') || token[0] === 'OUTDENT' && this.tag(i - 1) === ')'; }; action = function(token, i) { return this.tokens[token[0] === 'OUTDENT' ? i - 1 : i][0] = 'CALL_END'; }; return this.scanTokens(function(token, i) { if (token[0] === 'CALL_START') { this.detectEnd(i + 1, condition, action); } return 1; }); }; Rewriter.prototype.closeOpenIndexes = function() { var action, condition; condition = function(token, i) { var _ref; return (_ref = token[0]) === ']' || _ref === 'INDEX_END'; }; action = function(token, i) { return token[0] = 'INDEX_END'; }; return this.scanTokens(function(token, i) { if (token[0] === 'INDEX_START') { this.detectEnd(i + 1, condition, action); } return 1; }); }; Rewriter.prototype.addImplicitBraces = function() { var action, condition, sameLine, stack, start, startIndent, startIndex, startsLine; stack = []; start = null; startsLine = null; sameLine = true; startIndent = 0; startIndex = 0; condition = function(token, i) { var one, tag, three, two, _ref, _ref1; _ref = this.tokens.slice(i + 1, +(i + 3) + 1 || 9e9), one = _ref[0], two = _ref[1], three = _ref[2]; if ('HERECOMMENT' === (one != null ? one[0] : void 0)) { return false; } tag = token[0]; if (__indexOf.call(LINEBREAKS, tag) >= 0) { sameLine = false; } return (((tag === 'TERMINATOR' || tag === 'OUTDENT') || (__indexOf.call(IMPLICIT_END, tag) >= 0 && sameLine && !(i - startIndex === 1))) && ((!startsLine && this.tag(i - 1) !== ',') || !((two != null ? two[0] : void 0) === ':' || (one != null ? one[0] : void 0) === '@' && (three != null ? three[0] : void 0) === ':'))) || (tag === ',' && one && ((_ref1 = one[0]) !== 'IDENTIFIER' && _ref1 !== 'NUMBER' && _ref1 !== 'STRING' && _ref1 !== '@' && _ref1 !== 'TERMINATOR' && _ref1 !== 'OUTDENT')); }; action = function(token, i) { var tok; tok = this.generate('}', '}', token[2]); return this.tokens.splice(i, 0, tok); }; return this.scanTokens(function(token, i, tokens) { var ago, idx, prevTag, tag, tok, value, _ref, _ref1; if (_ref = (tag = token[0]), __indexOf.call(EXPRESSION_START, _ref) >= 0) { stack.push([(tag === 'INDENT' && this.tag(i - 1) === '{' ? '{' : tag), i]); return 1; } if (__indexOf.call(EXPRESSION_END, tag) >= 0) { start = stack.pop(); return 1; } if (!(tag === ':' && ((ago = this.tag(i - 2)) === ':' || ((_ref1 = stack[stack.length - 1]) != null ? _ref1[0] : void 0) !== '{'))) { return 1; } sameLine = true; startIndex = i + 1; stack.push(['{']); idx = ago === '@' ? i - 2 : i - 1; while (this.tag(idx - 2) === 'HERECOMMENT') { idx -= 2; } prevTag = this.tag(idx - 1); startsLine = !prevTag || (__indexOf.call(LINEBREAKS, prevTag) >= 0); value = new String('{'); value.generated = true; tok = this.generate('{', value, token[2]); tokens.splice(idx, 0, tok); this.detectEnd(i + 2, condition, action); return 2; }); }; Rewriter.prototype.addImplicitParentheses = function() { var action, condition, noCall, seenControl, seenSingle; noCall = seenSingle = seenControl = false; condition = function(token, i) { var post, tag, _ref, _ref1; tag = token[0]; if (!seenSingle && token.fromThen) { return true; } if (tag === 'IF' || tag === 'ELSE' || tag === 'CATCH' || tag === '->' || tag === '=>' || tag === 'CLASS') { seenSingle = true; } if (tag === 'IF' || tag === 'ELSE' || tag === 'SWITCH' || tag === 'TRY' || tag === '=') { seenControl = true; } if ((tag === '.' || tag === '?.' || tag === '::') && this.tag(i - 1) === 'OUTDENT') { return true; } return !token.generated && this.tag(i - 1) !== ',' && (__indexOf.call(IMPLICIT_END, tag) >= 0 || (tag === 'INDENT' && !seenControl)) && (tag !== 'INDENT' || (((_ref = this.tag(i - 2)) !== 'CLASS' && _ref !== 'EXTENDS') && (_ref1 = this.tag(i - 1), __indexOf.call(IMPLICIT_BLOCK, _ref1) < 0) && !((post = this.tokens[i + 1]) && post.generated && post[0] === '{'))); }; action = function(token, i) { return this.tokens.splice(i, 0, this.generate('CALL_END', ')', token[2])); }; return this.scanTokens(function(token, i, tokens) { var callObject, current, next, prev, tag, _ref, _ref1, _ref2; tag = token[0]; if (tag === 'CLASS' || tag === 'IF' || tag === 'FOR' || tag === 'WHILE') { noCall = true; } _ref = tokens.slice(i - 1, +(i + 1) + 1 || 9e9), prev = _ref[0], current = _ref[1], next = _ref[2]; callObject = !noCall && tag === 'INDENT' && next && next.generated && next[0] === '{' && prev && (_ref1 = prev[0], __indexOf.call(IMPLICIT_FUNC, _ref1) >= 0); seenSingle = false; seenControl = false; if (__indexOf.call(LINEBREAKS, tag) >= 0) { noCall = false; } if (prev && !prev.spaced && tag === '?') { token.call = true; } if (token.fromThen) { return 1; } if (!(callObject || (prev != null ? prev.spaced : void 0) && (prev.call || (_ref2 = prev[0], __indexOf.call(IMPLICIT_FUNC, _ref2) >= 0)) && (__indexOf.call(IMPLICIT_CALL, tag) >= 0 || !(token.spaced || token.newLine) && __indexOf.call(IMPLICIT_UNSPACED_CALL, tag) >= 0))) { return 1; } tokens.splice(i, 0, this.generate('CALL_START', '(', token[2])); this.detectEnd(i + 1, condition, action); if (prev[0] === '?') { prev[0] = 'FUNC_EXIST'; } return 2; }); }; Rewriter.prototype.addImplicitIndentation = function() { var action, condition, indent, outdent, starter; starter = indent = outdent = null; condition = function(token, i) { var _ref; return token[1] !== ';' && (_ref = token[0], __indexOf.call(SINGLE_CLOSERS, _ref) >= 0) && !(token[0] === 'ELSE' && (starter !== 'IF' && starter !== 'THEN')); }; action = function(token, i) { return this.tokens.splice((this.tag(i - 1) === ',' ? i - 1 : i), 0, outdent); }; return this.scanTokens(function(token, i, tokens) { var tag, _ref, _ref1; tag = token[0]; if (tag === 'TERMINATOR' && this.tag(i + 1) === 'THEN') { tokens.splice(i, 1); return 0; } if (tag === 'ELSE' && this.tag(i - 1) !== 'OUTDENT') { tokens.splice.apply(tokens, [i, 0].concat(__slice.call(this.indentation(token)))); return 2; } if (tag === 'CATCH' && ((_ref = this.tag(i + 2)) === 'OUTDENT' || _ref === 'TERMINATOR' || _ref === 'FINALLY')) { tokens.splice.apply(tokens, [i + 2, 0].concat(__slice.call(this.indentation(token)))); return 4; } if (__indexOf.call(SINGLE_LINERS, tag) >= 0 && this.tag(i + 1) !== 'INDENT' && !(tag === 'ELSE' && this.tag(i + 1) === 'IF')) { starter = tag; _ref1 = this.indentation(token, true), indent = _ref1[0], outdent = _ref1[1]; if (starter === 'THEN') { indent.fromThen = true; } tokens.splice(i + 1, 0, indent); this.detectEnd(i + 2, condition, action); if (tag === 'THEN') { tokens.splice(i, 1); } return 1; } return 1; }); }; Rewriter.prototype.tagPostfixConditionals = function() { var action, condition, original; original = null; condition = function(token, i) { var _ref; return (_ref = token[0]) === 'TERMINATOR' || _ref === 'INDENT'; }; action = function(token, i) { if (token[0] !== 'INDENT' || (token.generated && !token.fromThen)) { return original[0] = 'POST_' + original[0]; } }; return this.scanTokens(function(token, i) { if (token[0] !== 'IF') { return 1; } original = token; this.detectEnd(i + 1, condition, action); return 1; }); }; Rewriter.prototype.indentation = function(token, implicit) { var indent, outdent; if (implicit == null) { implicit = false; } indent = ['INDENT', 2, token[2]]; outdent = ['OUTDENT', 2, token[2]]; if (implicit) { indent.generated = outdent.generated = true; } return [indent, outdent]; }; Rewriter.prototype.generate = function(tag, value, line) { var tok; tok = [tag, value, line]; tok.generated = true; return tok; }; Rewriter.prototype.tag = function(i) { var _ref; return (_ref = this.tokens[i]) != null ? _ref[0] : void 0; }; return Rewriter; })(); BALANCED_PAIRS = [['(', ')'], ['[', ']'], ['{', '}'], ['INDENT', 'OUTDENT'], ['CALL_START', 'CALL_END'], ['PARAM_START', 'PARAM_END'], ['INDEX_START', 'INDEX_END']]; exports.INVERSES = INVERSES = {}; EXPRESSION_START = []; EXPRESSION_END = []; for (_i = 0, _len = BALANCED_PAIRS.length; _i < _len; _i++) { _ref = BALANCED_PAIRS[_i], left = _ref[0], rite = _ref[1]; EXPRESSION_START.push(INVERSES[rite] = left); EXPRESSION_END.push(INVERSES[left] = rite); } EXPRESSION_CLOSE = ['CATCH', 'WHEN', 'ELSE', 'FINALLY'].concat(EXPRESSION_END); IMPLICIT_FUNC = ['IDENTIFIER', 'SUPER', ')', 'CALL_END', ']', 'INDEX_END', '@', 'THIS']; IMPLICIT_CALL = ['IDENTIFIER', 'NUMBER', 'STRING', 'JS', 'REGEX', 'NEW', 'PARAM_START', 'CLASS', 'IF', 'TRY', 'SWITCH', 'THIS', 'BOOL', 'NULL', 'UNDEFINED', 'UNARY', 'SUPER', '@', '->', '=>', '[', '(', '{', '--', '++']; IMPLICIT_UNSPACED_CALL = ['+', '-']; IMPLICIT_BLOCK = ['->', '=>', '{', '[', ',']; IMPLICIT_END = ['POST_IF', 'FOR', 'WHILE', 'UNTIL', 'WHEN', 'BY', 'LOOP', 'TERMINATOR']; SINGLE_LINERS = ['ELSE', '->', '=>', 'TRY', 'FINALLY', 'THEN']; SINGLE_CLOSERS = ['TERMINATOR', 'CATCH', 'FINALLY', 'ELSE', 'OUTDENT', 'LEADING_WHEN']; LINEBREAKS = ['TERMINATOR', 'INDENT', 'OUTDENT']; }).call(this); coffee-script-1.4.0/lib/coffee-script/scope.js000066400000000000000000000072301204160075300212130ustar00rootroot00000000000000// Generated by CoffeeScript 1.4.0 (function() { var Scope, extend, last, _ref; _ref = require('./helpers'), extend = _ref.extend, last = _ref.last; exports.Scope = Scope = (function() { Scope.root = null; function Scope(parent, expressions, method) { this.parent = parent; this.expressions = expressions; this.method = method; this.variables = [ { name: 'arguments', type: 'arguments' } ]; this.positions = {}; if (!this.parent) { Scope.root = this; } } Scope.prototype.add = function(name, type, immediate) { if (this.shared && !immediate) { return this.parent.add(name, type, immediate); } if (Object.prototype.hasOwnProperty.call(this.positions, name)) { return this.variables[this.positions[name]].type = type; } else { return this.positions[name] = this.variables.push({ name: name, type: type }) - 1; } }; Scope.prototype.namedMethod = function() { if (this.method.name || !this.parent) { return this.method; } return this.parent.namedMethod(); }; Scope.prototype.find = function(name) { if (this.check(name)) { return true; } this.add(name, 'var'); return false; }; Scope.prototype.parameter = function(name) { if (this.shared && this.parent.check(name, true)) { return; } return this.add(name, 'param'); }; Scope.prototype.check = function(name) { var _ref1; return !!(this.type(name) || ((_ref1 = this.parent) != null ? _ref1.check(name) : void 0)); }; Scope.prototype.temporary = function(name, index) { if (name.length > 1) { return '_' + name + (index > 1 ? index - 1 : ''); } else { return '_' + (index + parseInt(name, 36)).toString(36).replace(/\d/g, 'a'); } }; Scope.prototype.type = function(name) { var v, _i, _len, _ref1; _ref1 = this.variables; for (_i = 0, _len = _ref1.length; _i < _len; _i++) { v = _ref1[_i]; if (v.name === name) { return v.type; } } return null; }; Scope.prototype.freeVariable = function(name, reserve) { var index, temp; if (reserve == null) { reserve = true; } index = 0; while (this.check((temp = this.temporary(name, index)))) { index++; } if (reserve) { this.add(temp, 'var', true); } return temp; }; Scope.prototype.assign = function(name, value) { this.add(name, { value: value, assigned: true }, true); return this.hasAssignments = true; }; Scope.prototype.hasDeclarations = function() { return !!this.declaredVariables().length; }; Scope.prototype.declaredVariables = function() { var realVars, tempVars, v, _i, _len, _ref1; realVars = []; tempVars = []; _ref1 = this.variables; for (_i = 0, _len = _ref1.length; _i < _len; _i++) { v = _ref1[_i]; if (v.type === 'var') { (v.name.charAt(0) === '_' ? tempVars : realVars).push(v.name); } } return realVars.sort().concat(tempVars.sort()); }; Scope.prototype.assignedVariables = function() { var v, _i, _len, _ref1, _results; _ref1 = this.variables; _results = []; for (_i = 0, _len = _ref1.length; _i < _len; _i++) { v = _ref1[_i]; if (v.type.assigned) { _results.push("" + v.name + " = " + v.type.value); } } return _results; }; return Scope; })(); }).call(this); coffee-script-1.4.0/package.json000066400000000000000000000016761204160075300165430ustar00rootroot00000000000000{ "name": "coffee-script", "description": "Unfancy JavaScript", "keywords": ["javascript", "language", "coffeescript", "compiler"], "author": "Jeremy Ashkenas", "version": "1.4.0", "licenses": [{ "type": "MIT", "url": "https://raw.github.com/jashkenas/coffee-script/master/LICENSE" }], "engines": { "node": ">=0.4.0" }, "directories" : { "lib" : "./lib/coffee-script" }, "main" : "./lib/coffee-script/coffee-script", "bin": { "coffee": "./bin/coffee", "cake": "./bin/cake" }, "scripts": { "test": "node ./bin/cake test" }, "homepage": "http://coffeescript.org", "bugs": "https://github.com/jashkenas/coffee-script/issues", "repository": { "type": "git", "url": "git://github.com/jashkenas/coffee-script.git" }, "devDependencies": { "uglify-js": ">=1.0.0", "jison": ">=0.2.0" } } coffee-script-1.4.0/src/000077500000000000000000000000001204160075300150325ustar00rootroot00000000000000coffee-script-1.4.0/src/browser.coffee000066400000000000000000000034531204160075300176730ustar00rootroot00000000000000# Override exported methods for non-Node.js engines. CoffeeScript = require './coffee-script' CoffeeScript.require = require # Use standard JavaScript `eval` to eval code. CoffeeScript.eval = (code, options = {}) -> options.bare ?= on eval CoffeeScript.compile code, options # Running code does not provide access to this scope. CoffeeScript.run = (code, options = {}) -> options.bare = on Function(CoffeeScript.compile code, options)() # If we're not in a browser environment, we're finished with the public API. return unless window? # Load a remote script from the current domain via XHR. CoffeeScript.load = (url, callback) -> xhr = if window.ActiveXObject new window.ActiveXObject('Microsoft.XMLHTTP') else new XMLHttpRequest() xhr.open 'GET', url, true xhr.overrideMimeType 'text/plain' if 'overrideMimeType' of xhr xhr.onreadystatechange = -> if xhr.readyState is 4 if xhr.status in [0, 200] CoffeeScript.run xhr.responseText else throw new Error "Could not load #{url}" callback() if callback xhr.send null # 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. runScripts = -> scripts = document.getElementsByTagName 'script' coffees = (s for s in scripts when s.type is 'text/coffeescript') index = 0 length = coffees.length do execute = -> script = coffees[index++] if script?.type is 'text/coffeescript' if script.src CoffeeScript.load script.src, execute else CoffeeScript.run script.innerHTML execute() null # Listen for window load, both in browsers and in IE. if window.addEventListener addEventListener 'DOMContentLoaded', runScripts, no else attachEvent 'onload', runScripts coffee-script-1.4.0/src/cake.coffee000066400000000000000000000066771204160075300171260ustar00rootroot00000000000000# `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' optparse = require './optparse' CoffeeScript = require './coffee-script' existsSync = fs.existsSync or path.existsSync # 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, an optional sentence description, # and the function to run as the action itself. task: (name, description, 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 # as the first argument to the action. option: (letter, flag, description) -> switches.push [letter, flag, description] # Invoke another task in the current Cakefile. invoke: (name) -> missingTask name unless tasks[name] tasks[name].action options # Run `cake`. Executes all of the tasks you pass, in order. Note that Node's # asynchrony may cause tasks to execute in a different order than you'd expect. # If no tasks are passed, print the help screen. Keep a reference to the # original directory name, when running Cake tasks from subdirectories. exports.run = -> global.__originalDirname = fs.realpathSync '.' process.chdir cakefileDirectory __originalDirname args = process.argv[2..] CoffeeScript.run fs.readFileSync('Cakefile').toString(), filename: 'Cakefile' oparse = new optparse.OptionParser switches return printTasks() unless args.length try options = oparse.parse(args) catch e return fatalError "#{e}" invoke arg for arg in options.arguments # Display the list of Cake tasks in a format similar to `rake -T` printTasks = -> relative = path.relative or path.resolve cakefilePath = path.join relative(__originalDirname, process.cwd()), 'Cakefile' console.log "#{cakefilePath} defines the following tasks:\n" for name, task of tasks spaces = 20 - name.length spaces = if spaces > 0 then Array(spaces + 1).join(' ') else '' desc = if task.description then "# #{task.description}" else '' console.log "cake #{name}#{spaces} #{desc}" console.log oparse.help() if switches.length # Print an error and exit when attempting to use an invalid task/option. fatalError = (message) -> console.error message + '\n' console.log 'To see a list of all tasks/options, run "cake"' process.exit 1 missingTask = (task) -> fatalError "No such task: #{task}" # When `cake` is invoked, search in the current and all parent directories # to find the relevant Cakefile. cakefileDirectory = (dir) -> return dir if existsSync path.join dir, 'Cakefile' parent = path.normalize path.join dir, '..' return cakefileDirectory parent unless parent is dir throw new Error "Cakefile not found in #{process.cwd()}" coffee-script-1.4.0/src/coffee-script.coffee000066400000000000000000000113241204160075300207350ustar00rootroot00000000000000# 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 tokenizing, 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. fs = require 'fs' path = require 'path' {Lexer,RESERVED} = require './lexer' {parser} = require './parser' vm = require 'vm' stripBOM = (content) -> if content.charCodeAt(0) is 0xFEFF then content.substring 1 else content if require.extensions require.extensions['.coffee'] = (module, filename) -> content = compile stripBOM(fs.readFileSync filename, 'utf8'), {filename} module._compile content, filename # The current CoffeeScript version number. exports.VERSION = '1.4.0' # Words that cannot be used as identifiers in CoffeeScript code exports.RESERVED = RESERVED # Expose helpers for testing. exports.helpers = require './helpers' # Compile a string of CoffeeScript code to JavaScript, using the Coffee/Jison # compiler. exports.compile = compile = (code, options = {}) -> {merge} = exports.helpers try js = (parser.parse lexer.tokenize code).compile options return js unless options.header catch err err.message = "In #{options.filename}, #{err.message}" if options.filename throw err header = "Generated by CoffeeScript #{@VERSION}" "// #{header}\n#{js}" # Tokenize a string of CoffeeScript code, and return the array of tokens. exports.tokens = (code, options) -> lexer.tokenize code, options # Parse a string of CoffeeScript code or an array of lexed tokens, and # return the AST. You can then compile it by calling `.compile()` on the root, # or traverse it by using `.traverseChildren()` with a callback. exports.nodes = (source, options) -> if typeof source is 'string' parser.parse lexer.tokenize source, options else parser.parse source # Compile and execute a string of CoffeeScript (on the server), correctly # setting `__filename`, `__dirname`, and relative `require()`. exports.run = (code, options = {}) -> mainModule = require.main # Set the filename. mainModule.filename = process.argv[1] = if options.filename then fs.realpathSync(options.filename) else '.' # Clear the module cache. mainModule.moduleCache and= {} # Assign paths for node_modules loading mainModule.paths = require('module')._nodeModulePaths path.dirname fs.realpathSync options.filename # Compile. if path.extname(mainModule.filename) isnt '.coffee' or require.extensions mainModule._compile compile(code, options), mainModule.filename else mainModule._compile code, mainModule.filename # Compile and evaluate a string of CoffeeScript (in a Node.js-like environment). # The CoffeeScript REPL uses this to run the input. exports.eval = (code, options = {}) -> return unless code = code.trim() Script = vm.Script if Script if options.sandbox? if options.sandbox instanceof Script.createContext().constructor sandbox = options.sandbox else sandbox = Script.createContext() sandbox[k] = v for own k, v of options.sandbox sandbox.global = sandbox.root = sandbox.GLOBAL = sandbox else sandbox = global sandbox.__filename = options.filename || 'eval' sandbox.__dirname = path.dirname sandbox.__filename # define module/require only if they chose not to specify their own unless sandbox isnt global or sandbox.module or sandbox.require Module = require 'module' sandbox.module = _module = new Module(options.modulename || 'eval') sandbox.require = _require = (path) -> Module._load path, _module, true _module.filename = sandbox.__filename _require[r] = require[r] for r in Object.getOwnPropertyNames require when r isnt 'paths' # use the same hack node currently uses for their own REPL _require.paths = _module.paths = Module._nodeModulePaths process.cwd() _require.resolve = (request) -> Module._resolveFilename request, _module o = {} o[k] = v for own k, v of options o.bare = on # ensure return value js = compile code, o if sandbox is global vm.runInThisContext js else vm.runInContext js, sandbox # Instantiate a Lexer for our use here. lexer = new Lexer # 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: -> [tag, @yytext, @yylineno] = @tokens[@pos++] or [''] tag setInput: (@tokens) -> @pos = 0 upcomingInput: -> "" parser.yy = require './nodes' coffee-script-1.4.0/src/command.coffee000066400000000000000000000313631204160075300176270ustar00rootroot00000000000000# The `coffee` utility. Handles command-line compilation of CoffeeScript # into various forms: saved into `.js` files or printed to stdout, piped to # [JavaScript Lint](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. fs = require 'fs' path = require 'path' helpers = require './helpers' optparse = require './optparse' CoffeeScript = require './coffee-script' {spawn, exec} = require 'child_process' {EventEmitter} = require 'events' exists = fs.exists or path.exists # Allow CoffeeScript to emit Node.js events. helpers.extend CoffeeScript, new EventEmitter printLine = (line) -> process.stdout.write line + '\n' printWarn = (line) -> process.stderr.write line + '\n' hidden = (file) -> /^\.|~$/.test file # The help banner that is printed when `coffee` is called without arguments. BANNER = ''' Usage: coffee [options] path/to/script.coffee -- [args] If called without options, `coffee` will run your script. ''' # The list of all the valid option flags that `coffee` knows how to handle. SWITCHES = [ ['-b', '--bare', 'compile without a top-level function wrapper'] ['-c', '--compile', 'compile to JavaScript and save as .js files'] ['-e', '--eval', 'pass a string from the command line as input'] ['-h', '--help', 'display this help message'] ['-i', '--interactive', 'run an interactive CoffeeScript REPL'] ['-j', '--join [FILE]', 'concatenate the source CoffeeScript before compiling'] ['-l', '--lint', 'pipe the compiled JavaScript through JavaScript Lint'] ['-n', '--nodes', 'print out the parse tree that the parser produces'] [ '--nodejs [ARGS]', 'pass options directly to the "node" binary'] ['-o', '--output [DIR]', 'set the output directory for compiled JavaScript'] ['-p', '--print', 'print out the compiled JavaScript'] ['-r', '--require [FILE*]', 'require a library before executing your script'] ['-s', '--stdio', 'listen for and compile scripts over stdio'] ['-t', '--tokens', 'print out the tokens that the lexer/rewriter produce'] ['-v', '--version', 'display the version number'] ['-w', '--watch', 'watch scripts for changes and rerun commands'] ] # Top-level objects shared by all the functions. opts = {} sources = [] sourceCode = [] notSources = {} watchers = {} 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 = -> parseOptions() return forkNode() if opts.nodejs return usage() if opts.help return version() if opts.version loadRequires() if opts.require return require './repl' if opts.interactive if opts.watch and !fs.watch return printWarn "The --watch feature depends on Node v0.6.0+. You are running #{process.version}." return compileStdio() if opts.stdio return compileScript null, sources[0] if opts.eval return require './repl' unless sources.length literals = if opts.run then sources.splice 1 else [] process.argv = process.argv[0..1].concat literals process.argv[0] = 'coffee' process.execPath = require.main.filename for source in sources compilePath source, yes, path.normalize source # Compile a path, which could be a script or a directory. If a directory # is passed, recursively compile all '.coffee' extension source files in it # and all subdirectories. compilePath = (source, topLevel, base) -> fs.stat source, (err, stats) -> throw err if err and err.code isnt 'ENOENT' if err?.code is 'ENOENT' if topLevel and source[-7..] isnt '.coffee' source = sources[sources.indexOf(source)] = "#{source}.coffee" return compilePath source, topLevel, base if topLevel console.error "File not found: #{source}" process.exit 1 return if stats.isDirectory() watchDir source, base if opts.watch fs.readdir source, (err, files) -> throw err if err and err.code isnt 'ENOENT' return if err?.code is 'ENOENT' index = sources.indexOf source files = files.filter (file) -> not hidden file sources[index..index] = (path.join source, file for file in files) sourceCode[index..index] = files.map -> null files.forEach (file) -> compilePath (path.join source, file), no, base else if topLevel or path.extname(source) is '.coffee' watch source, base if opts.watch fs.readFile source, (err, code) -> throw err if err and err.code isnt 'ENOENT' return if err?.code is 'ENOENT' compileScript(source, code.toString(), base) else notSources[source] = yes removeSource source, base # Compile a single source script, containing the given code, according to the # requested options. If evaluating the script directly sets `__filename`, # `__dirname` and `module.filename` to be correct relative to the script's path. compileScript = (file, input, base) -> o = opts options = compileOptions file try t = task = {file, input, options} CoffeeScript.emit 'compile', task if o.tokens then printTokens CoffeeScript.tokens t.input else if o.nodes then printLine CoffeeScript.nodes(t.input).toString().trim() else if o.run then CoffeeScript.run t.input, t.options else if o.join and t.file isnt o.join sourceCode[sources.indexOf(t.file)] = t.input compileJoin() else t.output = CoffeeScript.compile t.input, t.options CoffeeScript.emit 'success', task if o.print then printLine t.output.trim() else if o.compile then writeJs t.file, t.output, base else if o.lint then lint t.file, t.output catch err CoffeeScript.emit 'failure', err, task return if CoffeeScript.listeners('failure').length return printLine err.message + '\x07' if o.watch printWarn err instanceof Error and err.stack or "ERROR: #{err}" process.exit 1 # Attach the appropriate listeners to compile scripts incoming over **stdin**, # and write them back to **stdout**. compileStdio = -> code = '' stdin = process.openStdin() stdin.on 'data', (buffer) -> code += buffer.toString() if buffer stdin.on 'end', -> compileScript null, code # If all of the source files are done being read, concatenate and compile # them together. joinTimeout = null compileJoin = -> return unless opts.join unless sourceCode.some((code) -> code is null) clearTimeout joinTimeout joinTimeout = wait 100, -> compileScript opts.join, sourceCode.join('\n'), opts.join # Load files that are to-be-required before compilation occurs. loadRequires = -> realFilename = module.filename module.filename = '.' require req for req in opts.require module.filename = realFilename # Watch a source CoffeeScript file using `fs.watch`, recompiling it every # time the file is updated. May be used in combination with other options, # such as `--lint` or `--print`. watch = (source, base) -> prevStats = null compileTimeout = null watchErr = (e) -> if e.code is 'ENOENT' return if sources.indexOf(source) is -1 try rewatch() compile() catch e removeSource source, base, yes compileJoin() else throw e compile = -> clearTimeout compileTimeout compileTimeout = wait 25, -> fs.stat source, (err, stats) -> return watchErr err if err return rewatch() if prevStats and stats.size is prevStats.size and stats.mtime.getTime() is prevStats.mtime.getTime() prevStats = stats fs.readFile source, (err, code) -> return watchErr err if err compileScript(source, code.toString(), base) rewatch() try watcher = fs.watch source, compile catch e watchErr e rewatch = -> watcher?.close() watcher = fs.watch source, compile # Watch a directory of files for new additions. watchDir = (source, base) -> readdirTimeout = null try watcher = fs.watch source, -> clearTimeout readdirTimeout readdirTimeout = wait 25, -> fs.readdir source, (err, files) -> if err throw err unless err.code is 'ENOENT' watcher.close() return unwatchDir source, base for file in files when not hidden(file) and not notSources[file] file = path.join source, file continue if sources.some (s) -> s.indexOf(file) >= 0 sources.push file sourceCode.push null compilePath file, no, base catch e throw e unless e.code is 'ENOENT' unwatchDir = (source, base) -> prevSources = sources[..] toRemove = (file for file in sources when file.indexOf(source) >= 0) removeSource file, base, yes for file in toRemove return unless sources.some (s, i) -> prevSources[i] isnt s compileJoin() # Remove a file from our source list, and source code cache. Optionally remove # the compiled JS version as well. removeSource = (source, base, removeJs) -> index = sources.indexOf source sources.splice index, 1 sourceCode.splice index, 1 if removeJs and not opts.join jsPath = outputPath source, base exists jsPath, (itExists) -> if itExists fs.unlink jsPath, (err) -> throw err if err and err.code isnt 'ENOENT' timeLog "removed #{source}" # Get the corresponding output JavaScript path for a source file. outputPath = (source, base) -> filename = path.basename(source, path.extname(source)) + '.js' srcDir = path.dirname source baseDir = if base is '.' then srcDir else srcDir.substring base.length dir = if opts.output then path.join opts.output, baseDir else srcDir path.join dir, filename # 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`. writeJs = (source, js, base) -> jsPath = outputPath source, base jsDir = path.dirname jsPath compile = -> js = ' ' if js.length <= 0 fs.writeFile jsPath, js, (err) -> if err printLine err.message else if opts.compile and opts.watch timeLog "compiled #{source}" exists jsDir, (itExists) -> if itExists then compile() else exec "mkdir -p #{jsDir}", compile # Convenience for cleaner setTimeouts. wait = (milliseconds, func) -> setTimeout func, milliseconds # When watching scripts, it's useful to log changes with the timestamp. timeLog = (message) -> console.log "#{(new Date).toLocaleTimeString()} - #{message}" # Pipe compiled JS through JSLint (requires a working `jsl` command), printing # any errors or warnings that arise. lint = (file, js) -> printIt = (buffer) -> printLine file + ':\t' + buffer.toString().trim() conf = __dirname + '/../../extras/jsl.conf' jsl = spawn 'jsl', ['-nologo', '-stdin', '-conf', conf] jsl.stdout.on 'data', printIt jsl.stderr.on 'data', printIt jsl.stdin.write js jsl.stdin.end() # Pretty-print a stream of tokens. printTokens = (tokens) -> strings = for token in tokens [tag, value] = [token[0], token[1].toString().replace(/\n/, '\\n')] "[#{tag} #{value}]" printLine strings.join(' ') # Use the [OptionParser module](optparse.html) to extract all options from # `process.argv` that are specified in `SWITCHES`. parseOptions = -> optionParser = new optparse.OptionParser SWITCHES, BANNER o = opts = optionParser.parse process.argv[2..] o.compile or= !!o.output o.run = not (o.compile or o.print or o.lint) o.print = !! (o.print or (o.eval or o.stdio and o.compile)) sources = o.arguments sourceCode[i] = null for source, i in sources return # The compile-time options to pass to the CoffeeScript compiler. compileOptions = (filename) -> {filename, bare: opts.bare, header: opts.compile} # Start up a new Node.js instance with the arguments in `--nodejs` passed to # the `node` binary, preserving the other options. forkNode = -> nodeArgs = opts.nodejs.split /\s+/ args = process.argv[1..] args.splice args.indexOf('--nodejs'), 2 spawn process.execPath, nodeArgs.concat(args), cwd: process.cwd() env: process.env customFds: [0, 1, 2] # Print the `--help` usage message and exit. Deprecated switches are not # shown. usage = -> printLine (new optparse.OptionParser SWITCHES, BANNER).help() # Print the `--version` message and exit. version = -> printLine "CoffeeScript version #{CoffeeScript.VERSION}" coffee-script-1.4.0/src/grammar.coffee000066400000000000000000000554721204160075300176460ustar00rootroot00000000000000# 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' # 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 = (patternString, action, options) -> patternString = patternString.replace /\s{2,}/g, ' ' return [patternString, '$$ = $1;', options] unless action action = if match = unwrap.exec action then match[1] else "(#{action}())" action = action.replace /\bnew /g, '$&yy.' action = action.replace /\b(?:Block\.wrap|extend)\b/g, 'yy.$&' [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 '', -> new Block o 'Body' o 'Block TERMINATOR' ] # Any list of statements and expressions, separated by line breaks or semicolons. Body: [ o 'Line', -> Block.wrap [$1] o 'Body TERMINATOR Line', -> $1.push $3 o 'Body TERMINATOR' ] # Block 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 'Comment' o 'STATEMENT', -> new Literal $1 ] # All the different types of expressions in our language. The basic unit of # CoffeeScript is the **Expression** -- everything that can be an expression # is one. Blocks serve as the building blocks of many other rules, making # them somewhat circular. Expression: [ o 'Value' o 'Invocation' o 'Code' o 'Operation' o 'Assign' o 'If' o 'Try' o 'While' o 'For' o 'Switch' o 'Class' o 'Throw' ] # 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 OUTDENT', -> new Block o 'INDENT Body OUTDENT', -> $2 ] # A literal identifier, a variable name or property. Identifier: [ o 'IDENTIFIER', -> new Literal $1 ] # Alphanumerics are separated from the other **Literal** matchers because # they can also serve as keys in object literals. AlphaNumeric: [ o 'NUMBER', -> new Literal $1 o 'STRING', -> new Literal $1 ] # All of our immediate values. Generally these can be passed straight # through and printed to JavaScript. Literal: [ o 'AlphaNumeric' o 'JS', -> new Literal $1 o 'REGEX', -> new Literal $1 o 'DEBUGGER', -> new Literal $1 o 'UNDEFINED', -> new Undefined o 'NULL', -> new Null o 'BOOL', -> new Bool $1 ] # Assignment of a variable, property, or index to a value. Assign: [ o 'Assignable = Expression', -> new Assign $1, $3 o 'Assignable = TERMINATOR Expression', -> new Assign $1, $4 o 'Assignable = INDENT Expression OUTDENT', -> new Assign $1, $4 ] # 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 'ObjAssignable', -> new Value $1 o 'ObjAssignable : Expression', -> new Assign new Value($1), $3, 'object' o 'ObjAssignable : INDENT Expression OUTDENT', -> new Assign new Value($1), $4, 'object' o 'Comment' ] ObjAssignable: [ o 'Identifier' o 'AlphaNumeric' o 'ThisProperty' ] # A return statement from a function body. Return: [ o 'RETURN Expression', -> new Return $2 o 'RETURN', -> new Return ] # A block comment. Comment: [ o 'HERECOMMENT', -> new Comment $1 ] # The **Code** node is the function literal. It's defined by an indented block # of **Block** preceded by a function arrow, with an optional parameter # list. Code: [ o 'PARAM_START ParamList PARAM_END FuncGlyph Block', -> new Code $2, $5, $4 o 'FuncGlyph Block', -> new Code [], $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 '->', -> 'func' o '=>', -> 'boundfunc' ] # An optional, trailing comma. OptComma: [ o '' o ',' ] # The list of parameters that a function accepts can be of any length. ParamList: [ o '', -> [] o 'Param', -> [$1] o 'ParamList , Param', -> $1.concat $3 o 'ParamList OptComma TERMINATOR Param', -> $1.concat $4 o 'ParamList OptComma INDENT ParamList OptComma OUTDENT', -> $1.concat $4 ] # A single parameter in a function definition can be ordinary, or a splat # that hoovers up the remaining arguments. Param: [ o 'ParamVar', -> new Param $1 o 'ParamVar ...', -> new Param $1, null, on o 'ParamVar = Expression', -> new Param $1, $3 ] # Function Parameters ParamVar: [ o 'Identifier' o 'ThisProperty' o 'Array' o 'Object' ] # A splat that occurs outside of a parameter list. Splat: [ o 'Expression ...', -> new Splat $1 ] # Variables and properties that can be assigned to. SimpleAssignable: [ o 'Identifier', -> new Value $1 o 'Value Accessor', -> $1.add $2 o 'Invocation Accessor', -> new Value $1, [].concat $2 o 'ThisProperty' ] # Everything that can be assigned to. Assignable: [ o 'SimpleAssignable' o 'Array', -> new Value $1 o 'Object', -> new Value $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', -> new Value $1 o 'Parenthetical', -> new Value $1 o 'Range', -> new Value $1 o 'This' ] # The general group of accessors into an object, by property, by prototype # or by array index or slice. Accessor: [ o '. Identifier', -> new Access $2 o '?. Identifier', -> new Access $2, 'soak' o ':: Identifier', -> [(new Access new Literal 'prototype'), new Access $2] o '::', -> new Access new Literal 'prototype' o 'Index' ] # Indexing into an object or array using bracket notation. Index: [ o 'INDEX_START IndexValue INDEX_END', -> $2 o 'INDEX_SOAK Index', -> extend $2, soak : yes ] IndexValue: [ o 'Expression', -> new Index $1 o 'Slice', -> new Slice $1 ] # In CoffeeScript, an object literal is simply a list of assignments. Object: [ o '{ AssignList OptComma }', -> new Obj $2, $1.generated ] # Assignment of properties within an object literal can be separated by # comma, as in JavaScript, or simply by newline. AssignList: [ o '', -> [] o 'AssignObj', -> [$1] o 'AssignList , AssignObj', -> $1.concat $3 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, # and optional references to the superclass. Class: [ o 'CLASS', -> new Class o 'CLASS Block', -> new Class null, null, $2 o 'CLASS EXTENDS Expression', -> new Class null, $3 o 'CLASS EXTENDS Expression Block', -> new Class null, $3, $4 o 'CLASS SimpleAssignable', -> new Class $2 o 'CLASS SimpleAssignable Block', -> new Class $2, null, $3 o 'CLASS SimpleAssignable EXTENDS Expression', -> new Class $2, $4 o 'CLASS SimpleAssignable EXTENDS Expression Block', -> new Class $2, $4, $5 ] # Ordinary function invocation, or a chained series of calls. Invocation: [ o 'Value OptFuncExist Arguments', -> new Call $1, $3, $2 o 'Invocation OptFuncExist Arguments', -> new Call $1, $3, $2 o 'SUPER', -> new Call 'super', [new Splat new Literal 'arguments'] o 'SUPER Arguments', -> new Call 'super', $2 ] # An optional existence check on a function. OptFuncExist: [ o '', -> no o 'FUNC_EXIST', -> yes ] # The list of arguments to a function call. Arguments: [ o 'CALL_START CALL_END', -> [] o 'CALL_START ArgList OptComma CALL_END', -> $2 ] # A reference to the *this* current object. This: [ o 'THIS', -> new Value new Literal 'this' o '@', -> new Value new Literal 'this' ] # A reference to a property on *this*. ThisProperty: [ o '@ Identifier', -> new Value new Literal('this'), [new Access($2)], 'this' ] # The array literal. Array: [ o '[ ]', -> new Arr [] o '[ ArgList OptComma ]', -> new Arr $2 ] # Inclusive and exclusive range dots. RangeDots: [ o '..', -> 'inclusive' o '...', -> 'exclusive' ] # The CoffeeScript range literal. Range: [ o '[ Expression RangeDots Expression ]', -> new Range $2, $4, $3 ] # Array slice literals. Slice: [ o 'Expression RangeDots Expression', -> new Range $1, $3, $2 o 'Expression RangeDots', -> new Range $1, null, $2 o 'RangeDots Expression', -> new Range null, $2, $1 o 'RangeDots', -> new Range null, null, $1 ] # 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 'Arg', -> [$1] o 'ArgList , Arg', -> $1.concat $3 o 'ArgList OptComma TERMINATOR Arg', -> $1.concat $4 o 'INDENT ArgList OptComma OUTDENT', -> $2 o 'ArgList OptComma INDENT ArgList OptComma OUTDENT', -> $1.concat $4 ] # Valid arguments are Blocks or Splats. Arg: [ o 'Expression' o 'Splat' ] # 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', -> [].concat $1, $3 ] # The variants of *try/catch/finally* exception handling blocks. Try: [ o 'TRY Block', -> new Try $2 o 'TRY Block Catch', -> new Try $2, $3[0], $3[1] o 'TRY Block FINALLY Block', -> new Try $2, null, null, $4 o 'TRY Block Catch FINALLY Block', -> new Try $2, $3[0], $3[1], $5 ] # A catch clause names its error and runs a block of code. Catch: [ o 'CATCH Identifier Block', -> [$2, $3] ] # Throw an exception object. Throw: [ o 'THROW Expression', -> new Throw $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 '( Body )', -> new Parens $2 o '( INDENT Body OUTDENT )', -> new Parens $3 ] # The condition portion of a while loop. WhileSource: [ o 'WHILE Expression', -> new While $2 o 'WHILE Expression WHEN Expression', -> new While $2, guard: $4 o 'UNTIL Expression', -> new While $2, invert: true o 'UNTIL Expression WHEN Expression', -> new While $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.addBody $2 o 'Statement WhileSource', -> $2.addBody Block.wrap [$1] o 'Expression WhileSource', -> $2.addBody Block.wrap [$1] o 'Loop', -> $1 ] Loop: [ o 'LOOP Block', -> new While(new Literal 'true').addBody $2 o 'LOOP Expression', -> new While(new Literal 'true').addBody Block.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 ForBody', -> new For $1, $2 o 'Expression ForBody', -> new For $1, $2 o 'ForBody Block', -> new For $2, $1 ] ForBody: [ o 'FOR Range', -> source: new Value($2) o 'ForStart ForSource', -> $2.own = $1.own; $2.name = $1[0]; $2.index = $1[1]; $2 ] ForStart: [ o 'FOR ForVariables', -> $2 o 'FOR OWN ForVariables', -> $3.own = yes; $3 ] # An array of all accepted values for a variable inside the loop. # This enables support for pattern matching. ForValue: [ o 'Identifier' o 'ThisProperty' o 'Array', -> new Value $1 o 'Object', -> new Value $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 'ForValue', -> [$1] o 'ForValue , ForValue', -> [$1, $3] ] # 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 'FORIN Expression', -> source: $2 o 'FOROF Expression', -> source: $2, object: yes o 'FORIN Expression WHEN Expression', -> source: $2, guard: $4 o 'FOROF Expression WHEN Expression', -> source: $2, guard: $4, object: yes o 'FORIN Expression BY Expression', -> source: $2, step: $4 o 'FORIN Expression WHEN Expression BY Expression', -> source: $2, guard: $4, step: $6 o 'FORIN Expression BY Expression WHEN Expression', -> source: $2, step: $4, guard: $6 ] Switch: [ o 'SWITCH Expression INDENT Whens OUTDENT', -> new Switch $2, $4 o 'SWITCH Expression INDENT Whens ELSE Block OUTDENT', -> new Switch $2, $4, $6 o 'SWITCH INDENT Whens OUTDENT', -> new Switch null, $3 o 'SWITCH INDENT Whens ELSE Block OUTDENT', -> new Switch null, $3, $5 ] Whens: [ o 'When' o 'Whens When', -> $1.concat $2 ] # An individual **When** clause, with action. When: [ o 'LEADING_WHEN SimpleArgs Block', -> [[$2, $3]] o 'LEADING_WHEN SimpleArgs Block TERMINATOR', -> [[$2, $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. IfBlock: [ o 'IF Expression Block', -> new If $2, $3, type: $1 o 'IfBlock ELSE IF Expression Block', -> $1.addElse new If $4, $5, type: $3 ] # The full complement of *if* expressions, including postfix one-liner # *if* and *unless*. If: [ o 'IfBlock' o 'IfBlock ELSE Block', -> $1.addElse $3 o 'Statement POST_IF Expression', -> new If $3, Block.wrap([$1]), type: $2, statement: true o 'Expression POST_IF Expression', -> new If $3, Block.wrap([$1]), type: $2, statement: 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 'UNARY Expression', -> new Op $1 , $2 o '- Expression', (-> new Op '-', $2), prec: 'UNARY' o '+ Expression', (-> new Op '+', $2), prec: 'UNARY' o '-- SimpleAssignable', -> new Op '--', $2 o '++ SimpleAssignable', -> new Op '++', $2 o 'SimpleAssignable --', -> new Op '--', $1, null, true o 'SimpleAssignable ++', -> new Op '++', $1, null, true # [The existential operator](http://jashkenas.github.com/coffee-script/#existence). o 'Expression ?', -> new Existence $1 o 'Expression + Expression', -> new Op '+' , $1, $3 o 'Expression - Expression', -> new Op '-' , $1, $3 o 'Expression MATH Expression', -> new Op $2, $1, $3 o 'Expression SHIFT Expression', -> new Op $2, $1, $3 o 'Expression COMPARE Expression', -> new Op $2, $1, $3 o 'Expression LOGIC Expression', -> new Op $2, $1, $3 o 'Expression RELATION Expression', -> if $2.charAt(0) is '!' new Op($2[1..], $1, $3).invert() else new Op $2, $1, $3 o 'SimpleAssignable COMPOUND_ASSIGN Expression', -> new Assign $1, $3, $2 o 'SimpleAssignable COMPOUND_ASSIGN INDENT Expression OUTDENT', -> new Assign $1, $4, $2 o 'SimpleAssignable EXTENDS Expression', -> new Extends $1, $3 ] # 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', '.', '?.', '::'] ['left', 'CALL_START', 'CALL_END'] ['nonassoc', '++', '--'] ['left', '?'] ['right', 'UNARY'] ['left', 'MATH'] ['left', '+', '-'] ['left', 'SHIFT'] ['left', 'RELATION'] ['left', 'COMPARE'] ['left', 'LOGIC'] ['nonassoc', 'INDENT', 'OUTDENT'] ['right', '=', ':', 'COMPOUND_ASSIGN', 'RETURN', 'THROW', 'EXTENDS'] ['right', 'FORIN', 'FOROF', 'BY', 'WHEN'] ['right', 'IF', 'ELSE', 'FOR', 'WHILE', 'UNTIL', 'LOOP', 'SUPER', 'CLASS'] ['right', 'POST_IF'] ] # Wrapping Up # ----------- # Finally, now that we have our **grammar** and our **operators**, we can create # our **Jison.Parser**. We do this by processing all of our rules, recording all # terminals (every symbol which does not appear as the name of a rule above) # as "tokens". tokens = [] for name, alternatives of grammar grammar[name] = for alt in alternatives for token in alt[0].split ' ' tokens.push token unless grammar[token] alt[1] = "return #{alt[1]}" if name is 'Root' alt # 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 operators : operators.reverse() startSymbol : 'Root' coffee-script-1.4.0/src/helpers.coffee000066400000000000000000000040761204160075300176540ustar00rootroot00000000000000# 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. # Peek at the beginning of a given string to see if it matches a sequence. exports.starts = (string, literal, start) -> literal is string.substr start, literal.length # Peek at the end of a given string to see if it matches a sequence. exports.ends = (string, literal, back) -> len = literal.length literal is string.substr string.length - len - (back or 0), len # Trim out all falsy values from an array. exports.compact = (array) -> item for item in array when item # Count the number of occurrences of a string in a string. exports.count = (string, substr) -> num = pos = 0 return 1/0 unless substr.length num++ while pos = 1 + string.indexOf substr, pos num # Merge objects, returning a fresh copy with attributes from both sides. # Used every time `Base#compile` is called, to allow properties in the # options hash to propagate down the tree without polluting other branches. exports.merge = (options, overrides) -> extend (extend {}, options), overrides # Extend a source object with the properties of another object (shallow copy). extend = exports.extend = (object, properties) -> for key, val of properties object[key] = val object # Return a flattened version of an array. # Handy for getting a list of `children` from the nodes. exports.flatten = flatten = (array) -> flattened = [] for element in array if element instanceof Array flattened = flattened.concat flatten element else flattened.push element flattened # Delete a key from an object, returning the value. Useful when a node is # looking for a particular method in an options hash. exports.del = (obj, key) -> val = obj[key] delete obj[key] val # Gets the last item of an array(-like) object. exports.last = (array, back) -> array[array.length - (back or 0) - 1] # Typical Array::some exports.some = Array::some ? (fn) -> return true for e in this when fn e false coffee-script-1.4.0/src/index.coffee000066400000000000000000000001541204160075300173120ustar00rootroot00000000000000# Loader for CoffeeScript as a Node.js library. exports[key] = val for key, val of require './coffee-script'coffee-script-1.4.0/src/lexer.coffee000066400000000000000000000603771204160075300173370ustar00rootroot00000000000000# 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, lineNumber] # # Which is a format that can be fed directly into [Jison](http://github.com/zaach/jison). {Rewriter, INVERSES} = require './rewriter' # Import the helpers we need. {count, starts, compact, last} = require './helpers' # The Lexer Class # --------------- # The Lexer class reads a stream of CoffeeScript and divvies it up into tagged # tokens. Some potential ambiguity in the grammar has been avoided by # pushing some extra smarts into the Lexer. exports.Lexer = class 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 returning the number of characters # it has consumed. # # Before returning the token stream, run it through the [Rewriter](rewriter.html) # unless explicitly asked not to. tokenize: (code, opts = {}) -> code = "\n#{code}" if WHITESPACE.test code code = code.replace(/\r/g, '').replace TRAILING_SPACES, '' @code = code # The remainder of the source code. @line = opts.line or 0 # The current line. @indent = 0 # The current indentation level. @indebt = 0 # The over-indentation at the current level. @outdebt = 0 # The under-outdentation at the current level. @indents = [] # The stack of all current indentation levels. @ends = [] # The stack for pairing up tokens. @tokens = [] # Stream of parsed tokens in the form `['TYPE', value, line]`. # At every position, run through this list of attempted matches, # short-circuiting if any of them succeed. Their order determines precedence: # `@literalToken` is the fallback catch-all. i = 0 while @chunk = code[i..] i += @identifierToken() or @commentToken() or @whitespaceToken() or @lineToken() or @heredocToken() or @stringToken() or @numberToken() or @regexToken() or @jsToken() or @literalToken() @closeIndentation() @error "missing #{tag}" if tag = @ends.pop() return @tokens if opts.rewrite is off (new Rewriter).rewrite @tokens # Tokenizers # ---------- # 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. identifierToken: -> return 0 unless match = IDENTIFIER.exec @chunk [input, id, colon] = match if id is 'own' and @tag() is 'FOR' @token 'OWN', id return id.length forcedIdentifier = colon or (prev = last @tokens) and (prev[0] in ['.', '?.', '::'] or not prev.spaced and prev[0] is '@') tag = 'IDENTIFIER' if not forcedIdentifier and (id in JS_KEYWORDS or id in COFFEE_KEYWORDS) tag = id.toUpperCase() if tag is 'WHEN' and @tag() in LINE_BREAK tag = 'LEADING_WHEN' else if tag is 'FOR' @seenFor = yes else if tag is 'UNLESS' tag = 'IF' else if tag in UNARY tag = 'UNARY' else if tag in RELATION if tag isnt 'INSTANCEOF' and @seenFor tag = 'FOR' + tag @seenFor = no else tag = 'RELATION' if @value() is '!' @tokens.pop() id = '!' + id if id in JS_FORBIDDEN if forcedIdentifier tag = 'IDENTIFIER' id = new String id id.reserved = yes else if id in RESERVED @error "reserved word \"#{id}\"" unless forcedIdentifier id = COFFEE_ALIAS_MAP[id] if id in COFFEE_ALIASES tag = switch id when '!' then 'UNARY' when '==', '!=' then 'COMPARE' when '&&', '||' then 'LOGIC' when 'true', 'false' then 'BOOL' when 'break', 'continue' then 'STATEMENT' else tag @token tag, id @token ':', ':' if colon input.length # Matches numbers, including decimals, hex, and exponential notation. # Be careful not to interfere with ranges-in-progress. numberToken: -> return 0 unless match = NUMBER.exec @chunk number = match[0] if /^0[BOX]/.test number @error "radix prefix '#{number}' must be lowercase" else if /E/.test(number) and not /^0x/.test number @error "exponential notation '#{number}' must be indicated with a lowercase 'e'" else if /^0\d*[89]/.test number @error "decimal literal '#{number}' must not be prefixed with '0'" else if /^0\d+/.test number @error "octal literal '#{number}' must be prefixed with '0o'" lexedLength = number.length if octalLiteral = /^0o([0-7]+)/.exec number number = '0x' + (parseInt octalLiteral[1], 8).toString 16 if binaryLiteral = /^0b([01]+)/.exec number number = '0x' + (parseInt binaryLiteral[1], 2).toString 16 @token 'NUMBER', number lexedLength # Matches strings, including multi-line strings. Ensures that quotation marks # are balanced within the string's contents, and within nested interpolations. stringToken: -> switch @chunk.charAt 0 when "'" return 0 unless match = SIMPLESTR.exec @chunk @token 'STRING', (string = match[0]).replace MULTILINER, '\\\n' when '"' return 0 unless string = @balancedString @chunk, '"' if 0 < string.indexOf '#{', 1 @interpolateString string[1...-1] else @token 'STRING', @escapeLines string else return 0 if octalEsc = /^(?:\\.|[^\\])*\\(?:0[0-7]|[1-7])/.test string @error "octal escape sequences #{string} are not allowed" @line += count string, '\n' string.length # Matches heredocs, adjusting indentation to the correct level, as heredocs # preserve whitespace, but ignore indentation to the left. heredocToken: -> return 0 unless match = HEREDOC.exec @chunk heredoc = match[0] quote = heredoc.charAt 0 doc = @sanitizeHeredoc match[2], quote: quote, indent: null if quote is '"' and 0 <= doc.indexOf '#{' @interpolateString doc, heredoc: yes else @token 'STRING', @makeString doc, quote, yes @line += count heredoc, '\n' heredoc.length # Matches and consumes comments. commentToken: -> return 0 unless match = @chunk.match COMMENT [comment, here] = match if here @token 'HERECOMMENT', @sanitizeHeredoc here, herecomment: true, indent: Array(@indent + 1).join(' ') @line += count comment, '\n' comment.length # Matches JavaScript interpolated directly into the source via backticks. jsToken: -> return 0 unless @chunk.charAt(0) is '`' and match = JSTOKEN.exec @chunk @token 'JS', (script = match[0])[1...-1] @line += count script, '\n' script.length # Matches regular expression literals. Lexing regular expressions is difficult # to distinguish from division, so we borrow some basic heuristics from # JavaScript and Ruby. regexToken: -> return 0 if @chunk.charAt(0) isnt '/' if match = HEREGEX.exec @chunk length = @heregexToken match @line += count match[0], '\n' return length prev = last @tokens return 0 if prev and (prev[0] in (if prev.spaced then NOT_REGEX else NOT_SPACED_REGEX)) return 0 unless match = REGEX.exec @chunk [match, regex, flags] = match if regex[..1] is '/*' then @error 'regular expressions cannot begin with `*`' if regex is '//' then regex = '/(?:)/' @token 'REGEX', "#{regex}#{flags}" match.length # Matches multiline extended regular expressions. heregexToken: (match) -> [heregex, body, flags] = match if 0 > body.indexOf '#{' re = body.replace(HEREGEX_OMIT, '').replace(/\//g, '\\/') if re.match /^\*/ then @error 'regular expressions cannot begin with `*`' @token 'REGEX', "/#{ re or '(?:)' }/#{flags}" return heregex.length @token 'IDENTIFIER', 'RegExp' @tokens.push ['CALL_START', '('] tokens = [] for [tag, value] in @interpolateString(body, regex: yes) if tag is 'TOKENS' tokens.push value... else continue unless value = value.replace HEREGEX_OMIT, '' value = value.replace /\\/g, '\\\\' tokens.push ['STRING', @makeString(value, '"', yes)] tokens.push ['+', '+'] tokens.pop() @tokens.push ['STRING', '""'], ['+', '+'] unless tokens[0]?[0] is 'STRING' @tokens.push tokens... @tokens.push [',', ','], ['STRING', '"' + flags + '"'] if flags @token ')', ')' heregex.length # 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. lineToken: -> return 0 unless match = MULTI_DENT.exec @chunk indent = match[0] @line += count indent, '\n' @seenFor = no size = indent.length - 1 - indent.lastIndexOf '\n' noNewlines = @unfinished() if size - @indebt is @indent if noNewlines then @suppressNewlines() else @newlineToken() return indent.length if size > @indent if noNewlines @indebt = size - @indent @suppressNewlines() return indent.length diff = size - @indent + @outdebt @token 'INDENT', diff @indents.push diff @ends.push 'OUTDENT' @outdebt = @indebt = 0 else @indebt = 0 @outdentToken @indent - size, noNewlines @indent = size indent.length # Record an outdent token or multiple tokens, if we happen to be moving back # inwards past several recorded indents. outdentToken: (moveOut, noNewlines) -> while moveOut > 0 len = @indents.length - 1 if @indents[len] is undefined moveOut = 0 else if @indents[len] is @outdebt moveOut -= @outdebt @outdebt = 0 else if @indents[len] < @outdebt @outdebt -= @indents[len] moveOut -= @indents[len] else dent = @indents.pop() - @outdebt moveOut -= dent @outdebt = 0 @pair 'OUTDENT' @token 'OUTDENT', dent @outdebt -= moveOut if dent @tokens.pop() while @value() is ';' @token 'TERMINATOR', '\n' unless @tag() is 'TERMINATOR' or noNewlines this # Matches and consumes non-meaningful whitespace. Tag the previous token # as being "spaced", because there are some cases where it makes a difference. whitespaceToken: -> return 0 unless (match = WHITESPACE.exec @chunk) or (nline = @chunk.charAt(0) is '\n') prev = last @tokens prev[if match then 'spaced' else 'newLine'] = true if prev if match then match[0].length else 0 # Generate a newline token. Consecutive newlines get merged together. newlineToken: -> @tokens.pop() while @value() is ';' @token 'TERMINATOR', '\n' unless @tag() is 'TERMINATOR' this # Use a `\` at a line-ending to suppress the newline. # The slash is removed here once its job is done. suppressNewlines: -> @tokens.pop() if @value() is '\\' this # We treat all other single characters as a token. E.g.: `( ) , . !` # 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. literalToken: -> if match = OPERATOR.exec @chunk [value] = match @tagParameters() if CODE.test value else value = @chunk.charAt 0 tag = value prev = last @tokens if value is '=' and prev if not prev[1].reserved and prev[1] in JS_FORBIDDEN @error "reserved word \"#{@value()}\" can't be assigned" if prev[1] in ['||', '&&'] prev[0] = 'COMPOUND_ASSIGN' prev[1] += '=' return value.length if value is ';' @seenFor = no tag = 'TERMINATOR' else if value in MATH then tag = 'MATH' else if value in COMPARE then tag = 'COMPARE' else if value in COMPOUND_ASSIGN then tag = 'COMPOUND_ASSIGN' else if value in UNARY then tag = 'UNARY' else if value in SHIFT then tag = 'SHIFT' else if value in LOGIC or value is '?' and prev?.spaced then tag = 'LOGIC' else if prev and not prev.spaced if value is '(' and prev[0] in CALLABLE prev[0] = 'FUNC_EXIST' if prev[0] is '?' tag = 'CALL_START' else if value is '[' and prev[0] in INDEXABLE tag = 'INDEX_START' switch prev[0] when '?' then prev[0] = 'INDEX_SOAK' switch value when '(', '{', '[' then @ends.push INVERSES[value] when ')', '}', ']' then @pair value @token tag, value value.length # Token Manipulators # ------------------ # Sanitize a heredoc or herecomment by # erasing all external indentation on the left-hand side. sanitizeHeredoc: (doc, options) -> {indent, herecomment} = options if herecomment if HEREDOC_ILLEGAL.test doc @error "block comment cannot contain \"*/\", starting" return doc if doc.indexOf('\n') <= 0 else while match = HEREDOC_INDENT.exec doc attempt = match[1] indent = attempt if indent is null or 0 < attempt.length < indent.length doc = doc.replace /// \n #{indent} ///g, '\n' if indent doc = doc.replace /^\n/, '' unless herecomment doc # 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. tagParameters: -> return this if @tag() isnt ')' stack = [] {tokens} = this i = tokens.length tokens[--i][0] = 'PARAM_END' while tok = tokens[--i] switch tok[0] when ')' stack.push tok when '(', 'CALL_START' if stack.length then stack.pop() else if tok[0] is '(' tok[0] = 'PARAM_START' return this else return this this # Close up all remaining open blocks at the end of the file. closeIndentation: -> @outdentToken @indent # 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, end) -> continueCount = 0 stack = [end] for i in [1...str.length] if continueCount --continueCount continue switch letter = str.charAt i when '\\' ++continueCount continue when end stack.pop() unless stack.length return str[0..i] end = stack[stack.length - 1] continue if end is '}' and letter in ['"', "'"] stack.push end = letter else if end is '}' and letter is '/' and match = (HEREGEX.exec(str[i..]) or REGEX.exec(str[i..])) continueCount += match[0].length - 1 else if end is '}' and letter is '{' stack.push end = '}' else if end is '"' and prev is '#' and letter is '{' stack.push end = '}' prev = letter @error "missing #{ stack.pop() }, starting" # Expand variables and expressions inside double-quoted strings using # Ruby-like notation for substitution of arbitrary expressions. # # "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. interpolateString: (str, options = {}) -> {heredoc, regex} = options tokens = [] pi = 0 i = -1 while letter = str.charAt i += 1 if letter is '\\' i += 1 continue unless letter is '#' and str.charAt(i+1) is '{' and (expr = @balancedString str[i + 1..], '}') continue tokens.push ['NEOSTRING', str[pi...i]] if pi < i inner = expr[1...-1] if inner.length nested = new Lexer().tokenize inner, line: @line, rewrite: off nested.pop() nested.shift() if nested[0]?[0] is 'TERMINATOR' if len = nested.length if len > 1 nested.unshift ['(', '(', @line] nested.push [')', ')', @line] tokens.push ['TOKENS', nested] i += expr.length pi = i + 1 tokens.push ['NEOSTRING', str[pi..]] if i > pi < str.length return tokens if regex return @token 'STRING', '""' unless tokens.length tokens.unshift ['', ''] unless tokens[0][0] is 'NEOSTRING' @token '(', '(' if interpolated = tokens.length > 1 for [tag, value], i in tokens @token '+', '+' if i if tag is 'TOKENS' @tokens.push value... else @token 'STRING', @makeString value, '"', heredoc @token ')', ')' if interpolated tokens # Pairs up a closing token, ensuring that all listed pairs of tokens are # correctly balanced throughout the course of the token stream. pair: (tag) -> unless tag is wanted = last @ends @error "unmatched #{tag}" unless 'OUTDENT' is wanted # Auto-close INDENT to support syntax like this: # # el.click((event) -> # el.hide()) # @indent -= size = last @indents @outdentToken size, true return @pair tag @ends.pop() # Helpers # ------- # Add a token to the results, taking note of the line number. token: (tag, value) -> @tokens.push [tag, value, @line] # Peek at a tag in the current token stream. tag: (index, tag) -> (tok = last @tokens, index) and if tag then tok[0] = tag else tok[0] # Peek at a value in the current token stream. value: (index, val) -> (tok = last @tokens, index) and if val then tok[1] = val else tok[1] # Are we in the midst of an unfinished expression? unfinished: -> LINE_CONTINUER.test(@chunk) or @tag() in ['\\', '.', '?.', 'UNARY', 'MATH', '+', '-', 'SHIFT', 'RELATION' 'COMPARE', 'LOGIC', 'THROW', 'EXTENDS'] # Converts newlines for string literals. escapeLines: (str, heredoc) -> str.replace MULTILINER, if heredoc then '\\n' else '' # Constructs a string token by escaping quotes and newlines. makeString: (body, quote, heredoc) -> return quote + quote unless body body = body.replace /\\([\s\S])/g, (match, contents) -> if contents in ['\n', quote] then contents else match body = body.replace /// #{quote} ///g, '\\$&' quote + @escapeLines(body, heredoc) + quote # Throws a syntax error on the current `@line`. error: (message) -> throw SyntaxError "#{message} on line #{ @line + 1}" # Constants # --------- # Keywords that CoffeeScript shares in common with JavaScript. JS_KEYWORDS = [ 'true', 'false', 'null', 'this' 'new', 'delete', 'typeof', 'in', 'instanceof' 'return', 'throw', 'break', 'continue', 'debugger' 'if', 'else', 'switch', 'for', 'while', 'do', 'try', 'catch', 'finally' 'class', 'extends', 'super' ] # CoffeeScript-only keywords. COFFEE_KEYWORDS = ['undefined', 'then', 'unless', 'until', 'loop', 'of', 'by', 'when'] COFFEE_ALIAS_MAP = and : '&&' or : '||' is : '==' isnt : '!=' not : '!' yes : 'true' no : 'false' on : 'true' off : 'false' COFFEE_ALIASES = (key for key of COFFEE_ALIAS_MAP) COFFEE_KEYWORDS = COFFEE_KEYWORDS.concat COFFEE_ALIASES # 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', 'function', 'var', 'void', 'with', 'const', 'let', 'enum' 'export', 'import', 'native', '__hasProp', '__extends', '__slice', '__bind' '__indexOf', 'implements', 'interface', 'package', 'private', 'protected' 'public', 'static', 'yield' ] STRICT_PROSCRIBED = ['arguments', 'eval'] # The superset of both JavaScript keywords and reserved words, none of which may # be used as identifiers or properties. JS_FORBIDDEN = JS_KEYWORDS.concat(RESERVED).concat(STRICT_PROSCRIBED) exports.RESERVED = RESERVED.concat(JS_KEYWORDS).concat(COFFEE_KEYWORDS).concat(STRICT_PROSCRIBED) exports.STRICT_PROSCRIBED = STRICT_PROSCRIBED # Token matching regexes. IDENTIFIER = /// ^ ( [$A-Za-z_\x7f-\uffff][$\w\x7f-\uffff]* ) ( [^\n\S]* : (?!:) )? # Is this a property name? /// NUMBER = /// ^ 0b[01]+ | # binary ^ 0o[0-7]+ | # octal ^ 0x[\da-f]+ | # hex ^ \d*\.?\d+ (?:e[+-]?\d+)? # decimal ///i HEREDOC = /// ^ ("""|''') ([\s\S]*?) (?:\n[^\n\S]*)? \1 /// OPERATOR = /// ^ ( ?: [-=]> # function | [-+*/%<>&|^!?=]= # compound assign / compare | >>>=? # zero-fill right shift | ([-+:])\1 # doubles | ([&|<>])\2=? # logic / shift | \?\. # soak access | \.{2,3} # range or splat ) /// WHITESPACE = /^[^\n\S]+/ COMMENT = /^###([^#][\s\S]*?)(?:###[^\n\S]*|(?:###)?$)|^(?:\s*#(?!##[^#]).*)+/ CODE = /^[-=]>/ MULTI_DENT = /^(?:\n[^\n\S]*)+/ SIMPLESTR = /^'[^\\']*(?:\\.[^\\']*)*'/ JSTOKEN = /^`[^\\`]*(?:\\.[^\\`]*)*`/ # Regex-matching-regexes. REGEX = /// ^ (/ (?! [\s=] ) # disallow leading whitespace or equals signs [^ [ / \n \\ ]* # every other thing (?: (?: \\[\s\S] # anything escaped | \[ # character class [^ \] \n \\ ]* (?: \\[\s\S] [^ \] \n \\ ]* )* ] ) [^ [ / \n \\ ]* )* /) ([imgy]{0,4}) (?!\w) /// HEREGEX = /// ^ /{3} ([\s\S]+?) /{3} ([imgy]{0,4}) (?!\w) /// HEREGEX_OMIT = /\s+(?:#.*)?/g # Token cleaning regexes. MULTILINER = /\n/g HEREDOC_INDENT = /\n+([^\n\S]*)/g HEREDOC_ILLEGAL = /\*\// LINE_CONTINUER = /// ^ \s* (?: , | \??\.(?![.\d]) | :: ) /// TRAILING_SPACES = /\s+$/ # Compound assignment tokens. COMPOUND_ASSIGN = [ '-=', '+=', '/=', '*=', '%=', '||=', '&&=', '?=', '<<=', '>>=', '>>>=', '&=', '^=', '|=' ] # Unary tokens. UNARY = ['!', '~', 'NEW', 'TYPEOF', 'DELETE', 'DO'] # Logical tokens. LOGIC = ['&&', '||', '&', '|', '^'] # Bit-shifting tokens. SHIFT = ['<<', '>>', '>>>'] # Comparison tokens. COMPARE = ['==', '!=', '<', '>', '<=', '>='] # Mathematical tokens. MATH = ['*', '/', '%'] # Relational tokens that are negatable with `not` prefix. RELATION = ['IN', 'OF', 'INSTANCEOF'] # Boolean tokens. BOOL = ['TRUE', 'FALSE'] # 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', 'BOOL', 'NULL', 'UNDEFINED', '++', '--', ']'] # If the previous token is not spaced, there are more preceding tokens that # force a division parse: NOT_SPACED_REGEX = NOT_REGEX.concat ')', '}', 'THIS', 'IDENTIFIER', 'STRING' # Tokens which could legitimately be invoked or indexed. An opening # parentheses or bracket following these tokens will be recorded as the start # of a function invocation or indexing operation. CALLABLE = ['IDENTIFIER', 'STRING', 'REGEX', ')', ']', '}', '?', '::', '@', 'THIS', 'SUPER'] INDEXABLE = CALLABLE.concat 'NUMBER', 'BOOL', 'NULL', 'UNDEFINED' # 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. LINE_BREAK = ['INDENT', 'OUTDENT', 'TERMINATOR'] coffee-script-1.4.0/src/nodes.coffee000066400000000000000000002133711204160075300173220ustar00rootroot00000000000000# `nodes.coffee` contains all of the node classes for the syntax tree. Most # nodes are created as the result of actions in the [grammar](grammar.html), # but some are created by other nodes as a method of code generation. To convert # the syntax tree into a string of JavaScript code, call `compile()` on the root. {Scope} = require './scope' {RESERVED, STRICT_PROSCRIBED} = require './lexer' # Import the helpers we plan to use. {compact, flatten, extend, merge, del, starts, ends, last, some} = require './helpers' exports.extend = extend # for parser # Constant functions for nodes that don't need customization. YES = -> yes NO = -> no THIS = -> this NEGATE = -> @negated = not @negated; this #### Base # The **Base** is the abstract base class for all nodes in the syntax tree. # Each subclass implements the `compileNode` method, which performs the # code generation for that node. To compile a node to JavaScript, # call `compile` on it, which wraps `compileNode` in some generic extra smarts, # to know when the generated code needs to be wrapped up in a closure. # An options hash is passed and cloned throughout, containing information about # the environment from higher in the tree (such as if a returned value is # being requested by the surrounding function), information about the current # scope, and indentation level. exports.Base = class Base # Common logic for determining whether to wrap this node in a closure before # compiling it, or to compile directly. We need to wrap if this node is a # *statement*, and it's not a *pureStatement*, and we're not at # the top level of a block (which would be unnecessary), and we haven't # already been asked to return the result (because statements know how to # return results). compile: (o, lvl) -> o = extend {}, o o.level = lvl if lvl node = @unfoldSoak(o) or this node.tab = o.indent if o.level is LEVEL_TOP or not node.isStatement(o) node.compileNode o else node.compileClosure o # Statements converted into expressions via closure-wrapping share a scope # object with their parent closure, to preserve the expected lexical scope. compileClosure: (o) -> if @jumps() throw SyntaxError 'cannot use a pure statement in an expression.' o.sharedScope = yes Closure.wrap(this).compileNode o # If the code generation wishes to use the result of a complex expression # in multiple places, ensure that the expression is only ever evaluated once, # by assigning it to a temporary variable. Pass a level to precompile. cache: (o, level, reused) -> unless @isComplex() ref = if level then @compile o, level else this [ref, ref] else ref = new Literal reused or o.scope.freeVariable 'ref' sub = new Assign ref, this if level then [sub.compile(o, level), ref.value] else [sub, ref] # Compile to a source/variable pair suitable for looping. compileLoopReference: (o, name) -> src = tmp = @compile o, LEVEL_LIST unless -Infinity < +src < Infinity or IDENTIFIER.test(src) and o.scope.check(src, yes) src = "#{ tmp = o.scope.freeVariable name } = #{src}" [src, tmp] # Construct a node that returns the current node's result. # Note that this is overridden for smarter behavior for # many statement nodes (e.g. If, For)... makeReturn: (res) -> me = @unwrapAll() if res new Call new Literal("#{res}.push"), [me] else new Return me # Does this node, or any of its children, contain a node of a certain kind? # Recursively traverses down the *children* of the nodes, yielding to a block # and returning true when the block finds a match. `contains` does not cross # scope boundaries. contains: (pred) -> contains = no @traverseChildren no, (node) -> if pred node contains = yes return no contains # Is this node of a certain type, or does it contain the type? containsType: (type) -> this instanceof type or @contains (node) -> node instanceof type # Pull out the last non-comment node of a node list. lastNonComment: (list) -> i = list.length return list[i] while i-- when list[i] not instanceof Comment null # `toString` representation of the node, for inspecting the parse tree. # This is what `coffee --nodes` prints out. toString: (idt = '', name = @constructor.name) -> tree = '\n' + idt + name tree += '?' if @soak @eachChild (node) -> tree += node.toString idt + TAB tree # Passes each child to a function, breaking when the function returns `false`. eachChild: (func) -> return this unless @children for attr in @children when @[attr] for child in flatten [@[attr]] return this if func(child) is false this traverseChildren: (crossScope, func) -> @eachChild (child) -> return false if func(child) is false child.traverseChildren crossScope, func invert: -> new Op '!', this unwrapAll: -> node = this continue until node is node = node.unwrap() node # Default implementations of the common node properties and methods. Nodes # will override these with custom logic, if needed. children: [] isStatement : NO jumps : NO isComplex : YES isChainable : NO isAssignable : NO unwrap : THIS unfoldSoak : NO # Is this node used to assign a certain variable? assigns: NO #### Block # The block is the list of expressions that forms the body of an # indented block of code -- the implementation of a function, a clause in an # `if`, `switch`, or `try`, and so on... exports.Block = class Block extends Base constructor: (nodes) -> @expressions = compact flatten nodes or [] children: ['expressions'] # Tack an expression on to the end of this expression list. push: (node) -> @expressions.push node this # Remove and return the last expression of this expression list. pop: -> @expressions.pop() # Add an expression at the beginning of this expression list. unshift: (node) -> @expressions.unshift node this # If this Block consists of just a single node, unwrap it by pulling # it back out. unwrap: -> if @expressions.length is 1 then @expressions[0] else this # Is this an empty block of code? isEmpty: -> not @expressions.length isStatement: (o) -> for exp in @expressions when exp.isStatement o return yes no jumps: (o) -> for exp in @expressions return exp if exp.jumps o # A Block node does not return its entire body, rather it # ensures that the final expression is returned. makeReturn: (res) -> len = @expressions.length while len-- expr = @expressions[len] if expr not instanceof Comment @expressions[len] = expr.makeReturn res @expressions.splice(len, 1) if expr instanceof Return and not expr.expression break this # A **Block** is the only node that can serve as the root. compile: (o = {}, level) -> if o.scope then super o, level else @compileRoot o # Compile all expressions within the **Block** body. If we need to # return the result, and it's an expression, simply return it. If it's a # statement, ask the statement to do so. compileNode: (o) -> @tab = o.indent top = o.level is LEVEL_TOP codes = [] for node in @expressions node = node.unwrapAll() node = (node.unfoldSoak(o) or node) if node instanceof Block # This is a nested block. We don't do anything special here like enclose # it in a new scope; we just compile the statements in this block along with # our own codes.push node.compileNode o else if top node.front = true code = node.compile o unless node.isStatement o code = "#{@tab}#{code};" code = "#{code}\n" if node instanceof Literal codes.push code else codes.push node.compile o, LEVEL_LIST if top if @spaced return "\n#{codes.join '\n\n'}\n" else return codes.join '\n' code = codes.join(', ') or 'void 0' if codes.length > 1 and o.level >= LEVEL_LIST then "(#{code})" else code # If we happen to be the top-level **Block**, wrap everything in # a safety closure, unless requested not to. # It would be better not to generate them in the first place, but for now, # clean up obvious double-parentheses. compileRoot: (o) -> o.indent = if o.bare then '' else TAB o.scope = new Scope null, this, null o.level = LEVEL_TOP @spaced = yes prelude = "" unless o.bare preludeExps = for exp, i in @expressions break unless exp.unwrap() instanceof Comment exp rest = @expressions[preludeExps.length...] @expressions = preludeExps prelude = "#{@compileNode merge(o, indent: '')}\n" if preludeExps.length @expressions = rest code = @compileWithDeclarations o return code if o.bare "#{prelude}(function() {\n#{code}\n}).call(this);\n" # Compile the expressions body for the contents of a function, with # declarations of all inner variables pushed up to the top. compileWithDeclarations: (o) -> code = post = '' for exp, i in @expressions exp = exp.unwrap() break unless exp instanceof Comment or exp instanceof Literal o = merge(o, level: LEVEL_TOP) if i rest = @expressions.splice i, 9e9 [spaced, @spaced] = [@spaced, no] [code , @spaced] = [(@compileNode o), spaced] @expressions = rest post = @compileNode o {scope} = o if scope.expressions is this declars = o.scope.hasDeclarations() assigns = scope.hasAssignments if declars or assigns code += '\n' if i code += "#{@tab}var " if declars code += scope.declaredVariables().join ', ' if assigns code += ",\n#{@tab + TAB}" if declars code += scope.assignedVariables().join ",\n#{@tab + TAB}" code += ';\n' code + post # Wrap up the given nodes as a **Block**, unless it already happens # to be one. @wrap: (nodes) -> return nodes[0] if nodes.length is 1 and nodes[0] instanceof Block new Block nodes #### Literal # Literals are static values that can be passed through directly into # JavaScript without translation, such as: strings, numbers, # `true`, `false`, `null`... exports.Literal = class Literal extends Base constructor: (@value) -> makeReturn: -> if @isStatement() then this else super isAssignable: -> IDENTIFIER.test @value isStatement: -> @value in ['break', 'continue', 'debugger'] isComplex: NO assigns: (name) -> name is @value jumps: (o) -> return this if @value is 'break' and not (o?.loop or o?.block) return this if @value is 'continue' and not o?.loop compileNode: (o) -> code = if @value is 'this' if o.scope.method?.bound then o.scope.method.context else @value else if @value.reserved "\"#{@value}\"" else @value if @isStatement() then "#{@tab}#{code};" else code toString: -> ' "' + @value + '"' class exports.Undefined extends Base isAssignable: NO isComplex: NO compileNode: (o) -> if o.level >= LEVEL_ACCESS then '(void 0)' else 'void 0' class exports.Null extends Base isAssignable: NO isComplex: NO compileNode: -> "null" class exports.Bool extends Base isAssignable: NO isComplex: NO compileNode: -> @val constructor: (@val) -> #### Return # A `return` is a *pureStatement* -- wrapping it in a closure wouldn't # make sense. exports.Return = class Return extends Base constructor: (expr) -> @expression = expr if expr and not expr.unwrap().isUndefined children: ['expression'] isStatement: YES makeReturn: THIS jumps: THIS compile: (o, level) -> expr = @expression?.makeReturn() if expr and expr not instanceof Return then expr.compile o, level else super o, level compileNode: (o) -> @tab + "return#{[" #{@expression.compile o, LEVEL_PAREN}" if @expression]};" #### Value # A value, variable or literal or parenthesized, indexed or dotted into, # or vanilla. exports.Value = class Value extends Base constructor: (base, props, tag) -> return base if not props and base instanceof Value @base = base @properties = props or [] @[tag] = true if tag return this children: ['base', 'properties'] # Add a property (or *properties* ) `Access` to the list. add: (props) -> @properties = @properties.concat props this hasProperties: -> !!@properties.length # Some boolean checks for the benefit of other nodes. isArray : -> not @properties.length and @base instanceof Arr isComplex : -> @hasProperties() or @base.isComplex() isAssignable : -> @hasProperties() or @base.isAssignable() isSimpleNumber : -> @base instanceof Literal and SIMPLENUM.test @base.value isString : -> @base instanceof Literal and IS_STRING.test @base.value isAtomic : -> for node in @properties.concat @base return no if node.soak or node instanceof Call yes isStatement : (o) -> not @properties.length and @base.isStatement o assigns : (name) -> not @properties.length and @base.assigns name jumps : (o) -> not @properties.length and @base.jumps o isObject: (onlyGenerated) -> return no if @properties.length (@base instanceof Obj) and (not onlyGenerated or @base.generated) isSplice: -> last(@properties) instanceof Slice # The value can be unwrapped as its inner node, if there are no attached # properties. unwrap: -> if @properties.length then this else @base # A reference has base part (`this` value) and name part. # We cache them separately for compiling complex expressions. # `a()[b()] ?= c` -> `(_base = a())[_name = b()] ? _base[_name] = c` cacheReference: (o) -> name = last @properties if @properties.length < 2 and not @base.isComplex() and not name?.isComplex() return [this, this] # `a` `a.b` base = new Value @base, @properties[...-1] if base.isComplex() # `a().b` bref = new Literal o.scope.freeVariable 'base' base = new Value new Parens new Assign bref, base return [base, bref] unless name # `a()` if name.isComplex() # `a[b()]` nref = new Literal o.scope.freeVariable 'name' name = new Index new Assign nref, name.index nref = new Index nref [base.add(name), new Value(bref or base.base, [nref or name])] # We compile a value to JavaScript by compiling and joining each property. # Things get much more interesting if the chain of properties has *soak* # operators `?.` interspersed. Then we have to take care not to accidentally # evaluate anything twice when building the soak chain. compileNode: (o) -> @base.front = @front props = @properties code = @base.compile o, if props.length then LEVEL_ACCESS else null code = "#{code}." if (@base instanceof Parens or props.length) and SIMPLENUM.test code code += prop.compile o for prop in props code # Unfold a soak into an `If`: `a?.b` -> `a.b if a?` unfoldSoak: (o) -> return @unfoldedSoak if @unfoldedSoak? result = do => if ifn = @base.unfoldSoak o Array::push.apply ifn.body.properties, @properties return ifn for prop, i in @properties when prop.soak prop.soak = off fst = new Value @base, @properties[...i] snd = new Value @base, @properties[i..] if fst.isComplex() ref = new Literal o.scope.freeVariable 'ref' fst = new Parens new Assign ref, fst snd.base = ref return new If new Existence(fst), snd, soak: on null @unfoldedSoak = result or no #### Comment # CoffeeScript passes through block comments as JavaScript block comments # at the same position. exports.Comment = class Comment extends Base constructor: (@comment) -> isStatement: YES makeReturn: THIS compileNode: (o, level) -> code = '/*' + multident(@comment, @tab) + "\n#{@tab}*/\n" code = o.indent + code if (level or o.level) is LEVEL_TOP code #### Call # Node for a function invocation. Takes care of converting `super()` calls into # calls against the prototype's function of the same name. exports.Call = class Call extends Base constructor: (variable, @args = [], @soak) -> @isNew = false @isSuper = variable is 'super' @variable = if @isSuper then null else variable children: ['variable', 'args'] # Tag this invocation as creating a new instance. newInstance: -> base = @variable?.base or @variable if base instanceof Call and not base.isNew base.newInstance() else @isNew = true this # Grab the reference to the superclass's implementation of the current # method. superReference: (o) -> method = o.scope.namedMethod() throw SyntaxError 'cannot call super outside of a function.' unless method {name} = method throw SyntaxError 'cannot call super on an anonymous function.' unless name? if method.klass accesses = [new Access(new Literal '__super__')] accesses.push new Access new Literal 'constructor' if method.static accesses.push new Access new Literal name (new Value (new Literal method.klass), accesses).compile o else "#{name}.__super__.constructor" # The appropriate `this` value for a `super` call. superThis : (o) -> method = o.scope.method (method and not method.klass and method.context) or "this" # Soaked chained invocations unfold into if/else ternary structures. unfoldSoak: (o) -> if @soak if @variable return ifn if ifn = unfoldSoak o, this, 'variable' [left, rite] = new Value(@variable).cacheReference o else left = new Literal @superReference o rite = new Value left rite = new Call rite, @args rite.isNew = @isNew left = new Literal "typeof #{ left.compile o } === \"function\"" return new If left, new Value(rite), soak: yes call = this list = [] loop if call.variable instanceof Call list.push call call = call.variable continue break unless call.variable instanceof Value list.push call break unless (call = call.variable.base) instanceof Call for call in list.reverse() if ifn if call.variable instanceof Call call.variable = ifn else call.variable.base = ifn ifn = unfoldSoak o, call, 'variable' ifn # Walk through the objects in the arguments, moving over simple values. # This allows syntax like `call a: b, c` into `call({a: b}, c);` filterImplicitObjects: (list) -> nodes = [] for node in list unless node.isObject?() and node.base.generated nodes.push node continue obj = null for prop in node.base.properties if prop instanceof Assign or prop instanceof Comment nodes.push obj = new Obj properties = [], true if not obj properties.push prop else nodes.push prop obj = null nodes # Compile a vanilla function call. compileNode: (o) -> @variable?.front = @front if code = Splat.compileSplattedArray o, @args, true return @compileSplat o, code args = @filterImplicitObjects @args args = (arg.compile o, LEVEL_LIST for arg in args).join ', ' if @isSuper @superReference(o) + ".call(#{@superThis(o)}#{ args and ', ' + args })" else (if @isNew then 'new ' else '') + @variable.compile(o, LEVEL_ACCESS) + "(#{args})" # `super()` is converted into a call against the superclass's implementation # of the current function. compileSuper: (args, o) -> "#{@superReference(o)}.call(#{@superThis(o)}#{ if args.length then ', ' else '' }#{args})" # If you call a function with a splat, it's converted into a JavaScript # `.apply()` call to allow an array of arguments to be passed. # If it's a constructor, then things get real tricky. We have to inject an # inner constructor in order to be able to pass the varargs. compileSplat: (o, splatArgs) -> return "#{ @superReference o }.apply(#{@superThis(o)}, #{splatArgs})" if @isSuper if @isNew idt = @tab + TAB return """ (function(func, args, ctor) { #{idt}ctor.prototype = func.prototype; #{idt}var child = new ctor, result = func.apply(child, args); #{idt}return Object(result) === result ? result : child; #{@tab}})(#{ @variable.compile o, LEVEL_LIST }, #{splatArgs}, function(){}) """ base = new Value @variable if (name = base.properties.pop()) and base.isComplex() ref = o.scope.freeVariable 'ref' fun = "(#{ref} = #{ base.compile o, LEVEL_LIST })#{ name.compile o }" else fun = base.compile o, LEVEL_ACCESS fun = "(#{fun})" if SIMPLENUM.test fun if name ref = fun fun += name.compile o else ref = 'null' "#{fun}.apply(#{ref}, #{splatArgs})" #### Extends # Node to extend an object's prototype with an ancestor object. # After `goog.inherits` from the # [Closure Library](http://closure-library.googlecode.com/svn/docs/closureGoogBase.js.html). exports.Extends = class Extends extends Base constructor: (@child, @parent) -> children: ['child', 'parent'] # Hooks one constructor into another's prototype chain. compile: (o) -> new Call(new Value(new Literal utility 'extends'), [@child, @parent]).compile o #### Access # A `.` access into a property of a value, or the `::` shorthand for # an access into the object's prototype. exports.Access = class Access extends Base constructor: (@name, tag) -> @name.asKey = yes @soak = tag is 'soak' children: ['name'] compile: (o) -> name = @name.compile o if IDENTIFIER.test name then ".#{name}" else "[#{name}]" isComplex: NO #### Index # A `[ ... ]` indexed access into an array or object. exports.Index = class Index extends Base constructor: (@index) -> children: ['index'] compile: (o) -> "[#{ @index.compile o, LEVEL_PAREN }]" isComplex: -> @index.isComplex() #### Range # A range literal. Ranges can be used to extract portions (slices) of arrays, # to specify a range for comprehensions, or as a value, to be expanded into the # corresponding array of integers at runtime. exports.Range = class Range extends Base children: ['from', 'to'] constructor: (@from, @to, tag) -> @exclusive = tag is 'exclusive' @equals = if @exclusive then '' else '=' # Compiles the range's source variables -- where it starts and where it ends. # But only if they need to be cached to avoid double evaluation. compileVariables: (o) -> o = merge o, top: true [@fromC, @fromVar] = @from.cache o, LEVEL_LIST [@toC, @toVar] = @to.cache o, LEVEL_LIST [@step, @stepVar] = step.cache o, LEVEL_LIST if step = del o, 'step' [@fromNum, @toNum] = [@fromVar.match(SIMPLENUM), @toVar.match(SIMPLENUM)] @stepNum = @stepVar.match(SIMPLENUM) if @stepVar # When compiled normally, the range returns the contents of the *for loop* # needed to iterate over the values in the range. Used by comprehensions. compileNode: (o) -> @compileVariables o unless @fromVar return @compileArray(o) unless o.index # Set up endpoints. known = @fromNum and @toNum idx = del o, 'index' idxName = del o, 'name' namedIndex = idxName and idxName isnt idx varPart = "#{idx} = #{@fromC}" varPart += ", #{@toC}" if @toC isnt @toVar varPart += ", #{@step}" if @step isnt @stepVar [lt, gt] = ["#{idx} <#{@equals}", "#{idx} >#{@equals}"] # Generate the condition. condPart = if @stepNum if +@stepNum > 0 then "#{lt} #{@toVar}" else "#{gt} #{@toVar}" else if known [from, to] = [+@fromNum, +@toNum] if from <= to then "#{lt} #{to}" else "#{gt} #{to}" else cond = "#{@fromVar} <= #{@toVar}" "#{cond} ? #{lt} #{@toVar} : #{gt} #{@toVar}" # Generate the step. stepPart = if @stepVar "#{idx} += #{@stepVar}" else if known if namedIndex if from <= to then "++#{idx}" else "--#{idx}" else if from <= to then "#{idx}++" else "#{idx}--" else if namedIndex "#{cond} ? ++#{idx} : --#{idx}" else "#{cond} ? #{idx}++ : #{idx}--" varPart = "#{idxName} = #{varPart}" if namedIndex stepPart = "#{idxName} = #{stepPart}" if namedIndex # The final loop body. "#{varPart}; #{condPart}; #{stepPart}" # When used as a value, expand the range into the equivalent array. compileArray: (o) -> if @fromNum and @toNum and Math.abs(@fromNum - @toNum) <= 20 range = [+@fromNum..+@toNum] range.pop() if @exclusive return "[#{ range.join(', ') }]" idt = @tab + TAB i = o.scope.freeVariable 'i' result = o.scope.freeVariable 'results' pre = "\n#{idt}#{result} = [];" if @fromNum and @toNum o.index = i body = @compileNode o else vars = "#{i} = #{@fromC}" + if @toC isnt @toVar then ", #{@toC}" else '' cond = "#{@fromVar} <= #{@toVar}" body = "var #{vars}; #{cond} ? #{i} <#{@equals} #{@toVar} : #{i} >#{@equals} #{@toVar}; #{cond} ? #{i}++ : #{i}--" post = "{ #{result}.push(#{i}); }\n#{idt}return #{result};\n#{o.indent}" hasArgs = (node) -> node?.contains (n) -> n instanceof Literal and n.value is 'arguments' and not n.asKey args = ', arguments' if hasArgs(@from) or hasArgs(@to) "(function() {#{pre}\n#{idt}for (#{body})#{post}}).apply(this#{args ? ''})" #### Slice # An array slice literal. Unlike JavaScript's `Array#slice`, the second parameter # specifies the index of the end of the slice, just as the first parameter # is the index of the beginning. exports.Slice = class Slice extends Base children: ['range'] constructor: (@range) -> super() # We have to be careful when trying to slice through the end of the array, # `9e9` is used because not all implementations respect `undefined` or `1/0`. # `9e9` should be safe because `9e9` > `2**32`, the max array length. compileNode: (o) -> {to, from} = @range fromStr = from and from.compile(o, LEVEL_PAREN) or '0' compiled = to and to.compile o, LEVEL_PAREN if to and not (not @range.exclusive and +compiled is -1) toStr = ', ' + if @range.exclusive compiled else if SIMPLENUM.test compiled "#{+compiled + 1}" else compiled = to.compile o, LEVEL_ACCESS "+#{compiled} + 1 || 9e9" ".slice(#{ fromStr }#{ toStr or '' })" #### Obj # An object literal, nothing fancy. exports.Obj = class Obj extends Base constructor: (props, @generated = false) -> @objects = @properties = props or [] children: ['properties'] compileNode: (o) -> props = @properties return (if @front then '({})' else '{}') unless props.length if @generated for node in props when node instanceof Value throw new Error 'cannot have an implicit value in an implicit object' idt = o.indent += TAB lastNoncom = @lastNonComment @properties props = for prop, i in props join = if i is props.length - 1 '' else if prop is lastNoncom or prop instanceof Comment '\n' else ',\n' indent = if prop instanceof Comment then '' else idt if prop instanceof Value and prop.this prop = new Assign prop.properties[0].name, prop, 'object' if prop not instanceof Comment if prop not instanceof Assign prop = new Assign prop, prop, 'object' (prop.variable.base or prop.variable).asKey = yes indent + prop.compile(o, LEVEL_TOP) + join props = props.join '' obj = "{#{ props and '\n' + props + '\n' + @tab }}" if @front then "(#{obj})" else obj assigns: (name) -> for prop in @properties when prop.assigns name then return yes no #### Arr # An array literal. exports.Arr = class Arr extends Base constructor: (objs) -> @objects = objs or [] children: ['objects'] filterImplicitObjects: Call::filterImplicitObjects compileNode: (o) -> return '[]' unless @objects.length o.indent += TAB objs = @filterImplicitObjects @objects return code if code = Splat.compileSplattedArray o, objs code = (obj.compile o, LEVEL_LIST for obj in objs).join ', ' if code.indexOf('\n') >= 0 "[\n#{o.indent}#{code}\n#{@tab}]" else "[#{code}]" assigns: (name) -> for obj in @objects when obj.assigns name then return yes no #### Class # The CoffeeScript class definition. # Initialize a **Class** with its name, an optional superclass, and a # list of prototype property assignments. exports.Class = class Class extends Base constructor: (@variable, @parent, @body = new Block) -> @boundFuncs = [] @body.classBody = yes children: ['variable', 'parent', 'body'] # Figure out the appropriate name for the constructor function of this class. determineName: -> return null unless @variable decl = if tail = last @variable.properties tail instanceof Access and tail.name.value else @variable.base.value if decl in STRICT_PROSCRIBED throw SyntaxError "variable name may not be #{decl}" decl and= IDENTIFIER.test(decl) and decl # For all `this`-references and bound functions in the class definition, # `this` is the Class being constructed. setContext: (name) -> @body.traverseChildren false, (node) -> return false if node.classBody if node instanceof Literal and node.value is 'this' node.value = name else if node instanceof Code node.klass = name node.context = name if node.bound # Ensure that all functions bound to the instance are proxied in the # constructor. addBoundFunctions: (o) -> if @boundFuncs.length for bvar in @boundFuncs lhs = (new Value (new Literal "this"), [new Access bvar]).compile o @ctor.body.unshift new Literal "#{lhs} = #{utility 'bind'}(#{lhs}, this)" # Merge the properties from a top-level object as prototypal properties # on the class. addProperties: (node, name, o) -> props = node.base.properties[..] exprs = while assign = props.shift() if assign instanceof Assign base = assign.variable.base delete assign.context func = assign.value if base.value is 'constructor' if @ctor throw new Error 'cannot define more than one constructor in a class' if func.bound throw new Error 'cannot define a constructor as a bound function' if func instanceof Code assign = @ctor = func else @externalCtor = o.scope.freeVariable 'class' assign = new Assign new Literal(@externalCtor), func else if assign.variable.this func.static = yes if func.bound func.context = name else assign.variable = new Value(new Literal(name), [(new Access new Literal 'prototype'), new Access base ]) if func instanceof Code and func.bound @boundFuncs.push base func.bound = no assign compact exprs # Walk the body of the class, looking for prototype properties to be converted. walkBody: (name, o) -> @traverseChildren false, (child) => return false if child instanceof Class if child instanceof Block for node, i in exps = child.expressions if node instanceof Value and node.isObject(true) exps[i] = @addProperties node, name, o child.expressions = exps = flatten exps # `use strict` (and other directives) must be the first expression statement(s) # of a function body. This method ensures the prologue is correctly positioned # above the `constructor`. hoistDirectivePrologue: -> index = 0 {expressions} = @body ++index while (node = expressions[index]) and node instanceof Comment or node instanceof Value and node.isString() @directives = expressions.splice 0, index # Make sure that a constructor is defined for the class, and properly # configured. ensureConstructor: (name) -> if not @ctor @ctor = new Code @ctor.body.push new Literal "#{name}.__super__.constructor.apply(this, arguments)" if @parent @ctor.body.push new Literal "#{@externalCtor}.apply(this, arguments)" if @externalCtor @ctor.body.makeReturn() @body.expressions.unshift @ctor @ctor.ctor = @ctor.name = name @ctor.klass = null @ctor.noReturn = yes # Instead of generating the JavaScript string directly, we build up the # equivalent syntax tree and compile that, in pieces. You can see the # constructor, property assignments, and inheritance getting built out below. compileNode: (o) -> decl = @determineName() name = decl or '_Class' name = "_#{name}" if name.reserved lname = new Literal name @hoistDirectivePrologue() @setContext name @walkBody name, o @ensureConstructor name @body.spaced = yes @body.expressions.unshift @ctor unless @ctor instanceof Code @body.expressions.push lname @body.expressions.unshift @directives... @addBoundFunctions o call = Closure.wrap @body if @parent @superClass = new Literal o.scope.freeVariable 'super', no @body.expressions.unshift new Extends lname, @superClass call.args.push @parent params = call.variable.params or call.variable.base.params params.push new Param @superClass klass = new Parens call, yes klass = new Assign @variable, klass if @variable klass.compile o #### Assign # The **Assign** is used to assign a local variable to value, or to set the # property of an object -- including within object literals. exports.Assign = class Assign extends Base constructor: (@variable, @value, @context, options) -> @param = options and options.param @subpattern = options and options.subpattern forbidden = (name = @variable.unwrapAll().value) in STRICT_PROSCRIBED if forbidden and @context isnt 'object' throw SyntaxError "variable name may not be \"#{name}\"" children: ['variable', 'value'] isStatement: (o) -> o?.level is LEVEL_TOP and @context? and "?" in @context assigns: (name) -> @[if @context is 'object' then 'value' else 'variable'].assigns name unfoldSoak: (o) -> unfoldSoak o, this, 'variable' # Compile an assignment, delegating to `compilePatternMatch` or # `compileSplice` if appropriate. Keep track of the name of the base object # we've been assigned to, for correct internal references. If the variable # has not been seen yet within the current scope, declare it. compileNode: (o) -> if isValue = @variable instanceof Value return @compilePatternMatch o if @variable.isArray() or @variable.isObject() return @compileSplice o if @variable.isSplice() return @compileConditional o if @context in ['||=', '&&=', '?='] name = @variable.compile o, LEVEL_LIST unless @context unless (varBase = @variable.unwrapAll()).isAssignable() throw SyntaxError "\"#{ @variable.compile o }\" cannot be assigned." unless varBase.hasProperties?() if @param o.scope.add name, 'var' else o.scope.find name if @value instanceof Code and match = METHOD_DEF.exec name @value.klass = match[1] if match[1] @value.name = match[2] ? match[3] ? match[4] ? match[5] val = @value.compile o, LEVEL_LIST return "#{name}: #{val}" if @context is 'object' val = name + " #{ @context or '=' } " + val if o.level <= LEVEL_LIST then val else "(#{val})" # Brief implementation of recursive pattern matching, when assigning array or # object literals to a value. Peeks at their properties to assign inner names. # See the [ECMAScript Harmony Wiki](http://wiki.ecmascript.org/doku.php?id=harmony:destructuring) # for details. compilePatternMatch: (o) -> top = o.level is LEVEL_TOP {value} = this {objects} = @variable.base unless olen = objects.length code = value.compile o return if o.level >= LEVEL_OP then "(#{code})" else code isObject = @variable.isObject() if top and olen is 1 and (obj = objects[0]) not instanceof Splat # Unroll simplest cases: `{v} = x` -> `v = x.v` if obj instanceof Assign {variable: {base: idx}, value: obj} = obj else if obj.base instanceof Parens [obj, idx] = new Value(obj.unwrapAll()).cacheReference o else idx = if isObject if obj.this then obj.properties[0].name else obj else new Literal 0 acc = IDENTIFIER.test idx.unwrap().value or 0 value = new Value value value.properties.push new (if acc then Access else Index) idx if obj.unwrap().value in RESERVED throw new SyntaxError "assignment to a reserved word: #{obj.compile o} = #{value.compile o}" return new Assign(obj, value, null, param: @param).compile o, LEVEL_TOP vvar = value.compile o, LEVEL_LIST assigns = [] splat = false if not IDENTIFIER.test(vvar) or @variable.assigns(vvar) assigns.push "#{ ref = o.scope.freeVariable 'ref' } = #{vvar}" vvar = ref for obj, i in objects # A regular array pattern-match. idx = i if isObject if obj instanceof Assign # A regular object pattern-match. {variable: {base: idx}, value: obj} = obj else # A shorthand `{a, b, @c} = val` pattern-match. if obj.base instanceof Parens [obj, idx] = new Value(obj.unwrapAll()).cacheReference o else idx = if obj.this then obj.properties[0].name else obj if not splat and obj instanceof Splat name = obj.name.unwrap().value obj = obj.unwrap() val = "#{olen} <= #{vvar}.length ? #{ utility 'slice' }.call(#{vvar}, #{i}" if rest = olen - i - 1 ivar = o.scope.freeVariable 'i' val += ", #{ivar} = #{vvar}.length - #{rest}) : (#{ivar} = #{i}, [])" else val += ") : []" val = new Literal val splat = "#{ivar}++" else name = obj.unwrap().value if obj instanceof Splat obj = obj.name.compile o throw new SyntaxError \ "multiple splats are disallowed in an assignment: #{obj}..." if typeof idx is 'number' idx = new Literal splat or idx acc = no else acc = isObject and IDENTIFIER.test idx.unwrap().value or 0 val = new Value new Literal(vvar), [new (if acc then Access else Index) idx] if name? and name in RESERVED throw new SyntaxError "assignment to a reserved word: #{obj.compile o} = #{val.compile o}" assigns.push new Assign(obj, val, null, param: @param, subpattern: yes).compile o, LEVEL_LIST assigns.push vvar unless top or @subpattern code = assigns.join ', ' if o.level < LEVEL_LIST then code else "(#{code})" # When compiling a conditional assignment, take care to ensure that the # operands are only evaluated once, even though we have to reference them # more than once. compileConditional: (o) -> [left, right] = @variable.cacheReference o # Disallow conditional assignment of undefined variables. if not left.properties.length and left.base instanceof Literal and left.base.value != "this" and not o.scope.check left.base.value throw new Error "the variable \"#{left.base.value}\" can't be assigned with #{@context} because it has not been defined." if "?" in @context then o.isExistentialEquals = true new Op(@context[...-1], left, new Assign(right, @value, '=') ).compile o # Compile the assignment from an array splice literal, using JavaScript's # `Array#splice` method. compileSplice: (o) -> {range: {from, to, exclusive}} = @variable.properties.pop() name = @variable.compile o [fromDecl, fromRef] = from?.cache(o, LEVEL_OP) or ['0', '0'] if to if from?.isSimpleNumber() and to.isSimpleNumber() to = +to.compile(o) - +fromRef to += 1 unless exclusive else to = to.compile(o, LEVEL_ACCESS) + ' - ' + fromRef to += ' + 1' unless exclusive else to = "9e9" [valDef, valRef] = @value.cache o, LEVEL_LIST code = "[].splice.apply(#{name}, [#{fromDecl}, #{to}].concat(#{valDef})), #{valRef}" if o.level > LEVEL_TOP then "(#{code})" else code #### Code # A function definition. This is the only node that creates a new Scope. # When for the purposes of walking the contents of a function body, the Code # has no *children* -- they're within the inner scope. exports.Code = class Code extends Base constructor: (params, body, tag) -> @params = params or [] @body = body or new Block @bound = tag is 'boundfunc' @context = '_this' if @bound children: ['params', 'body'] isStatement: -> !!@ctor jumps: NO # Compilation creates a new scope unless explicitly asked to share with the # outer scope. Handles splat parameters in the parameter list by peeking at # the JavaScript `arguments` object. If the function is bound with the `=>` # arrow, generates a wrapper that saves the current value of `this` through # a closure. compileNode: (o) -> o.scope = new Scope o.scope, @body, this o.scope.shared = del(o, 'sharedScope') o.indent += TAB delete o.bare delete o.isExistentialEquals params = [] exprs = [] for name in @paramNames() # this step must be performed before the others unless o.scope.check name then o.scope.parameter name for param in @params when param.splat for {name: p} in @params if p.this then p = p.properties[0].name if p.value then o.scope.add p.value, 'var', yes splats = new Assign new Value(new Arr(p.asReference o for p in @params)), new Value new Literal 'arguments' break for param in @params if param.isComplex() val = ref = param.asReference o val = new Op '?', ref, param.value if param.value exprs.push new Assign new Value(param.name), val, '=', param: yes else ref = param if param.value lit = new Literal ref.name.value + ' == null' val = new Assign new Value(param.name), param.value, '=' exprs.push new If lit, val params.push ref unless splats wasEmpty = @body.isEmpty() exprs.unshift splats if splats @body.expressions.unshift exprs... if exprs.length o.scope.parameter params[i] = p.compile o for p, i in params uniqs = [] for name in @paramNames() throw SyntaxError "multiple parameters named '#{name}'" if name in uniqs uniqs.push name @body.makeReturn() unless wasEmpty or @noReturn if @bound if o.scope.parent.method?.bound @bound = @context = o.scope.parent.method.context else if not @static o.scope.parent.assign '_this', 'this' idt = o.indent code = 'function' code += ' ' + @name if @ctor code += '(' + params.join(', ') + ') {' code += "\n#{ @body.compileWithDeclarations o }\n#{@tab}" unless @body.isEmpty() code += '}' return @tab + code if @ctor if @front or (o.level >= LEVEL_ACCESS) then "(#{code})" else code # A list of parameter names, excluding those generated by the compiler. paramNames: -> names = [] names.push param.names()... for param in @params names # Short-circuit `traverseChildren` method to prevent it from crossing scope boundaries # unless `crossScope` is `true`. traverseChildren: (crossScope, func) -> super(crossScope, func) if crossScope #### Param # A parameter in a function definition. Beyond a typical Javascript parameter, # these parameters can also attach themselves to the context of the function, # as well as be a splat, gathering up a group of parameters into an array. exports.Param = class Param extends Base constructor: (@name, @value, @splat) -> if (name = @name.unwrapAll().value) in STRICT_PROSCRIBED throw SyntaxError "parameter name \"#{name}\" is not allowed" children: ['name', 'value'] compile: (o) -> @name.compile o, LEVEL_LIST asReference: (o) -> return @reference if @reference node = @name if node.this node = node.properties[0].name if node.value.reserved node = new Literal o.scope.freeVariable node.value else if node.isComplex() node = new Literal o.scope.freeVariable 'arg' node = new Value node node = new Splat node if @splat @reference = node isComplex: -> @name.isComplex() # Finds the name or names of a `Param`; useful for detecting duplicates. # In a sense, a destructured parameter represents multiple JS parameters, # thus this method returns an `Array` of names. # Reserved words used as param names, as well as the Object and Array # literals used for destructured params, get a compiler generated name # during the `Code` compilation step, so this is necessarily an incomplete # list of a parameter's names. names: (name = @name)-> atParam = (obj) -> {value} = obj.properties[0].name return if value.reserved then [] else [value] # * simple literals `foo` return [name.value] if name instanceof Literal # * at-params `@foo` return atParam(name) if name instanceof Value names = [] for obj in name.objects # * assignments within destructured parameters `{foo:bar}` if obj instanceof Assign names.push obj.value.unwrap().value # * splats within destructured parameters `[xs...]` else if obj instanceof Splat names.push obj.name.unwrap().value else if obj instanceof Value # * destructured parameters within destructured parameters `[{a}]` if obj.isArray() or obj.isObject() names.push @names(obj.base)... # * at-params within destructured parameters `{@foo}` else if obj.this names.push atParam(obj)... # * simple destructured parameters {foo} else names.push obj.base.value else throw SyntaxError "illegal parameter #{obj.compile()}" names #### Splat # A splat, either as a parameter to a function, an argument to a call, # or as part of a destructuring assignment. exports.Splat = class Splat extends Base children: ['name'] isAssignable: YES constructor: (name) -> @name = if name.compile then name else new Literal name assigns: (name) -> @name.assigns name compile: (o) -> if @index? then @compileParam o else @name.compile o unwrap: -> @name # Utility function that converts an arbitrary number of elements, mixed with # splats, to a proper array. @compileSplattedArray: (o, list, apply) -> index = -1 continue while (node = list[++index]) and node not instanceof Splat return '' if index >= list.length if list.length is 1 code = list[0].compile o, LEVEL_LIST return code if apply return "#{ utility 'slice' }.call(#{code})" args = list[index..] for node, i in args code = node.compile o, LEVEL_LIST args[i] = if node instanceof Splat then "#{ utility 'slice' }.call(#{code})" else "[#{code}]" return args[0] + ".concat(#{ args[1..].join ', ' })" if index is 0 base = (node.compile o, LEVEL_LIST for node in list[...index]) "[#{ base.join ', ' }].concat(#{ args.join ', ' })" #### While # A while loop, the only sort of low-level loop exposed by CoffeeScript. From # it, all other loops can be manufactured. Useful in cases where you need more # flexibility or more speed than a comprehension can provide. exports.While = class While extends Base constructor: (condition, options) -> @condition = if options?.invert then condition.invert() else condition @guard = options?.guard children: ['condition', 'guard', 'body'] isStatement: YES makeReturn: (res) -> if res super else @returns = not @jumps loop: yes this addBody: (@body) -> this jumps: -> {expressions} = @body return no unless expressions.length for node in expressions return node if node.jumps loop: yes no # The main difference from a JavaScript *while* is that the CoffeeScript # *while* can be used as a part of a larger expression -- while loops may # return an array containing the computed result of each iteration. compileNode: (o) -> o.indent += TAB set = '' {body} = this if body.isEmpty() body = '' else if @returns body.makeReturn rvar = o.scope.freeVariable 'results' set = "#{@tab}#{rvar} = [];\n" if @guard if body.expressions.length > 1 body.expressions.unshift new If (new Parens @guard).invert(), new Literal "continue" else body = Block.wrap [new If @guard, body] if @guard body = "\n#{ body.compile o, LEVEL_TOP }\n#{@tab}" code = set + @tab + "while (#{ @condition.compile o, LEVEL_PAREN }) {#{body}}" if @returns code += "\n#{@tab}return #{rvar};" code #### Op # Simple Arithmetic and logical operations. Performs some conversion from # CoffeeScript operations into their JavaScript equivalents. exports.Op = class Op extends Base constructor: (op, first, second, flip ) -> return new In first, second if op is 'in' if op is 'do' return @generateDo first if op is 'new' return first.newInstance() if first instanceof Call and not first.do and not first.isNew first = new Parens first if first instanceof Code and first.bound or first.do @operator = CONVERSIONS[op] or op @first = first @second = second @flip = !!flip return this # The map of conversions from CoffeeScript to JavaScript symbols. CONVERSIONS = '==': '===' '!=': '!==' 'of': 'in' # The map of invertible operators. INVERSIONS = '!==': '===' '===': '!==' children: ['first', 'second'] isSimpleNumber: NO isUnary: -> not @second isComplex: -> not (@isUnary() and (@operator in ['+', '-'])) or @first.isComplex() # Am I capable of # [Python-style comparison chaining](http://docs.python.org/reference/expressions.html#notin)? isChainable: -> @operator in ['<', '>', '>=', '<=', '===', '!=='] invert: -> if @isChainable() and @first.isChainable() allInvertable = yes curr = this while curr and curr.operator allInvertable and= (curr.operator of INVERSIONS) curr = curr.first return new Parens(this).invert() unless allInvertable curr = this while curr and curr.operator curr.invert = !curr.invert curr.operator = INVERSIONS[curr.operator] curr = curr.first this else if op = INVERSIONS[@operator] @operator = op if @first.unwrap() instanceof Op @first.invert() this else if @second new Parens(this).invert() else if @operator is '!' and (fst = @first.unwrap()) instanceof Op and fst.operator in ['!', 'in', 'instanceof'] fst else new Op '!', this unfoldSoak: (o) -> @operator in ['++', '--', 'delete'] and unfoldSoak o, this, 'first' generateDo: (exp) -> passedParams = [] func = if exp instanceof Assign and (ref = exp.value.unwrap()) instanceof Code ref else exp for param in func.params or [] if param.value passedParams.push param.value delete param.value else passedParams.push param call = new Call exp, passedParams call.do = yes call compileNode: (o) -> isChain = @isChainable() and @first.isChainable() # In chains, there's no need to wrap bare obj literals in parens, # as the chained expression is wrapped. @first.front = @front unless isChain if @operator is 'delete' and o.scope.check(@first.unwrapAll().value) throw SyntaxError 'delete operand may not be argument or var' if @operator in ['--', '++'] and @first.unwrapAll().value in STRICT_PROSCRIBED throw SyntaxError 'prefix increment/decrement may not have eval or arguments operand' return @compileUnary o if @isUnary() return @compileChain o if isChain return @compileExistence o if @operator is '?' code = @first.compile(o, LEVEL_OP) + ' ' + @operator + ' ' + @second.compile(o, LEVEL_OP) if o.level <= LEVEL_OP then code else "(#{code})" # Mimic Python's chained comparisons when multiple comparison operators are # used sequentially. For example: # # bin/coffee -e 'console.log 50 < 65 > 10' # true compileChain: (o) -> [@first.second, shared] = @first.second.cache o fst = @first.compile o, LEVEL_OP code = "#{fst} #{if @invert then '&&' else '||'} #{ shared.compile o } #{@operator} #{ @second.compile o, LEVEL_OP }" "(#{code})" compileExistence: (o) -> if @first.isComplex() ref = new Literal o.scope.freeVariable 'ref' fst = new Parens new Assign ref, @first else fst = @first ref = fst new If(new Existence(fst), ref, type: 'if').addElse(@second).compile o # Compile a unary **Op**. compileUnary: (o) -> if o.level >= LEVEL_ACCESS return (new Parens this).compile o parts = [op = @operator] plusMinus = op in ['+', '-'] parts.push ' ' if op in ['new', 'typeof', 'delete'] or plusMinus and @first instanceof Op and @first.operator is op if (plusMinus && @first instanceof Op) or (op is 'new' and @first.isStatement o) @first = new Parens @first parts.push @first.compile o, LEVEL_OP parts.reverse() if @flip parts.join '' toString: (idt) -> super idt, @constructor.name + ' ' + @operator #### In exports.In = class In extends Base constructor: (@object, @array) -> children: ['object', 'array'] invert: NEGATE compileNode: (o) -> if @array instanceof Value and @array.isArray() for obj in @array.base.objects when obj instanceof Splat hasSplat = yes break # `compileOrTest` only if we have an array literal with no splats return @compileOrTest o unless hasSplat @compileLoopTest o compileOrTest: (o) -> return "#{!!@negated}" if @array.base.objects.length is 0 [sub, ref] = @object.cache o, LEVEL_OP [cmp, cnj] = if @negated then [' !== ', ' && '] else [' === ', ' || '] tests = for item, i in @array.base.objects (if i then ref else sub) + cmp + item.compile o, LEVEL_ACCESS tests = tests.join cnj if o.level < LEVEL_OP then tests else "(#{tests})" compileLoopTest: (o) -> [sub, ref] = @object.cache o, LEVEL_LIST code = utility('indexOf') + ".call(#{ @array.compile o, LEVEL_LIST }, #{ref}) " + if @negated then '< 0' else '>= 0' return code if sub is ref code = sub + ', ' + code if o.level < LEVEL_LIST then code else "(#{code})" toString: (idt) -> super idt, @constructor.name + if @negated then '!' else '' #### Try # A classic *try/catch/finally* block. exports.Try = class Try extends Base constructor: (@attempt, @error, @recovery, @ensure) -> children: ['attempt', 'recovery', 'ensure'] isStatement: YES jumps: (o) -> @attempt.jumps(o) or @recovery?.jumps(o) makeReturn: (res) -> @attempt = @attempt .makeReturn res if @attempt @recovery = @recovery.makeReturn res if @recovery this # Compilation is more or less as you would expect -- the *finally* clause # is optional, the *catch* is not. compileNode: (o) -> o.indent += TAB errorPart = if @error then " (#{ @error.compile o }) " else ' ' tryPart = @attempt.compile o, LEVEL_TOP catchPart = if @recovery if @error.value in STRICT_PROSCRIBED throw SyntaxError "catch variable may not be \"#{@error.value}\"" o.scope.add @error.value, 'param' unless o.scope.check @error.value " catch#{errorPart}{\n#{ @recovery.compile o, LEVEL_TOP }\n#{@tab}}" else unless @ensure or @recovery ' catch (_error) {}' ensurePart = if @ensure then " finally {\n#{ @ensure.compile o, LEVEL_TOP }\n#{@tab}}" else '' """#{@tab}try { #{tryPart} #{@tab}}#{ catchPart or '' }#{ensurePart}""" #### Throw # Simple node to throw an exception. exports.Throw = class Throw extends Base constructor: (@expression) -> children: ['expression'] isStatement: YES jumps: NO # A **Throw** is already a return, of sorts... makeReturn: THIS compileNode: (o) -> @tab + "throw #{ @expression.compile o };" #### Existence # Checks a variable for existence -- not *null* and not *undefined*. This is # similar to `.nil?` in Ruby, and avoids having to consult a JavaScript truth # table. exports.Existence = class Existence extends Base constructor: (@expression) -> children: ['expression'] invert: NEGATE compileNode: (o) -> @expression.front = @front code = @expression.compile o, LEVEL_OP if IDENTIFIER.test(code) and not o.scope.check code [cmp, cnj] = if @negated then ['===', '||'] else ['!==', '&&'] code = "typeof #{code} #{cmp} \"undefined\" #{cnj} #{code} #{cmp} null" else # do not use strict equality here; it will break existing code code = "#{code} #{if @negated then '==' else '!='} null" if o.level <= LEVEL_COND then code else "(#{code})" #### Parens # An extra set of parentheses, specified explicitly in the source. At one time # we tried to clean up the results by detecting and removing redundant # parentheses, but no longer -- you can put in as many as you please. # # Parentheses are a good way to force any statement to become an expression. exports.Parens = class Parens extends Base constructor: (@body) -> children: ['body'] unwrap : -> @body isComplex : -> @body.isComplex() compileNode: (o) -> expr = @body.unwrap() if expr instanceof Value and expr.isAtomic() expr.front = @front return expr.compile o code = expr.compile o, LEVEL_PAREN bare = o.level < LEVEL_OP and (expr instanceof Op or expr instanceof Call or (expr instanceof For and expr.returns)) if bare then code else "(#{code})" #### For # CoffeeScript's replacement for the *for* loop is our array and object # comprehensions, that compile into *for* loops here. They also act as an # expression, able to return the result of each filtered iteration. # # Unlike Python array comprehensions, they can be multi-line, and you can pass # the current index of the loop as a second parameter. Unlike Ruby blocks, # you can map and filter in a single pass. exports.For = class For extends While constructor: (body, source) -> {@source, @guard, @step, @name, @index} = source @body = Block.wrap [body] @own = !!source.own @object = !!source.object [@name, @index] = [@index, @name] if @object throw SyntaxError 'index cannot be a pattern matching expression' if @index instanceof Value @range = @source instanceof Value and @source.base instanceof Range and not @source.properties.length @pattern = @name instanceof Value throw SyntaxError 'indexes do not apply to range loops' if @range and @index throw SyntaxError 'cannot pattern match over range loops' if @range and @pattern @returns = false children: ['body', 'source', 'guard', 'step'] # Welcome to the hairiest method in all of CoffeeScript. Handles the inner # loop, filtering, stepping, and result saving for array, object, and range # comprehensions. Some of the generated code can be shared in common, and # some cannot. compileNode: (o) -> body = Block.wrap [@body] lastJumps = last(body.expressions)?.jumps() @returns = no if lastJumps and lastJumps instanceof Return source = if @range then @source.base else @source scope = o.scope name = @name and @name.compile o, LEVEL_LIST index = @index and @index.compile o, LEVEL_LIST scope.find(name) if name and not @pattern scope.find(index) if index rvar = scope.freeVariable 'results' if @returns ivar = (@object and index) or scope.freeVariable 'i' kvar = (@range and name) or index or ivar kvarAssign = if kvar isnt ivar then "#{kvar} = " else "" # the `_by` variable is created twice in `Range`s if we don't prevent it from being declared here stepvar = scope.freeVariable "step" if @step and not @range name = ivar if @pattern varPart = '' guardPart = '' defPart = '' idt1 = @tab + TAB if @range forPart = source.compile merge(o, {index: ivar, name, @step}) else svar = @source.compile o, LEVEL_LIST if (name or @own) and not IDENTIFIER.test svar defPart = "#{@tab}#{ref = scope.freeVariable 'ref'} = #{svar};\n" svar = ref if name and not @pattern namePart = "#{name} = #{svar}[#{kvar}]" unless @object lvar = scope.freeVariable 'len' forVarPart = "#{kvarAssign}#{ivar} = 0, #{lvar} = #{svar}.length" forVarPart += ", #{stepvar} = #{@step.compile o, LEVEL_OP}" if @step stepPart = "#{kvarAssign}#{if @step then "#{ivar} += #{stepvar}" else (if kvar isnt ivar then "++#{ivar}" else "#{ivar}++")}" forPart = "#{forVarPart}; #{ivar} < #{lvar}; #{stepPart}" if @returns resultPart = "#{@tab}#{rvar} = [];\n" returnResult = "\n#{@tab}return #{rvar};" body.makeReturn rvar if @guard if body.expressions.length > 1 body.expressions.unshift new If (new Parens @guard).invert(), new Literal "continue" else body = Block.wrap [new If @guard, body] if @guard if @pattern body.expressions.unshift new Assign @name, new Literal "#{svar}[#{kvar}]" defPart += @pluckDirectCall o, body varPart = "\n#{idt1}#{namePart};" if namePart if @object forPart = "#{kvar} in #{svar}" guardPart = "\n#{idt1}if (!#{utility 'hasProp'}.call(#{svar}, #{kvar})) continue;" if @own body = body.compile merge(o, indent: idt1), LEVEL_TOP body = '\n' + body + '\n' if body """ #{defPart}#{resultPart or ''}#{@tab}for (#{forPart}) {#{guardPart}#{varPart}#{body}#{@tab}}#{returnResult or ''} """ pluckDirectCall: (o, body) -> defs = '' for expr, idx in body.expressions expr = expr.unwrapAll() continue unless expr instanceof Call val = expr.variable.unwrapAll() continue unless (val instanceof Code) or (val instanceof Value and val.base?.unwrapAll() instanceof Code and val.properties.length is 1 and val.properties[0].name?.value in ['call', 'apply']) fn = val.base?.unwrapAll() or val ref = new Literal o.scope.freeVariable 'fn' base = new Value ref if val.base [val.base, base] = [base, val] body.expressions[idx] = new Call base, expr.args defs += @tab + new Assign(ref, fn).compile(o, LEVEL_TOP) + ';\n' defs #### Switch # A JavaScript *switch* statement. Converts into a returnable expression on-demand. exports.Switch = class Switch extends Base constructor: (@subject, @cases, @otherwise) -> children: ['subject', 'cases', 'otherwise'] isStatement: YES jumps: (o = {block: yes}) -> for [conds, block] in @cases return block if block.jumps o @otherwise?.jumps o makeReturn: (res) -> pair[1].makeReturn res for pair in @cases @otherwise or= new Block [new Literal 'void 0'] if res @otherwise?.makeReturn res this compileNode: (o) -> idt1 = o.indent + TAB idt2 = o.indent = idt1 + TAB code = @tab + "switch (#{ @subject?.compile(o, LEVEL_PAREN) or false }) {\n" for [conditions, block], i in @cases for cond in flatten [conditions] cond = cond.invert() unless @subject code += idt1 + "case #{ cond.compile o, LEVEL_PAREN }:\n" code += body + '\n' if body = block.compile o, LEVEL_TOP break if i is @cases.length - 1 and not @otherwise expr = @lastNonComment block.expressions continue if expr instanceof Return or (expr instanceof Literal and expr.jumps() and expr.value isnt 'debugger') code += idt2 + 'break;\n' code += idt1 + "default:\n#{ @otherwise.compile o, LEVEL_TOP }\n" if @otherwise and @otherwise.expressions.length code + @tab + '}' #### If # *If/else* statements. Acts as an expression by pushing down requested returns # to the last line of each clause. # # Single-expression **Ifs** are compiled into conditional operators if possible, # because ternaries are already proper expressions, and don't need conversion. exports.If = class If extends Base constructor: (condition, @body, options = {}) -> @condition = if options.type is 'unless' then condition.invert() else condition @elseBody = null @isChain = false {@soak} = options children: ['condition', 'body', 'elseBody'] bodyNode: -> @body?.unwrap() elseBodyNode: -> @elseBody?.unwrap() # Rewrite a chain of **Ifs** to add a default case as the final *else*. addElse: (elseBody) -> if @isChain @elseBodyNode().addElse elseBody else @isChain = elseBody instanceof If @elseBody = @ensureBlock elseBody this # The **If** only compiles into a statement if either of its bodies needs # to be a statement. Otherwise a conditional operator is safe. isStatement: (o) -> o?.level is LEVEL_TOP or @bodyNode().isStatement(o) or @elseBodyNode()?.isStatement(o) jumps: (o) -> @body.jumps(o) or @elseBody?.jumps(o) compileNode: (o) -> if @isStatement o then @compileStatement o else @compileExpression o makeReturn: (res) -> @elseBody or= new Block [new Literal 'void 0'] if res @body and= new Block [@body.makeReturn res] @elseBody and= new Block [@elseBody.makeReturn res] this ensureBlock: (node) -> if node instanceof Block then node else new Block [node] # Compile the `If` as a regular *if-else* statement. Flattened chains # force inner *else* bodies into statement form. compileStatement: (o) -> child = del o, 'chainChild' exeq = del o, 'isExistentialEquals' if exeq return new If(@condition.invert(), @elseBodyNode(), type: 'if').compile o cond = @condition.compile o, LEVEL_PAREN o.indent += TAB body = @ensureBlock(@body) ifPart = "if (#{cond}) {\n#{body.compile(o)}\n#{@tab}}" ifPart = @tab + ifPart unless child return ifPart unless @elseBody ifPart + ' else ' + if @isChain o.indent = @tab o.chainChild = yes @elseBody.unwrap().compile o, LEVEL_TOP else "{\n#{ @elseBody.compile o, LEVEL_TOP }\n#{@tab}}" # Compile the `If` as a conditional operator. compileExpression: (o) -> cond = @condition.compile o, LEVEL_COND body = @bodyNode().compile o, LEVEL_LIST alt = if @elseBodyNode() then @elseBodyNode().compile(o, LEVEL_LIST) else 'void 0' code = "#{cond} ? #{body} : #{alt}" if o.level >= LEVEL_COND then "(#{code})" else code unfoldSoak: -> @soak and this # Faux-Nodes # ---------- # Faux-nodes are never created by the grammar, but are used during code # generation to generate other combinations of nodes. #### Closure # A faux-node used to wrap an expressions body in a closure. Closure = # Wrap the expressions body, unless it contains a pure statement, # in which case, no dice. If the body mentions `this` or `arguments`, # then make sure that the closure wrapper preserves the original values. wrap: (expressions, statement, noReturn) -> return expressions if expressions.jumps() func = new Code [], Block.wrap [expressions] args = [] if (mentionsArgs = expressions.contains @literalArgs) or expressions.contains @literalThis meth = new Literal if mentionsArgs then 'apply' else 'call' args = [new Literal 'this'] args.push new Literal 'arguments' if mentionsArgs func = new Value func, [new Access meth] func.noReturn = noReturn call = new Call func, args if statement then Block.wrap [call] else call literalArgs: (node) -> node instanceof Literal and node.value is 'arguments' and not node.asKey literalThis: (node) -> (node instanceof Literal and node.value is 'this' and not node.asKey) or (node instanceof Code and node.bound) or (node instanceof Call and node.isSuper) # Unfold a node's child if soak, then tuck the node under created `If` unfoldSoak = (o, parent, name) -> return unless ifn = parent[name].unfoldSoak o parent[name] = ifn.body ifn.body = new Value parent ifn # Constants # --------- UTILITIES = # Correctly set up a prototype chain for inheritance, including a reference # to the superclass for `super()` calls, and copies of any static properties. extends: -> """ function(child, parent) { for (var key in parent) { if (#{utility 'hasProp'}.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; } """ # Create a function bound to the current value of "this". bind: -> ''' function(fn, me){ return function(){ return fn.apply(me, arguments); }; } ''' # Discover if an item is in an array. indexOf: -> """ [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; } """ # Shortcuts to speed up the lookup time for native functions. hasProp: -> '{}.hasOwnProperty' slice : -> '[].slice' # Levels indicate a node's position in the AST. Useful for knowing if # parens are necessary or superfluous. LEVEL_TOP = 1 # ...; LEVEL_PAREN = 2 # (...) LEVEL_LIST = 3 # [...] LEVEL_COND = 4 # ... ? x : y LEVEL_OP = 5 # !... LEVEL_ACCESS = 6 # ...[0] # Tabs are two spaces for pretty printing. TAB = ' ' IDENTIFIER_STR = "[$A-Za-z_\\x7f-\\uffff][$\\w\\x7f-\\uffff]*" IDENTIFIER = /// ^ #{IDENTIFIER_STR} $ /// SIMPLENUM = /^[+-]?\d+$/ METHOD_DEF = /// ^ (?: (#{IDENTIFIER_STR}) \.prototype (?: \.(#{IDENTIFIER_STR}) | \[("(?:[^\\"\r\n]|\\.)*"|'(?:[^\\'\r\n]|\\.)*')\] | \[(0x[\da-fA-F]+ | \d*\.?\d+ (?:[eE][+-]?\d+)?)\] ) ) | (#{IDENTIFIER_STR}) $ /// # Is a literal value a string? IS_STRING = /^['"]/ # Utility Functions # ----------------- # Helper for ensuring that utility functions are assigned at the top level. utility = (name) -> ref = "__#{name}" Scope.root.assign ref, UTILITIES[name]() ref multident = (code, tab) -> code = code.replace /\n/g, '$&' + tab code.replace /\s+$/, '' coffee-script-1.4.0/src/optparse.coffee000066400000000000000000000077161204160075300200530ustar00rootroot00000000000000# A simple **OptionParser** class to parse option flags from the command-line. # Use it like so: # # 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: # # [short-flag, long-flag, description] # # Along with an an optional banner for the usage help. constructor: (rules, @banner) -> @rules = buildRules rules # Parse the list of arguments, populating an `options` object with all of the # specified options, and return it. Options after the first non-option # argument are treated as arguments. `options.arguments` will be an array # containing the remaining 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. parse: (args) -> options = arguments: [] skippingArgument = no originalArgs = args args = normalizeArguments args for arg, i in args if skippingArgument skippingArgument = no continue if arg is '--' pos = originalArgs.indexOf '--' options.arguments = options.arguments.concat originalArgs[(pos + 1)..] break isOption = !!(arg.match(LONG_FLAG) or arg.match(SHORT_FLAG)) # the CS option parser is a little odd; options after the first # non-option argument are treated as non-option arguments themselves seenNonOptionArg = options.arguments.length > 0 unless seenNonOptionArg matchedRule = no for rule in @rules if rule.shortFlag is arg or rule.longFlag is arg value = true if rule.hasArgument skippingArgument = yes value = args[i + 1] options[rule.name] = if rule.isList then (options[rule.name] or []).concat value else value matchedRule = yes break throw new Error "unrecognized option: #{arg}" if isOption and not matchedRule if seenNonOptionArg or not isOption options.arguments.push arg options # Return the help text for this **OptionParser**, listing and describing all # of the valid options, for `--help` and such. help: -> lines = [] lines.unshift "#{@banner}\n" if @banner for rule in @rules spaces = 15 - rule.longFlag.length spaces = if spaces > 0 then Array(spaces + 1).join(' ') else '' letPart = if rule.shortFlag then rule.shortFlag + ', ' else ' ' lines.push ' ' + letPart + rule.longFlag + spaces + rule.description "\n#{ lines.join('\n') }\n" # Helpers # ------- # Regex matchers for option flags. LONG_FLAG = /^(--\w[\w\-]*)/ SHORT_FLAG = /^(-\w)$/ MULTI_FLAG = /^-(\w{2,})/ OPTIONAL = /\[(\w+(\*?))\]/ # Build and return the list of option rules. If the optional *short-flag* is # unspecified, leave it out by padding with `null`. buildRules = (rules) -> for tuple in rules tuple.unshift null if tuple.length < 3 buildRule tuple... # Build a rule from a `-o` short flag, a `--output [DIR]` long flag, and the # description of what the option does. buildRule = (shortFlag, longFlag, description, options = {}) -> match = longFlag.match(OPTIONAL) longFlag = longFlag.match(LONG_FLAG)[1] { name: longFlag.substr 2 shortFlag: shortFlag longFlag: longFlag description: description hasArgument: !!(match and match[1]) isList: !!(match and match[2]) } # Normalize arguments by expanding merged flags into multiple flags. This allows # you to have `-wl` be the same as `--watch --lint`. normalizeArguments = (args) -> args = args[..] result = [] for arg in args if match = arg.match MULTI_FLAG result.push '-' + l for l in match[1].split '' else result.push arg result coffee-script-1.4.0/src/repl.coffee000066400000000000000000000133571204160075300171560ustar00rootroot00000000000000# 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> console.log "#{num} bottles of beer" for num in [99..1] # Start by opening up `stdin` and `stdout`. stdin = process.openStdin() stdout = process.stdout # Require the **coffee-script** module to get access to the compiler. CoffeeScript = require './coffee-script' readline = require 'readline' {inspect} = require 'util' {Script} = require 'vm' Module = require 'module' # REPL Setup # Config REPL_PROMPT = 'coffee> ' REPL_PROMPT_MULTILINE = '------> ' REPL_PROMPT_CONTINUATION = '......> ' enableColours = no unless process.platform is 'win32' enableColours = not process.env.NODE_DISABLE_COLORS # Log an error. error = (err) -> stdout.write (err.stack or err.toString()) + '\n' ## Autocompletion # Regexes to match complete-able bits of text. ACCESSOR = /\s*([\w\.]+)(?:\.(\w*))$/ SIMPLEVAR = /(\w+)$/i # Returns a list of completions, and the completed text. autocomplete = (text) -> completeAttribute(text) or completeVariable(text) or [[], text] # Attempt to autocomplete a chained dotted attribute: `one.two.three`. completeAttribute = (text) -> if match = text.match ACCESSOR [all, obj, prefix] = match try obj = Script.runInThisContext obj catch e return return unless obj? obj = Object obj candidates = Object.getOwnPropertyNames obj while obj = Object.getPrototypeOf obj for key in Object.getOwnPropertyNames obj when key not in candidates candidates.push key completions = getCompletions prefix, candidates [completions, prefix] # Attempt to autocomplete an in-scope free variable: `one`. completeVariable = (text) -> free = text.match(SIMPLEVAR)?[1] free = "" if text is "" if free? vars = Script.runInThisContext 'Object.getOwnPropertyNames(Object(this))' keywords = (r for r in CoffeeScript.RESERVED when r[..1] isnt '__') candidates = vars for key in keywords when key not in candidates candidates.push key completions = getCompletions free, candidates [completions, free] # Return elements of candidates for which `prefix` is a prefix. getCompletions = (prefix, candidates) -> el for el in candidates when 0 is el.indexOf prefix # Make sure that uncaught exceptions don't kill the REPL. process.on 'uncaughtException', error # The current backlog of multi-line code. backlog = '' # The main REPL function. **run** is called every time a line of code is entered. # Attempt to evaluate the command. If there's an exception, print it out instead # of exiting. run = (buffer) -> # remove single-line comments buffer = buffer.replace /(^|[\r\n]+)(\s*)##?(?:[^#\r\n][^\r\n]*|)($|[\r\n])/, "$1$2$3" # remove trailing newlines buffer = buffer.replace /[\r\n]+$/, "" if multilineMode backlog += "#{buffer}\n" repl.setPrompt REPL_PROMPT_CONTINUATION repl.prompt() return if !buffer.toString().trim() and !backlog repl.prompt() return code = backlog += buffer if code[code.length - 1] is '\\' backlog = "#{backlog[...-1]}\n" repl.setPrompt REPL_PROMPT_CONTINUATION repl.prompt() return repl.setPrompt REPL_PROMPT backlog = '' try _ = global._ returnValue = CoffeeScript.eval "_=(#{code}\n)", { filename: 'repl' modulename: 'repl' } if returnValue is undefined global._ = _ repl.output.write "#{inspect returnValue, no, 2, enableColours}\n" catch err error err repl.prompt() if stdin.readable and stdin.isRaw # handle piped input pipedInput = '' repl = prompt: -> stdout.write @_prompt setPrompt: (p) -> @_prompt = p input: stdin output: stdout on: -> stdin.on 'data', (chunk) -> pipedInput += chunk return unless /\n/.test pipedInput lines = pipedInput.split "\n" pipedInput = lines[lines.length - 1] for line in lines[...-1] when line stdout.write "#{line}\n" run line return stdin.on 'end', -> for line in pipedInput.trim().split "\n" when line stdout.write "#{line}\n" run line stdout.write '\n' process.exit 0 else # Create the REPL by listening to **stdin**. if readline.createInterface.length < 3 repl = readline.createInterface stdin, autocomplete stdin.on 'data', (buffer) -> repl.write buffer else repl = readline.createInterface stdin, stdout, autocomplete multilineMode = off # Handle multi-line mode switch repl.input.on 'keypress', (char, key) -> # test for Ctrl-v return unless key and key.ctrl and not key.meta and not key.shift and key.name is 'v' cursorPos = repl.cursor repl.output.cursorTo 0 repl.output.clearLine 1 multilineMode = not multilineMode repl._line() if not multilineMode and backlog backlog = '' repl.setPrompt (newPrompt = if multilineMode then REPL_PROMPT_MULTILINE else REPL_PROMPT) repl.prompt() repl.output.cursorTo newPrompt.length + (repl.cursor = cursorPos) # Handle Ctrl-d press at end of last line in multiline mode repl.input.on 'keypress', (char, key) -> return unless multilineMode and repl.line # test for Ctrl-d return unless key and key.ctrl and not key.meta and not key.shift and key.name is 'd' multilineMode = off repl._line() repl.on 'attemptClose', -> if multilineMode multilineMode = off repl.output.cursorTo 0 repl.output.clearLine 1 repl._onLine repl.line return if backlog or repl.line backlog = '' repl.historyIndex = -1 repl.setPrompt REPL_PROMPT repl.output.write '\n(^C again to quit)' repl._line (repl.line = '') else repl.close() repl.on 'close', -> repl.output.write '\n' repl.input.destroy() repl.on 'line', run repl.setPrompt REPL_PROMPT repl.prompt() coffee-script-1.4.0/src/rewriter.coffee000066400000000000000000000267641204160075300200650ustar00rootroot00000000000000# 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, and generally clean things up. # The **Rewriter** class is used by the [Lexer](lexer.html), directly against # its internal array of tokens. class exports.Rewriter # Helpful snippet for debugging: # console.log (t[0] + '/' + t[1] for t in @tokens).join ' ' # 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. rewrite: (@tokens) -> @removeLeadingNewlines() @removeMidExpressionNewlines() @closeOpenCalls() @closeOpenIndexes() @addImplicitIndentation() @tagPostfixConditionals() @addImplicitBraces() @addImplicitParentheses() @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. scanTokens: (block) -> {tokens} = this i = 0 i += block.call this, token, i, tokens while token = tokens[i] true detectEnd: (i, condition, action) -> {tokens} = this levels = 0 while token = tokens[i] return action.call this, token, i if levels is 0 and condition.call this, token, i return action.call this, token, i - 1 if not token or levels < 0 if token[0] in EXPRESSION_START levels += 1 else if token[0] in EXPRESSION_END levels -= 1 i += 1 i - 1 # Leading newlines would introduce an ambiguity in the grammar, so we # dispatch them here. removeLeadingNewlines: -> break for [tag], i in @tokens when tag isnt 'TERMINATOR' @tokens.splice 0, i if i # Some blocks occur in the middle of expressions -- when we're expecting # this, remove their trailing newlines. removeMidExpressionNewlines: -> @scanTokens (token, i, tokens) -> return 1 unless token[0] is 'TERMINATOR' and @tag(i + 1) in EXPRESSION_CLOSE tokens.splice i, 1 0 # The lexer has tagged the opening parenthesis of a method call. Match it with # its paired close. We have the mis-nested outdent case included here for # calls that close on the same line, just before their outdent. closeOpenCalls: -> condition = (token, i) -> token[0] in [')', 'CALL_END'] or token[0] is 'OUTDENT' and @tag(i - 1) is ')' action = (token, i) -> @tokens[if token[0] is 'OUTDENT' then i - 1 else i][0] = 'CALL_END' @scanTokens (token, i) -> @detectEnd i + 1, condition, action if token[0] is 'CALL_START' 1 # The lexer has tagged the opening parenthesis of an indexing operation call. # Match it with its paired close. closeOpenIndexes: -> condition = (token, i) -> token[0] in [']', 'INDEX_END'] action = (token, i) -> token[0] = 'INDEX_END' @scanTokens (token, i) -> @detectEnd i + 1, condition, action if token[0] is 'INDEX_START' 1 # Object literals may be written with implicit braces, for simple cases. # Insert the missing braces here, so that the parser doesn't have to. addImplicitBraces: -> stack = [] start = null startsLine = null sameLine = yes startIndent = 0 startIndex = 0 condition = (token, i) -> [one, two, three] = @tokens[i + 1 .. i + 3] return no if 'HERECOMMENT' is one?[0] [tag] = token sameLine = no if tag in LINEBREAKS return ( (tag in ['TERMINATOR', 'OUTDENT'] or (tag in IMPLICIT_END and sameLine and not (i - startIndex is 1))) and ((!startsLine and @tag(i - 1) isnt ',') or not (two?[0] is ':' or one?[0] is '@' and three?[0] is ':'))) or (tag is ',' and one and one[0] not in ['IDENTIFIER', 'NUMBER', 'STRING', '@', 'TERMINATOR', 'OUTDENT'] ) action = (token, i) -> tok = @generate '}', '}', token[2] @tokens.splice i, 0, tok @scanTokens (token, i, tokens) -> if (tag = token[0]) in EXPRESSION_START stack.push [(if tag is 'INDENT' and @tag(i - 1) is '{' then '{' else tag), i] return 1 if tag in EXPRESSION_END start = stack.pop() return 1 return 1 unless tag is ':' and ((ago = @tag i - 2) is ':' or stack[stack.length - 1]?[0] isnt '{') sameLine = yes startIndex = i + 1 stack.push ['{'] idx = if ago is '@' then i - 2 else i - 1 idx -= 2 while @tag(idx - 2) is 'HERECOMMENT' prevTag = @tag(idx - 1) startsLine = not prevTag or (prevTag in LINEBREAKS) value = new String('{') value.generated = yes tok = @generate '{', value, token[2] tokens.splice idx, 0, tok @detectEnd i + 2, condition, action 2 # 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. addImplicitParentheses: -> noCall = seenSingle = seenControl = no condition = (token, i) -> [tag] = token return yes if not seenSingle and token.fromThen seenSingle = yes if tag in ['IF', 'ELSE', 'CATCH', '->', '=>', 'CLASS'] seenControl = yes if tag in ['IF', 'ELSE', 'SWITCH', 'TRY', '='] return yes if tag in ['.', '?.', '::'] and @tag(i - 1) is 'OUTDENT' not token.generated and @tag(i - 1) isnt ',' and (tag in IMPLICIT_END or (tag is 'INDENT' and not seenControl)) and (tag isnt 'INDENT' or (@tag(i - 2) not in ['CLASS', 'EXTENDS'] and @tag(i - 1) not in IMPLICIT_BLOCK and not ((post = @tokens[i + 1]) and post.generated and post[0] is '{'))) action = (token, i) -> @tokens.splice i, 0, @generate 'CALL_END', ')', token[2] @scanTokens (token, i, tokens) -> tag = token[0] noCall = yes if tag in ['CLASS', 'IF', 'FOR', 'WHILE'] [prev, current, next] = tokens[i - 1 .. i + 1] callObject = not noCall and tag is 'INDENT' and next and next.generated and next[0] is '{' and prev and prev[0] in IMPLICIT_FUNC seenSingle = no seenControl = no noCall = no if tag in LINEBREAKS token.call = yes if prev and not prev.spaced and tag is '?' return 1 if token.fromThen return 1 unless callObject or prev?.spaced and (prev.call or prev[0] in IMPLICIT_FUNC) and (tag in IMPLICIT_CALL or not (token.spaced or token.newLine) and tag in IMPLICIT_UNSPACED_CALL) tokens.splice i, 0, @generate 'CALL_START', '(', token[2] @detectEnd i + 1, condition, action prev[0] = 'FUNC_EXIST' if prev[0] is '?' 2 # 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. addImplicitIndentation: -> starter = indent = outdent = null condition = (token, i) -> token[1] isnt ';' and token[0] in SINGLE_CLOSERS and not (token[0] is 'ELSE' and starter not in ['IF', 'THEN']) action = (token, i) -> @tokens.splice (if @tag(i - 1) is ',' then i - 1 else i), 0, outdent @scanTokens (token, i, tokens) -> [tag] = token if tag is 'TERMINATOR' and @tag(i + 1) is 'THEN' tokens.splice i, 1 return 0 if tag is 'ELSE' and @tag(i - 1) isnt 'OUTDENT' tokens.splice i, 0, @indentation(token)... return 2 if tag is 'CATCH' and @tag(i + 2) in ['OUTDENT', 'TERMINATOR', 'FINALLY'] tokens.splice i + 2, 0, @indentation(token)... return 4 if tag in SINGLE_LINERS and @tag(i + 1) isnt 'INDENT' and not (tag is 'ELSE' and @tag(i + 1) is 'IF') starter = tag [indent, outdent] = @indentation token, yes indent.fromThen = true if starter is 'THEN' tokens.splice i + 1, 0, indent @detectEnd i + 2, condition, action tokens.splice i, 1 if tag is 'THEN' return 1 return 1 # Tag postfix conditionals as such, so that we can parse them with a # different precedence. tagPostfixConditionals: -> original = null condition = (token, i) -> token[0] in ['TERMINATOR', 'INDENT'] action = (token, i) -> if token[0] isnt 'INDENT' or (token.generated and not token.fromThen) original[0] = 'POST_' + original[0] @scanTokens (token, i) -> return 1 unless token[0] is 'IF' original = token @detectEnd i + 1, condition, action 1 # Generate the indentation tokens, based on another token on the same line. indentation: (token, implicit = no) -> indent = ['INDENT', 2, token[2]] outdent = ['OUTDENT', 2, token[2]] indent.generated = outdent.generated = yes if implicit [indent, outdent] # Create a generated token: one that exists due to a use of implicit syntax. generate: (tag, value, line) -> tok = [tag, value, line] tok.generated = yes tok # Look up a tag by token index. tag: (i) -> @tokens[i]?[0] # Constants # --------- # List of the token pairs that must be balanced. BALANCED_PAIRS = [ ['(', ')'] ['[', ']'] ['{', '}'] ['INDENT', 'OUTDENT'], ['CALL_START', 'CALL_END'] ['PARAM_START', 'PARAM_END'] ['INDEX_START', 'INDEX_END'] ] # The inverse mappings of `BALANCED_PAIRS` we're trying to fix up, so we can # look things up from either end. exports.INVERSES = INVERSES = {} # The tokens that signal the start/end of a balanced pair. EXPRESSION_START = [] EXPRESSION_END = [] for [left, rite] in BALANCED_PAIRS EXPRESSION_START.push INVERSES[rite] = left EXPRESSION_END .push INVERSES[left] = rite # Tokens that indicate the close of a clause of an expression. 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', '@', 'THIS'] # If preceded by an `IMPLICIT_FUNC`, indicates a function invocation. IMPLICIT_CALL = [ 'IDENTIFIER', 'NUMBER', 'STRING', 'JS', 'REGEX', 'NEW', 'PARAM_START', 'CLASS' 'IF', 'TRY', 'SWITCH', 'THIS', 'BOOL', 'NULL', 'UNDEFINED', 'UNARY', 'SUPER' '@', '->', '=>', '[', '(', '{', '--', '++' ] IMPLICIT_UNSPACED_CALL = ['+', '-'] # Tokens indicating that the implicit call must enclose a block of expressions. IMPLICIT_BLOCK = ['->', '=>', '{', '[', ','] # Tokens that always mark the end of an implicit call for single-liners. IMPLICIT_END = ['POST_IF', 'FOR', 'WHILE', 'UNTIL', 'WHEN', 'BY', 'LOOP', 'TERMINATOR'] # Single-line flavors of block expressions that have unclosed endings. # The grammar can't disambiguate them, so we insert the implicit indentation. SINGLE_LINERS = ['ELSE', '->', '=>', 'TRY', 'FINALLY', 'THEN'] SINGLE_CLOSERS = ['TERMINATOR', 'CATCH', 'FINALLY', 'ELSE', 'OUTDENT', 'LEADING_WHEN'] # Tokens that end a line. LINEBREAKS = ['TERMINATOR', 'INDENT', 'OUTDENT'] coffee-script-1.4.0/src/scope.coffee000066400000000000000000000073321204160075300173210ustar00rootroot00000000000000# 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. # Import the helpers we plan to use. {extend, last} = require './helpers' exports.Scope = class Scope # The top-level **Scope** object. @root: null # Initialize a scope with its parent, for lookups up the chain, # as well as a reference to the **Block** node it belongs to, which is # where it should declare its variables, and a reference to the function that # it wraps. constructor: (@parent, @expressions, @method) -> @variables = [{name: 'arguments', type: 'arguments'}] @positions = {} Scope.root = this unless @parent # Adds a new variable or overrides an existing one. add: (name, type, immediate) -> return @parent.add name, type, immediate if @shared and not immediate if Object::hasOwnProperty.call @positions, name @variables[@positions[name]].type = type else @positions[name] = @variables.push({name, type}) - 1 # When `super` is called, we need to find the name of the current method we're # in, so that we know how to invoke the same method of the parent class. This # can get complicated if super is being called from an inner function. # `namedMethod` will walk up the scope tree until it either finds the first # function object that has a name filled in, or bottoms out. namedMethod: -> return @method if @method.name or !@parent @parent.namedMethod() # Look up a variable name in lexical scope, and declare it if it does not # already exist. find: (name) -> return yes if @check name @add name, 'var' no # Reserve a variable name as originating from a function parameter for this # scope. No `var` required for internal references. parameter: (name) -> return if @shared and @parent.check name, yes @add name, 'param' # Just check to see if a variable has already been declared, without reserving, # walks up to the root scope. check: (name) -> !!(@type(name) or @parent?.check(name)) # Generate a temporary variable name at the given index. temporary: (name, index) -> if name.length > 1 '_' + name + if index > 1 then index - 1 else '' else '_' + (index + parseInt name, 36).toString(36).replace /\d/g, 'a' # Gets the type of a variable. type: (name) -> return v.type for v in @variables when v.name is name null # If we need to store an intermediate result, find an available name for a # compiler-generated variable. `_var`, `_var2`, and so on... freeVariable: (name, reserve=true) -> index = 0 index++ while @check((temp = @temporary name, index)) @add temp, 'var', yes if reserve temp # Ensure that an assignment is made at the top of this scope # (or at the top-level scope, if requested). assign: (name, value) -> @add name, {value, assigned: yes}, yes @hasAssignments = yes # Does this scope have any declared variables? hasDeclarations: -> !!@declaredVariables().length # Return the list of variables first declared in this scope. declaredVariables: -> realVars = [] tempVars = [] for v in @variables when v.type is 'var' (if v.name.charAt(0) is '_' then tempVars else realVars).push v.name realVars.sort().concat tempVars.sort() # Return the list of assignments that are supposed to be made at the top # of this scope. assignedVariables: -> "#{v.name} = #{v.type.value}" for v in @variables when v.type.assigned coffee-script-1.4.0/test/000077500000000000000000000000001204160075300152225ustar00rootroot00000000000000coffee-script-1.4.0/test/arrays.coffee000066400000000000000000000025761204160075300177060ustar00rootroot00000000000000# Array Literals # -------------- # * Array Literals # * Splats in Array Literals # TODO: add indexing and method invocation tests: [1][0] is 1, [].toString() test "trailing commas", -> trailingComma = [1, 2, 3,] ok (trailingComma[0] is 1) and (trailingComma[2] is 3) and (trailingComma.length is 3) trailingComma = [ 1, 2, 3, 4, 5, 6 7, 8, 9, ] (sum = (sum or 0) + n) for n in trailingComma a = [((x) -> x), ((x) -> x * x)] ok a.length is 2 test "incorrect indentation without commas", -> result = [['a'] {b: 'c'}] ok result[0][0] is 'a' ok result[1]['b'] is 'c' # Splats in Array Literals test "array splat expansions with assignments", -> nums = [1, 2, 3] list = [a = 0, nums..., b = 4] eq 0, a eq 4, b arrayEq [0,1,2,3,4], list test "mixed shorthand objects in array lists", -> arr = [ a:1 'b' c:1 ] ok arr.length is 3 ok arr[2].c is 1 arr = [b: 1, a: 2, 100] eq arr[1], 100 arr = [a:0, b:1, (1 + 1)] eq arr[1], 2 arr = [a:1, 'a', b:1, 'b'] eq arr.length, 4 eq arr[2].b, 1 eq arr[3], 'b' test "array splats with nested arrays", -> nonce = {} a = [nonce] list = [1, 2, a...] eq list[0], 1 eq list[2], nonce a = [[nonce]] list = [1, 2, a...] arrayEq list, [1, 2, [nonce]] test "#1274: `[] = a()` compiles to `false` instead of `a()`", -> a = false fn = -> a = true [] = fn() ok a coffee-script-1.4.0/test/assignment.coffee000066400000000000000000000225661204160075300205560ustar00rootroot00000000000000# Assignment # ---------- # * Assignment # * Compound Assignment # * Destructuring Assignment # * Context Property (@) Assignment # * Existential Assignment (?=) test "context property assignment (using @)", -> nonce = {} addMethod = -> @method = -> nonce this eq nonce, addMethod.call({}).method() test "unassignable values", -> nonce = {} for nonref in ['', '""', '0', 'f()'].concat CoffeeScript.RESERVED eq nonce, (try CoffeeScript.compile "#{nonref} = v" catch e then nonce) # Compound Assignment test "boolean operators", -> nonce = {} a = 0 a or= nonce eq nonce, a b = 1 b or= nonce eq 1, b c = 0 c and= nonce eq 0, c d = 1 d and= nonce eq nonce, d # ensure that RHS is treated as a group e = f = false e and= f or true eq false, e test "compound assignment as a sub expression", -> [a, b, c] = [1, 2, 3] eq 6, (a + b += c) eq 1, a eq 5, b eq 3, c # *note: this test could still use refactoring* test "compound assignment should be careful about caching variables", -> count = 0 list = [] list[++count] or= 1 eq 1, list[1] eq 1, count list[++count] ?= 2 eq 2, list[2] eq 2, count list[count++] and= 6 eq 6, list[2] eq 3, count base = -> ++count base base().four or= 4 eq 4, base.four eq 4, count base().five ?= 5 eq 5, base.five eq 5, count test "compound assignment with implicit objects", -> obj = undefined obj ?= one: 1 eq 1, obj.one obj and= two: 2 eq undefined, obj.one eq 2, obj.two test "compound assignment (math operators)", -> num = 10 num -= 5 eq 5, num num *= 10 eq 50, num num /= 10 eq 5, num num %= 3 eq 2, num test "more compound assignment", -> a = {} val = undefined val ||= a val ||= true eq a, val b = {} val &&= true eq val, true val &&= b eq b, val c = {} val = null val ?= c val ?= true eq c, val # Destructuring Assignment test "empty destructuring assignment", -> {} = [] = undefined test "chained destructuring assignments", -> [a] = {0: b} = {'0': c} = [nonce={}] eq nonce, a eq nonce, b eq nonce, c test "variable swapping to verify caching of RHS values when appropriate", -> a = nonceA = {} b = nonceB = {} c = nonceC = {} [a, b, c] = [b, c, a] eq nonceB, a eq nonceC, b eq nonceA, c [a, b, c] = [b, c, a] eq nonceC, a eq nonceA, b eq nonceB, c fn = -> [a, b, c] = [b, c, a] arrayEq [nonceA,nonceB,nonceC], fn() eq nonceA, a eq nonceB, b eq nonceC, c test "#713", -> nonces = [nonceA={},nonceB={}] eq nonces, [a, b] = [c, d] = nonces eq nonceA, a eq nonceA, c eq nonceB, b eq nonceB, d test "destructuring assignment with splats", -> a = {}; b = {}; c = {}; d = {}; e = {} [x,y...,z] = [a,b,c,d,e] eq a, x arrayEq [b,c,d], y eq e, z test "deep destructuring assignment with splats", -> a={}; b={}; c={}; d={}; e={}; f={}; g={}; h={}; i={} [u, [v, w..., x], y..., z] = [a, [b, c, d, e], f, g, h, i] eq a, u eq b, v arrayEq [c,d], w eq e, x arrayEq [f,g,h], y eq i, z test "destructuring assignment with objects", -> a={}; b={}; c={} obj = {a,b,c} {a:x, b:y, c:z} = obj eq a, x eq b, y eq c, z test "deep destructuring assignment with objects", -> a={}; b={}; c={}; d={} obj = { a b: { 'c': { d: [ b {e: c, f: d} ] } } } {a: w, 'b': {c: d: [x, {'f': z, e: y}]}} = obj eq a, w eq b, x eq c, y eq d, z test "destructuring assignment with objects and splats", -> a={}; b={}; c={}; d={} obj = a: b: [a, b, c, d] {a: b: [y, z...]} = obj eq a, y arrayEq [b,c,d], z test "destructuring assignment against an expression", -> a={}; b={} [y, z] = if true then [a, b] else [b, a] eq a, y eq b, z test "bracket insertion when necessary", -> [a] = [0] ? [1] eq a, 0 # for implicit destructuring assignment in comprehensions, see the comprehension tests test "destructuring assignment with context (@) properties", -> a={}; b={}; c={}; d={}; e={} obj = fn: () -> local = [a, {b, c}, d, e] [@a, {b: @b, c: @c}, @d, @e] = local eq undefined, obj[key] for key in ['a','b','c','d','e'] obj.fn() eq a, obj.a eq b, obj.b eq c, obj.c eq d, obj.d eq e, obj.e test "#1024", -> eq 2 * [] = 3 + 5, 16 test "#1005: invalid identifiers allowed on LHS of destructuring assignment", -> disallowed = ['eval', 'arguments'].concat CoffeeScript.RESERVED throws (-> CoffeeScript.compile "[#{disallowed.join ', '}] = x"), null, 'all disallowed' throws (-> CoffeeScript.compile "[#{disallowed.join '..., '}...] = x"), null, 'all disallowed as splats' t = tSplat = null for v in disallowed when v isnt 'class' # `class` by itself is an expression throws (-> CoffeeScript.compile t), null, t = "[#{v}] = x" throws (-> CoffeeScript.compile tSplat), null, tSplat = "[#{v}...] = x" doesNotThrow -> for v in disallowed CoffeeScript.compile "[a.#{v}] = x" CoffeeScript.compile "[a.#{v}...] = x" CoffeeScript.compile "[@#{v}] = x" CoffeeScript.compile "[@#{v}...] = x" test "#2055: destructuring assignment with `new`", -> {length} = new Array eq 0, length # Existential Assignment test "existential assignment", -> nonce = {} a = false a ?= nonce eq false, a b = undefined b ?= nonce eq nonce, b c = null c ?= nonce eq nonce, c test "#1627: prohibit conditional assignment of undefined variables", -> throws (-> CoffeeScript.compile "x ?= 10"), null, "prohibit (x ?= 10)" throws (-> CoffeeScript.compile "x ||= 10"), null, "prohibit (x ||= 10)" throws (-> CoffeeScript.compile "x or= 10"), null, "prohibit (x or= 10)" throws (-> CoffeeScript.compile "do -> x ?= 10"), null, "prohibit (do -> x ?= 10)" throws (-> CoffeeScript.compile "do -> x ||= 10"), null, "prohibit (do -> x ||= 10)" throws (-> CoffeeScript.compile "do -> x or= 10"), null, "prohibit (do -> x or= 10)" doesNotThrow (-> CoffeeScript.compile "x = null; x ?= 10"), "allow (x = null; x ?= 10)" doesNotThrow (-> CoffeeScript.compile "x = null; x ||= 10"), "allow (x = null; x ||= 10)" doesNotThrow (-> CoffeeScript.compile "x = null; x or= 10"), "allow (x = null; x or= 10)" doesNotThrow (-> CoffeeScript.compile "x = null; do -> x ?= 10"), "allow (x = null; do -> x ?= 10)" doesNotThrow (-> CoffeeScript.compile "x = null; do -> x ||= 10"), "allow (x = null; do -> x ||= 10)" doesNotThrow (-> CoffeeScript.compile "x = null; do -> x or= 10"), "allow (x = null; do -> x or= 10)" throws (-> CoffeeScript.compile "-> -> -> x ?= 10"), null, "prohibit (-> -> -> x ?= 10)" doesNotThrow (-> CoffeeScript.compile "x = null; -> -> -> x ?= 10"), "allow (x = null; -> -> -> x ?= 10)" test "more existential assignment", -> global.temp ?= 0 eq global.temp, 0 global.temp or= 100 eq global.temp, 100 delete global.temp test "#1348, #1216: existential assignment compilation", -> nonce = {} a = nonce b = (a ?= 0) eq nonce, b #the first ?= compiles into a statement; the second ?= compiles to a ternary expression eq a ?= b ?= 1, nonce if a then a ?= 2 else a = 3 eq a, nonce test "#1591, #1101: splatted expressions in destructuring assignment must be assignable", -> nonce = {} for nonref in ['', '""', '0', 'f()', '(->)'].concat CoffeeScript.RESERVED eq nonce, (try CoffeeScript.compile "[#{nonref}...] = v" catch e then nonce) test "#1643: splatted accesses in destructuring assignments should not be declared as variables", -> nonce = {} accesses = ['o.a', 'o["a"]', '(o.a)', '(o.a).a', '@o.a', 'C::a', 'C::', 'f().a', 'o?.a', 'o?.a.b', 'f?().a'] for access in accesses for i,j in [1,2,3] #position can matter code = """ nonce = {}; nonce2 = {}; nonce3 = {}; @o = o = new (class C then a:{}); f = -> o [#{new Array(i).join('x,')}#{access}...] = [#{new Array(i).join('0,')}nonce, nonce2, nonce3] unless #{access}[0] is nonce and #{access}[1] is nonce2 and #{access}[2] is nonce3 then throw new Error('[...]') """ eq nonce, unless (try CoffeeScript.run code, bare: true catch e then true) then nonce # subpatterns like `[[a]...]` and `[{a}...]` subpatterns = ['[sub, sub2, sub3]', '{0: sub, 1: sub2, 2: sub3}'] for subpattern in subpatterns for i,j in [1,2,3] code = """ nonce = {}; nonce2 = {}; nonce3 = {}; [#{new Array(i).join('x,')}#{subpattern}...] = [#{new Array(i).join('0,')}nonce, nonce2, nonce3] unless sub is nonce and sub2 is nonce2 and sub3 is nonce3 then throw new Error('[sub...]') """ eq nonce, unless (try CoffeeScript.run code, bare: true catch e then true) then nonce test "#1838: Regression with variable assignment", -> name = 'dave' eq name, 'dave' test '#2211: splats in destructured parameters', -> doesNotThrow -> CoffeeScript.compile '([a...]) ->' doesNotThrow -> CoffeeScript.compile '([a...],b) ->' doesNotThrow -> CoffeeScript.compile '([a...],[b...]) ->' throws -> CoffeeScript.compile '([a...,[a...]]) ->' doesNotThrow -> CoffeeScript.compile '([a...,[b...]]) ->' test '#2213: invocations within destructured parameters', -> throws -> CoffeeScript.compile '([a()])->' throws -> CoffeeScript.compile '([a:b()])->' throws -> CoffeeScript.compile '([a:b.c()])->' throws -> CoffeeScript.compile '({a()})->' throws -> CoffeeScript.compile '({a:b()})->' throws -> CoffeeScript.compile '({a:b.c()})->' coffee-script-1.4.0/test/booleans.coffee000066400000000000000000000010311204160075300201700ustar00rootroot00000000000000# Boolean Literals # ---------------- # TODO: add method invocation tests: true.toString() is "true" test "#764 Booleans should be indexable", -> toString = Boolean::toString eq toString, true['toString'] eq toString, false['toString'] eq toString, yes['toString'] eq toString, no['toString'] eq toString, on['toString'] eq toString, off['toString'] eq toString, true.toString eq toString, false.toString eq toString, yes.toString eq toString, no.toString eq toString, on.toString eq toString, off.toString coffee-script-1.4.0/test/classes.coffee000066400000000000000000000306421204160075300200350ustar00rootroot00000000000000# Classes # ------- # * Class Definition # * Class Instantiation # * Inheritance and Super test "classes with a four-level inheritance chain", -> class Base func: (string) -> "zero/#{string}" @static: (string) -> "static/#{string}" class FirstChild extends Base func: (string) -> super('one/') + string SecondChild = class extends FirstChild func: (string) -> super('two/') + string thirdCtor = -> @array = [1, 2, 3] class ThirdChild extends SecondChild constructor: -> thirdCtor.call this # Gratuitous comment for testing. func: (string) -> super('three/') + string result = (new ThirdChild).func 'four' ok result is 'zero/one/two/three/four' ok Base.static('word') is 'static/word' FirstChild::func = (string) -> super('one/').length + string result = (new ThirdChild).func 'four' ok result is '9two/three/four' ok (new ThirdChild).array.join(' ') is '1 2 3' test "constructors with inheritance and super", -> identity = (f) -> f class TopClass constructor: (arg) -> @prop = 'top-' + arg class SuperClass extends TopClass constructor: (arg) -> identity super 'super-' + arg class SubClass extends SuperClass constructor: -> identity super 'sub' ok (new SubClass).prop is 'top-super-sub' test "Overriding the static property new doesn't clobber Function::new", -> class OneClass @new: 'new' function: 'function' constructor: (name) -> @name = name class TwoClass extends OneClass delete TwoClass.new Function.prototype.new = -> new this arguments... ok (TwoClass.new('three')).name is 'three' ok (new OneClass).function is 'function' ok OneClass.new is 'new' delete Function.prototype.new test "basic classes, again, but in the manual prototype style", -> Base = -> Base::func = (string) -> 'zero/' + string Base::['func-func'] = (string) -> "dynamic-#{string}" FirstChild = -> SecondChild = -> ThirdChild = -> @array = [1, 2, 3] this ThirdChild extends SecondChild extends FirstChild extends Base FirstChild::func = (string) -> super('one/') + string SecondChild::func = (string) -> super('two/') + string ThirdChild::func = (string) -> super('three/') + string result = (new ThirdChild).func 'four' ok result is 'zero/one/two/three/four' ok (new ThirdChild)['func-func']('thing') is 'dynamic-thing' test "super with plain ol' functions as the original constructors", -> TopClass = (arg) -> @prop = 'top-' + arg this SuperClass = (arg) -> super 'super-' + arg this SubClass = -> super 'sub' this SuperClass extends TopClass SubClass extends SuperClass ok (new SubClass).prop is 'top-super-sub' test "'@' referring to the current instance, and not being coerced into a call", -> class ClassName amI: -> @ instanceof ClassName obj = new ClassName ok obj.amI() test "super() calls in constructors of classes that are defined as object properties", -> class Hive constructor: (name) -> @name = name class Hive.Bee extends Hive constructor: (name) -> super maya = new Hive.Bee 'Maya' ok maya.name is 'Maya' test "classes with JS-keyword properties", -> class Class class: 'class' name: -> @class instance = new Class ok instance.class is 'class' ok instance.name() is 'class' test "Classes with methods that are pre-bound to the instance, or statically, to the class", -> class Dog constructor: (name) -> @name = name bark: => "#{@name} woofs!" @static = => new this('Dog') spark = new Dog('Spark') fido = new Dog('Fido') fido.bark = spark.bark ok fido.bark() is 'Spark woofs!' obj = func: Dog.static ok obj.func().name is 'Dog' test "a bound function in a bound function", -> class Mini num: 10 generate: => for i in [1..3] => @num m = new Mini eq (func() for func in m.generate()).join(' '), '10 10 10' test "contructor called with varargs", -> class Connection constructor: (one, two, three) -> [@one, @two, @three] = [one, two, three] out: -> "#{@one}-#{@two}-#{@three}" list = [3, 2, 1] conn = new Connection list... ok conn instanceof Connection ok conn.out() is '3-2-1' test "calling super and passing along all arguments", -> class Parent method: (args...) -> @args = args class Child extends Parent method: -> super c = new Child c.method 1, 2, 3, 4 ok c.args.join(' ') is '1 2 3 4' test "classes wrapped in decorators", -> func = (klass) -> klass::prop = 'value' klass func class Test prop2: 'value2' ok (new Test).prop is 'value' ok (new Test).prop2 is 'value2' test "anonymous classes", -> obj = klass: class method: -> 'value' instance = new obj.klass ok instance.method() is 'value' test "Implicit objects as static properties", -> class Static @static = one: 1 two: 2 ok Static.static.one is 1 ok Static.static.two is 2 test "nothing classes", -> c = class ok c instanceof Function test "classes with static-level implicit objects", -> class A @static = one: 1 two: 2 class B @static = one: 1, two: 2 eq A.static.one, 1 eq A.static.two, undefined eq (new A).two, 2 eq B.static.one, 1 eq B.static.two, 2 eq (new B).two, undefined test "classes with value'd constructors", -> counter = 0 classMaker = -> inner = ++counter -> @value = inner class One constructor: classMaker() class Two constructor: classMaker() eq (new One).value, 1 eq (new Two).value, 2 eq (new One).value, 1 eq (new Two).value, 2 test "exectuable class bodies", -> class A if true b: 'b' else c: 'c' a = new A eq a.b, 'b' eq a.c, undefined test "mild metaprogramming", -> class Base @attr: (name) -> @::[name] = (val) -> if arguments.length > 0 @["_#{name}"] = val else @["_#{name}"] class Robot extends Base @attr 'power' @attr 'speed' robby = new Robot ok robby.power() is undefined robby.power 11 robby.speed Infinity eq robby.power(), 11 eq robby.speed(), Infinity test "namespaced classes do not reserve their function name in outside scope", -> one = {} two = {} class one.Klass @label = "one" class two.Klass @label = "two" eq typeof Klass, 'undefined' eq one.Klass.label, 'one' eq two.Klass.label, 'two' test "nested classes", -> class Outer constructor: -> @label = 'outer' class @Inner constructor: -> @label = 'inner' eq (new Outer).label, 'outer' eq (new Outer.Inner).label, 'inner' test "variables in constructor bodies are correctly scoped", -> class A x = 1 constructor: -> x = 10 y = 20 y = 2 captured: -> {x, y} a = new A eq a.captured().x, 10 eq a.captured().y, 2 test "Issue #924: Static methods in nested classes", -> class A @B: class @c = -> 5 eq A.B.c(), 5 test "`class extends this`", -> class A func: -> 'A' B = null makeClass = -> B = class extends this func: -> super + ' B' makeClass.call A eq (new B()).func(), 'A B' test "ensure that constructors invoked with splats return a new object", -> args = [1, 2, 3] Type = (@args) -> type = new Type args ok type and type instanceof Type ok type.args and type.args instanceof Array ok v is args[i] for v, i in type.args Type1 = (@a, @b, @c) -> type1 = new Type1 args... ok type1 instanceof Type1 eq type1.constructor, Type1 ok type1.a is args[0] and type1.b is args[1] and type1.c is args[2] # Ensure that constructors invoked with splats cache the function. called = 0 get = -> if called++ then false else class Type new get() args... test "`new` shouldn't add extra parens", -> ok new Date().constructor is Date test "`new` works against bare function", -> eq Date, new -> eq this, new => this Date test "#1182: a subclass should be able to set its constructor to an external function", -> ctor = -> @val = 1 class A class B extends A constructor: ctor eq (new B).val, 1 test "#1182: external constructors continued", -> ctor = -> class A class B extends A method: -> constructor: ctor ok B::method test "#1313: misplaced __extends", -> nonce = {} class A class B extends A prop: nonce constructor: -> eq nonce, B::prop test "#1182: execution order needs to be considered as well", -> counter = 0 makeFn = (n) -> eq n, ++counter; -> class B extends (makeFn 1) @B: makeFn 2 constructor: makeFn 3 test "#1182: external constructors with bound functions", -> fn = -> {one: 1} this class B class A constructor: fn method: => this instanceof A ok (new A).method.call(new B) test "#1372: bound class methods with reserved names", -> class C delete: => ok C::delete test "#1380: `super` with reserved names", -> class C do: -> super ok C::do class B 0: -> super ok B::[0] test "#1464: bound class methods should keep context", -> nonce = {} nonce2 = {} class C constructor: (@id) -> @boundStaticColon: => new this(nonce) @boundStaticEqual= => new this(nonce2) eq nonce, C.boundStaticColon().id eq nonce2, C.boundStaticEqual().id test "#1009: classes with reserved words as determined names", -> (-> eq 'function', typeof (class @for) ok not /\beval\b/.test (class @eval).toString() ok not /\barguments\b/.test (class @arguments).toString() ).call {} test "#1482: classes can extend expressions", -> id = (x) -> x nonce = {} class A then nonce: nonce class B extends id A eq nonce, (new B).nonce test "#1598: super works for static methods too", -> class Parent method: -> 'NO' @method: -> 'yes' class Child extends Parent @method: -> 'pass? ' + super eq Child.method(), 'pass? yes' test "#1842: Regression with bound functions within bound class methods", -> class Store @bound: => do => eq this, Store Store.bound() # And a fancier case: class Store eq this, Store @bound: => do => eq this, Store @unbound: -> eq this, Store instance: => ok this instanceof Store Store.bound() Store.unbound() (new Store).instance() test "#1876: Class @A extends A", -> class A class @A extends A ok (new @A) instanceof A test "#1813: Passing class definitions as expressions", -> ident = (x) -> x result = ident class A then x = 1 eq result, A result = ident class B extends A x = 1 eq result, B test "#1966: external constructors should produce their return value", -> ctor = -> {} class A then constructor: ctor ok (new A) not instanceof A test "#1980: regression with an inherited class with static function members", -> class A class B extends A @static: => 'value' eq B.static(), 'value' test "#1534: class then 'use strict'", -> # [14.1 Directive Prologues and the Use Strict Directive](http://es5.github.com/#x14.1) nonce = {} error = 'do -> ok this' strictTest = "do ->'use strict';#{error}" return unless (try CoffeeScript.run strictTest, bare: yes catch e then nonce) is nonce throws -> CoffeeScript.run "class then 'use strict';#{error}", bare: yes doesNotThrow -> CoffeeScript.run "class then #{error}", bare: yes doesNotThrow -> CoffeeScript.run "class then #{error};'use strict'", bare: yes # comments are ignored in the Directive Prologue comments = [""" class ### comment ### 'use strict' #{error}""", """ class ### comment 1 ### ### comment 2 ### 'use strict' #{error}""", """ class ### comment 1 ### ### comment 2 ### 'use strict' #{error} ### comment 3 ###""" ] throws (-> CoffeeScript.run comment, bare: yes) for comment in comments # [ES5 §14.1](http://es5.github.com/#x14.1) allows for other directives directives = [""" class 'directive 1' 'use strict' #{error}""", """ class 'use strict' 'directive 2' #{error}""", """ class ### comment 1 ### 'directive 1' 'use strict' #{error}""", """ class ### comment 1 ### 'directive 1' ### comment 2 ### 'use strict' #{error}""" ] throws (-> CoffeeScript.run directive, bare: yes) for directive in directives test "#2052: classes should work in strict mode", -> try do -> 'use strict' class A catch e ok no coffee-script-1.4.0/test/comments.coffee000066400000000000000000000054061204160075300202250ustar00rootroot00000000000000# Comments # -------- # * Single-Line Comments # * Block Comments # Note: awkward spacing seen in some tests is likely intentional. test "comments in objects", -> obj1 = { # comment # comment # comment one: 1 # comment two: 2 # comment } ok Object::hasOwnProperty.call(obj1,'one') eq obj1.one, 1 ok Object::hasOwnProperty.call(obj1,'two') eq obj1.two, 2 test "comments in YAML-style objects", -> obj2 = # comment # comment # comment three: 3 # comment four: 4 # comment ok Object::hasOwnProperty.call(obj2,'three') eq obj2.three, 3 ok Object::hasOwnProperty.call(obj2,'four') eq obj2.four, 4 test "comments following operators that continue lines", -> sum = 1 + 1 + # comment 1 eq 3, sum test "comments in functions", -> fn = -> # comment false false # comment false # comment # comment true ok fn() fn2 = -> #comment fn() # comment ok fn2() test "trailing comment before an outdent", -> nonce = {} fn3 = -> if true undefined # comment nonce eq nonce, fn3() test "comments in a switch", -> nonce = {} result = switch nonce #comment # comment when false then undefined # comment when null #comment undefined else nonce # comment eq nonce, result test "comment with conditional statements", -> nonce = {} result = if false # comment undefined #comment else # comment nonce # comment eq nonce, result test "spaced comments with conditional statements", -> nonce = {} result = if false undefined # comment else if false undefined # comment else nonce eq nonce, result # Block Comments ### This is a here-comment. Kind of like a heredoc. ### test "block comments in objects", -> a = {} b = {} obj = { a: a ### comment ### b: b } eq a, obj.a eq b, obj.b test "block comments in YAML-style", -> a = {} b = {} obj = a: a ### comment ### b: b eq a, obj.a eq b, obj.b test "block comments in functions", -> nonce = {} fn1 = -> true ### false ### ok fn1() fn2 = -> ### block comment ### nonce eq nonce, fn2() fn3 = -> nonce ### block comment ### eq nonce, fn3() fn4 = -> one = -> ### block comment ### two = -> three = -> nonce eq nonce, fn4()()()() test "block comments inside class bodies", -> class A a: -> ### Comment ### b: -> ok A.prototype.b instanceof Function class B ### Comment ### a: -> b: -> ok B.prototype.a instanceof Function test "#2037: herecomments shouldn't imply line terminators", -> do (-> ### ###; fail) coffee-script-1.4.0/test/compilation.coffee000066400000000000000000000032011204160075300207050ustar00rootroot00000000000000# Compilation # ----------- # helper to assert that a string should fail compilation cantCompile = (code) -> throws -> CoffeeScript.compile code test "ensure that carriage returns don't break compilation on Windows", -> doesNotThrow -> CoffeeScript.compile 'one\r\ntwo', bare: on test "--bare", -> eq -1, CoffeeScript.compile('x = y', bare: on).indexOf 'function' ok 'passed' is CoffeeScript.eval '"passed"', bare: on, filename: 'test' test "header (#1778)", -> header = "// Generated by CoffeeScript #{CoffeeScript.VERSION}\n" eq 0, CoffeeScript.compile('x = y', header: on).indexOf header test "header is disabled by default", -> header = "// Generated by CoffeeScript #{CoffeeScript.VERSION}\n" eq -1, CoffeeScript.compile('x = y').indexOf header test "multiple generated references", -> a = {b: []} a.b[true] = -> this == a.b c = 0 d = [] ok a.b[0<++c<2] d... test "splat on a line by itself is invalid", -> cantCompile "x 'a'\n...\n" test "Issue 750", -> cantCompile 'f(->' cantCompile 'a = (break)' cantCompile 'a = (return 5 for item in list)' cantCompile 'a = (return 5 while condition)' cantCompile 'a = for x in y\n return 5' test "Issue #986: Unicode identifiers", -> λ = 5 eq λ, 5 test "don't accidentally stringify keywords", -> ok (-> this == 'this')() is false test "#1026", -> cantCompile ''' if a b else c else d ''' test "#1050", -> cantCompile "### */ ###" test "#1106: __proto__ compilation", -> object = eq @["__proto__"] = true ok __proto__ test "reference named hasOwnProperty", -> CoffeeScript.compile 'hasOwnProperty = 0; a = 1' coffee-script-1.4.0/test/comprehensions.coffee000066400000000000000000000233211204160075300214300ustar00rootroot00000000000000# Comprehensions # -------------- # * Array Comprehensions # * Range Comprehensions # * Object Comprehensions # * Implicit Destructuring Assignment # * Comprehensions with Nonstandard Step # TODO: refactor comprehension tests test "Basic array comprehensions.", -> nums = (n * n for n in [1, 2, 3] when n & 1) results = (n * 2 for n in nums) ok results.join(',') is '2,18' test "Basic object comprehensions.", -> obj = {one: 1, two: 2, three: 3} names = (prop + '!' for prop of obj) odds = (prop + '!' for prop, value of obj when value & 1) ok names.join(' ') is "one! two! three!" ok odds.join(' ') is "one! three!" test "Basic range comprehensions.", -> nums = (i * 3 for i in [1..3]) negs = (x for x in [-20..-5*2]) negs = negs[0..2] result = nums.concat(negs).join(', ') ok result is '3, 6, 9, -20, -19, -18' test "With range comprehensions, you can loop in steps.", -> results = (x for x in [0...15] by 5) ok results.join(' ') is '0 5 10' results = (x for x in [0..100] by 10) ok results.join(' ') is '0 10 20 30 40 50 60 70 80 90 100' test "And can loop downwards, with a negative step.", -> results = (x for x in [5..1]) ok results.join(' ') is '5 4 3 2 1' ok results.join(' ') is [(10-5)..(-2+3)].join(' ') results = (x for x in [10..1]) ok results.join(' ') is [10..1].join(' ') results = (x for x in [10...0] by -2) ok results.join(' ') is [10, 8, 6, 4, 2].join(' ') test "Range comprehension gymnastics.", -> eq "#{i for i in [5..1]}", '5,4,3,2,1' eq "#{i for i in [5..-5] by -5}", '5,0,-5' a = 6 b = 0 c = -2 eq "#{i for i in [a..b]}", '6,5,4,3,2,1,0' eq "#{i for i in [a..b] by c}", '6,4,2,0' test "Multiline array comprehension with filter.", -> evens = for num in [1, 2, 3, 4, 5, 6] when not (num & 1) num *= -1 num -= 2 num * -1 eq evens + '', '4,6,8' test "The in operator still works, standalone.", -> ok 2 of evens test "all isn't reserved.", -> all = 1 test "Ensure that the closure wrapper preserves local variables.", -> obj = {} for method in ['one', 'two', 'three'] then do (method) -> obj[method] = -> "I'm " + method ok obj.one() is "I'm one" ok obj.two() is "I'm two" ok obj.three() is "I'm three" test "Index values at the end of a loop.", -> i = 0 for i in [1..3] -> 'func' break if false ok i is 4 test "Ensure that local variables are closed over for range comprehensions.", -> funcs = for i in [1..3] do (i) -> -> -i eq (func() for func in funcs).join(' '), '-1 -2 -3' ok i is 4 test "Even when referenced in the filter.", -> list = ['one', 'two', 'three'] methods = for num, i in list when num isnt 'two' and i isnt 1 do (num, i) -> -> num + ' ' + i ok methods.length is 2 ok methods[0]() is 'one 0' ok methods[1]() is 'three 2' test "Even a convoluted one.", -> funcs = [] for i in [1..3] do (i) -> x = i * 2 ((z)-> funcs.push -> z + ' ' + i )(x) ok (func() for func in funcs).join(', ') is '2 1, 4 2, 6 3' funcs = [] results = for i in [1..3] do (i) -> z = (x * 3 for x in [1..i]) ((a, b, c) -> [a, b, c].join(' ')).apply this, z ok results.join(', ') is '3 , 3 6 , 3 6 9' test "Naked ranges are expanded into arrays.", -> array = [0..10] ok(num % 2 is 0 for num in array by 2) test "Nested shared scopes.", -> foo = -> for i in [0..7] do (i) -> for j in [0..7] do (j) -> -> i + j eq foo()[3][4](), 7 test "Scoped loop pattern matching.", -> a = [[0], [1]] funcs = [] for [v] in a do (v) -> funcs.push -> v eq funcs[0](), 0 eq funcs[1](), 1 test "Nested comprehensions.", -> multiLiner = for x in [3..5] for y in [3..5] [x, y] singleLiner = (([x, y] for y in [3..5]) for x in [3..5]) ok multiLiner.length is singleLiner.length ok 5 is multiLiner[2][2][1] ok 5 is singleLiner[2][2][1] test "Comprehensions within parentheses.", -> result = null store = (obj) -> result = obj store (x * 2 for x in [3, 2, 1]) ok result.join(' ') is '6 4 2' test "Closure-wrapped comprehensions that refer to the 'arguments' object.", -> expr = -> result = (item * item for item in arguments) ok expr(2, 4, 8).join(' ') is '4 16 64' test "Fast object comprehensions over all properties, including prototypal ones.", -> class Cat constructor: -> @name = 'Whiskers' breed: 'tabby' hair: 'cream' whiskers = new Cat own = (value for own key, value of whiskers) all = (value for key, value of whiskers) ok own.join(' ') is 'Whiskers' ok all.sort().join(' ') is 'Whiskers cream tabby' test "Optimized range comprehensions.", -> exxes = ('x' for [0...10]) ok exxes.join(' ') is 'x x x x x x x x x x' test "Loop variables should be able to reference outer variables", -> outer = 1 do -> null for outer in [1, 2, 3] eq outer, 3 test "Lenient on pure statements not trying to reach out of the closure", -> val = for i in [1] for j in [] then break i ok val[0] is i test "Comprehensions only wrap their last line in a closure, allowing other lines to have pure expressions in them.", -> func = -> for i in [1] break if i is 2 j for j in [1] ok func()[0][0] is 1 i = 6 odds = while i-- continue unless i & 1 i ok odds.join(', ') is '5, 3, 1' test "Issue #897: Ensure that plucked function variables aren't leaked.", -> facets = {} list = ['one', 'two'] (-> for entity in list facets[entity] = -> entity )() eq typeof entity, 'undefined' eq facets['two'](), 'two' test "Issue #905. Soaks as the for loop subject.", -> a = {b: {c: [1, 2, 3]}} for d in a.b?.c e = d eq e, 3 test "Issue #948. Capturing loop variables.", -> funcs = [] list = -> [1, 2, 3] for y in list() do (y) -> z = y funcs.push -> "y is #{y} and z is #{z}" eq funcs[1](), "y is 2 and z is 2" test "Cancel the comprehension if there's a jump inside the loop.", -> result = try for i in [0...10] continue if i < 5 i eq result, 10 test "Comprehensions over break.", -> arrayEq (break for [1..10]), [] test "Comprehensions over continue.", -> arrayEq (continue for [1..10]), [] test "Comprehensions over function literals.", -> a = 0 for f in [-> a = 1] do (f) -> do f eq a, 1 test "Comprehensions that mention arguments.", -> list = [arguments: 10] args = for f in list do (f) -> f.arguments eq args[0], 10 test "expression conversion under explicit returns", -> nonce = {} fn = -> return (nonce for x in [1,2,3]) arrayEq [nonce,nonce,nonce], fn() fn = -> return [nonce for x in [1,2,3]][0] arrayEq [nonce,nonce,nonce], fn() fn = -> return [(nonce for x in [1..3])][0] arrayEq [nonce,nonce,nonce], fn() test "implicit destructuring assignment in object of objects", -> a={}; b={}; c={} obj = { a: { d: a }, b: { d: b } c: { d: c } } result = ([y,z] for y, { d: z } of obj) arrayEq [['a',a],['b',b],['c',c]], result test "implicit destructuring assignment in array of objects", -> a={}; b={}; c={}; d={}; e={}; f={} arr = [ { a: a, b: { c: b } }, { a: c, b: { c: d } }, { a: e, b: { c: f } } ] result = ([y,z] for { a: y, b: { c: z } } in arr) arrayEq [[a,b],[c,d],[e,f]], result test "implicit destructuring assignment in array of arrays", -> a={}; b={}; c={}; d={}; e={}; f={} arr = [[a, [b]], [c, [d]], [e, [f]]] result = ([y,z] for [y, [z]] in arr) arrayEq [[a,b],[c,d],[e,f]], result test "issue #1124: don't assign a variable in two scopes", -> lista = [1, 2, 3, 4, 5] listb = (_i + 1 for _i in lista) arrayEq [2, 3, 4, 5, 6], listb test "#1326: `by` value is uncached", -> a = [0,1,2] fi = gi = hi = 0 f = -> ++fi g = -> ++gi h = -> ++hi forCompile = [] rangeCompileSimple = [] #exercises For.compile for v,i in a by f() then forCompile.push i #exercises Range.compileSimple rangeCompileSimple = (i for i in [0..2] by g()) arrayEq a, forCompile arrayEq a, rangeCompileSimple #exercises Range.compile eq "#{i for i in [0..2] by h()}", '0,1,2' test "#1669: break/continue should skip the result only for that branch", -> ns = for n in [0..99] if n > 9 break else if n & 1 continue else n eq "#{ns}", '0,2,4,6,8' # `else undefined` is implied. ns = for n in [1..9] if n % 2 continue unless n % 5 n eq "#{ns}", "1,,3,,,7,,9" # Ditto. ns = for n in [1..9] switch when n % 2 continue unless n % 5 n eq "#{ns}", "1,,3,,,7,,9" test "#1850: inner `for` should not be expression-ized if `return`ing", -> eq '3,4,5', do -> for a in [1..9] then \ for b in [1..9] c = Math.sqrt a*a + b*b return String [a, b, c] unless c % 1 test "#1910: loop index should be mutable within a loop iteration and immutable between loop iterations", -> n = 1 iterations = 0 arr = [0..n] for v, k in arr ++iterations v = k = 5 eq 5, k eq 2, k eq 2, iterations iterations = 0 for v in [0..n] ++iterations eq 2, k eq 2, iterations arr = ([v, v + 1] for v in [0..5]) iterations = 0 for own [v0, v1], k in arr when v0 k += 3 ++iterations eq 6, k eq 5, iterations test "#2007: Return object literal from comprehension", -> y = for x in [1, 2] foo: "foo" + x eq 2, y.length eq "foo1", y[0].foo eq "foo2", y[1].foo x = 2 y = while x x: --x eq 2, y.length eq 1, y[0].x eq 0, y[1].x test "#2274: Allow @values as loop variables", -> obj = { item: null method: -> for @item in [1, 2, 3] null } eq obj.item, null obj.method() eq obj.item, 3 coffee-script-1.4.0/test/control_flow.coffee000066400000000000000000000163351204160075300211120ustar00rootroot00000000000000# Control Flow # ------------ # * Conditionals # * Loops # * For # * While # * Until # * Loop # * Switch # * Throw # TODO: make sure postfix forms and expression coercion are properly tested # shared identity function id = (_) -> if arguments.length is 1 then _ else Array::slice.call(arguments) # Conditionals test "basic conditionals", -> if false ok false else if false ok false else ok true if true ok true else if true ok false else ok true unless true ok false else unless true ok false else ok true unless false ok true else unless false ok false else ok true test "single-line conditional", -> if false then ok false else ok true unless false then ok true else ok false test "nested conditionals", -> nonce = {} eq nonce, (if true unless false if false then false else if true nonce) test "nested single-line conditionals", -> nonce = {} a = if false then undefined else b = if 0 then undefined else nonce eq nonce, a eq nonce, b c = if false then undefined else (if 0 then undefined else nonce) eq nonce, c d = if true then id(if false then undefined else nonce) eq nonce, d test "empty conditional bodies", -> eq undefined, (if false else if false else) test "conditional bodies containing only comments", -> eq undefined, (if true ### block comment ### else # comment ) eq undefined, (if false # comment else if true ### block comment ### else) test "return value of if-else is from the proper body", -> nonce = {} eq nonce, if false then undefined else nonce test "return value of unless-else is from the proper body", -> nonce = {} eq nonce, unless true then undefined else nonce test "assign inside the condition of a conditional statement", -> nonce = {} if a = nonce then 1 eq nonce, a 1 if b = nonce eq nonce, b # Interactions With Functions test "single-line function definition with single-line conditional", -> fn = -> if 1 < 0.5 then 1 else -1 ok fn() is -1 test "function resturns conditional value with no `else`", -> fn = -> return if false then true eq undefined, fn() test "function returns a conditional value", -> a = {} fnA = -> return if false then undefined else a eq a, fnA() b = {} fnB = -> return unless false then b else undefined eq b, fnB() test "passing a conditional value to a function", -> nonce = {} eq nonce, id if false then undefined else nonce test "unmatched `then` should catch implicit calls", -> a = 0 trueFn = -> true if trueFn undefined then a++ eq 1, a # if-to-ternary test "if-to-ternary with instanceof requires parentheses", -> nonce = {} eq nonce, (if {} instanceof Object nonce else undefined) test "if-to-ternary as part of a larger operation requires parentheses", -> ok 2, 1 + if false then 0 else 1 # Odd Formatting test "if-else indented within an assignment", -> nonce = {} result = if false undefined else nonce eq nonce, result test "suppressed indentation via assignment", -> nonce = {} result = if false then undefined else if no then undefined else if 0 then undefined else if 1 < 0 then undefined else id( if false then undefined else nonce ) eq nonce, result test "tight formatting with leading `then`", -> nonce = {} eq nonce, if true then nonce else undefined test "#738", -> nonce = {} fn = if true then -> nonce eq nonce, fn() test "#748: trailing reserved identifiers", -> nonce = {} obj = delete: true result = if obj.delete nonce eq nonce, result test "basic `while` loops", -> i = 5 list = while i -= 1 i * 2 ok list.join(' ') is "8 6 4 2" i = 5 list = (i * 3 while i -= 1) ok list.join(' ') is "12 9 6 3" i = 5 func = (num) -> i -= num assert = -> ok i < 5 > 0 results = while func 1 assert() i ok results.join(' ') is '4 3 2 1' i = 10 results = while i -= 1 when i % 2 is 0 i * 2 ok results.join(' ') is '16 12 8 4' test "Issue 759: `if` within `while` condition", -> 2 while if 1 then 0 test "assignment inside the condition of a `while` loop", -> nonce = {} count = 1 a = nonce while count-- eq nonce, a count = 1 while count-- b = nonce eq nonce, b test "While over break.", -> i = 0 result = while i < 10 i++ break arrayEq result, [] test "While over continue.", -> i = 0 result = while i < 10 i++ continue arrayEq result, [] test "Basic `until`", -> value = false i = 0 results = until value value = true if i is 5 i++ ok i is 6 test "Basic `loop`", -> i = 5 list = [] loop i -= 1 break if i is 0 list.push i * 2 ok list.join(' ') is '8 6 4 2' test "break at the top level", -> for i in [1,2,3] result = i if i == 2 break eq 2, result test "break *not* at the top level", -> someFunc = -> i = 0 while ++i < 3 result = i break if i > 1 result eq 2, someFunc() test "basic `switch`", -> num = 10 result = switch num when 5 then false when 'a' true true false when 10 then true # Mid-switch comment with whitespace # and multi line when 11 then false else false ok result func = (num) -> switch num when 2, 4, 6 true when 1, 3, 5 false ok func(2) ok func(6) ok !func(3) eq func(8), undefined test "Ensure that trailing switch elses don't get rewritten.", -> result = false switch "word" when "one thing" doSomething() else result = true unless false ok result result = false switch "word" when "one thing" doSomething() when "other thing" doSomething() else result = true unless false ok result test "Should be able to handle switches sans-condition.", -> result = switch when null then 0 when !1 then 1 when '' not of {''} then 2 when [] not instanceof Array then 3 when true is false then 4 when 'x' < 'y' > 'z' then 5 when 'a' in ['b', 'c'] then 6 when 'd' in (['e', 'f']) then 7 else ok eq result, ok test "Should be able to use `@properties` within the switch clause.", -> obj = { num: 101 func: -> switch @num when 101 then '101!' else 'other' } ok obj.func() is '101!' test "Should be able to use `@properties` within the switch cases.", -> obj = { num: 101 func: (yesOrNo) -> result = switch yesOrNo when yes then @num else 'other' result } ok obj.func(yes) is 101 test "Switch with break as the return value of a loop.", -> i = 10 results = while i > 0 i-- switch i % 2 when 1 then i when 0 then break eq results.join(', '), '9, 7, 5, 3, 1' test "Issue #997. Switch doesn't fallthrough.", -> val = 1 switch true when true if false return 5 else val = 2 eq val, 1 test "Throw should be usable as an expression.", -> try false or throw 'up' throw new Error 'failed' catch e ok e is 'up' coffee-script-1.4.0/test/eval.coffee000066400000000000000000000015661204160075300173320ustar00rootroot00000000000000if vm = require? 'vm' test "CoffeeScript.eval runs in the global context by default", -> global.punctuation = '!' code = ''' global.fhqwhgads = "global superpower#{global.punctuation}" ''' result = CoffeeScript.eval code eq result, 'global superpower!' eq fhqwhgads, 'global superpower!' test "CoffeeScript.eval can run in, and modify, a Script context sandbox", -> sandbox = vm.Script.createContext() sandbox.foo = 'bar' code = ''' global.foo = 'not bar!' ''' result = CoffeeScript.eval code, {sandbox} eq result, 'not bar!' eq sandbox.foo, 'not bar!' test "CoffeeScript.eval can run in, but cannot modify, an ordinary object sandbox", -> sandbox = {foo: 'bar'} code = ''' global.foo = 'not bar!' ''' result = CoffeeScript.eval code, {sandbox} eq result, 'not bar!' eq sandbox.foo, 'bar' coffee-script-1.4.0/test/exception_handling.coffee000066400000000000000000000035571204160075300222470ustar00rootroot00000000000000# Exception Handling # ------------------ # shared nonce nonce = {} # Throw test "basic exception throwing", -> throws (-> throw 'error'), 'error' # Empty Try/Catch/Finally test "try can exist alone", -> try test "try/catch with empty try, empty catch", -> try # nothing catch err # nothing test "single-line try/catch with empty try, empty catch", -> try catch err test "try/finally with empty try, empty finally", -> try # nothing finally # nothing test "single-line try/finally with empty try, empty finally", -> try finally test "try/catch/finally with empty try, empty catch, empty finally", -> try catch err finally test "single-line try/catch/finally with empty try, empty catch, empty finally", -> try catch err then finally # Try/Catch/Finally as an Expression test "return the result of try when no exception is thrown", -> result = try nonce catch err undefined finally undefined eq nonce, result test "single-line result of try when no exception is thrown", -> result = try nonce catch err then undefined eq nonce, result test "return the result of catch when an exception is thrown", -> fn = -> try throw -> catch err nonce doesNotThrow fn eq nonce, fn() test "single-line result of catch when an exception is thrown", -> fn = -> try throw (->) catch err then nonce doesNotThrow fn eq nonce, fn() test "optional catch", -> fn = -> try throw -> nonce doesNotThrow fn eq nonce, fn() # Try/Catch/Finally Interaction With Other Constructs test "try/catch with empty catch as last statement in a function body", -> fn = -> try nonce catch err eq nonce, fn() # Catch leads to broken scoping: #1595 test "try/catch with a reused variable name.", -> do -> try inner = 5 catch inner # nothing eq typeof inner, 'undefined' coffee-script-1.4.0/test/formatting.coffee000066400000000000000000000055761204160075300205620ustar00rootroot00000000000000# Formatting # ---------- # TODO: maybe this file should be split up into their respective sections: # operators -> operators # array literals -> array literals # string literals -> string literals # function invocations -> function invocations # * Line Continuation # * Property Accesss # * Operators # * Array Literals # * Function Invocations # * String Literals doesNotThrow -> CoffeeScript.compile "a = then b" test "multiple semicolon-separated statements in parentheticals", -> nonce = {} eq nonce, (1; 2; nonce) eq nonce, (-> return (1; 2; nonce))() # Line Continuation # Property Access test "chained accesses split on period/newline, backwards and forwards", -> str = 'abc' result = str. split(''). reverse(). reverse(). reverse() arrayEq ['c','b','a'], result arrayEq ['c','b','a'], str. split(''). reverse(). reverse(). reverse() result = str .split('') .reverse() .reverse() .reverse() arrayEq ['c','b','a'], result arrayEq ['c','b','a'], str .split('') .reverse() .reverse() .reverse() arrayEq ['c','b','a'], str. split('') .reverse(). reverse() .reverse() # Operators test "newline suppression for operators", -> six = 1 + 2 + 3 eq 6, six test "`?.` and `::` should continue lines", -> ok not Date :: ?.foo #eq Object::toString, Date?. #prototype #:: #?.foo doesNotThrow -> CoffeeScript.compile """ oh. yes oh?. true oh:: return """ doesNotThrow -> CoffeeScript.compile """ a?[b..] a?[...b] a?[b..c] """ # Array Literals test "indented array literals don't trigger whitespace rewriting", -> getArgs = -> arguments result = getArgs( [[[[[], []], [[]]]], []]) eq 1, result.length # Function Invocations doesNotThrow -> CoffeeScript.compile """ obj = then fn 1, 1: 1 a: b: -> fn c, d: e f: 1 """ # String Literals test "indented heredoc", -> result = ((_) -> _)( """ abc """) eq "abc", result # Nested blocks caused by paren unwrapping test "#1492: Nested blocks don't cause double semicolons", -> js = CoffeeScript.compile '(0;0)' eq -1, js.indexOf ';;' test "#1195 Ignore trailing semicolons (before newlines or as the last char in a program)", -> preNewline = (numSemicolons) -> """ nonce = {}; nonce2 = {} f = -> nonce#{Array(numSemicolons+1).join(';')} nonce2 unless f() is nonce then throw new Error('; before linebreak should = newline') """ CoffeeScript.run(preNewline(n), bare: true) for n in [1,2,3] lastChar = '-> lastChar;' doesNotThrow -> CoffeeScript.compile lastChar, bare: true test "#1299: Disallow token misnesting", -> try CoffeeScript.compile ''' [{ ]} ''' ok no catch e eq 'unmatched ] on line 2', e.message coffee-script-1.4.0/test/function_invocation.coffee000066400000000000000000000247131204160075300224600ustar00rootroot00000000000000# Function Invocation # ------------------- # * Function Invocation # * Splats in Function Invocations # * Implicit Returns # * Explicit Returns # shared identity function id = (_) -> if arguments.length is 1 then _ else [arguments...] test "basic argument passing", -> a = {} b = {} c = {} eq 1, (id 1) eq 2, (id 1, 2)[1] eq a, (id a) eq c, (id a, b, c)[2] test "passing arguments on separate lines", -> a = {} b = {} c = {} ok(id( a b c )[1] is b) eq(0, id( 0 10 )[0]) eq(a,id( a )) eq b, (id b) test "optional parens can be used in a nested fashion", -> call = (func) -> func() add = (a,b) -> a + b result = call -> inner = call -> add 5, 5 ok result is 10 test "hanging commas and semicolons in argument list", -> fn = () -> arguments.length eq 2, fn(0,1,) eq 3, fn 0, 1, 2 eq 2, fn(0, 1;) # TODO: this test fails (the string compiles), but should it? #throws -> CoffeeScript.compile "fn(0,1,;)" throws -> CoffeeScript.compile "fn(0,1,;;)" throws -> CoffeeScript.compile "fn(0, 1;,)" throws -> CoffeeScript.compile "fn(,0)" throws -> CoffeeScript.compile "fn(;0)" test "function invocation", -> func = -> return if true eq undefined, func() result = ("hello".slice) 3 ok result is 'lo' test "And even with strange things like this:", -> funcs = [((x) -> x), ((x) -> x * x)] result = funcs[1] 5 ok result is 25 test "More fun with optional parens.", -> fn = (arg) -> arg ok fn(fn {prop: 101}).prop is 101 okFunc = (f) -> ok(f()) okFunc -> true test "chained function calls", -> nonce = {} identityWrap = (x) -> -> x eq nonce, identityWrap(identityWrap(nonce))()() eq nonce, (identityWrap identityWrap nonce)()() test "Multi-blocks with optional parens.", -> fn = (arg) -> arg result = fn( -> fn -> "Wrapped" ) ok result()() is 'Wrapped' test "method calls", -> fnId = (fn) -> -> fn.apply this, arguments math = { add: (a, b) -> a + b anonymousAdd: (a, b) -> a + b fastAdd: fnId (a, b) -> a + b } ok math.add(5, 5) is 10 ok math.anonymousAdd(10, 10) is 20 ok math.fastAdd(20, 20) is 40 test "Ensure that functions can have a trailing comma in their argument list", -> mult = (x, mids..., y) -> x *= n for n in mids x *= y ok mult(1, 2,) is 2 ok mult(1, 2, 3,) is 6 ok mult(10, (i for i in [1..6])...) is 7200 test "`@` and `this` should both be able to invoke a method", -> nonce = {} fn = (arg) -> eq nonce, arg fn.withAt = -> @ nonce fn.withThis = -> this nonce fn.withAt() fn.withThis() test "Trying an implicit object call with a trailing function.", -> a = null meth = (arg, obj, func) -> a = [obj.a, arg, func()].join ' ' meth 'apple', b: 1, a: 13, -> 'orange' ok a is '13 apple orange' test "Ensure that empty functions don't return mistaken values.", -> obj = func: (@param, @rest...) -> ok obj.func(101, 102, 103, 104) is undefined ok obj.param is 101 ok obj.rest.join(' ') is '102 103 104' test "Passing multiple functions without paren-wrapping is legal, and should compile.", -> sum = (one, two) -> one() + two() result = sum -> 7 + 9 , -> 1 + 3 ok result is 20 test "Implicit call with a trailing if statement as a param.", -> func = -> arguments[1] result = func 'one', if false then 100 else 13 ok result is 13 test "Test more function passing:", -> sum = (one, two) -> one() + two() result = sum( -> 1 + 2 , -> 2 + 1 ) ok result is 6 sum = (a, b) -> a + b result = sum(1 , 2) ok result is 3 test "Chained blocks, with proper indentation levels:", -> counter = results: [] tick: (func) -> @results.push func() this counter .tick -> 3 .tick -> 2 .tick -> 1 arrayEq [3,2,1], counter.results test "This is a crazy one.", -> x = (obj, func) -> func obj ident = (x) -> x result = x {one: ident 1}, (obj) -> inner = ident(obj) ident inner ok result.one is 1 test "More paren compilation tests:", -> reverse = (obj) -> obj.reverse() ok reverse([1, 2].concat 3).join(' ') is '3 2 1' test "Test for inline functions with parentheses and implicit calls.", -> combine = (func, num) -> func() * num result = combine (-> 1 + 2), 3 ok result is 9 test "Test for calls/parens/multiline-chains.", -> f = (x) -> x result = (f 1).toString() .length ok result is 1 test "Test implicit calls in functions in parens:", -> result = ((val) -> [].push val val )(10) ok result is 10 test "Ensure that chained calls with indented implicit object literals below are alright.", -> result = null obj = method: (val) -> this second: (hash) -> result = hash.three obj .method( 101 ).second( one: two: 2 three: 3 ) eq result, 3 test "Test newline-supressed call chains with nested functions.", -> obj = call: -> this func = -> obj .call -> one two .call -> three four 101 eq func(), 101 test "Implicit objects with number arguments.", -> func = (x, y) -> y obj = prop: func "a", 1 ok obj.prop is 1 test "Non-spaced unary and binary operators should cause a function call.", -> func = (val) -> val + 1 ok (func +5) is 6 ok (func -5) is -4 test "Prefix unary assignment operators are allowed in parenless calls.", -> func = (val) -> val + 1 val = 5 ok (func --val) is 5 test "#855: execution context for `func arr...` should be `null`", -> contextTest = -> eq @, if window? then window else global array = [] contextTest array contextTest.apply null, array contextTest array... test "#904: Destructuring function arguments with same-named variables in scope", -> a = b = nonce = {} fn = ([a,b]) -> {a:a,b:b} result = fn([c={},d={}]) eq c, result.a eq d, result.b eq nonce, a eq nonce, b test "Simple Destructuring function arguments with same-named variables in scope", -> x = 1 f = ([x]) -> x eq f([2]), 2 eq x, 1 test "caching base value", -> obj = index: 0 0: {method: -> this is obj[0]} ok obj[obj.index++].method([]...) test "passing splats to functions", -> arrayEq [0..4], id id [0..4]... fn = (a, b, c..., d) -> [a, b, c, d] range = [0..3] [first, second, others, last] = fn range..., 4, [5...8]... eq 0, first eq 1, second arrayEq [2..6], others eq 7, last test "splat variables are local to the function", -> outer = "x" clobber = (avar, outer...) -> outer clobber "foo", "bar" eq "x", outer test "Issue 894: Splatting against constructor-chained functions.", -> x = null class Foo bar: (y) -> x = y new Foo().bar([101]...) eq x, 101 test "Functions with splats being called with too few arguments.", -> pen = null method = (first, variable..., penultimate, ultimate) -> pen = penultimate method 1, 2, 3, 4, 5, 6, 7, 8, 9 ok pen is 8 method 1, 2, 3 ok pen is 2 method 1, 2 ok pen is 2 test "splats with super() within classes.", -> class Parent meth: (args...) -> args class Child extends Parent meth: -> nums = [3, 2, 1] super nums... ok (new Child).meth().join(' ') is '3 2 1' test "#1011: passing a splat to a method of a number", -> eq '1011', 11.toString [2]... eq '1011', (31).toString [3]... eq '1011', 69.0.toString [4]... eq '1011', (131.0).toString [5]... test "splats and the `new` operator: functions that return `null` should construct their instance", -> args = [] child = new (constructor = -> null) args... ok child instanceof constructor test "splats and the `new` operator: functions that return functions should construct their return value", -> args = [] fn = -> child = new (constructor = -> fn) args... ok child not instanceof constructor eq fn, child test "implicit return", -> eq ok, new -> ok ### Should `return` implicitly ### ### even with trailing comments. ### test "implicit returns with multiple branches", -> nonce = {} fn = -> if false for a in b return c if d else nonce eq nonce, fn() test "implicit returns with switches", -> nonce = {} fn = -> switch nonce when nonce then nonce else return undefined eq nonce, fn() test "preserve context when generating closure wrappers for expression conversions", -> nonce = {} obj = property: nonce method: -> this.result = if false 10 else "a" "b" this.property eq nonce, obj.method() eq nonce, obj.property test "don't wrap 'pure' statements in a closure", -> nonce = {} items = [0, 1, 2, 3, nonce, 4, 5] fn = (items) -> for item in items return item if item is nonce eq nonce, fn items test "usage of `new` is careful about where the invocation parens end up", -> eq 'object', typeof new try Array eq 'object', typeof new do -> -> test "implicit call against control structures", -> result = null save = (obj) -> result = obj save switch id false when true 'true' when false 'false' eq result, 'false' save if id false 'false' else 'true' eq result, 'true' save unless id false 'true' else 'false' eq result, 'true' save try doesnt exist catch error 'caught' eq result, 'caught' save try doesnt(exist) catch error then 'caught2' eq result, 'caught2' test "#1420: things like `(fn() ->)`; there are no words for this one", -> fn = -> (f) -> f() nonce = {} eq nonce, (fn() -> nonce) test "#1416: don't omit one 'new' when compiling 'new new'", -> nonce = {} obj = new new -> -> {prop: nonce} eq obj.prop, nonce test "#1416: don't omit one 'new' when compiling 'new new fn()()'", -> nonce = {} argNonceA = {} argNonceB = {} fn = (a) -> (b) -> {a, b, prop: nonce} obj = new new fn(argNonceA)(argNonceB) eq obj.prop, nonce eq obj.a, argNonceA eq obj.b, argNonceB test "#1840: accessing the `prototype` after function invocation should compile", -> doesNotThrow -> CoffeeScript.compile 'fn()::prop' nonce = {} class Test then id: nonce dotAccess = -> Test:: protoAccess = -> Test eq dotAccess().id, nonce eq protoAccess()::id, nonce test "#960: improved 'do'", -> do (nonExistent = 'one') -> eq nonExistent, 'one' overridden = 1 do (overridden = 2) -> eq overridden, 2 two = 2 do (one = 1, two, three = 3) -> eq one, 1 eq two, 2 eq three, 3 ret = do func = (two) -> eq two, 2 func eq ret, func coffee-script-1.4.0/test/functions.coffee000066400000000000000000000110661204160075300204070ustar00rootroot00000000000000# Function Literals # ----------------- # TODO: add indexing and method invocation tests: (->)[0], (->).call() # * Function Definition # * Bound Function Definition # * Parameter List Features # * Splat Parameters # * Context (@) Parameters # * Parameter Destructuring # * Default Parameters # Function Definition x = 1 y = {} y.x = -> 3 ok x is 1 ok typeof(y.x) is 'function' ok y.x instanceof Function ok y.x() is 3 # The empty function should not cause a syntax error. -> () -> # Multiple nested function declarations mixed with implicit calls should not # cause a syntax error. (one) -> (two) -> three four, (five) -> six seven, eight, (nine) -> # with multiple single-line functions on the same line. func = (x) -> (x) -> (x) -> x ok func(1)(2)(3) is 3 # Make incorrect indentation safe. func = -> obj = { key: 10 } obj.key - 5 eq func(), 5 # Ensure that functions with the same name don't clash with helper functions. del = -> 5 ok del() is 5 # Bound Function Definition obj = bound: -> (=> this)() unbound: -> (-> this)() nested: -> (=> (=> (=> this)() )() )() eq obj, obj.bound() ok obj isnt obj.unbound() eq obj, obj.nested() test "even more fancy bound functions", -> obj = one: -> do => return this.two() two: -> do => do => do => return this.three three: 3 eq obj.one(), 3 test "self-referencing functions", -> changeMe = -> changeMe = 2 changeMe() eq changeMe, 2 # Parameter List Features test "splats", -> arrayEq [0, 1, 2], (((splat...) -> splat) 0, 1, 2) arrayEq [2, 3], (((_, _1, splat...) -> splat) 0, 1, 2, 3) arrayEq [0, 1], (((splat..., _, _1) -> splat) 0, 1, 2, 3) arrayEq [2], (((_, _1, splat..., _2) -> splat) 0, 1, 2, 3) test "destructured splatted parameters", -> arr = [0,1,2] splatArray = ([a...]) -> a splatArrayRest = ([a...],b...) -> arrayEq(a,b); b arrayEq splatArray(arr), arr arrayEq splatArrayRest(arr,0,1,2), arr test "@-parameters: automatically assign an argument's value to a property of the context", -> nonce = {} ((@prop) ->).call context = {}, nonce eq nonce, context.prop # allow splats along side the special argument ((splat..., @prop) ->).apply context = {}, [0, 0, nonce] eq nonce, context.prop # allow the argument itself to be a splat ((@prop...) ->).call context = {}, 0, nonce, 0 eq nonce, context.prop[1] # the argument should still be able to be referenced normally eq nonce, (((@prop) -> prop).call {}, nonce) test "@-parameters and splats with constructors", -> a = {} b = {} class Klass constructor: (@first, splat..., @last) -> obj = new Klass a, 0, 0, b eq a, obj.first eq b, obj.last test "destructuring in function definition", -> (([{a: [b], c}]...) -> eq 1, b eq 2, c ) {a: [1], c: 2} test "default values", -> nonceA = {} nonceB = {} a = (_,_1,arg=nonceA) -> arg eq nonceA, a() eq nonceA, a(0) eq nonceB, a(0,0,nonceB) eq nonceA, a(0,0,undefined) eq nonceA, a(0,0,null) eq false , a(0,0,false) eq nonceB, a(undefined,undefined,nonceB,undefined) b = (_,arg=nonceA,_1,_2) -> arg eq nonceA, b() eq nonceA, b(0) eq nonceB, b(0,nonceB) eq nonceA, b(0,undefined) eq nonceA, b(0,null) eq false , b(0,false) eq nonceB, b(undefined,nonceB,undefined) c = (arg=nonceA,_,_1) -> arg eq nonceA, c() eq 0, c(0) eq nonceB, c(nonceB) eq nonceA, c(undefined) eq nonceA, c(null) eq false , c(false) eq nonceB, c(nonceB,undefined,undefined) test "default values with @-parameters", -> a = {} b = {} obj = f: (q = a, @p = b) -> q eq a, obj.f() eq b, obj.p test "default values with splatted arguments", -> withSplats = (a = 2, b..., c = 3, d = 5) -> a * (b.length + 1) * c * d eq 30, withSplats() eq 15, withSplats(1) eq 5, withSplats(1,1) eq 1, withSplats(1,1,1) eq 2, withSplats(1,1,1,1) test "default values with function calls", -> doesNotThrow -> CoffeeScript.compile "(x = f()) ->" test "arguments vs parameters", -> doesNotThrow -> CoffeeScript.compile "f(x) ->" f = (g) -> g() eq 5, f (x) -> 5 test "#1844: bound functions in nested comprehensions causing empty var statements", -> a = ((=>) for a in [0] for b in [0]) eq 1, a.length test "#1859: inline function bodies shouldn't modify prior postfix ifs", -> list = [1, 2, 3] ok true if list.some (x) -> x is 2 test "#2258: allow whitespace-style parameter lists in function definitions", -> func = ( a, b, c ) -> c eq func(1, 2, 3), 3 func = ( a b c ) -> b eq func(1, 2, 3), 2coffee-script-1.4.0/test/helpers.coffee000066400000000000000000000045031204160075300200370ustar00rootroot00000000000000# Helpers # ------- # pull the helpers from `CoffeeScript.helpers` into local variables {starts, ends, compact, count, merge, extend, flatten, del, last} = CoffeeScript.helpers # `starts` test "the `starts` helper tests if a string starts with another string", -> ok starts('01234', '012') ok not starts('01234', '123') test "the `starts` helper can take an optional offset", -> ok starts('01234', '34', 3) ok not starts('01234', '01', 1) # `ends` test "the `ends` helper tests if a string ends with another string", -> ok ends('01234', '234') ok not ends('01234', '012') test "the `ends` helper can take an optional offset", -> ok ends('01234', '012', 2) ok not ends('01234', '234', 6) # `compact` test "the `compact` helper removes falsey values from an array, preserves truthy ones", -> allValues = [1, 0, false, obj={}, [], '', ' ', -1, null, undefined, true] truthyValues = [1, obj, [], ' ', -1, true] arrayEq truthyValues, compact(allValues) # `count` test "the `count` helper counts the number of occurances of a string in another string", -> eq 1/0, count('abc', '') eq 0, count('abc', 'z') eq 1, count('abc', 'a') eq 1, count('abc', 'b') eq 2, count('abcdc', 'c') eq 2, count('abcdabcd','abc') # `merge` test "the `merge` helper makes a new object with all properties of the objects given as its arguments", -> ary = [0, 1, 2, 3, 4] obj = {} merged = merge obj, ary ok merged isnt obj ok merged isnt ary for own key, val of ary eq val, merged[key] # `extend` test "the `extend` helper performs a shallow copy", -> ary = [0, 1, 2, 3] obj = {} # should return the object being extended eq obj, extend(obj, ary) # should copy the other object's properties as well (obviously) eq 2, obj[2] # `flatten` test "the `flatten` helper flattens an array", -> success = yes (success and= typeof n is 'number') for n in flatten [0, [[[1]], 2], 3, [4]] ok success # `del` test "the `del` helper deletes a property from an object and returns the deleted value", -> obj = [0, 1, 2] eq 1, del(obj, 1) ok 1 not of obj # `last` test "the `last` helper returns the last item of an array-like object", -> ary = [0, 1, 2, 3, 4] eq 4, last(ary) test "the `last` helper allows one to specify an optional offset", -> ary = [0, 1, 2, 3, 4] eq 2, last(ary, 2) coffee-script-1.4.0/test/importing.coffee000066400000000000000000000006551204160075300204110ustar00rootroot00000000000000# Importing # --------- unless window? or testingBrowser? test "coffeescript modules can be imported and executed", -> magicKey = __filename magicValue = 0xFFFF if global[magicKey]? if exports? local = magicValue exports.method = -> local else global[magicKey] = {} if require?.extensions? ok require(__filename).method() is magicValue delete global[magicKey] coffee-script-1.4.0/test/interpolation.coffee000066400000000000000000000067201204160075300212670ustar00rootroot00000000000000# Interpolation # ------------- # * String Interpolation # * Regular Expression Interpolation # String Interpolation # TODO: refactor string interpolation tests eq 'multiline nested "interpolations" work', """multiline #{ "nested #{ ok true "\"interpolations\"" }" } work""" # Issue #923: Tricky interpolation. eq "#{ "{" }", "{" eq "#{ '#{}}' } }", '#{}} }' eq "#{"'#{ ({a: "b#{1}"}['a']) }'"}", "'b1'" # Issue #1150: String interpolation regression eq "#{'"/'}", '"/' eq "#{"/'"}", "/'" eq "#{/'"/}", '/\'"/' eq "#{"'/" + '/"' + /"'/}", '\'//"/"\'/' eq "#{"'/"}#{'/"'}#{/"'/}", '\'//"/"\'/' eq "#{6 / 2}", '3' eq "#{6 / 2}#{6 / 2}", '33' # parsed as division eq "#{6 + /2}#{6/ + 2}", '6/2}#{6/2' # parsed as a regex eq "#{6/2} #{6/2}", '3 3' # newline cannot be part of a regex, so it's division eq "#{/// "'/'"/" ///}", '/"\'\\/\'"\\/"/' # heregex, stuffed with spicy characters eq "#{/\\'/}", "/\\\\'/" hello = 'Hello' world = 'World' ok '#{hello} #{world}!' is '#{hello} #{world}!' ok "#{hello} #{world}!" is 'Hello World!' ok "[#{hello}#{world}]" is '[HelloWorld]' ok "#{hello}##{world}" is 'Hello#World' ok "Hello #{ 1 + 2 } World" is 'Hello 3 World' ok "#{hello} #{ 1 + 2 } #{world}" is "Hello 3 World" [s, t, r, i, n, g] = ['s', 't', 'r', 'i', 'n', 'g'] ok "#{s}#{t}#{r}#{i}#{n}#{g}" is 'string' ok "\#{s}\#{t}\#{r}\#{i}\#{n}\#{g}" is '#{s}#{t}#{r}#{i}#{n}#{g}' ok "\#{string}" is '#{string}' ok "\#{Escaping} first" is '#{Escaping} first' ok "Escaping \#{in} middle" is 'Escaping #{in} middle' ok "Escaping \#{last}" is 'Escaping #{last}' ok "##" is '##' ok "#{}" is '' ok "#{}A#{} #{} #{}B#{}" is 'A B' ok "\\\#{}" is '\\#{}' ok "I won ##{20} last night." is 'I won #20 last night.' ok "I won ##{'#20'} last night." is 'I won ##20 last night.' ok "#{hello + world}" is 'HelloWorld' ok "#{hello + ' ' + world + '!'}" is 'Hello World!' list = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] ok "values: #{list.join(', ')}, length: #{list.length}." is 'values: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, length: 10.' ok "values: #{list.join ' '}" is 'values: 0 1 2 3 4 5 6 7 8 9' obj = { name: 'Joe' hi: -> "Hello #{@name}." cya: -> "Hello #{@name}.".replace('Hello','Goodbye') } ok obj.hi() is "Hello Joe." ok obj.cya() is "Goodbye Joe." ok "With #{"quotes"}" is 'With quotes' ok 'With #{"quotes"}' is 'With #{"quotes"}' ok "Where is #{obj["name"] + '?'}" is 'Where is Joe?' ok "Where is #{"the nested #{obj["name"]}"}?" is 'Where is the nested Joe?' ok "Hello #{world ? "#{hello}"}" is 'Hello World' ok "Hello #{"#{"#{obj["name"]}" + '!'}"}" is 'Hello Joe!' a = """ Hello #{ "Joe" } """ ok a is "Hello Joe" a = 1 b = 2 c = 3 ok "#{a}#{b}#{c}" is '123' result = null stash = (str) -> result = str stash "a #{ ('aa').replace /a/g, 'b' } c" ok result is 'a bb c' foo = "hello" ok "#{foo.replace("\"", "")}" is 'hello' val = 10 a = """ basic heredoc #{val} on two lines """ b = ''' basic heredoc #{val} on two lines ''' ok a is "basic heredoc 10\non two lines" ok b is "basic heredoc \#{val}\non two lines" eq 'multiline nested "interpolations" work', """multiline #{ "nested #{(-> ok yes "\"interpolations\"" )()}" } work""" # Regular Expression Interpolation # TODO: improve heregex interpolation tests test "heregex interpolation", -> eq /\\#{}\\\"/ + '', /// #{ "#{ '\\' }" # normal comment } # regex comment \#{} \\ \" /// + '' coffee-script-1.4.0/test/javascript_literals.coffee000066400000000000000000000003251204160075300224400ustar00rootroot00000000000000# Javascript Literals # ------------------- # TODO: refactor javascript literal tests # TODO: add indexing and method invocation tests: `[1]`[0] is 1, `function(){}`.call() eq '\\`', ` // Inline JS "\\\`" ` coffee-script-1.4.0/test/numbers.coffee000066400000000000000000000034361204160075300200540ustar00rootroot00000000000000# Number Literals # --------------- # * Decimal Integer Literals # * Octal Integer Literals # * Hexadecimal Integer Literals # * Scientific Notation Integer Literals # * Scientific Notation Non-Integer Literals # * Non-Integer Literals # * Binary Integer Literals # Binary Integer Literals # Binary notation is understood as would be decimal notation. test "Parser recognises binary numbers", -> eq 4, 0b100 # Decimal Integer Literals test "call methods directly on numbers", -> eq 4, 4.valueOf() eq '11', 4.toString 3 eq -1, 3 -4 #764: Numbers should be indexable eq Number::toString, 42['toString'] eq Number::toString, 42.toString # Non-Integer Literals # Decimal number literals. value = .25 + .75 ok value is 1 value = 0.0 + -.25 - -.75 + 0.0 ok value is 0.5 #764: Numbers should be indexable eq Number::toString, 4['toString'] eq Number::toString, 4.2['toString'] eq Number::toString, .42['toString'] eq Number::toString, (4)['toString'] eq Number::toString, 4.toString eq Number::toString, 4.2.toString eq Number::toString, .42.toString eq Number::toString, (4).toString test '#1168: leading floating point suppresses newline', -> eq 1, do -> 1 .5 + 0.5 test "Python-style octal literal notation '0o777'", -> eq 511, 0o777 eq 1, 0o1 eq 1, 0o00001 eq parseInt('0777', 8), 0o777 eq '777', 0o777.toString 8 eq 4, 0o4.valueOf() eq Number::toString, 0o777['toString'] eq Number::toString, 0o777.toString test "#2060: Disallow uppercase radix prefixes and exponential notation", -> for char in ['b', 'o', 'x', 'e'] program = "0#{char}0" doesNotThrow -> CoffeeScript.compile program, bare: yes throws -> CoffeeScript.compile program.toUpperCase(), bare: yes test "#2224: hex literals with 0b or B or E", -> eq 176, 0x0b0 eq 177, 0x0B1 eq 225, 0xE1 coffee-script-1.4.0/test/objects.coffee000066400000000000000000000120431204160075300200240ustar00rootroot00000000000000# Object Literals # --------------- # TODO: refactor object literal tests # TODO: add indexing and method invocation tests: {a}['a'] is a, {a}.a() trailingComma = {k1: "v1", k2: 4, k3: (-> true),} ok trailingComma.k3() and (trailingComma.k2 is 4) and (trailingComma.k1 is "v1") ok {a: (num) -> num is 10 }.a 10 moe = { name: 'Moe' greet: (salutation) -> salutation + " " + @name hello: -> @['greet'] "Hello" 10: 'number' } ok moe.hello() is "Hello Moe" ok moe[10] is 'number' moe.hello = -> this['greet'] "Hello" ok moe.hello() is 'Hello Moe' obj = { is: -> yes, 'not': -> no, } ok obj.is() ok not obj.not() ### Top-level object literal... ### obj: 1 ### ...doesn't break things. ### # Object literals should be able to include keywords. obj = {class: 'höt'} obj.function = 'dog' ok obj.class + obj.function is 'hötdog' # Implicit objects as part of chained calls. pluck = (x) -> x.a eq 100, pluck pluck pluck a: a: a: 100 test "YAML-style object literals", -> obj = a: 1 b: 2 eq 1, obj.a eq 2, obj.b config = development: server: 'localhost' timeout: 10 production: server: 'dreamboat' timeout: 1000 ok config.development.server is 'localhost' ok config.production.server is 'dreamboat' ok config.development.timeout is 10 ok config.production.timeout is 1000 obj = a: 1, b: 2, ok obj.a is 1 ok obj.b is 2 # Implicit objects nesting. obj = options: value: yes fn: -> {} null ok obj.options.value is yes ok obj.fn() is null # Implicit objects with wacky indentation: obj = 'reverse': (obj) -> Array.prototype.reverse.call obj abc: -> @reverse( @reverse @reverse ['a', 'b', 'c'].reverse() ) one: [1, 2, a: 'b' 3, 4] red: orange: yellow: green: 'blue' indigo: 'violet' misdent: [[], [], [], []] ok obj.abc().join(' ') is 'a b c' ok obj.one.length is 5 ok obj.one[4] is 4 ok obj.one[2].a is 'b' ok (key for key of obj.red).length is 2 ok obj.red.orange.yellow.green is 'blue' ok obj.red.indigo is 'violet' ok obj.misdent.toString() is ',,,' #542: Objects leading expression statement should be parenthesized. {f: -> ok yes }.f() + 1 # String-keyed objects shouldn't suppress newlines. one = '>!': 3 six: -> 10 ok not one.six # Shorthand objects with property references. obj = ### comment one ### ### comment two ### one: 1 two: 2 object: -> {@one, @two} list: -> [@one, @two] result = obj.object() eq result.one, 1 eq result.two, 2 eq result.two, obj.list()[1] third = (a, b, c) -> c obj = one: 'one' two: third 'one', 'two', 'three' ok obj.one is 'one' ok obj.two is 'three' test "invoking functions with implicit object literals", -> generateGetter = (prop) -> (obj) -> obj[prop] getA = generateGetter 'a' getArgs = -> arguments a = b = 30 result = getA a: 10 eq 10, result result = getA "a": 20 eq 20, result result = getA a, b:1 eq undefined, result result = getA b:1, a:43 eq 43, result result = getA b:1, a:62 eq undefined, result result = getA b:1 a eq undefined, result result = getA a: b:2 b:1 eq 2, result.b result = getArgs a:1 b c:1 ok result.length is 3 ok result[2].c is 1 result = getA b: 13, a: 42, 2 eq 42, result result = getArgs a:1, (1 + 1) ok result[1] is 2 result = getArgs a:1, b ok result.length is 2 ok result[1] is 30 result = getArgs a:1, b, b:1, a ok result.length is 4 ok result[2].b is 1 throws -> CoffeeScript.compile "a = b:1, c" test "some weird indentation in YAML-style object literals", -> two = (a, b) -> b obj = then two 1, 1: 1 a: b: -> fn c, d: e f: 1 eq 1, obj[1] test "#1274: `{} = a()` compiles to `false` instead of `a()`", -> a = false fn = -> a = true {} = fn() ok a test "#1436: `for` etc. work as normal property names", -> obj = {} eq no, obj.hasOwnProperty 'for' obj.for = 'foo' of obj eq yes, obj.hasOwnProperty 'for' test "#1322: implicit call against implicit object with block comments", -> ((obj, arg) -> eq obj.x * obj.y, 6 ok not arg ) ### x ### x: 2 ### y ### y: 3 test "#1513: Top level bare objs need to be wrapped in parens for unary and existence ops", -> doesNotThrow -> CoffeeScript.run "{}?", bare: true doesNotThrow -> CoffeeScript.run "{}.a++", bare: true test "#1871: Special case for IMPLICIT_END in the middle of an implicit object", -> result = 'result' ident = (x) -> x result = ident one: 1 if false eq result, 'result' result = ident one: 1 two: 2 for i in [1..3] eq result.two.join(' '), '2 2 2' test "#1961, #1974, regression with compound assigning to an implicit object", -> obj = null obj ?= one: 1 two: 2 eq obj.two, 2 obj = null obj or= three: 3 four: 4 eq obj.four, 4 test "#2207: Immediate implicit closes don't close implicit objects", -> func = -> key: for i in [1, 2, 3] then i eq func().key.join(' '), '1 2 3' coffee-script-1.4.0/test/operators.coffee000066400000000000000000000143421204160075300204150ustar00rootroot00000000000000# Operators # --------- # * Operators # * Existential Operator (Binary) # * Existential Operator (Unary) # * Aliased Operators # * [not] in/of # * Chained Comparison test "binary (2-ary) math operators do not require spaces", -> a = 1 b = -1 eq +1, a*-b eq -1, a*+b eq +1, a/-b eq -1, a/+b test "operators should respect new lines as spaced", -> a = 123 + 456 eq 579, a b = "1#{2}3" + "456" eq '123456', b test "multiple operators should space themselves", -> eq (+ +1), (- -1) test "bitwise operators", -> eq 2, (10 & 3) eq 11, (10 | 3) eq 9, (10 ^ 3) eq 80, (10 << 3) eq 1, (10 >> 3) eq 1, (10 >>> 3) num = 10; eq 2, (num &= 3) num = 10; eq 11, (num |= 3) num = 10; eq 9, (num ^= 3) num = 10; eq 80, (num <<= 3) num = 10; eq 1, (num >>= 3) num = 10; eq 1, (num >>>= 3) test "`instanceof`", -> ok new String instanceof String ok new Boolean instanceof Boolean # `instanceof` supports negation by prefixing the operator with `not` ok new Number not instanceof String ok new Array not instanceof Boolean test "use `::` operator on keywords `this` and `@`", -> nonce = {} obj = withAt: -> @::prop withThis: -> this::prop obj.prototype = prop: nonce eq nonce, obj.withAt() eq nonce, obj.withThis() # Existential Operator (Binary) test "binary existential operator", -> nonce = {} b = a ? nonce eq nonce, b a = null b = undefined b = a ? nonce eq nonce, b a = false b = a ? nonce eq false, b a = 0 b = a ? nonce eq 0, b test "binary existential operator conditionally evaluates second operand", -> i = 1 func = -> i -= 1 result = func() ? func() eq result, 0 test "binary existential operator with negative number", -> a = null ? - 1 eq -1, a # Existential Operator (Unary) test "postfix existential operator", -> ok (if nonexistent? then false else true) defined = true ok defined? defined = false ok defined? test "postfix existential operator only evaluates its operand once", -> semaphore = 0 fn = -> ok false if semaphore ++semaphore ok(if fn()? then true else false) test "negated postfix existential operator", -> ok !nothing?.value test "postfix existential operator on expressions", -> eq true, (1 or 0)?, true # `is`,`isnt`,`==`,`!=` test "`==` and `is` should be interchangeable", -> a = b = 1 ok a is 1 and b == 1 ok a == b ok a is b test "`!=` and `isnt` should be interchangeable", -> a = 0 b = 1 ok a isnt 1 and b != 0 ok a != b ok a isnt b # [not] in/of # - `in` should check if an array contains a value using `indexOf` # - `of` should check if a property is defined on an object using `in` test "in, of", -> arr = [1] ok 0 of arr ok 1 in arr # prefixing `not` to `in and `of` should negate them ok 1 not of arr ok 0 not in arr test "`in` should be able to operate on an array literal", -> ok 2 in [0, 1, 2, 3] ok 4 not in [0, 1, 2, 3] arr = [0, 1, 2, 3] ok 2 in arr ok 4 not in arr # should cache the value used to test the array arr = [0] val = 0 ok val++ in arr ok val++ not in arr val = 0 ok val++ of arr ok val++ not of arr test "`of` and `in` should be able to operate on instance variables", -> obj = { list: [2,3] in_list: (value) -> value in @list not_in_list: (value) -> value not in @list of_list: (value) -> value of @list not_of_list: (value) -> value not of @list } ok obj.in_list 3 ok obj.not_in_list 1 ok obj.of_list 0 ok obj.not_of_list 2 test "#???: `in` with cache and `__indexOf` should work in argument lists", -> eq 1, [Object() in Array()].length test "#737: `in` should have higher precedence than logical operators", -> eq 1, 1 in [1] and 1 test "#768: `in` should preserve evaluation order", -> share = 0 a = -> share++ if share is 0 b = -> share++ if share is 1 c = -> share++ if share is 2 ok a() not in [b(),c()] eq 3, share test "#1099: empty array after `in` should compile to `false`", -> eq 1, [5 in []].length eq false, do -> return 0 in [] test "#1354: optimized `in` checks should not happen when splats are present", -> a = [6, 9] eq 9 in [3, a...], true test "#1100: precedence in or-test compilation of `in`", -> ok 0 in [1 and 0] ok 0 in [1, 1 and 0] ok not (0 in [1, 0 or 1]) test "#1630: `in` should check `hasOwnProperty`", -> ok undefined not in length: 1 test "#1714: lexer bug with raw range `for` followed by `in`", -> 0 for [1..2] ok not ('a' in ['b']) 0 for [1..2]; ok not ('a' in ['b']) 0 for [1..10] # comment ending ok not ('a' in ['b']) test "#1099: statically determined `not in []` reporting incorrect result", -> ok 0 not in [] # Chained Comparison test "chainable operators", -> ok 100 > 10 > 1 > 0 > -1 ok -1 < 0 < 1 < 10 < 100 test "`is` and `isnt` may be chained", -> ok true is not false is true is not false ok 0 is 0 isnt 1 is 1 test "different comparison operators (`>`,`<`,`is`,etc.) may be combined", -> ok 1 < 2 > 1 ok 10 < 20 > 2+3 is 5 test "some chainable operators can be negated by `unless`", -> ok (true unless 0==10!=100) test "operator precedence: `|` lower than `<`", -> eq 1, 1 | 2 < 3 < 4 test "preserve references", -> a = b = c = 1 # `a == b <= c` should become `a === b && b <= c` # (this test does not seem to test for this) ok a == b <= c test "chained operations should evaluate each value only once", -> a = 0 ok 1 > a++ < 1 test "#891: incorrect inversion of chained comparisons", -> ok (true unless 0 > 1 > 2) ok (true unless (NaN = 0/0) < 0/0 < NaN) test "#1234: Applying a splat to :: applies the splat to the wrong object", -> nonce = {} class C method: -> @nonce nonce: nonce arr = [] eq nonce, C::method arr... # should be applied to `C::` test "#1102: String literal prevents line continuation", -> eq "': '", '' + "': '" test "#1703, ---x is invalid JS", -> x = 2 eq (- --x), -1 test "Regression with implicit calls against an indented assignment", -> eq 1, a = 1 eq a, 1 test "#2155 ... conditional assignment to a closure", -> x = null func = -> x ?= (-> if true then 'hi') func() eq x(), 'hi' test "#2197: Existential existential double trouble", -> counter = 0 func = -> counter++ func()? ? 100 eq counter, 1 coffee-script-1.4.0/test/option_parser.coffee000066400000000000000000000024731204160075300212650ustar00rootroot00000000000000# Option Parser # ------------- # TODO: refactor option parser tests # Ensure that the OptionParser handles arguments correctly. return unless require? {OptionParser} = require './../lib/coffee-script/optparse' opt = new OptionParser [ ['-r', '--required [DIR]', 'desc required'] ['-o', '--optional', 'desc optional'] ['-l', '--list [FILES*]', 'desc list'] ] test "basic arguments", -> args = ['one', 'two', 'three', '-r', 'dir'] result = opt.parse args arrayEq args, result.arguments eq undefined, result.required test "boolean and parameterised options", -> result = opt.parse ['--optional', '-r', 'folder', 'one', 'two'] ok result.optional eq 'folder', result.required arrayEq ['one', 'two'], result.arguments test "list options", -> result = opt.parse ['-l', 'one.txt', '-l', 'two.txt', 'three'] arrayEq ['one.txt', 'two.txt'], result.list arrayEq ['three'], result.arguments test "-- and interesting combinations", -> result = opt.parse ['-o','-r','a','-r','b','-o','--','-a','b','--c','d'] arrayEq ['-a', 'b', '--c', 'd'], result.arguments ok result.optional eq 'b', result.required args = ['--','-o','a','-r','c','-o','--','-a','arg0','-b','arg1'] result = opt.parse args eq undefined, result.optional eq undefined, result.required arrayEq args[1..], result.arguments coffee-script-1.4.0/test/ranges.coffee000066400000000000000000000044521204160075300176570ustar00rootroot00000000000000# Range Literals # -------------- # TODO: add indexing and method invocation tests: [1..4][0] is 1, [0...3].toString() # shared array shared = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] test "basic inclusive ranges", -> arrayEq [1, 2, 3] , [1..3] arrayEq [0, 1, 2] , [0..2] arrayEq [0, 1] , [0..1] arrayEq [0] , [0..0] arrayEq [-1] , [-1..-1] arrayEq [-1, 0] , [-1..0] arrayEq [-1, 0, 1], [-1..1] test "basic exclusive ranges", -> arrayEq [1, 2, 3] , [1...4] arrayEq [0, 1, 2] , [0...3] arrayEq [0, 1] , [0...2] arrayEq [0] , [0...1] arrayEq [-1] , [-1...0] arrayEq [-1, 0] , [-1...1] arrayEq [-1, 0, 1], [-1...2] arrayEq [], [1...1] arrayEq [], [0...0] arrayEq [], [-1...-1] test "downward ranges", -> arrayEq shared, [9..0].reverse() arrayEq [5, 4, 3, 2] , [5..2] arrayEq [2, 1, 0, -1], [2..-1] arrayEq [3, 2, 1] , [3..1] arrayEq [2, 1, 0] , [2..0] arrayEq [1, 0] , [1..0] arrayEq [0] , [0..0] arrayEq [-1] , [-1..-1] arrayEq [0, -1] , [0..-1] arrayEq [1, 0, -1] , [1..-1] arrayEq [0, -1, -2], [0..-2] arrayEq [4, 3, 2], [4...1] arrayEq [3, 2, 1], [3...0] arrayEq [2, 1] , [2...0] arrayEq [1] , [1...0] arrayEq [] , [0...0] arrayEq [] , [-1...-1] arrayEq [0] , [0...-1] arrayEq [0, -1] , [0...-2] arrayEq [1, 0] , [1...-1] arrayEq [2, 1, 0], [2...-1] test "ranges with variables as enpoints", -> [a, b] = [1, 3] arrayEq [1, 2, 3], [a..b] arrayEq [1, 2] , [a...b] b = -2 arrayEq [1, 0, -1, -2], [a..b] arrayEq [1, 0, -1] , [a...b] test "ranges with expressions as endpoints", -> [a, b] = [1, 3] arrayEq [2, 3, 4, 5, 6], [(a+1)..2*b] arrayEq [2, 3, 4, 5] , [(a+1)...2*b] test "large ranges are generated with looping constructs", -> down = [99..0] eq 100, (len = down.length) eq 0, down[len - 1] up = [0...100] eq 100, (len = up.length) eq 99, up[len - 1] test "#1012 slices with arguments object", -> expected = [0..9] argsAtStart = (-> [arguments[0]..9]) 0 arrayEq expected, argsAtStart argsAtEnd = (-> [0..arguments[0]]) 9 arrayEq expected, argsAtEnd argsAtBoth = (-> [arguments[0]..arguments[1]]) 0, 9 arrayEq expected, argsAtBoth test "#1409: creating large ranges outside of a function body", -> CoffeeScript.eval '[0..100]' coffee-script-1.4.0/test/regexps.coffee000066400000000000000000000025021204160075300200470ustar00rootroot00000000000000# Regular Expression Literals # --------------------------- # TODO: add method invocation tests: /regex/.toString() # * Regexen # * Heregexen test "basic regular expression literals", -> ok 'a'.match(/a/) ok 'a'.match /a/ ok 'a'.match(/a/g) ok 'a'.match /a/g test "division is not confused for a regular expression", -> eq 2, 4 / 2 / 1 a = 4 b = 2 g = 1 eq 2, a / b/g a = 10 b = a /= 4 / 2 eq a, 5 obj = method: -> 2 two = 2 eq 2, (obj.method()/two + obj.method()/two) i = 1 eq 2, (4)/2/i eq 1, i/i/i test "#764: regular expressions should be indexable", -> eq /0/['source'], ///#{0}///['source'] test "#584: slashes are allowed unescaped in character classes", -> ok /^a\/[/]b$/.test 'a//b' test "#1724: regular expressions beginning with `*`", -> throws -> CoffeeScript.compile '/*/' # Heregexe(n|s) test "a heregex will ignore whitespace and comments", -> eq /^I'm\x20+[a]\s+Heregex?\/\/\//gim + '', /// ^ I'm \x20+ [a] \s+ Heregex? / // # or not ///gim + '' test "an empty heregex will compile to an empty, non-capturing group", -> eq /(?:)/ + '', /// /// + '' test "#1724: regular expressions beginning with `*`", -> throws -> CoffeeScript.compile '/// * ///' test "empty regular expressions with flags", -> fn = (x) -> x a = "" + //i fn "" eq '/(?:)/i', a coffee-script-1.4.0/test/repl.coffee000066400000000000000000000000411204160075300173300ustar00rootroot00000000000000# REPL # ---- # TODO: add tests coffee-script-1.4.0/test/scope.coffee000066400000000000000000000037771204160075300175220ustar00rootroot00000000000000# Scope # ----- # * Variable Safety # * Variable Shadowing # * Auto-closure (`do`) # * Global Scope Leaks test "reference `arguments` inside of functions", -> sumOfArgs = -> sum = (a,b) -> a + b sum = 0 sum += num for num in arguments sum eq 10, sumOfArgs(0, 1, 2, 3, 4) test "assignment to an Object.prototype-named variable should not leak to outer scope", -> # FIXME: fails on IE (-> constructor = 'word' )() ok constructor isnt 'word' test "siblings of splat parameters shouldn't leak to surrounding scope", -> x = 10 oops = (x, args...) -> oops(20, 1, 2, 3) eq x, 10 test "catch statements should introduce their argument to scope", -> try throw '' catch e do -> e = 5 eq 5, e class Array then slice: fail # needs to be global class Object then hasOwnProperty: fail test "#1973: redefining Array/Object constructors shouldn't confuse __X helpers", -> arr = [1..4] arrayEq [3, 4], arr[2..] obj = {arr} for own k of obj eq arr, obj[k] test "#2255: global leak with splatted @-params", -> ok not x? arrayEq [0], ((@x...) -> @x).call {}, 0 ok not x? test "#1183: super + fat arrows", -> dolater = (cb) -> cb() class A constructor: -> @_i = 0 foo : (cb) -> dolater => @_i += 1 cb() class B extends A constructor : -> super foo : (cb) -> dolater => dolater => @_i += 2 super cb b = new B b.foo => eq b._i, 3 test "#1183: super + wrap", -> class A m : -> 10 class B extends A constructor : -> super B::m = -> r = try super() eq (new B).m(), 10 test "#1183: super + closures", -> class A constructor: -> @i = 10 foo : -> @i class B extends A foo : -> ret = switch 1 when 0 then 0 when 1 then super() ret eq (new B).foo(), 10 test "#2331: bound super regression", -> class A @value = 'A' method: -> @constructor.value class B extends A method: => super eq (new B).method(), 'A'coffee-script-1.4.0/test/slicing_and_splicing.coffee000066400000000000000000000062731204160075300225450ustar00rootroot00000000000000# Slicing and Splicing # -------------------- # * Slicing # * Splicing # shared array shared = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] # Slicing test "basic slicing", -> arrayEq [7, 8, 9] , shared[7..9] arrayEq [2, 3] , shared[2...4] arrayEq [2, 3, 4, 5], shared[2...6] test "slicing with variables as endpoints", -> [a, b] = [1, 4] arrayEq [1, 2, 3, 4], shared[a..b] arrayEq [1, 2, 3] , shared[a...b] test "slicing with expressions as endpoints", -> [a, b] = [1, 3] arrayEq [2, 3, 4, 5, 6], shared[(a+1)..2*b] arrayEq [2, 3, 4, 5] , shared[a+1...(2*b)] test "unbounded slicing", -> arrayEq [7, 8, 9] , shared[7..] arrayEq [8, 9] , shared[-2..] arrayEq [9] , shared[-1...] arrayEq [0, 1, 2] , shared[...3] arrayEq [0, 1, 2, 3], shared[..-7] arrayEq shared , shared[..-1] arrayEq shared[0..8], shared[...-1] for a in [-shared.length..shared.length] arrayEq shared[a..] , shared[a...] for a in [-shared.length+1...shared.length] arrayEq shared[..a][...-1] , shared[...a] arrayEq [1, 2, 3], [1, 2, 3][..] test "#930, #835, #831, #746 #624: inclusive slices to -1 should slice to end", -> arrayEq shared, shared[0..-1] arrayEq shared, shared[..-1] arrayEq shared.slice(1,shared.length), shared[1..-1] test "string slicing", -> str = "abcdefghijklmnopqrstuvwxyz" ok str[1...1] is "" ok str[1..1] is "b" ok str[1...5] is "bcde" ok str[0..4] is "abcde" ok str[-5..] is "vwxyz" test "#1722: operator precedence in unbounded slice compilation", -> list = [0..9] n = 2 # some truthy number in `list` arrayEq [0..n], list[..n] arrayEq [0..n], list[..n or 0] arrayEq [0..n], list[..if n then n else 0] test "#2349: inclusive slicing to numeric strings", -> arrayEq [0, 1], [0..10][.."1"] # Splicing test "basic splicing", -> ary = [0..9] ary[5..9] = [0, 0, 0] arrayEq [0, 1, 2, 3, 4, 0, 0, 0], ary ary = [0..9] ary[2...8] = [] arrayEq [0, 1, 8, 9], ary test "unbounded splicing", -> ary = [0..9] ary[3..] = [9, 8, 7] arrayEq [0, 1, 2, 9, 8, 7]. ary ary[...3] = [7, 8, 9] arrayEq [7, 8, 9, 9, 8, 7], ary ary[..] = [1, 2, 3] arrayEq [1, 2, 3], ary test "splicing with variables as endpoints", -> [a, b] = [1, 8] ary = [0..9] ary[a..b] = [2, 3] arrayEq [0, 2, 3, 9], ary ary = [0..9] ary[a...b] = [5] arrayEq [0, 5, 8, 9], ary test "splicing with expressions as endpoints", -> [a, b] = [1, 3] ary = [0..9] ary[ a+1 .. 2*b+1 ] = [4] arrayEq [0, 1, 4, 8, 9], ary ary = [0..9] ary[a+1...2*b+1] = [4] arrayEq [0, 1, 4, 7, 8, 9], ary test "splicing to the end, against a one-time function", -> ary = null fn = -> if ary throw 'err' else ary = [1, 2, 3] fn()[0..] = 1 arrayEq ary, [1] test "the return value of a splice literal should be the RHS", -> ary = [0, 0, 0] eq (ary[0..1] = 2), 2 ary = [0, 0, 0] eq (ary[0..] = 3), 3 arrayEq [ary[0..0] = 0], [0] test "#1723: operator precedence in unbounded splice compilation", -> n = 4 # some truthy number in `list` list = [0..9] list[..n] = n arrayEq [n..9], list list = [0..9] list[..n or 0] = n arrayEq [n..9], list list = [0..9] list[..if n then n else 0] = n arrayEq [n..9], list coffee-script-1.4.0/test/soaks.coffee000066400000000000000000000061131204160075300175140ustar00rootroot00000000000000# Soaks # ----- # * Soaked Property Access # * Soaked Method Invocation # * Soaked Function Invocation # Soaked Property Access test "soaked property access", -> nonce = {} obj = a: b: nonce eq nonce , obj?.a.b eq nonce , obj?['a'].b eq nonce , obj.a?.b eq nonce , obj?.a?['b'] eq undefined, obj?.a?.non?.existent?.property test "soaked property access caches method calls", -> nonce ={} obj = fn: -> a: nonce eq nonce , obj.fn()?.a eq undefined, obj.fn()?.b test "soaked property access caching", -> nonce = {} counter = 0 fn = -> counter++ 'self' obj = self: -> @ prop: nonce eq nonce, obj[fn()]()[fn()]()[fn()]()?.prop eq 3, counter test "method calls on soaked methods", -> nonce = {} obj = null eq undefined, obj?.a().b() obj = a: -> b: -> nonce eq nonce , obj?.a().b() test "postfix existential operator mixes well with soaked property accesses", -> eq false, nonexistent?.property? test "function invocation with soaked property access", -> id = (_) -> _ eq undefined, id nonexistent?.method() test "if-to-ternary should safely parenthesize soaked property accesses", -> ok (if nonexistent?.property then false else true) test "#726", -> # TODO: check this test, looks like it's not really testing anything eq undefined, nonexistent?[Date()] test "#756", -> # TODO: improve this test a = null ok isNaN a?.b.c + 1 eq undefined, a?.b.c += 1 eq undefined, ++a?.b.c eq undefined, delete a?.b.c test "operations on soaked properties", -> # TODO: improve this test a = b: {c: 0} eq 1, a?.b.c + 1 eq 1, a?.b.c += 1 eq 2, ++a?.b.c eq yes, delete a?.b.c # Soaked Method Invocation test "soaked method invocation", -> nonce = {} counter = 0 obj = self: -> @ increment: -> counter++; @ eq obj , obj.self?() eq undefined, obj.method?() eq nonce , obj.self?().property = nonce eq undefined, obj.method?().property = nonce eq obj , obj.increment().increment().self?() eq 2 , counter test "#733", -> a = b: {c: null} eq a.b?.c?(), undefined a.b?.c or= (it) -> it eq a.b?.c?(1), 1 eq a.b?.c?([2, 3]...), 2 # Soaked Function Invocation test "soaked function invocation", -> nonce = {} id = (_) -> _ eq nonce , id?(nonce) eq nonce , (id? nonce) eq undefined, nonexistent?(nonce) eq undefined, (nonexistent? nonce) test "soaked function invocation with generated functions", -> nonce = {} id = (_) -> _ maybe = (fn, arg) -> if typeof fn is 'function' then () -> fn(arg) eq maybe(id, nonce)?(), nonce eq (maybe id, nonce)?(), nonce eq (maybe false, nonce)?(), undefined test "soaked constructor invocation", -> eq 42 , +new Number? 42 eq undefined, new Other? 42 test "soaked constructor invocations with caching and property access", -> semaphore = 0 nonce = {} class C constructor: -> ok false if semaphore semaphore++ prop: nonce eq nonce, (new C())?.prop eq 1, semaphore test "soaked function invocation safe on non-functions", -> eq undefined, 0?(1) eq undefined, 0? 1, 2 coffee-script-1.4.0/test/strict.coffee000066400000000000000000000123231204160075300177040ustar00rootroot00000000000000# Strict Early Errors # ------------------- # The following are prohibited under ES5's `strict` mode # * `Octal Integer Literals` # * `Octal Escape Sequences` # * duplicate property definitions in `Object Literal`s # * duplicate formal parameter # * `delete` operand is a variable # * `delete` operand is a parameter # * `delete` operand is `undefined` # * `Future Reserved Word`s as identifiers: implements, interface, let, package, private, protected, public, static, yield # * `eval` or `arguments` as `catch` identifier # * `eval` or `arguments` as formal parameter # * `eval` or `arguments` as function declaration identifier # * `eval` or `arguments` as LHS of assignment # * `eval` or `arguments` as the operand of a post/pre-fix inc/dec-rement expression # helper to assert that code complies with strict prohibitions strict = (code, msg) -> throws (-> CoffeeScript.compile code), null, msg ? code strictOk = (code, msg) -> doesNotThrow (-> CoffeeScript.compile code), msg ? code test "octal integer literals prohibited", -> strict '01' strict '07777' # decimals with a leading '0' are also prohibited strict '09' strict '079' strictOk '`01`' test "octal escape sequences prohibited", -> strict '"\\1"' strict '"\\7"' strict '"\\001"' strict '"\\777"' strict '"_\\1"' strict '"\\1_"' strict '"_\\1_"' strict '"\\\\\\1"' strictOk '"\\0"' eq "\x00", "\0" strictOk '"\\08"' eq "\x008", "\08" strictOk '"\\0\\8"' eq "\x008", "\0\8" strictOk '"\\8"' eq "8", "\8" strictOk '"\\\\1"' eq "\\" + "1", "\\1" strictOk '"\\\\\\\\1"' eq "\\\\" + "1", "\\\\1" strictOk "`'\\1'`" eq "\\" + "1", `"\\1"` test "duplicate formal parameters are prohibited", -> nonce = {} # a Param can be an Identifier, ThisProperty( @-param ), Array, or Object # a Param can also be a splat (...) or an assignment (param=value) # the following function expressions should throw errors strict '(_,_)->', 'param, param' strict '(_,@_)->', 'param, @param' strict '(_,_...)->', 'param, param...' strict '(@_,_...)->', '@param, param...' strict '(_,_ = true)->', 'param, param=' strict '(@_,@_)->', 'two @params' strict '(_,@_ = true)->', 'param, @param=' strict '(_,{_})->', 'param, {param}' strict '(@_,{_})->', '@param, {param}' strict '({_,_})->', '{param, param}' strict '({_,@_})->', '{param, @param}' strict '(_,[_])->', 'param, [param]' strict '([_,_])->', '[param, param]' strict '([_,@_])->', '[param, @param]' strict '(_,[_]=true)->', 'param, [param]=' strict '(_,[@_,{_}])->', 'param, [@param, {param}]' strict '(_,[_,{@_}])->', 'param, [param, {@param}]' strict '(_,[_,{_}])->', 'param, [param, {param}]' strict '(_,[_,{__}])->', 'param, [param, {param2}]' strict '(_,[__,{_}])->', 'param, [param2, {param}]' strict '(__,[_,{_}])->', 'param, [param2, {param2}]' strict '(0:a,1:a)->', '0:param,1:param' strict '({0:a,1:a})->', '{0:param,1:param}' # the following function expressions should **not** throw errors strictOk '({},_arg)->' strictOk '({},{})->' strictOk '([]...,_arg)->' strictOk '({}...,_arg)->' strictOk '({}...,[],_arg)->' strictOk '([]...,{},_arg)->' strictOk '(@case,_case)->' strictOk '(@case,_case...)->' strictOk '(@case...,_case)->' strictOk '(_case,@case)->' strictOk '(_case,@case...)->' strictOk '(a:a)->' strictOk '(a:a,a:b)->' test "`delete` operand restrictions", -> strict 'a = 1; delete a' strictOk 'delete a' #noop strict '(a) -> delete a' strict '(@a) -> delete a' strict '(a...) -> delete a' strict '(a = 1) -> delete a' strict '([a]) -> delete a' strict '({a}) -> delete a' test "`Future Reserved Word`s, `eval` and `arguments` restrictions", -> access = (keyword, check = strict) -> check "#{keyword}.a = 1" check "#{keyword}[0] = 1" assign = (keyword, check = strict) -> check "#{keyword} = 1" check "#{keyword} += 1" check "#{keyword} -= 1" check "#{keyword} *= 1" check "#{keyword} /= 1" check "#{keyword} ?= 1" check "{keyword}++" check "++{keyword}" check "{keyword}--" check "--{keyword}" destruct = (keyword, check = strict) -> check "{#{keyword}}" check "o = {#{keyword}}" invoke = (keyword, check = strict) -> check "#{keyword} yes" check "do #{keyword}" fnDecl = (keyword, check = strict) -> check "class #{keyword}" param = (keyword, check = strict) -> check "(#{keyword}) ->" check "({#{keyword}}) ->" prop = (keyword, check = strict) -> check "a.#{keyword} = 1" tryCatch = (keyword, check = strict) -> check "try new Error catch #{keyword}" future = 'implements interface let package private protected public static yield'.split ' ' for keyword in future access keyword assign keyword destruct keyword invoke keyword fnDecl keyword param keyword prop keyword, strictOk tryCatch keyword for keyword in ['eval', 'arguments'] access keyword, strictOk assign keyword destruct keyword, strictOk invoke keyword, strictOk fnDecl keyword param keyword prop keyword, strictOk tryCatch keyword coffee-script-1.4.0/test/strings.coffee000066400000000000000000000027561204160075300200760ustar00rootroot00000000000000# String Literals # --------------- # TODO: refactor string literal tests # TODO: add indexing and method invocation tests: "string"["toString"] is String::toString, "string".toString() is "string" # * Strings # * Heredocs test "backslash escapes", -> eq "\\/\\\\", /\/\\/.source eq '(((dollars)))', '\(\(\(dollars\)\)\)' eq 'one two three', "one two three" eq "four five", 'four five' #647 eq "''Hello, World\\''", ''' '\'Hello, World\\\'' ''' eq '""Hello, World\\""', """ "\"Hello, World\\\"" """ eq 'Hello, World\n', ''' Hello, World\ ''' a = """ basic heredoc on two lines """ ok a is "basic heredoc\non two lines" a = ''' a "b c ''' ok a is "a\n \"b\nc" a = """ a b c """ ok a is "a\n b\n c" a = '''one-liner''' ok a is 'one-liner' a = """ out here """ ok a is "out\nhere" a = ''' a b c ''' ok a is " a\n b\nc" a = ''' a b c ''' ok a is "a\n\n\nb c" a = '''more"than"one"quote''' ok a is 'more"than"one"quote' a = '''here's an apostrophe''' ok a is "here's an apostrophe" # The indentation detector ignores blank lines without trailing whitespace a = """ one two """ ok a is "one\ntwo\n" eq ''' line 0 should not be relevant to the indent level ''', ' line 0\n should not be relevant\n to the indent level ' eq ''' '\\\' ''', " '\\' " eq """ "\\\" """, ' "\\" ' eq ''' <- keep these spaces -> ''', ' <- keep these spaces -> ' test "#1046, empty string interpolations", -> eq "#{ }", '' coffee-script-1.4.0/test/test.html000066400000000000000000000044511204160075300170730ustar00rootroot00000000000000 CoffeeScript Test Suite

CoffeeScript Test Suite