coffeescript-1.12.7/000077500000000000000000000000001313305734200142575ustar00rootroot00000000000000coffeescript-1.12.7/.gitignore000066400000000000000000000001761313305734200162530ustar00rootroot00000000000000raw presentation test.coffee test*.coffee test.litcoffee test*.litcoffee test/*.js parser.output /node_modules npm-debug.log* coffeescript-1.12.7/.nojekyll000066400000000000000000000000001313305734200160750ustar00rootroot00000000000000coffeescript-1.12.7/CONTRIBUTING.md000066400000000000000000000014461313305734200165150ustar00rootroot00000000000000## How to contribute to CoffeeScript * Before you open a ticket or send a pull request, [search](https://github.com/jashkenas/coffeescript/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/coffeescript/tree/master/test). * Use the same coding style as the rest of the [codebase](https://github.com/jashkenas/coffeescript/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. coffeescript-1.12.7/Cakefile000066400000000000000000000353001313305734200157060ustar00rootroot00000000000000fs = require 'fs' path = require 'path' _ = require 'underscore' { spawn, exec, execSync } = require 'child_process' CoffeeScript = require './lib/coffee-script' helpers = require './lib/coffee-script/helpers' # ANSI Terminal Colors. bold = red = green = reset = '' unless process.env.NODE_DISABLE_COLORS 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 */ """ # Used in folder names like `docs/v1`. majorVersion = parseInt CoffeeScript.VERSION.split('.')[0], 10 # Log a message with a color. log = (message, color, explanation) -> console.log color + message + reset + ' ' + (explanation or '') spawnNodeProcess = (args, output = 'stderr', callback) -> relayOutput = (buffer) -> console.log buffer.toString() proc = spawn 'node', args proc.stdout.on 'data', relayOutput if output is 'both' or output is 'stdout' proc.stderr.on 'data', relayOutput if output is 'both' or output is 'stderr' proc.on 'exit', (status) -> callback(status) if typeof callback is 'function' # Run a CoffeeScript through our node/coffee interpreter. run = (args, callback) -> spawnNodeProcess ['bin/coffee'].concat(args), 'stderr', (status) -> process.exit(1) if status isnt 0 callback() if typeof callback is 'function' # Build the CoffeeScript language from source. buildParser = -> helpers.extend global, require 'util' require 'jison' parser = require('./lib/coffee-script/grammar').parser.generate() # Patch Jison’s output, until https://github.com/zaach/jison/pull/339 is accepted, # to ensure that require('fs') is only called where it exists. parser = parser.replace "var source = require('fs')", """ var source = ''; var fs = require('fs'); if (typeof fs !== 'undefined' && fs !== null) source = fs""" fs.writeFileSync 'lib/coffee-script/parser.js', parser buildExceptParser = (callback) -> files = fs.readdirSync 'src' files = ('src/' + file for file in files when file.match(/\.(lit)?coffee$/)) run ['-c', '-o', 'lib/coffee-script'].concat(files), callback build = (callback) -> buildParser() buildExceptParser callback testBuiltCode = (watch = no) -> csPath = './lib/coffee-script' csDir = path.dirname require.resolve csPath for mod of require.cache when csDir is mod[0 ... csDir.length] delete require.cache[mod] testResults = runTests require csPath unless watch process.exit 1 unless testResults buildAndTest = (includingParser = yes, harmony = no) -> process.stdout.write '\x1Bc' # Clear terminal screen. execSync 'git checkout lib/*', stdio: [0,1,2] # Reset the generated compiler. buildArgs = ['bin/cake'] buildArgs.push if includingParser then 'build' else 'build:except-parser' log "building#{if includingParser then ', including parser' else ''}...", green spawnNodeProcess buildArgs, 'both', -> log 'testing...', green testArgs = if harmony then ['--harmony'] else [] testArgs = testArgs.concat ['bin/cake', 'test'] spawnNodeProcess testArgs, 'both' watchAndBuildAndTest = (harmony = no) -> buildAndTest yes, harmony fs.watch 'src/', interval: 200, (eventType, filename) -> if eventType is 'change' log "src/#{filename} changed, rebuilding..." buildAndTest (filename is 'grammar.coffee'), harmony fs.watch 'test/', {interval: 200, recursive: yes}, (eventType, filename) -> if eventType is 'change' log "test/#{filename} changed, rebuilding..." buildAndTest no, harmony task 'build', 'build the CoffeeScript compiler from source', build task 'build:parser', 'build the Jison parser only', buildParser task 'build:except-parser', 'build the CoffeeScript compiler, except for the Jison parser', buildExceptParser task 'build:full', 'build the CoffeeScript compiler from source twice, and run the tests', -> build -> build testBuiltCode task 'build:browser', 'merge the built scripts into a single file for use in a browser', -> code = """ require['../../package.json'] = (function() { return #{fs.readFileSync "./package.json"}; })(); """ for name in ['helpers', 'rewriter', 'lexer', 'parser', 'scope', 'nodes', 'sourcemap', 'coffee-script', 'browser'] code += """ require['./#{name}'] = (function() { var exports = {}, module = {exports: exports}; #{fs.readFileSync "lib/coffee-script/#{name}.js"} return module.exports; })(); """ 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' {compiledCode: code} = require('google-closure-compiler-js').compile jsCode: [ src: code languageOut: if majorVersion is 1 then 'ES5' else 'ES6' ] outputFolder = "docs/v#{majorVersion}/browser-compiler" fs.mkdirSync outputFolder unless fs.existsSync outputFolder fs.writeFileSync "#{outputFolder}/coffee-script.js", header + '\n' + code task 'build:browser:full', 'merge the built scripts into a single file for use in a browser, and test it', -> invoke 'build:browser' console.log "built ... running browser tests:" invoke 'test:browser' task 'build:watch', 'watch and continually rebuild the CoffeeScript compiler, running tests on each build', -> watchAndBuildAndTest() task 'build:watch:harmony', 'watch and continually rebuild the CoffeeScript compiler, running harmony tests on each build', -> watchAndBuildAndTest yes buildDocs = (watch = no) -> # Constants indexFile = 'documentation/index.html' versionedSourceFolder = "documentation/v#{majorVersion}" sectionsSourceFolder = 'documentation/sections' examplesSourceFolder = 'documentation/examples' outputFolder = "docs/v#{majorVersion}" # Helpers releaseHeader = (date, version, prevVersion) -> monthNames = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'] formatDate = (date) -> date.replace /^(\d\d\d\d)-(\d\d)-(\d\d)$/, (match, $1, $2, $3) -> "#{monthNames[$2 - 1]} #{+$3}, #{$1}" """

#{prevVersion and "#{version}" or version}

""" codeFor = require "./documentation/v#{majorVersion}/code.coffee" htmlFor = -> markdownRenderer = require('markdown-it') html: yes typographer: yes # Add some custom overrides to Markdown-It’s rendering, per # https://github.com/markdown-it/markdown-it/blob/master/docs/architecture.md#renderer defaultFence = markdownRenderer.renderer.rules.fence markdownRenderer.renderer.rules.fence = (tokens, idx, options, env, slf) -> code = tokens[idx].content if code.indexOf('codeFor(') is 0 or code.indexOf('releaseHeader(') is 0 "<%= #{code} %>" else "
#{defaultFence.apply @, arguments}
" (file, bookmark) -> md = fs.readFileSync "#{sectionsSourceFolder}/#{file}.md", 'utf-8' md = md.replace /<%= releaseHeader %>/g, releaseHeader md = md.replace /<%= majorVersion %>/g, majorVersion md = md.replace /<%= fullVersion %>/g, CoffeeScript.VERSION html = markdownRenderer.render md html = _.template(html) codeFor: codeFor() releaseHeader: releaseHeader include = -> (file) -> file = "#{versionedSourceFolder}/#{file}" if file.indexOf('/') is -1 output = fs.readFileSync file, 'utf-8' if /\.html$/.test(file) render = _.template output output = render releaseHeader: releaseHeader majorVersion: majorVersion fullVersion: CoffeeScript.VERSION htmlFor: htmlFor() codeFor: codeFor() include: include() output # Task do renderIndex = -> render = _.template fs.readFileSync(indexFile, 'utf-8') output = render include: include() fs.writeFileSync "#{outputFolder}/index.html", output log 'compiled', green, "#{indexFile} → #{outputFolder}/index.html" try fs.symlinkSync "v#{majorVersion}/index.html", 'docs/index.html' catch exception if watch for target in [indexFile, versionedSourceFolder, examplesSourceFolder, sectionsSourceFolder] fs.watch target, interval: 200, renderIndex log 'watching...', green task 'doc:site', 'build the documentation for the website', -> buildDocs() task 'doc:site:watch', 'watch and continually rebuild the documentation for the website', -> buildDocs yes buildDocTests = (watch = no) -> # Constants testFile = 'documentation/test.html' testsSourceFolder = 'test' outputFolder = "docs/v#{majorVersion}" # Included in test.html testHelpers = fs.readFileSync('test/support/helpers.coffee', 'utf-8').replace /exports\./g, '@' # Helpers testsInScriptBlocks = -> output = '' for filename in fs.readdirSync testsSourceFolder if filename.indexOf('.coffee') isnt -1 type = 'coffeescript' else if filename.indexOf('.litcoffee') isnt -1 type = 'literate-coffeescript' else continue # Set the type to text/x-coffeescript or text/x-literate-coffeescript # to prevent the browser compiler from automatically running the script output += """ \n """ output # Task do renderTest = -> render = _.template fs.readFileSync(testFile, 'utf-8') output = render testHelpers: testHelpers tests: testsInScriptBlocks() fs.writeFileSync "#{outputFolder}/test.html", output log 'compiled', green, "#{testFile} → #{outputFolder}/test.html" if watch for target in [testFile, testsSourceFolder] fs.watch target, interval: 200, renderTest log 'watching...', green task 'doc:test', 'build the browser-based tests', -> buildDocTests() task 'doc:test:watch', 'watch and continually rebuild the browser-based tests', -> buildDocTests yes buildAnnotatedSource = (watch = no) -> do generateAnnotatedSource = -> exec "node_modules/docco/bin/docco src/*.*coffee --output docs/v#{majorVersion}/annotated-source", (err) -> throw err if err log 'generated', green, "annotated source in docs/v#{majorVersion}/annotated-source/" if watch fs.watch 'src/', interval: 200, generateAnnotatedSource log 'watching...', green task 'doc:source', 'build the annotated source documentation', -> buildAnnotatedSource() task 'doc:source:watch', 'watch and continually rebuild the annotated source documentation', -> buildAnnotatedSource yes task 'release', 'build and test the CoffeeScript source, and build the documentation', -> invoke 'build:full' invoke 'build:browser:full' invoke 'doc:site' invoke 'doc:test' invoke 'doc:source' task 'bench', 'quick benchmark of compilation time', -> {Rewriter} = require './lib/coffee-script/rewriter' sources = ['coffee-script', 'grammar', 'helpers', 'lexer', 'nodes', 'rewriter'] coffee = sources.map((name) -> fs.readFileSync "src/#{name}.coffee").join '\n' litcoffee = fs.readFileSync("src/scope.litcoffee").toString() 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 coffee, rewrite: no littokens = CoffeeScript.tokens litcoffee, rewrite: no, literate: yes tokens = tokens.concat(littokens) 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: yes console.log "Compile#{time()} (#{js.length} chars)" console.log "total #{ fmt total }" # Run the CoffeeScript test suite. runTests = (CoffeeScript) -> CoffeeScript.register() startTime = Date.now() currentFile = null passedTests = 0 failures = [] global[name] = func for name, func of require 'assert' # Convenience aliases. global.CoffeeScript = CoffeeScript global.Repl = require './lib/coffee-script/repl' # Our test helper function for delimiting different test cases. global.test = (description, fn) -> try fn.test = {description, currentFile} fn.call(fn) ++passedTests catch e failures.push filename: currentFile error: e description: description if description? source: fn.toString() if fn.toString? helpers.extend global, require './test/support/helpers' # 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, description, source} = fail console.log '' log " #{description}", red if description log " #{error.stack}", red console.log " #{source}" if source return # Run every test in the `test` folder, recording failures. files = fs.readdirSync 'test' for file in files when helpers.isCoffee file literate = helpers.isLiterate file currentFile = filename = path.join 'test', file code = fs.readFileSync filename try CoffeeScript.run code.toString(), {filename, literate} catch error failures.push {filename, error} return !failures.length task 'test', 'run the CoffeeScript language test suite', -> testResults = runTests CoffeeScript process.exit 1 unless testResults task 'test:browser', 'run the test suite against the merged browser script', -> source = fs.readFileSync "docs/v#{majorVersion}/browser-compiler/coffee-script.js", 'utf-8' result = {} global.testingBrowser = yes (-> eval source).call result testResults = runTests result.CoffeeScript process.exit 1 unless testResults coffeescript-1.12.7/LICENSE000066400000000000000000000020501313305734200152610ustar00rootroot00000000000000Copyright (c) 2009-2017 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. coffeescript-1.12.7/README.md000066400000000000000000000034601313305734200155410ustar00rootroot00000000000000 { } } { { { } } } }{ { { }{ } } _____ __ __ { }{ }{ { } / ____| / _|/ _| .- { { } { }} -. | | ___ | |_| |_ ___ ___ ( { } { } { } } ) | | / _ \| _| _/ _ \/ _ \ |`-..________ ..-'| | |___| (_) | | | || __/ __/ | | \_____\___/|_| |_| \___|\___| | ;--. | (__ \ _____ _ _ | | ) ) / ____| (_) | | | |/ / | (___ ___ _ __ _ _ __ | |_ | ( / \___ \ / __| '__| | '_ \| __| | |/ ____) | (__| | | | |_) | |_ | | |_____/ \___|_| |_| .__/ \__| `-.._________..-' | | |_| CoffeeScript is a little language that compiles into JavaScript. ## Installation Once you have Node.js installed: ```shell npm install --global coffeescript ``` Leave off the `--global` if you don’t wish to install globally. ## Getting Started Execute a script: ```shell coffee /path/to/script.coffee ``` Compile a script: ```shell coffee -c /path/to/script.coffee ``` For documentation, usage, and examples, see: http://coffeescript.org/ To suggest a feature or report a bug: https://github.com/jashkenas/coffeescript/issues If you’d like to chat, drop by #coffeescript on Freenode IRC. The source repository: https://github.com/jashkenas/coffeescript.git Changelog: http://coffeescript.org/#changelog Our lovely and talented contributors are listed here: https://github.com/jashkenas/coffeescript/contributors coffeescript-1.12.7/bin/000077500000000000000000000000001313305734200150275ustar00rootroot00000000000000coffeescript-1.12.7/bin/cake000077500000000000000000000010371313305734200156610ustar00rootroot00000000000000#!/usr/bin/env node var path = require('path'); var fs = require('fs'); var potentialPaths = [ path.join(process.cwd(), 'node_modules/coffeescript/lib/coffeescript'), path.join(process.cwd(), 'node_modules/coffeescript/lib/coffee-script'), path.join(process.cwd(), 'node_modules/coffee-script/lib/coffee-script'), path.join(__dirname, '../lib/coffee-script') ]; for (var i = 0, len = potentialPaths.length; i < len; i++) { if (fs.existsSync(potentialPaths[i])) { require(potentialPaths[i] + '/cake').run(); break; } } coffeescript-1.12.7/bin/coffee000077500000000000000000000010421313305734200162010ustar00rootroot00000000000000#!/usr/bin/env node var path = require('path'); var fs = require('fs'); var potentialPaths = [ path.join(process.cwd(), 'node_modules/coffeescript/lib/coffeescript'), path.join(process.cwd(), 'node_modules/coffeescript/lib/coffee-script'), path.join(process.cwd(), 'node_modules/coffee-script/lib/coffee-script'), path.join(__dirname, '../lib/coffee-script') ]; for (var i = 0, len = potentialPaths.length; i < len; i++) { if (fs.existsSync(potentialPaths[i])) { require(potentialPaths[i] + '/command').run(); break; } } coffeescript-1.12.7/bower.json000066400000000000000000000004501313305734200162670ustar00rootroot00000000000000{ "name": "coffee-script", "main": [ "lib/coffee-script/coffee-script.js" ], "description": "Unfancy JavaScript", "keywords": [ "javascript", "language", "coffeescript", "compiler" ], "author": { "name": "Jeremy Ashkenas" }, "ignore": [ "test" ] } coffeescript-1.12.7/docs/000077500000000000000000000000001313305734200152075ustar00rootroot00000000000000coffeescript-1.12.7/docs/CNAME000066400000000000000000000000211313305734200157460ustar00rootroot00000000000000coffeescript.org coffeescript-1.12.7/docs/android-chrome-192x192.png000066400000000000000000000174621313305734200215570ustar00rootroot00000000000000PNG  IHDRRlgAMA a cHRMz&u0`:pQ<bKGDtIME !QIDATxy\Uǿݝ}_:!itH"DAQ8:8Ό88. nDd=a Y!$tNz?~nW{u~>Sޫs=l 0 0 0 0 0 0 0 0 0 0 0 0 0AUOGCcSpwFa@;.wt@yr_N0H1YB> 1uh@n$6`'lֺc {PP S XP8x$HwׅU`x CN;Os.}B K4(p68 8I \ g Es3E/zTxvy"|T0_z֢|)ǮO? +-RT[ȬH;߂=h[ Bℿ8 6dW 3jel6ܵǽd^Рq;fMI'_Aݚ`+c~_vCޅn`kCc!;-W0t8p622izP <|Ϣ`kH(w9{Z{*p4Z7#C XnP1.*#h5c a'"S ~xhVz1Y>!yJrEEE_@K+Eh[y?EBF̤Aik4,%yVs,2h Ó,$&/"}B$xM [4OM:z_DD]=%Xش7 B$a:yGlw &݌L;o@ 9Ed n"x8G7ܽyi@ӱŚwD_H@xY/rPAUl?@Am|>\G&s5Vk/5 4v=rAuLDܹ]>3ldn(s*s7ROPNK8u)ى#s%ED1Q$8g]wFD9Gk.sv@>xwhF^kSH ١_Dl^CSRg\nC%7tGL HyN }(*$4Zg1tܫB^z.4\t[s~dc[E̽A4(9n/v{,IIE73 _Lم܋a`g{~Aed/aF#ۤa$peCcSkY/AS@9hArA)#XW=h!DmEݵEz³?$warމFQЈ6/Ky7c2r睍ܙG!oJ\Wp G ?NU4f\y\-w RXxP]z{SLkѠ6/Ud89D©r09ӣQo2~ )eEu-hv{yGW3ߝ.~?gxٶ(&ЗP^MT6\NPo`$˧?yt!%EFېiA*A{ tEQ@T.tMdy.A#EpM| 6TcLx&Qֿ4d3Q(A;8JFq̜)ȕxw!*IwR -J3㵕E^P\ fn y쉓  ҟ*܇rVEfbKHE(hy|BXJ "ALÑ~?Ҕtnd,&f&EHBYg!*M`]dnAF)2MfQ@^Mq&E=$P$C4ttM"N9 vk )ADY[գ|7\eًf=H ;]Y^w;;z9 ˣ?U]#ǑYX2yA~~xwLFMwd#}}cJ\ր Ta㘏dQYڝu{[ K_etuԐKY $hFnF#è&4Sˮޚa+!_|bN69+Vv1#"&OF Nwb 2кay&Rr!t#3q p>~5Z*)|yDy9>{4LH!@J1{Dk&y19αLUT-RÑ#D,7$nCޯm؈;G#zKUHvUfL9hrJc.I. Icp}>?p.Rv'B +Aƥ>#a#з絻צJ#Fn 0 1;Q?k`!+i+]ǹǹc,}}/=?{d:ϣ߼7c02w4 jw=8vg{=Es.dz*!T~^f7?kre;CvP++@.~F _mH}'I8Խh8 -ԈA; vЙ\(31bsrb!xȣxH!o\P"afd@ m)&t F؃֩#Xb6VޣRxͦdHw Ϊ(0D+𧁞Y<|mg4LF|8Wh'܆y6>Wgի J 1z'Y6ᷢmQlz[pm pJp C+CUh3 (6 ~v]C=hӼ!0+b詆> 3|mmkh3m(/-(}h2}&| [ptʹ[}sq^+|-^<6O1 a$:A{MR="=Hvp'Ձ}hy`RòQlGptH)`@ ^ReT& .xj$_N "Ȇ{"8Qw[&KX^HxC㉹wŊf,F]IY64 a3n1h5}煩Bޣ.j%Z7¸) o'ZPN%3/cs.0N NtKyF@r8 & r[Fchr+*- V-{ۈFbB?=V.{- !^AX yQȳQqjH4nRZ-p }kb;2֔fe%HܪDJ*[ x$J}Sa{o`[sOQ%Uwn?:J4{(,]Gk9FI\tO@Q,0SݢWaJV\DݵZ xyP@bdFF+ehVٺq5ulPm]}֍x90sM+SaIJTRv{ָj8p`X\_By"}:;8څz{HSumu_;NAewFt:ށ)Ȥp$~ Rx h=*UB9> O)3"8%-9[9FݜǡQOs9 V}MCi~HH|u(c*Q\;J؄̚.7b~*)$(%@K tbb;ԛ_,^$F!D9ۿ=>R3(9Ŏ P3P2 |<)huTS, Rx1q gHi@T@'ݨQb[:t7uL[W>*ZO=z"V@-W$ VS/#Q%;ɳ(6R'?x W?z2 ю=;!3x'nFۨs; N'!Чna4r^N-ȋv#2wBe~UE1EÇ_Ԋ!>By:ppsh|ϯ"OS.V1N.Lr)d43b6r{ׅ|+{Q/f"aWK, 2LDh1^^DGs:B/-uxkAQHuh!=߽f$OJ )@x Qb Q#!hcт{{M W.t [ PfԞd >E3F"̥1oQA鞷-{"t !t0 0 0 0 0 0 0 0 0 0 0 0 0 E%tEXtdate:create2016-12-07T07:17:00+01:00?e %tEXtdate:modify2016-12-07T07:17:00+01:00sbݵWzTXtRaw profile type iptcx qV((OIR# .c #K D4d#T ˀHJ.tB5IENDB`coffeescript-1.12.7/docs/android-chrome-512x512.png000066400000000000000000000571771313305734200215560ustar00rootroot00000000000000PNG  IHDRxgAMA a cHRMz&u0`:pQ<bKGDtIME !Q] IDATxw]WyFeԛG45w1ئ9LB)\!$K%=!BBH(78ġ"Wٖ%˲zo#i4xFr.|߯~>{=kg= lLd}ffijLތ%5Rr-jp ,`zhc*08zC !Še*jQnqXcVё4S~W!$? t`8;-v` I`r\Ű `FD _,fSnԛ[F1F }^A&`؆>XYՅ*_,NVgo>YCZ` $ !&f6)Q~3Q*_Ys GTz>~q8Zs`f)_'~zZ %OxxxxSß.|쫧<܊F +Zu80h2२? 53> ln8p`U|x!7짣BN%ֶ]ǖ>qE=sހzd' xn PVڶu͵lMR4riuwd{ &lව?F ~gҌ=6jimzl}Ye(j9О9e %86VFc_Elc5P;:=Ѐ|ӰE~egmr_ǦprD(Z_u?%Κϴ5 )d[q`r9JK@%LQe}8S,ԳXωYM] :ZϿ,s>ѹH0RQ%ZF h}SjNtE  :Z'AArF m 2_,F|m"+&tmUSCe~mui B6Lf5C(>Chcf[5jLHR t u0G[Ij8騺oҽTd) .;v܉FPw4GF8z}rZtLxFZ%(Ȝy>tphɳQ-cKSm̋D#|5jx>z&y`-)/Ukutޏh{ Q >[2LGG[FNF554j0r]ʪ7{N luP#z/qxH lAӎD欟IV4}m eශ_z)/Go|]uhQ YTfވz}?oDN!{-<90`XNԐ]Kݨbi{Ҿ+%,{5Qo\C@7uq< P0lD}|;xJlRTB3]h*w ntNztQOձ^;QKZZފ*Z|4I޽i(ɚuRb29b4?:4OX"mXؒF˘DFEQA[.GDžhhNu&u4uF (ĽUI<QsxB9K&iҚ;?FD {(*E<7FzEyhPDjvߟBnyh Jpyh5I%8?|M=?>T¢JB7ns(*|ojiܙZi_GIuQiy;ʟZ {춇Nov%O-h}F:)ឆzdTd! ~l;JicѨy+ <(w^>UOJ(>ԫըR)㿃P7.Bfԣ:ͫF M@G5sQ?%- DAG^ #G;2k bP2!JC4v5 tM?Zy_tSc8꛿|5Qý*wӹWasPK_߄v=8R-n<4]CGBAmFR Gм<5/R*3F&4b5gڤhP^,@ [G5L" JD+. Pß%T+ڵUfel?]-m3 Tf7]ߌ楛.aCsZr*`6Z#<Gzdt%(#޲1Ae_]cu#ꭟ& ڃr&H} ^vZR_7%86Zjim;hՇF} r}\;돀MkV]ShQt%iDI?$͠l| u^S46ֶҞkSP)~O FyPmWy4N00zkQ]'GzdmkFj~T_:rJFg}Ӻ0-jRKT!ZDC]Ûe.Wځ)Up5O^&$J65uf*}a{!Thx_E_@g.ҏzхþ# Z( ۭ(bCyԱCdvдǃh&[VKTQ|%Ntm0Fx}fvN=4pj@lN {uE?zKQhlSBs:.D}7ZFx ONsHrz7\҇)ǀ^_C#^>'if%?E|r-j@q [G@`>0A ?@ &z='O7Jh#x,4|t4gz>pJM@fII?jȻPo@G6QsMX?G5Q,voS2݆ᜮK " F!PM('GARd"784zSN"ќ4gNj5;UHMMioD%a6gﺣnF"͔$Q00 $ECwMyu}gr%Z[^eK? p b5su'*ߎWT,\gGYMQv0 +c"JqnMHhf]j +Eak~4*-<+PHKk[ljffIKk[p*@1j%kf@Q9We aTe˨>𰟙,?xZ!:8"x 0a:܌oE=  ;а^ĝ6^8#HQ [Q0p/3(hGY4QQmMey>UPB[P-.𨀙YT= _6ZN{ߠbwϊf}NU2- ܁0OL4?[P8nv'/(u1ϫzn_w儫P⠃3Dk硝$/Em$Lڄv*3R;yÂfMG֞alDAh8g̬ff*p"p6p9z>|$'m$GfV3} /B٨?Ꞅy xF~UW.K_F P EAi4B5،zj3<.Dt@ 9h(w5Әҍt |Ռjh$+/ފvk: _Tc1h`4*'tmr磞}+ݟ3Pb;p-J:cu$ q6}+Z4Ԩ&)݋!>$0Ey Yhg^g%hu}н^㿁 .f4 P=vKyh}>!'3Q` O޷SB3;?}4e^_F Nģ|HHGTEkx$E8 EC64ە#qyG\PǏq]g#X(W6&3ACkP^v/* T4Up:gPQٸRFlЛ~|0M#SqCm7֣#( uQ DS(l4Mp Za /: 03K Z=D;=zܯ&) B9csqY- mx8-|?w` .Fm(`&bE;7\_@T.8 rxkM3L͔hN'Zu ~%90hFտNAS$$yfH {㫁G'h9J=DtFy +Ѵ ͬ 9:?6,>p{2VIe +߅gѽ;iwS }>-x;,;?50ˇd~0ߍFbom&ܧW "?2QÐXN@/≂hD`!XF c) cm^Pc݇VZu߁2w%wQ#n *o>l7og\\c[O_EDyo_)'cIhY#JeGsGQÝ FpEhgוh /x3p_)h #|![(x ֻ(@.h`EXB9 H sQ\40rbHV%(ƽE)7IcrvQN{h3:h?{߃MY{nz|![&Q05sPXڛp)e± cOh7>nsť:ʗY5%FM o\/CoUGfsPH:&# Pd=q:G=P(ȓP豲Ǟ̹ 'C.ok-s{اM*1/M;|zbUSP٨'~e1 %$B4$9 s9{Dw=%:P4Co؏nԻN>ĻpDc09?߫U ϱ }{/Yu}7:=񶏖Ô1eOdA33˭(g jLxMkD3p1pNTD{}]`ffh-PK@F|-q×EB )S <33Dhf8/|~V>P` *V5ɸs-*33hs-E8^"/@o8!j<*$.]a@33(o&Z%^66h|7(&wfOt8 -!\ /MHh'נF4T<-{ al@nZ@b ZSy1]-kff6Q+v4쟅 &ގe=aKo%y0J& ܃2(33 *^VYCs{+O#5'wwYÉ6iAhn"`i_Ѩvo'rI>zy:/P]Z`'%>X!YzVпퟍZfO~ɑ> t`E8A=V(903+џvݻ-;e=<Юkl 6-8x)X܏)~8rbR,ÿ8 < `<\?2*XtݨS*Aq@`f?% \Vrϡ> %%ڽh T0ZwtC8 03h,4r5EoP-(iJC2t^8ބ 6Ѱ}q03h8?im@mMjىvQnyh羶'%%%GٚOMh /743U} ? 9OB 7%?cԳ x e%jޞA%mF'uP7}9n=5+Q~1͛Ǩ(+k> MCl )ih3h`M \3#Qc? 5KPϾ ۟TOVjKG(1DI 4v̠bGplA ez>C4s=Y5D޴5gp,C̢TvT "ɿ2pڒp>>F -zh$qnSA|ԘRկD r7k(H/k<AUTTz.c$||PVlj܈ (*bPћoF=\ ؟n [L6Bcݛ Dg*z.Fsw(o2s (30+f V7Kqj,I[/E){|7 g "]Lf}"vL ʄrA7Z};]ǻv&l,(xO%Q_%߂Yhߍ|t)}a!QL= H<)' &PppM-L;:\}ZBȃk8Ѧ6QC /@q_ay_q_6)N9 qPЍkDA4] nt]lvwtD# }_ `ڧƹvz_F9n=F04W.(` D+h(ru!J(@Hd Q؏ao{GhHxF#  V;McxbOŔXnjga*Nѱ|q.a8PNLLzH)Q~CAB c/Gy{~=zN=ΣܰK~ \&n/ʝ\7EJcVkCW6?JEa<*(g'|OQp2@ *oFfgQϧ\asnyO)' z[1GG@<KGrNzt1Qʫ!# (DQ3✆OF&fу#& mXjiQgPngc4I=9OF܈[=rƤ.AٍY5Qn&= #O=GENoU}7ЕSNyㆺ2xMRp/cX(B*htUN,{ۀ\gEC?wmfzPwC"Dz> 33B益BsAfffu U(0̬l$Q46133˙U4>ALcXT`'bffaC Dc,'6L DLG33F׋FƏL䛋?'133vD~B;6e}fff{0->C DFƱ߱Ytb|aa/133..o5. Q@ffָ'Ǜ?,Gffff7R OYً Chnfff )`5L| Di33k,%{?@p+dff"iYYJ@G{Y㸗*-/d~03w*+z l'affVckޓ 03VBU{_4ɛˀd}Nfff5 ,\W>/33zn5@@o 83233AF`O5h!1;9YY I 4 LR$TorDCm,R܀JWU.7/x9033k$w@u{ 4뀏d}Nfffx?8W@h|89s233a] _ |?,Ck{"P_seffi5UIR*;$ j/> \)D P }33?x~7lKWFR 4M@' iARR<} EVR>33~Hj 3T/MEQ?E#fffyU ;:bR+d'Zf?DObdnR>/33c X/ ׀_>C7*_B+7x^fffDzo7_\F:~t39>vX233˃!Ĥ EIX_d-)Ye˫5LpY5QppaY֒hۀNS?UTg5=Q3Yc k0 HۓT?.Lfffmܳ1QMz028ǽ^r_-~x3VTx[֧jJ4E!`q?B&#Ztӟo`)f`Vփ6KHe$ 065I:43q+!2>!4R<'~Y‘!4 rlD,3=hDxM'2QqpmHFr),?A"B4\`zS"g ?7֬RWf\d?9 hffX`!pr'{>+9YUYd%R kSȶ ᘅ jn#C98A{$i;IOjWpEo dPn'1VpYrhffv#ZU5#iBD)(wh7(33/' ׋=-g.hp7@ [̞%{j߱hB K>|PO̪o+5YH.Q m?QM33+ (WC>TCG]P?KZyYDD(89ل<7_?(XLz'iB J (Sff4cp6**.@'bffc uSWb℄ O$33˥nTD^K $h0h{'bff#! 2hBy $!~ |l'Q'!Msn`Y'QeI=雲>33{A}4 $F: ֘YN?>3w?*s B^f:X 6 p-hf]hDIhD^QQzE>3|4f8XIT[t>Ae-Fmq)R̬O F̬66e}"YkiyP?hj6hܡD|NL.d}"]xAQF  TXNuy>8 s  @3xUAYD- `E'ffE0x?фd}" :0(:}$13#hKa2Y1  FBK03+;O{N #듨hiugbYlAe}"yԄEDa>J`f'#(!O̬zn O%h/$j-@AQ̬~ެO$І4ktp50^Q೨XSMSx||'5IX/r\53C$VBcWBN>-cK=h$oA{Խ}m/s23˹{?$Fk)Ph$! xeed'RM=̓Yq,jiDre(?6Mr@NEхkY#es)v>1hD2,'>[sG>1Y*hQxt%jaO}Y, R}t?~MoF(4@uDE'@3k\wt(pws(9YH]*5oP{{ On ֶ=f}>~r",%=U1Zn6By̬WM|]wp*`7*H'bfVh?]fjQ=h㝕YBmlдY_#tAOrhD- kՏ(yx޿W@ kLNZ[Z7JX4y03+Tkx_MQM!̬Ovє=-m2%pBd}Nff_ qOӨ@4 hdwv{h biL4pZef6C53X I7J.bm;-cnim+5P0^4m4Xd3 ђ%5s QnNFEZg>uD7[+QNY _>񯝩ИK)QRF`}#Qx)Мymh57u jLvFo^y p)ZN#VBSM4zcfgिZ;n (˾hN@Av੖ֶzl_o=B523E7ZM\/c * XOb{ģ7GlCK{iSϛW b>8<6XZ{\Ʊ+@1kV]?%cyϝNqw[\  xzdfZW<W5&GPcr "?bQ@WBU<֛5E74+QzY%PbԬVOc]tj< ObA/>jOQֶ#E FHWfVU `XhhRTx-hJT3`{=p.UNOq;N<רy 4O~6:7 Qf2afV->sf7Ш*Oݨn=LFZZDW'f}NfV7m~f@T(x]S}F2 8 4*pmg 6Ehf@{R 逭\:b:-w)? J<zY&ިqyXO+dTgPOz_Kkֶ"D[>:M'Oj^kaFX$= x؆6!ˈ9_N6' i'N&~f|=46SP7_2Kh'4nE;齈=?3~̬P%`<a \Fp<@Z2v{ã I;}~OF/AhKF7Ay?FS }Q]3 9!pwtނ_ 2"4M`ehzTr? U ? Yf{T\.ĚUѹ@w5D nA.U{hs3;/VInB_-\n(.j-2X @[є4=Uk Q.G_/Z o =`XcH+p`fDl|:" BB8-||FxL$xH|aq8ɘY.@YO]$Z:B\ Y.܏lNO]kp֡i33PάOWD,sh7s`c ݅6 2ƶ /,6Od}frzLz{l"PB5*+ 6Q?3kLj\ظD/ Yefr`u>3fKA>TZljhqЬ ׿mh;c3k,kdEe`X&1ձ5 9zMYc(%>6!Ѱ lfg}"69lwl`zW{f}V\{ `8yYM<&+iYՅ-'YU(_<`@] ,̬jp_?ؤEA3CW3>/3A+(8ƿ8 Ъ~ 8̬~ /UŞk,tJ tRY1 >{UU 8 g h>5VUQ>n`5y٘= .p;g*V.Vd}^fv\7zj" R˲>/3ZjR:4<2y%rXMEAh3SqbY ?EsCq`5(J|e7߀-(̲p*vnKMDA(/`ff@na-sw@E|=N U72p-3!0*Y-?DuǙ,CaJ`-@d}nfud3ߙxr ^Vi6C=b,7B 0x/&%2+O^J40x%xXn voq`' UB|/1p`54-_f]hs(֍o{hŨvQn76vyZD.CSV8|~?V8ш,x s>P Q &VDK_\62+A}&Յ(Y  xA+|#ߪՕsQ-W)˯A]*O}VB0Є \\LPRc(V?Y9 hb--%nCe}ޥRN\LˀKQ x %<*y2ZEi:dN5p'j s>˜"8 ͎E;Q|f#(6t*8 8yZP,ҿ?V,7P(3L)4M.9Q8BYNWlovؙdl~AKa-8PYau縼ďV_sGQf?I_9CZ7AYJShai|馪`i{6AX@J`zCMb1H^qxqyjq[dwܢltks]ex~xFPe:D[t{^fy`hzOXl}˯MVkPYnZbuR[oʫ\exck}W`sS\pemƼIRg̲쉾bKGDHtIME ;|1j IDATxiTSWPA$$Dlĉ@%  "E2RTDpRu)Uj֎Lby]}A4Em!C aa9rh!cbmd O8HNXdɎ6uW7j1 >cf|0:(xVNT6',\;3dˇiys0ZI\<<'vh9$'/HJL!1CSU+2I4|:G6 ,YE@-krpcF*rl+V~q٪ KPUB + L) } sh& .4 gygo$((mڜqbl5tJVB!lsQcn_iBTO+v* v*ᨃRΦ/NcǚZUc]% CmW;ܓ8J8PKAq{RU/l]juywb/Uow@1D10Yx7g1ȘҤӛ*ٙлOldpq'jҨX| lM\krt.4I]G`gG7đ$o?i; iUq"_1dt.aZrt2}g4GMF3.X N EP E^cH>;!N5e(Ժ<1}t83dÄ۔YjEPqjDL_]kw& SaCm&8 c+|)ʘFfHrv/X,Ff[&I!7wRuI^eiyl)i[aԜcroۚ.N8Kg{S$ mF/D,\LC7dz2q<[1#:ɘu2"a9wyp w^_ŅŐfUULbݺ~4.4׽g+Ein뚻;5<'wCVM ,X7dX6sݷ}~7#_wSVF~znSm]{ɵ-f揗_pSH_Ogmp' XɸfzQ@m_!QJpИͮ2M(e +SPW#-:uViwG;^/gf[Yg2s! m#m2 &kAxmeO7 $% / t/m:96*~ߥEt@#KP[w>-҅HS5TP~}B6ȹ6Wnr#֡س2[^9D`U?z:ⳓzV*[zLorui l 1XCNƫ.撣z/zr-<2Ʊ&[_}͘p7V,0603 -1!Ȼ oZ)Ks'4#iΛ h'6<꩞0\YNb14rirI^9ߝt4u,CY׾Χr:N8c)G \{ǿ.n"@\]s!g>HDL7l3 /cˊKi<8@.غB il]!86W)g!ځkl]!;D<8HlRCy s%{PgQ3 Йk.r%^0mЍEk:|%6ƕ%9kO {`Aw{K+z=UO*E Z$15adavXĊ'W_o %C*s6Zd'Or-qXE}phd Xqlk@mOO*)H?e }SxqP=yn0:Hيd"QK6&I#7^*Pgtku +F$$r.I*_V;dfzuw x5+@Fl pviEGY:K@ugT4eڀb>8S!9dVʯD,~(vRy'9\P  (o!:>{ean|GːIOjP G[ v) 3 c0ip}rDyfP,Lg:C*X,{B|70:+I VO9to:Jemzot;;JJ3~=\V ؛s }WB [')-ͨ]aK)a40rBޒϏl;)T(˦2$ZB%(dJu;™)m o& zR鈈}cW7n^d=-_ X 5!5Q޹ vYJ_̂׹^ٝZf~"sc\KvpM2X8NX CݸtxB ,}lbuxڈ~ A餎&~PF2Ce3^q MVd:Pkuw1;V9]z퓱1kxQk|t_|`e> wuF᳟-69Vֵ/hr_$߲dY=ޫ6K" pqgTyH^ŀ_UA7V;\?[f6Fs#"i4H?[)a,%tEXtdate:create2016-12-07T07:16:59+01:000E%tEXtdate:modify2016-12-07T07:16:59+01:00A<WzTXtRaw profile type iptcx qV((OIR# .c #K D4d#T ˀHJ.tB5IENDB`coffeescript-1.12.7/docs/browserconfig.xml000066400000000000000000000003471313305734200206060ustar00rootroot00000000000000 #da532c coffeescript-1.12.7/docs/favicon-16x16.png000066400000000000000000000017331313305734200201310ustar00rootroot00000000000000PNG  IHDR(-SgAMA a cHRMz&u0`:pQ<APLTE(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3LoԭitRNS* Heb3 wijg6 #2?rqs-oWE;:BQYp`^I\mnlfZG49a"={]A@ [d<*bKGDj%btIME ;|1jIDATc`L,l\@.7/ ? !%'w&1gGd  #X#Q 1qP~'##Cby*T 4 7-]"ትTϐQ1 X%tEXtdate:create2016-12-07T07:16:59+01:000E%tEXtdate:modify2016-12-07T07:16:59+01:00A<WzTXtRaw profile type iptcx qV((OIR# .c #K D4d#T ˀHJ.tB5IENDB`coffeescript-1.12.7/docs/favicon-32x32.png000066400000000000000000000031331313305734200201210ustar00rootroot00000000000000PNG  IHDR DgAMA a cHRMz&u0`:pQ<PLTE(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3L(3LtRNS 0R"[ɴ}(rwVcȥ6 +',YM\W%:8>=T#2?zZ G xFH~_q̱daBi˼;I!X-Ee^ϻK9Sv|&tuPʯԶͼbKGDjtIME ;|1jIDAT8c`:`dbfaecdgfddDRB",bR2r 0J̌L*jZ:z@F &f -,mm-] \=L3(cL3(L3( L3(+L3(L3(L3(L3(L3('L3(,L3(YL3(L3(L3(L3(L3(ML3(\L3(L3(WL3(L3(L3(L3(L3(rL3(L3(wL3(}L3(VL3( L3(cL3(L3(L3(L3(L3(L3(L3(L3(L3(L3(6L3(L3(0L3(RL3(RL3("L3(L3([L3(L3(L3(L3(L3(L3(}L3((L3(L3(L3( L3( L3(??<88ρ8~(  L3(L3(AL3(fL3(oL3(dL3(?L3(L3(3L3(L3(L3(L3(L3(L3(L3(L3(-L3( L3([L3(nL3(L3(L3(L3(L3(L3(L3(L3(L3(L3(L3(L3(L3(AL3(@L3(L3(L3(L3(L3(L3(L3(L3(L3(L3(3L3(L3(]L3(L3(L3(L3(L3(L3(L3(L3(L3(L3(L3(L3(L3(L3(L3(=L3({L3(L3(L3(L3(L3(L3(L3(L3(L3(L3(L3(L3(sL3(L3(L3(L3(L3(L3(L3(L3(L3(L3(L3(L3(L3(L3(L3(L3("L3(L3(L3(L3(L3(L3(L3(L3(L3(L3(L3(L3(L3(L3(L3(L3(nL3(L3(L3(L3(L3(L3(L3(lL3(aL3(^L3(aL3(lL3(L3(L3(L3(L3(L3(L3(^L3(:L3(6L3(IL3(\L3(gL3(mL3(nL3(lL3(fL3(ZL3(GL3(4L3(9L3(fL3( L3(bL3(L3(L3(oL3(WL3(EL3(;L3(:L3(BL3(QL3(YL3(pL3(L3(L3(`L3(#L3(L3(3L3(L3(2L3(iL3(wL3(?L3(L3(rL3(qL3(sL3(L3(L3(-L3(L3(L3(L3(L3( L3(wL3(iL3(jL3(L3(L3(L3(gL3(L3(6L3(L3( L3(L3(*L3( L3(L3(HL3(eL3(bL3(3L3(0``/coffeescript-1.12.7/docs/index.html000077700000000000000000000000001313305734200215222v1/index.htmlustar00rootroot00000000000000coffeescript-1.12.7/docs/manifest.json000066400000000000000000000004301313305734200177050ustar00rootroot00000000000000{ "name": "", "icons": [ { "src": "\/android-chrome-192x192.png", "sizes": "192x192", "type": "image\/png" }, { "src": "\/android-chrome-512x512.png", "sizes": "512x512", "type": "image\/png" } ], "theme_color": "#ffffff", "display": "standalone" } coffeescript-1.12.7/docs/mstile-150x150.png000066400000000000000000000104741313305734200201410ustar00rootroot00000000000000PNG  IHDRҸ1.gAMA a cHRMz&u0`:pQ<bKGD̿tIME !QIDATx{p\yjY7K_FPcaqb.C)!- 4ВL&e0)ҤCJB`[ nk01F`;mٖe!Ywb%v|4̬y>ﻏϾ}sc1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1A>3b#tDTRE:ʱd1͹ss)!LC6ꦅZ>=;NeP QLA8u,,.JQBzo.^W&!oڣIjSQKd*=**yڣەfX VRȌr*2':fJ2mO6 4#)es(e367P8܎餍:%@lHADUn3ZjN:/~NP:Ŭo ɂػ짊ZZiGȢٜR&#un>?aT_=f?cr]CCjt01aF6ݫre%戲w(eL j$[4Owj{.k6ֿuJ?(0KsDh.JQԭuX_Jڪo_9^j~`w<_G#lɡ4͍&A_jZtO" P]jVzL+V1\#Gzݬ@ $UnTNQD/MPڤ(zќAJ-[a-$յzbQCڧ߃Z\)(M7"4)R6:\9,q!KX@:)'Q>}Ҙ4JiM%Jȥ38Ebι 𚵕1wǟC#Ǩ>v!HI-CQxH38b2-vp|~* /\I,:hJFiy$Jtf2LYY9m#EdRBoFbzTK D4?MOYY4fCd$c2%0" )qR#5ۓH<2ȠSx#<~M=P/< @:!B ~Np3}hJ$׮\=;$g']Mjhm|70JdvFrbP#o!Hoa bK:1W:R%9&l\K $2eV2ucd?Oc!Newh:!7{ϓC%M垈l%!PX< u4>M|:|\H䅁=j¯7F ۅӃ09έFa'^+ivxMC-Yϑu;)MJhy|!r}ر]0<% b3h7<䜐~ W.9X^7~RnDOJco0?#<194ː>u#{HcB}irꈼO](%ǔAuX:8Hc-L\cxR)}bpr:SDh@E+a^L$)Le:S($I72E'MSKb%c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c\A c%tEXtdate:create2016-12-07T07:17:00+01:00?e %tEXtdate:modify2016-12-07T07:17:00+01:00sbݵWzTXtRaw profile type iptcx qV((OIR# .c #K D4d#T ˀHJ.tB5IENDB`coffeescript-1.12.7/docs/safari-pinned-tab.svg000066400000000000000000000053251313305734200212210ustar00rootroot00000000000000 Created by potrace 1.11, written by Peter Selinger 2001-2013 coffeescript-1.12.7/docs/v1/000077500000000000000000000000001313305734200155355ustar00rootroot00000000000000coffeescript-1.12.7/docs/v1/annotated-source/000077500000000000000000000000001313305734200210105ustar00rootroot00000000000000coffeescript-1.12.7/docs/v1/annotated-source/browser.html000066400000000000000000000300131313305734200233560ustar00rootroot00000000000000 browser.coffee
  • browser.coffee

  • This Browser compatibility layer extends core CoffeeScript functions to make things work smoothly when compiling code directly in the browser. We add support for loading remote Coffee scripts via XHR, and text/coffeescript script tags, source maps via data-URLs, and so on.

    CoffeeScript = require './coffee-script'
    CoffeeScript.require = require
    compile = CoffeeScript.compile
  • Use standard JavaScript eval to eval code.

    CoffeeScript.eval = (code, options = {}) ->
      options.bare ?= on
      eval compile code, options
  • Running code does not provide access to this scope.

    CoffeeScript.run = (code, options = {}) ->
      options.bare      = on
      options.shiftLine = on
      Function(compile code, options)()
  • If we’re not in a browser environment, we’re finished with the public API.

    return unless window?
  • Include source maps where possible. If we’ve got a base64 encoder, a JSON serializer, and tools for escaping unicode characters, we’re good to go. Ported from https://developer.mozilla.org/en-US/docs/DOM/window.btoa

    if btoa? and JSON?
      compile = (code, options = {}) ->
        options.inlineMap = true
        CoffeeScript.compile code, options
  • Load a remote script from the current domain via XHR.

    CoffeeScript.load = (url, callback, options = {}, hold = false) ->
      options.sourceFiles = [url]
      xhr = if window.ActiveXObject
        new window.ActiveXObject('Microsoft.XMLHTTP')
      else
        new window.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]
            param = [xhr.responseText, options]
            CoffeeScript.run param... unless hold
          else
            throw new Error "Could not load #{url}"
          callback param 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 = window.document.getElementsByTagName 'script'
      coffeetypes = ['text/coffeescript', 'text/literate-coffeescript']
      coffees = (s for s in scripts when s.type in coffeetypes)
      index = 0
    
      execute = ->
        param = coffees[index]
        if param instanceof Array
          CoffeeScript.run param...
          index++
          execute()
    
      for script, i in coffees
        do (script, i) ->
          options = literate: script.type is coffeetypes[1]
          source = script.src or script.getAttribute('data-src')
          if source
            CoffeeScript.load source,
              (param) ->
                coffees[i] = param
                execute()
              options
              true
          else
            options.sourceFiles = ['embedded']
            coffees[i] = [script.innerHTML, options]
    
      execute()
  • Listen for window load, both in decent browsers and in IE.

    if window.addEventListener
      window.addEventListener 'DOMContentLoaded', runScripts, no
    else
      window.attachEvent 'onload', runScripts
coffeescript-1.12.7/docs/v1/annotated-source/cake.html000066400000000000000000000337141313305734200226110ustar00rootroot00000000000000 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'
  • Register .coffee extension

    CoffeeScript.register()
  • 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 fs.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()}"
coffeescript-1.12.7/docs/v1/annotated-source/coffee-script.html000066400000000000000000001303711313305734200244340ustar00rootroot00000000000000 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 CoffeeScript directly in the browser. This module contains the main entry functions for tokenizing, parsing, and compiling source CoffeeScript into JavaScript.

    fs            = require 'fs'
    vm            = require 'vm'
    path          = require 'path'
    {Lexer}       = require './lexer'
    {parser}      = require './parser'
    helpers       = require './helpers'
    SourceMap     = require './sourcemap'
  • Require package.json, which is two levels above this file, as this file is evaluated from lib/coffee-script.

    packageJson   = require '../../package.json'
  • The current CoffeeScript version number.

    exports.VERSION = packageJson.version
    
    exports.FILE_EXTENSIONS = ['.coffee', '.litcoffee', '.coffee.md']
  • Expose helpers for testing.

    exports.helpers = helpers
  • Function that allows for btoa in both nodejs and the browser.

    base64encode = (src) -> switch
      when typeof Buffer is 'function'
        new Buffer(src).toString('base64')
      when typeof btoa is 'function'
  • The contents of a <script> block are encoded via UTF-16, so if any extended characters are used in the block, btoa will fail as it maxes out at UTF-8. See https://developer.mozilla.org/en-US/docs/Web/API/WindowBase64/Base64_encoding_and_decoding#The_Unicode_Problem for the gory details, and for the solution implemented here.

        btoa encodeURIComponent(src).replace /%([0-9A-F]{2})/g, (match, p1) ->
          String.fromCharCode '0x' + p1
      else
        throw new Error('Unable to base64 encode inline sourcemap.')
  • Function wrapper to add source file information to SyntaxErrors thrown by the lexer/parser/compiler.

    withPrettyErrors = (fn) ->
      (code, options = {}) ->
        try
          fn.call @, code, options
        catch err
          throw err if typeof code isnt 'string' # Support `CoffeeScript.nodes(tokens)`.
          throw helpers.updateSyntaxError err, code, options.filename
  • For each compiled file, save its source in memory in case we need to recompile it later. We might need to recompile if the first compilation didn’t create a source map (faster) but something went wrong and we need a stack trace. Assuming that most of the time, code isn’t throwing exceptions, it’s probably more efficient to compile twice only when we need a stack trace, rather than always generating a source map even when it’s not likely to be used. Save in form of filename: (source)

    sources = {}
  • Also save source maps if generated, in form of filename: (source map).

    sourceMaps = {}
  • Compile CoffeeScript code to JavaScript, using the Coffee/Jison compiler.

    If options.sourceMap is specified, then options.filename must also be specified. All options that can be passed to SourceMap#generate may also be passed here.

    This returns a javascript string, unless options.sourceMap is passed, in which case this returns a {js, v3SourceMap, sourceMap} object, where sourceMap is a sourcemap.coffee#SourceMap object, handy for doing programmatic lookups.

    exports.compile = compile = withPrettyErrors (code, options) ->
      {merge, extend} = helpers
      options = extend {}, options
  • Always generate a source map if no filename is passed in, since without a a filename we have no way to retrieve this source later in the event that we need to recompile it to get a source map for prepareStackTrace.

      generateSourceMap = options.sourceMap or options.inlineMap or not options.filename?
      filename = options.filename or '<anonymous>'
    
      sources[filename] = code
      map = new SourceMap if generateSourceMap
    
      tokens = lexer.tokenize code, options
  • Pass a list of referenced variables, so that generated variables won’t get the same name.

      options.referencedVars = (
        token[1] for token in tokens when token[0] is 'IDENTIFIER'
      )
  • Check for import or export; if found, force bare mode.

      unless options.bare? and options.bare is yes
        for token in tokens
          if token[0] in ['IMPORT', 'EXPORT']
            options.bare = yes
            break
    
      fragments = parser.parse(tokens).compileToFragments options
    
      currentLine = 0
      currentLine += 1 if options.header
      currentLine += 1 if options.shiftLine
      currentColumn = 0
      js = ""
      for fragment in fragments
  • Update the sourcemap with data from each fragment.

        if generateSourceMap
  • Do not include empty, whitespace, or semicolon-only fragments.

          if fragment.locationData and not /^[;\s]*$/.test fragment.code
            map.add(
              [fragment.locationData.first_line, fragment.locationData.first_column]
              [currentLine, currentColumn]
              {noReplace: true})
          newLines = helpers.count fragment.code, "\n"
          currentLine += newLines
          if newLines
            currentColumn = fragment.code.length - (fragment.code.lastIndexOf("\n") + 1)
          else
            currentColumn += fragment.code.length
  • Copy the code from each fragment into the final JavaScript.

        js += fragment.code
    
      if options.header
        header = "Generated by CoffeeScript #{@VERSION}"
        js = "// #{header}\n#{js}"
    
      if generateSourceMap
        v3SourceMap = map.generate(options, code)
        sourceMaps[filename] = map
    
      if options.inlineMap
        encoded = base64encode JSON.stringify v3SourceMap
        sourceMapDataURI = "//# sourceMappingURL=data:application/json;base64,#{encoded}"
        sourceURL = "//# sourceURL=#{options.filename ? 'coffeescript'}"
        js = "#{js}\n#{sourceMapDataURI}\n#{sourceURL}"
    
      if options.sourceMap
        {
          js
          sourceMap: map
          v3SourceMap: JSON.stringify v3SourceMap, null, 2
        }
      else
        js
  • Tokenize a string of CoffeeScript code, and return the array of tokens.

    exports.tokens = withPrettyErrors (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 = withPrettyErrors (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 '<anonymous>'
  • Clear the module cache.

      mainModule.moduleCache and= {}
  • Assign paths for node_modules loading

      dir = if options.filename?
        path.dirname fs.realpathSync options.filename
      else
        fs.realpathSync '.'
      mainModule.paths = require('module')._nodeModulePaths dir
  • Compile.

      if not helpers.isCoffee(mainModule.filename) or require.extensions
        answer = compile code, options
        code = answer.js ? answer
    
      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()
      createContext = vm.Script.createContext ? vm.createContext
    
      isContext = vm.isContext ? (ctx) ->
        options.sandbox instanceof createContext().constructor
    
      if createContext
        if options.sandbox?
          if isContext options.sandbox
            sandbox = options.sandbox
          else
            sandbox = 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
          for r in Object.getOwnPropertyNames require when r not in ['paths', 'arguments', 'caller']
            _require[r] = require[r]
  • 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
    
    exports.register = -> require './register'
  • Throw error with deprecation warning when depending upon implicit require.extensions registration

    if require.extensions
      for ext in @FILE_EXTENSIONS then do (ext) ->
        require.extensions[ext] ?= ->
          throw new Error """
          Use CoffeeScript.register() or require the coffee-script/register module to require #{ext} files.
          """
    
    exports._compileFile = (filename, sourceMap = no, inlineMap = no) ->
      raw = fs.readFileSync filename, 'utf8'
  • Strip the Unicode byte order mark, if this file begins with one.

      stripped = if raw.charCodeAt(0) is 0xFEFF then raw.substring 1 else raw
    
      try
        answer = compile stripped, {
          filename, sourceMap, inlineMap
          sourceFiles: [filename]
          literate: helpers.isLiterate filename
        }
      catch err
  • As the filename and code of a dynamically loaded file will be different from the original file compiled with CoffeeScript.run, add that information to error so it can be pretty-printed later.

        throw helpers.updateSyntaxError err, stripped, filename
    
      answer
  • 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: ->
        token = parser.tokens[@pos++]
        if token
          [tag, @yytext, @yylloc] = token
          parser.errorToken = token.origin or token
          @yylineno = @yylloc.first_line
        else
          tag = ''
    
        tag
      setInput: (tokens) ->
        parser.tokens = tokens
        @pos = 0
      upcomingInput: ->
        ""
  • Make all the AST nodes visible to the parser.

    parser.yy = require './nodes'
  • Override Jison’s default error handling function.

    parser.yy.parseError = (message, {token}) ->
  • Disregard Jison’s message, it contains redundant line number information. Disregard the token, we take its value directly from the lexer in case the error is caused by a generated token which might refer to its origin.

      {errorToken, tokens} = parser
      [errorTag, errorText, errorLoc] = errorToken
    
      errorText = switch
        when errorToken is tokens[tokens.length - 1]
          'end of input'
        when errorTag in ['INDENT', 'OUTDENT']
          'indentation'
        when errorTag in ['IDENTIFIER', 'NUMBER', 'INFINITY', 'STRING', 'STRING_START', 'REGEX', 'REGEX_START']
          errorTag.replace(/_START$/, '').toLowerCase()
        else
          helpers.nameWhitespaceCharacter errorText
  • The second argument has a loc property, which should have the location data for this token. Unfortunately, Jison seems to send an outdated loc (from the previous token), so we take the location information directly from the lexer.

      helpers.throwSyntaxError "unexpected #{errorText}", errorLoc
  • formatSourcePosition = (frame, getSourceMapping) ->
      filename = undefined
      fileLocation = ''
    
      if frame.isNative()
        fileLocation = "native"
      else
        if frame.isEval()
          filename = frame.getScriptNameOrSourceURL()
          fileLocation = "#{frame.getEvalOrigin()}, " unless filename
        else
          filename = frame.getFileName()
    
        filename or= "<anonymous>"
    
        line = frame.getLineNumber()
        column = frame.getColumnNumber()
  • Check for a sourceMap position

        source = getSourceMapping filename, line, column
        fileLocation =
          if source
            "#{filename}:#{source[0]}:#{source[1]}"
          else
            "#{filename}:#{line}:#{column}"
    
      functionName = frame.getFunctionName()
      isConstructor = frame.isConstructor()
      isMethodCall = not (frame.isToplevel() or isConstructor)
    
      if isMethodCall
        methodName = frame.getMethodName()
        typeName = frame.getTypeName()
    
        if functionName
          tp = as = ''
          if typeName and functionName.indexOf typeName
            tp = "#{typeName}."
          if methodName and functionName.indexOf(".#{methodName}") isnt functionName.length - methodName.length - 1
            as = " [as #{methodName}]"
    
          "#{tp}#{functionName}#{as} (#{fileLocation})"
        else
          "#{typeName}.#{methodName or '<anonymous>'} (#{fileLocation})"
      else if isConstructor
        "new #{functionName or '<anonymous>'} (#{fileLocation})"
      else if functionName
        "#{functionName} (#{fileLocation})"
      else
        fileLocation
    
    getSourceMap = (filename) ->
      if sourceMaps[filename]?
        sourceMaps[filename]
  • CoffeeScript compiled in a browser may get compiled with options.filename of <anonymous>, but the browser may request the stack trace with the filename of the script file.

      else if sourceMaps['<anonymous>']?
        sourceMaps['<anonymous>']
      else if sources[filename]?
        answer = compile sources[filename],
          filename: filename
          sourceMap: yes
          literate: helpers.isLiterate filename
        answer.sourceMap
      else
        null
  • Based on michaelficarra/CoffeeScriptRedux NodeJS / V8 have no support for transforming positions in stack traces using sourceMap, so we must monkey-patch Error to display CoffeeScript source positions.

    Error.prepareStackTrace = (err, stack) ->
      getSourceMapping = (filename, line, column) ->
        sourceMap = getSourceMap filename
        answer = sourceMap.sourceLocation [line - 1, column - 1] if sourceMap?
        if answer? then [answer[0] + 1, answer[1] + 1] else null
    
      frames = for frame in stack
        break if frame.getFunction() is exports.run
        "    at #{formatSourcePosition frame, getSourceMapping}"
    
      "#{err.toString()}\n#{frames.join '\n'}\n"
coffeescript-1.12.7/docs/v1/annotated-source/command.html000066400000000000000000001343321313305734200233220ustar00rootroot00000000000000 command.coffee
  • command.coffee

  • The coffee utility. Handles command-line compilation of CoffeeScript into various forms: saved into .js files or printed to stdout 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'
    
    useWinPathSep  = path.sep is '\\'
  • 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 in conjunction with -h/--help.

    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']
      ['-m', '--map',             'generate source map and save as .js.map files']
      ['-M', '--inline-map',      'generate source map and include it directly in output']
      ['-n', '--nodes',           'print out the parse tree that the parser produces']
      [      '--nodejs [ARGS]',   'pass options directly to the "node" binary']
      [      '--no-header',       'suppress the "Generated by" header']
      ['-o', '--output [DIR]',    'set the output directory for compiled JavaScript']
      ['-p', '--print',           'print out the compiled JavaScript']
      ['-r', '--require [MODULE*]', 'require the given module before eval or REPL']
      ['-s', '--stdio',           'listen for and compile scripts over stdio']
      ['-l', '--literate',        'treat stdio as literate style coffee-script']
      ['-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   = {}
    watchedDirs  = {}
    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()
  • Make the REPL CLI use the global context so as to (a) be consistent with the node REPL CLI and, therefore, (b) make packages that modify native prototypes (such as ‘colors’ and ‘sugar’) work as expected.

      replCliOpts = useGlobal: yes
      opts.prelude = makePrelude opts.require       if opts.require
      replCliOpts.prelude = opts.prelude
      return forkNode()                             if opts.nodejs
      return usage()                                if opts.help
      return version()                              if opts.version
      return require('./repl').start(replCliOpts)   if opts.interactive
      return compileStdio()                         if opts.stdio
      return compileScript null, opts.arguments[0]  if opts.eval
      return require('./repl').start(replCliOpts)   unless opts.arguments.length
      literals = if opts.run then opts.arguments.splice 1 else []
      process.argv = process.argv[0..1].concat literals
      process.argv[0] = 'coffee'
    
      opts.output = path.resolve opts.output  if opts.output
      if opts.join
        opts.join = path.resolve opts.join
        console.error '''
    
        The --join option is deprecated and will be removed in a future version.
    
        If for some reason it's necessary to share local variables between files,
        replace...
    
            $ coffee --compile --join bundle.js -- a.coffee b.coffee c.coffee
    
        with...
    
            $ cat a.coffee b.coffee c.coffee | coffee --compile --stdio > bundle.js
    
        '''
      for source in opts.arguments
        source = path.resolve source
        compilePath source, yes, source
    
    makePrelude = (requires) ->
      requires.map (module) ->
        [_, name, module] = match if match = module.match(/^(.*)=(.*)$/)
        name ||= helpers.baseFileName module, yes, useWinPathSep
        "#{name} = require('#{module}')"
      .join ';'
  • Compile a path, which could be a script or a directory. If a directory is passed, recursively compile all ‘.coffee’, ‘.litcoffee’, and ‘.coffee.md’ extension source files in it and all subdirectories.

    compilePath = (source, topLevel, base) ->
      return if source in sources   or
                watchedDirs[source] or
                not topLevel and (notSources[source] or hidden source)
      try
        stats = fs.statSync source
      catch err
        if err.code is 'ENOENT'
          console.error "File not found: #{source}"
          process.exit 1
        throw err
      if stats.isDirectory()
        if path.basename(source) is 'node_modules'
          notSources[source] = yes
          return
        if opts.run
          compilePath findDirectoryIndex(source), topLevel, base
          return
        watchDir source, base if opts.watch
        try
          files = fs.readdirSync source
        catch err
          if err.code is 'ENOENT' then return else throw err
        for file in files
          compilePath (path.join source, file), no, base
      else if topLevel or helpers.isCoffee source
        sources.push source
        sourceCode.push null
        delete notSources[source]
        watch source, base if opts.watch
        try
          code = fs.readFileSync source
        catch err
          if err.code is 'ENOENT' then return else throw err
        compileScript(source, code.toString(), base)
      else
        notSources[source] = yes
    
    findDirectoryIndex = (source) ->
      for ext in CoffeeScript.FILE_EXTENSIONS
        index = path.join source, "index#{ext}"
        try
          return index if (fs.statSync index).isFile()
        catch err
          throw err unless err.code is 'ENOENT'
      console.error "Missing index.coffee or index.litcoffee in #{source}"
      process.exit 1
  • 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 = null) ->
      o = opts
      options = compileOptions file, base
      try
        t = task = {file, input, options}
        CoffeeScript.emit 'compile', task
        if o.tokens
          printTokens CoffeeScript.tokens t.input, t.options
        else if o.nodes
          printLine CoffeeScript.nodes(t.input, t.options).toString().trim()
        else if o.run
          CoffeeScript.register()
          CoffeeScript.eval opts.prelude, t.options if opts.prelude
          CoffeeScript.run t.input, t.options
        else if o.join and t.file isnt o.join
          t.input = helpers.invertLiterate t.input if helpers.isLiterate file
          sourceCode[sources.indexOf(t.file)] = t.input
          compileJoin()
        else
          compiled = CoffeeScript.compile t.input, t.options
          t.output = compiled
          if o.map
            t.output = compiled.js
            t.sourceMap = compiled.v3SourceMap
    
          CoffeeScript.emit 'success', task
          if o.print
            printLine t.output.trim()
          else if o.compile or o.map
            writeJs base, t.file, t.output, options.jsPath, t.sourceMap
      catch err
        CoffeeScript.emit 'failure', err, task
        return if CoffeeScript.listeners('failure').length
        message = err?.stack or "#{err}"
        if o.watch
          printLine message + '\x07'
        else
          printWarn message
          process.exit 1
  • Attach the appropriate listeners to compile scripts incoming over stdin, and write them back to stdout.

    compileStdio = ->
      buffers = []
      stdin = process.openStdin()
      stdin.on 'data', (buffer) ->
        buffers.push buffer if buffer
      stdin.on 'end', ->
        compileScript null, Buffer.concat(buffers).toString()
  • 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
  • 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 --print.

    watch = (source, base) ->
      watcher        = null
      prevStats      = null
      compileTimeout = null
    
      watchErr = (err) ->
        throw err unless err.code is 'ENOENT'
        return unless source in sources
        try
          rewatch()
          compile()
        catch
          removeSource source, base
          compileJoin()
    
      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()
    
      startWatcher = ->
        watcher = fs.watch source
        .on 'change', compile
        .on 'error', (err) ->
          throw err unless err.code is 'EPERM'
          removeSource source, base
    
      rewatch = ->
        watcher?.close()
        startWatcher()
    
      try
        startWatcher()
      catch err
        watchErr err
  • Watch a directory of files for new additions.

    watchDir = (source, base) ->
      watcher        = null
      readdirTimeout = null
    
      startWatcher = ->
        watcher = fs.watch source
        .on 'error', (err) ->
          throw err unless err.code is 'EPERM'
          stopWatcher()
        .on 'change', ->
          clearTimeout readdirTimeout
          readdirTimeout = wait 25, ->
            try
              files = fs.readdirSync source
            catch err
              throw err unless err.code is 'ENOENT'
              return stopWatcher()
            for file in files
              compilePath (path.join source, file), no, base
    
      stopWatcher = ->
        watcher.close()
        removeSourceDir source, base
    
      watchedDirs[source] = yes
      try
        startWatcher()
      catch err
        throw err unless err.code is 'ENOENT'
    
    removeSourceDir = (source, base) ->
      delete watchedDirs[source]
      sourcesChanged = no
      for file in sources when source is path.dirname file
        removeSource file, base
        sourcesChanged = yes
      compileJoin() if sourcesChanged
  • Remove a file from our source list, and source code cache. Optionally remove the compiled JS version as well.

    removeSource = (source, base) ->
      index = sources.indexOf source
      sources.splice index, 1
      sourceCode.splice index, 1
      unless opts.join
        silentUnlink outputPath source, base
        silentUnlink outputPath source, base, '.js.map'
        timeLog "removed #{source}"
    
    silentUnlink = (path) ->
      try
        fs.unlinkSync path
      catch err
        throw err unless err.code in ['ENOENT', 'EPERM']
  • Get the corresponding output JavaScript path for a source file.

    outputPath = (source, base, extension=".js") ->
      basename  = helpers.baseFileName source, yes, useWinPathSep
      srcDir    = path.dirname source
      if not opts.output
        dir = srcDir
      else if source is base
        dir = opts.output
      else
        dir = path.join opts.output, path.relative base, srcDir
      path.join dir, basename + extension
  • Recursively mkdir, like mkdir -p.

    mkdirp = (dir, fn) ->
      mode = 0o777 & ~process.umask()
    
      do mkdirs = (p = dir, fn) ->
        fs.exists p, (exists) ->
          if exists
            fn()
          else
            mkdirs path.dirname(p), ->
              fs.mkdir p, mode, (err) ->
                return fn err if err
                fn()
  • 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.

    If generatedSourceMap is provided, this will write a .js.map file into the same directory as the .js file.

    writeJs = (base, sourcePath, js, jsPath, generatedSourceMap = null) ->
      sourceMapPath = outputPath sourcePath, base, ".js.map"
      jsDir  = path.dirname jsPath
      compile = ->
        if opts.compile
          js = ' ' if js.length <= 0
          if generatedSourceMap then js = "#{js}\n//# sourceMappingURL=#{helpers.baseFileName sourceMapPath, no, useWinPathSep}\n"
          fs.writeFile jsPath, js, (err) ->
            if err
              printLine err.message
              process.exit 1
            else if opts.compile and opts.watch
              timeLog "compiled #{sourcePath}"
        if generatedSourceMap
          fs.writeFile sourceMapPath, generatedSourceMap, (err) ->
            if err
              printLine "Could not write source map: #{err.message}"
              process.exit 1
      fs.exists jsDir, (itExists) ->
        if itExists then compile() else mkdirp 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}"
  • Pretty-print a stream of tokens, sans location data.

    printTokens = (tokens) ->
      strings = for token in tokens
        tag = token[0]
        value = 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.map)
      o.print       = !!  (o.print or (o.eval or o.stdio and o.compile))
  • The compile-time options to pass to the CoffeeScript compiler.

    compileOptions = (filename, base) ->
      answer = {
        filename
        literate: opts.literate or helpers.isLiterate(filename)
        bare: opts.bare
        header: opts.compile and not opts['no-header']
        sourceMap: opts.map
        inlineMap: opts['inline-map']
      }
      if filename
        if base
          cwd = process.cwd()
          jsPath = outputPath filename, base
          jsDir = path.dirname jsPath
          answer = helpers.merge answer, {
            jsPath
            sourceRoot: path.relative jsDir, cwd
            sourceFiles: [path.relative cwd, filename]
            generatedFile: helpers.baseFileName(jsPath, no, useWinPathSep)
          }
        else
          answer = helpers.merge answer,
            sourceRoot: ""
            sourceFiles: [helpers.baseFileName filename, no, useWinPathSep]
            generatedFile: helpers.baseFileName(filename, yes, useWinPathSep) + ".js"
      answer
  • 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
      p = spawn process.execPath, nodeArgs.concat(args),
        cwd:        process.cwd()
        env:        process.env
        stdio:      [0, 1, 2]
      p.on 'exit', (code) -> process.exit code
  • 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}"
coffeescript-1.12.7/docs/v1/annotated-source/docco.css000066400000000000000000000233011313305734200226100ustar00rootroot00000000000000/*--------------------- Typography ----------------------------*/ @font-face { font-family: 'aller-light'; src: url('public/fonts/aller-light.eot'); src: url('public/fonts/aller-light.eot?#iefix') format('embedded-opentype'), url('public/fonts/aller-light.woff') format('woff'), url('public/fonts/aller-light.ttf') format('truetype'); font-weight: normal; font-style: normal; } @font-face { font-family: 'aller-bold'; src: url('public/fonts/aller-bold.eot'); src: url('public/fonts/aller-bold.eot?#iefix') format('embedded-opentype'), url('public/fonts/aller-bold.woff') format('woff'), url('public/fonts/aller-bold.ttf') format('truetype'); font-weight: normal; font-style: normal; } @font-face { font-family: 'roboto-black'; src: url('public/fonts/roboto-black.eot'); src: url('public/fonts/roboto-black.eot?#iefix') format('embedded-opentype'), url('public/fonts/roboto-black.woff') format('woff'), url('public/fonts/roboto-black.ttf') format('truetype'); font-weight: normal; font-style: normal; } /*--------------------- Layout ----------------------------*/ html { height: 100%; } body { font-family: "aller-light"; font-size: 14px; line-height: 18px; color: #30404f; margin: 0; padding: 0; height:100%; } #container { min-height: 100%; } a { color: #000; } b, strong { font-weight: normal; font-family: "aller-bold"; } p { margin: 15px 0 0px; } .annotation ul, .annotation ol { margin: 25px 0; } .annotation ul li, .annotation ol li { font-size: 14px; line-height: 18px; margin: 10px 0; } h1, h2, h3, h4, h5, h6 { color: #112233; line-height: 1em; font-weight: normal; font-family: "roboto-black"; text-transform: uppercase; margin: 30px 0 15px 0; } h1 { margin-top: 40px; } h2 { font-size: 1.26em; } hr { border: 0; background: 1px #ddd; height: 1px; margin: 20px 0; } pre, tt, code { font-size: 12px; line-height: 16px; font-family: Menlo, Monaco, Consolas, "Lucida Console", monospace; margin: 0; padding: 0; } .annotation pre { display: block; margin: 0; padding: 7px 10px; background: #fcfcfc; -moz-box-shadow: inset 0 0 10px rgba(0,0,0,0.1); -webkit-box-shadow: inset 0 0 10px rgba(0,0,0,0.1); box-shadow: inset 0 0 10px rgba(0,0,0,0.1); overflow-x: auto; } .annotation pre code { border: 0; padding: 0; background: transparent; } blockquote { border-left: 5px solid #ccc; margin: 0; padding: 1px 0 1px 1em; } .sections blockquote p { font-family: Menlo, Consolas, Monaco, monospace; font-size: 12px; line-height: 16px; color: #999; margin: 10px 0 0; white-space: pre-wrap; } ul.sections { list-style: none; padding:0 0 5px 0;; margin:0; } /* Force border-box so that % widths fit the parent container without overlap because of margin/padding. More Info : http://www.quirksmode.org/css/box.html */ ul.sections > li > div { -moz-box-sizing: border-box; /* firefox */ -ms-box-sizing: border-box; /* ie */ -webkit-box-sizing: border-box; /* webkit */ -khtml-box-sizing: border-box; /* konqueror */ box-sizing: border-box; /* css3 */ } /*---------------------- Jump Page -----------------------------*/ #jump_to, #jump_page { margin: 0; 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: 16px Arial; cursor: pointer; text-align: right; list-style: none; } #jump_to a { text-decoration: none; } #jump_to a.large { display: none; } #jump_to a.small { font-size: 22px; font-weight: bold; color: #676767; } #jump_to, #jump_wrapper { position: fixed; right: 0; top: 0; padding: 10px 15px; margin:0; } #jump_wrapper { display: none; padding:0; } #jump_to:hover #jump_wrapper { display: block; } #jump_page_wrapper{ position: fixed; right: 0; top: 0; bottom: 0; } #jump_page { padding: 5px 0 3px; margin: 0 0 25px 25px; max-height: 100%; overflow: auto; } #jump_page .source { display: block; padding: 15px; text-decoration: none; border-top: 1px solid #eee; } #jump_page .source:hover { background: #f5f5ff; } #jump_page .source:first-child { } /*---------------------- Low resolutions (> 320px) ---------------------*/ @media only screen and (min-width: 320px) { .pilwrap { display: none; } ul.sections > li > div { display: block; padding:5px 10px 0 10px; } ul.sections > li > div.annotation ul, ul.sections > li > div.annotation ol { padding-left: 30px; } ul.sections > li > div.content { overflow-x:auto; -webkit-box-shadow: inset 0 0 5px #e5e5ee; box-shadow: inset 0 0 5px #e5e5ee; border: 1px solid #dedede; margin:5px 10px 5px 10px; padding-bottom: 5px; } ul.sections > li > div.annotation pre { margin: 7px 0 7px; padding-left: 15px; } ul.sections > li > div.annotation p tt, .annotation code { background: #f8f8ff; border: 1px solid #dedede; font-size: 12px; padding: 0 0.2em; } } /*---------------------- (> 481px) ---------------------*/ @media only screen and (min-width: 481px) { #container { position: relative; } body { background-color: #F5F5FF; font-size: 15px; line-height: 21px; } pre, tt, code { line-height: 18px; } p, ul, ol { margin: 0 0 15px; } #jump_to { padding: 5px 10px; } #jump_wrapper { padding: 0; } #jump_to, #jump_page { font: 10px Arial; text-transform: uppercase; } #jump_page .source { padding: 5px 10px; } #jump_to a.large { display: inline-block; } #jump_to a.small { display: none; } #background { position: absolute; top: 0; bottom: 0; width: 350px; background: #fff; border-right: 1px solid #e5e5ee; z-index: -1; } ul.sections > li > div.annotation ul, ul.sections > li > div.annotation ol { padding-left: 40px; } ul.sections > li { white-space: nowrap; } ul.sections > li > div { display: inline-block; } ul.sections > li > div.annotation { max-width: 350px; min-width: 350px; min-height: 5px; padding: 13px; overflow-x: hidden; white-space: normal; vertical-align: top; text-align: left; } ul.sections > li > div.annotation pre { margin: 15px 0 15px; padding-left: 15px; } ul.sections > li > div.content { padding: 13px; vertical-align: top; border: none; -webkit-box-shadow: none; box-shadow: none; } .pilwrap { position: relative; display: inline; } .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; } .for-h1 .pilcrow { top: 47px; } .for-h2 .pilcrow, .for-h3 .pilcrow, .for-h4 .pilcrow { top: 35px; } ul.sections > li > div.annotation:hover .pilcrow { opacity: 1; } } /*---------------------- (> 1025px) ---------------------*/ @media only screen and (min-width: 1025px) { body { font-size: 16px; line-height: 24px; } #background { width: 525px; } ul.sections > li > div.annotation { max-width: 525px; min-width: 525px; padding: 10px 25px 1px 50px; } ul.sections > li > div.content { padding: 9px 15px 16px 25px; } } /*---------------------- Syntax Highlighting -----------------------------*/ td.linenos { background-color: #f0f0f0; padding-right: 10px; } span.lineno { background-color: #f0f0f0; padding: 0 5px 0 5px; } /* github.com style (c) Vasily Polovnyov */ pre code { display: block; padding: 0.5em; color: #000; background: #f8f8ff } pre .hljs-comment, pre .hljs-template_comment, pre .hljs-diff .hljs-header, pre .hljs-javadoc { color: #408080; font-style: italic } pre .hljs-keyword, pre .hljs-assignment, pre .hljs-literal, pre .hljs-css .hljs-rule .hljs-keyword, pre .hljs-winutils, pre .hljs-javascript .hljs-title, pre .hljs-lisp .hljs-title, pre .hljs-subst { color: #954121; /*font-weight: bold*/ } pre .hljs-number, pre .hljs-hexcolor { color: #40a070 } pre .hljs-string, pre .hljs-tag .hljs-value, pre .hljs-phpdoc, pre .hljs-tex .hljs-formula { color: #219161; } pre .hljs-title, pre .hljs-id { color: #19469D; } pre .hljs-params { color: #00F; } pre .hljs-javascript .hljs-title, pre .hljs-lisp .hljs-title, pre .hljs-subst { font-weight: normal } pre .hljs-class .hljs-title, pre .hljs-haskell .hljs-label, pre .hljs-tex .hljs-command { color: #458; font-weight: bold } pre .hljs-tag, pre .hljs-tag .hljs-title, pre .hljs-rules .hljs-property, pre .hljs-django .hljs-tag .hljs-keyword { color: #000080; font-weight: normal } pre .hljs-attribute, pre .hljs-variable, pre .hljs-instancevar, pre .hljs-lisp .hljs-body { color: #008080 } pre .hljs-regexp { color: #B68 } pre .hljs-class { color: #458; font-weight: bold } pre .hljs-symbol, pre .hljs-ruby .hljs-symbol .hljs-string, pre .hljs-ruby .hljs-symbol .hljs-keyword, pre .hljs-ruby .hljs-symbol .hljs-keymethods, pre .hljs-lisp .hljs-keyword, pre .hljs-tex .hljs-special, pre .hljs-input_number { color: #990073 } pre .hljs-builtin, pre .hljs-constructor, pre .hljs-built_in, pre .hljs-lisp .hljs-title { color: #0086b3 } pre .hljs-preprocessor, pre .hljs-pi, pre .hljs-doctype, pre .hljs-shebang, pre .hljs-cdata { color: #999; font-weight: bold } pre .hljs-deletion { background: #fdd } pre .hljs-addition { background: #dfd } pre .hljs-diff .hljs-change { background: #0086b3 } pre .hljs-chunk { color: #aaa } pre .hljs-tex .hljs-formula { opacity: 0.5; } coffeescript-1.12.7/docs/v1/annotated-source/grammar.html000066400000000000000000003206171313305734200233350ustar00rootroot00000000000000 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, ' '
      patternCount = patternString.split(' ').length
      return [patternString, '$$ = $1;', options] unless action
      action = if match = unwrap.exec action then match[1] else "(#{action}())"
  • All runtime functions we need are defined on “yy”

      action = action.replace /\bnew /g, '$&yy.'
      action = action.replace /\b(?:Block\.wrap|extend)\b/g, 'yy.$&'
  • Returns a function which adds location data to the first parameter passed in, and returns the parameter. If the parameter is not a node, it will just be passed through unaffected.

      addLocationDataFn = (first, last) ->
        if not last
          "yy.addLocationDataFn(@#{first})"
        else
          "yy.addLocationDataFn(@#{first}, @#{last})"
    
      action = action.replace /LOC\(([0-9]*)\)/g, addLocationDataFn('$1')
      action = action.replace /LOC\(([0-9]*),\s*([0-9]*)\)/g, addLocationDataFn('$1', '$2')
    
      [patternString, "$$ = #{addLocationDataFn(1, patternCount)}(#{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'
      ]
  • 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. YieldReturn is a statement, but not included in Statement because that results in an ambiguous grammar.

      Line: [
        o 'Expression'
        o 'Statement'
        o 'YieldReturn'
      ]
  • Pure statements which cannot be expressions.

      Statement: [
        o 'Return'
        o 'Comment'
        o 'STATEMENT',                              -> new StatementLiteral $1
        o 'Import'
        o 'Export'
      ]
  • 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'
        o 'Yield'
      ]
    
      Yield: [
        o 'YIELD',                                  -> new Op $1, new Value new Literal ''
        o 'YIELD Expression',                       -> new Op $1, $2
        o 'YIELD FROM Expression',                  -> new Op $1.concat($2), $3
      ]
  • 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
      ]
    
      Identifier: [
        o 'IDENTIFIER',                             -> new IdentifierLiteral $1
      ]
    
      Property: [
        o 'PROPERTY',                               -> new PropertyName $1
      ]
  • Alphanumerics are separated from the other Literal matchers because they can also serve as keys in object literals.

      AlphaNumeric: [
        o 'NUMBER',                                 -> new NumberLiteral $1
        o 'String'
      ]
    
      String: [
        o 'STRING',                                 -> new StringLiteral $1
        o 'STRING_START Body STRING_END',           -> new StringWithInterpolations $2
      ]
    
      Regex: [
        o 'REGEX',                                  -> new RegexLiteral $1
        o 'REGEX_START Invocation REGEX_END',       -> new RegexWithInterpolations $2.args
      ]
  • All of our immediate values. Generally these can be passed straight through and printed to JavaScript.

      Literal: [
        o 'AlphaNumeric'
        o 'JS',                                     -> new PassthroughLiteral $1
        o 'Regex'
        o 'UNDEFINED',                              -> new UndefinedLiteral
        o 'NULL',                                   -> new NullLiteral
        o 'BOOL',                                   -> new BooleanLiteral $1
        o 'INFINITY',                               -> new InfinityLiteral $1
        o 'NAN',                                    -> new NaNLiteral
      ]
  • 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 LOC(1)(new Value $1), $3, 'object',
                                                                  operatorToken: LOC(2)(new Literal $2)
        o 'ObjAssignable :
           INDENT Expression OUTDENT',              -> new Assign LOC(1)(new Value $1), $4, 'object',
                                                                  operatorToken: LOC(2)(new Literal $2)
        o 'SimpleObjAssignable = Expression',       -> new Assign LOC(1)(new Value $1), $3, null,
                                                                  operatorToken: LOC(2)(new Literal $2)
        o 'SimpleObjAssignable =
           INDENT Expression OUTDENT',              -> new Assign LOC(1)(new Value $1), $4, null,
                                                                  operatorToken: LOC(2)(new Literal $2)
        o 'Comment'
      ]
    
      SimpleObjAssignable: [
        o 'Identifier'
        o 'Property'
        o 'ThisProperty'
      ]
    
      ObjAssignable: [
        o 'SimpleObjAssignable'
        o 'AlphaNumeric'
      ]
  • A return statement from a function body.

      Return: [
        o 'RETURN Expression',                      -> new Return $2
        o 'RETURN INDENT Object OUTDENT',           -> new Return new Value $3
        o 'RETURN',                                 -> new Return
      ]
    
      YieldReturn: [
        o 'YIELD RETURN Expression',                -> new YieldReturn $3
        o 'YIELD RETURN',                           -> new YieldReturn
      ]
  • 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
        o '...',                                    -> new Expansion
      ]
  • 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 '.  Property',                            -> new Access $2
        o '?. Property',                            -> new Access $2, 'soak'
        o ':: Property',                            -> [LOC(1)(new Access new PropertyName('prototype')), LOC(2)(new Access $2)]
        o '?:: Property',                           -> [LOC(1)(new Access new PropertyName('prototype'), 'soak'), LOC(2)(new Access $2)]
        o '::',                                     -> new Access new PropertyName '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
      ]
    
      Import: [
        o 'IMPORT String',                                                                -> new ImportDeclaration null, $2
        o 'IMPORT ImportDefaultSpecifier FROM String',                                    -> new ImportDeclaration new ImportClause($2, null), $4
        o 'IMPORT ImportNamespaceSpecifier FROM String',                                  -> new ImportDeclaration new ImportClause(null, $2), $4
        o 'IMPORT { } FROM String',                                                       -> new ImportDeclaration new ImportClause(null, new ImportSpecifierList []), $5
        o 'IMPORT { ImportSpecifierList OptComma } FROM String',                          -> new ImportDeclaration new ImportClause(null, new ImportSpecifierList $3), $7
        o 'IMPORT ImportDefaultSpecifier , ImportNamespaceSpecifier FROM String',         -> new ImportDeclaration new ImportClause($2, $4), $6
        o 'IMPORT ImportDefaultSpecifier , { ImportSpecifierList OptComma } FROM String', -> new ImportDeclaration new ImportClause($2, new ImportSpecifierList $5), $9
      ]
    
      ImportSpecifierList: [
        o 'ImportSpecifier',                                                          -> [$1]
        o 'ImportSpecifierList , ImportSpecifier',                                    -> $1.concat $3
        o 'ImportSpecifierList OptComma TERMINATOR ImportSpecifier',                  -> $1.concat $4
        o 'INDENT ImportSpecifierList OptComma OUTDENT',                              -> $2
        o 'ImportSpecifierList OptComma INDENT ImportSpecifierList OptComma OUTDENT', -> $1.concat $4
      ]
    
      ImportSpecifier: [
        o 'Identifier',                             -> new ImportSpecifier $1
        o 'Identifier AS Identifier',               -> new ImportSpecifier $1, $3
        o 'DEFAULT',                                -> new ImportSpecifier new Literal $1
        o 'DEFAULT AS Identifier',                  -> new ImportSpecifier new Literal($1), $3
      ]
    
      ImportDefaultSpecifier: [
        o 'Identifier',                             -> new ImportDefaultSpecifier $1
      ]
    
      ImportNamespaceSpecifier: [
        o 'IMPORT_ALL AS Identifier',               -> new ImportNamespaceSpecifier new Literal($1), $3
      ]
    
      Export: [
        o 'EXPORT { }',                                          -> new ExportNamedDeclaration new ExportSpecifierList []
        o 'EXPORT { ExportSpecifierList OptComma }',             -> new ExportNamedDeclaration new ExportSpecifierList $3
        o 'EXPORT Class',                                        -> new ExportNamedDeclaration $2
        o 'EXPORT Identifier = Expression',                      -> new ExportNamedDeclaration new Assign $2, $4, null,
                                                                                                          moduleDeclaration: 'export'
        o 'EXPORT Identifier = TERMINATOR Expression',           -> new ExportNamedDeclaration new Assign $2, $5, null,
                                                                                                          moduleDeclaration: 'export'
        o 'EXPORT Identifier = INDENT Expression OUTDENT',       -> new ExportNamedDeclaration new Assign $2, $5, null,
                                                                                                          moduleDeclaration: 'export'
        o 'EXPORT DEFAULT Expression',                           -> new ExportDefaultDeclaration $3
        o 'EXPORT EXPORT_ALL FROM String',                       -> new ExportAllDeclaration new Literal($2), $4
        o 'EXPORT { ExportSpecifierList OptComma } FROM String', -> new ExportNamedDeclaration new ExportSpecifierList($3), $7
      ]
    
      ExportSpecifierList: [
        o 'ExportSpecifier',                                                          -> [$1]
        o 'ExportSpecifierList , ExportSpecifier',                                    -> $1.concat $3
        o 'ExportSpecifierList OptComma TERMINATOR ExportSpecifier',                  -> $1.concat $4
        o 'INDENT ExportSpecifierList OptComma OUTDENT',                              -> $2
        o 'ExportSpecifierList OptComma INDENT ExportSpecifierList OptComma OUTDENT', -> $1.concat $4
      ]
    
      ExportSpecifier: [
        o 'Identifier',                             -> new ExportSpecifier $1
        o 'Identifier AS Identifier',               -> new ExportSpecifier $1, $3
        o 'Identifier AS DEFAULT',                  -> new ExportSpecifier $1, new Literal $3
        o 'DEFAULT',                                -> new ExportSpecifier new Literal $1
        o 'DEFAULT AS Identifier',                  -> new ExportSpecifier new Literal($1), $3
      ]
  • Ordinary function invocation, or a chained series of calls.

      Invocation: [
        o 'Value OptFuncExist String',              -> new TaggedTemplateCall $1, $3, $2
        o 'Value OptFuncExist Arguments',           -> new Call $1, $3, $2
        o 'Invocation OptFuncExist Arguments',      -> new Call $1, $3, $2
        o 'Super'
      ]
    
      Super: [
        o 'SUPER',                                  -> new SuperCall
        o 'SUPER Arguments',                        -> new SuperCall $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 ThisLiteral
        o '@',                                      -> new Value new ThisLiteral
      ]
  • A reference to a property on this.

      ThisProperty: [
        o '@ Property',                             -> new Value LOC(1)(new ThisLiteral), [LOC(2)(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'
        o '...',                                     -> new Expansion
      ]
  • 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]
        o 'CATCH Object Block',                     -> [LOC(2)(new Value($2)), $3]
        o 'CATCH Block',                            -> [null, $2]
      ]
  • 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 LOC(1) Block.wrap([$1])
        o 'Expression WhileSource',                 -> $2.addBody LOC(1) Block.wrap([$1])
        o 'Loop',                                   -> $1
      ]
    
      Loop: [
        o 'LOOP Block',                             -> new While(LOC(1) new BooleanLiteral 'true').addBody $2
        o 'LOOP Expression',                        -> new While(LOC(1) new BooleanLiteral 'true').addBody LOC(2) 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: (LOC(2) new Value($2))
        o 'FOR Range BY Expression',                -> source: (LOC(2) new Value($2)), step: $4
        o 'ForStart ForSource',                     -> $2.own = $1.own; $2.ownTag = $1.ownTag; $2.name = $1[0]; $2.index = $1[1]; $2
      ]
    
      ForStart: [
        o 'FOR ForVariables',                       -> $2
        o 'FOR OWN ForVariables',                   -> $3.own = yes; $3.ownTag = (LOC(2) new Literal($2)); $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
        o 'FORFROM Expression',                             -> source: $2, from: yes
        o 'FORFROM Expression WHEN Expression',             -> source: $2, guard: $4, from: yes
      ]
    
      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 LOC(3,5) 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, LOC(1)(Block.wrap [$1]), type: $2, statement: true
        o 'Expression POST_IF Expression',          -> new If $3, LOC(1)(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 'UNARY_MATH Expression',                  -> new Op $1 , $2
        o '-     Expression',                      (-> new Op '-', $2), prec: 'UNARY_MATH'
        o '+     Expression',                      (-> new Op '+', $2), prec: 'UNARY_MATH'
    
        o '-- SimpleAssignable',                    -> new Op '--', $2
        o '++ SimpleAssignable',                    -> new Op '++', $2
        o 'SimpleAssignable --',                    -> new Op '--', $1, null, true
        o 'SimpleAssignable ++',                    -> new Op '++', $1, null, true
  •     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 **       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 &        Expression',         -> new Op $2, $1, $3
        o 'Expression ^        Expression',         -> new Op $2, $1, $3
        o 'Expression |        Expression',         -> new Op $2, $1, $3
        o 'Expression &&       Expression',         -> new Op $2, $1, $3
        o 'Expression ||       Expression',         -> new Op $2, $1, $3
        o 'Expression BIN?     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 COMPOUND_ASSIGN TERMINATOR
           Expression',                             -> 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']
      ['right',     '**']
      ['right',     'UNARY_MATH']
      ['left',      'MATH']
      ['left',      '+', '-']
      ['left',      'SHIFT']
      ['left',      'RELATION']
      ['left',      'COMPARE']
      ['left',      '&']
      ['left',      '^']
      ['left',      '|']
      ['left',      '&&']
      ['left',      '||']
      ['left',      'BIN?']
      ['nonassoc',  'INDENT', 'OUTDENT']
      ['right',     'YIELD']
      ['right',     '=', ':', 'COMPOUND_ASSIGN', 'RETURN', 'THROW', 'EXTENDS']
      ['right',     'FORIN', 'FOROF', 'FORFROM', 'BY', 'WHEN']
      ['right',     'IF', 'ELSE', 'FOR', 'WHILE', 'UNTIL', 'LOOP', 'SUPER', 'CLASS', 'IMPORT', 'EXPORT']
      ['left',      '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'
coffeescript-1.12.7/docs/v1/annotated-source/helpers.html000066400000000000000000000634561313305734200233560ustar00rootroot00000000000000 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
  • Repeat a string n times.

    exports.repeat = repeat = (str, n) ->
  • Use clever algorithm to have O(log(n)) string concatenation operations.

      res = ''
      while n > 0
        res += str if n & 1
        n >>>= 1
        str += str
      res
  • 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 '[object Array]' is Object::toString.call element
          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
  • Typical Array::some

    exports.some = Array::some ? (fn) ->
      return true for e in this when fn e
      false
  • Simple function for inverting Literate CoffeeScript code by putting the documentation in comments, producing a string of CoffeeScript code that can be compiled “normally”.

    exports.invertLiterate = (code) ->
      maybe_code = true
      lines = for line in code.split('\n')
        if maybe_code and /^([ ]{4}|[ ]{0,3}\t)/.test line
          line
        else if maybe_code = /^\s*$/.test line
          line
        else
          '# ' + line
      lines.join '\n'
  • Merge two jison-style location data objects together. If last is not provided, this will simply return first.

    buildLocationData = (first, last) ->
      if not last
        first
      else
        first_line: first.first_line
        first_column: first.first_column
        last_line: last.last_line
        last_column: last.last_column
  • This returns a function which takes an object as a parameter, and if that object is an AST node, updates that object’s locationData. The object is returned either way.

    exports.addLocationDataFn = (first, last) ->
      (obj) ->
        if ((typeof obj) is 'object') and (!!obj['updateLocationDataIfMissing'])
          obj.updateLocationDataIfMissing buildLocationData(first, last)
    
        return obj
  • Convert jison location data to a string. obj can be a token, or a locationData.

    exports.locationDataToString = (obj) ->
      if ("2" of obj) and ("first_line" of obj[2]) then locationData = obj[2]
      else if "first_line" of obj then locationData = obj
    
      if locationData
        "#{locationData.first_line + 1}:#{locationData.first_column + 1}-" +
        "#{locationData.last_line + 1}:#{locationData.last_column + 1}"
      else
        "No location data"
  • A .coffee.md compatible version of basename, that returns the file sans-extension.

    exports.baseFileName = (file, stripExt = no, useWinPathSep = no) ->
      pathSep = if useWinPathSep then /\\|\// else /\//
      parts = file.split(pathSep)
      file = parts[parts.length - 1]
      return file unless stripExt and file.indexOf('.') >= 0
      parts = file.split('.')
      parts.pop()
      parts.pop() if parts[parts.length - 1] is 'coffee' and parts.length > 1
      parts.join('.')
  • Determine if a filename represents a CoffeeScript file.

    exports.isCoffee = (file) -> /\.((lit)?coffee|coffee\.md)$/.test file
  • Determine if a filename represents a Literate CoffeeScript file.

    exports.isLiterate = (file) -> /\.(litcoffee|coffee\.md)$/.test file
  • Throws a SyntaxError from a given location. The error’s toString will return an error message following the “standard” format <filename>:<line>:<col>: <message> plus the line with the error and a marker showing where the error is.

    exports.throwSyntaxError = (message, location) ->
      error = new SyntaxError message
      error.location = location
      error.toString = syntaxErrorToString
  • Instead of showing the compiler’s stacktrace, show our custom error message (this is useful when the error bubbles up in Node.js applications that compile CoffeeScript for example).

      error.stack = error.toString()
    
      throw error
  • Update a compiler SyntaxError with source code information if it didn’t have it already.

    exports.updateSyntaxError = (error, code, filename) ->
  • Avoid screwing up the stack property of other errors (i.e. possible bugs).

      if error.toString is syntaxErrorToString
        error.code or= code
        error.filename or= filename
        error.stack = error.toString()
      error
    
    syntaxErrorToString = ->
      return Error::toString.call @ unless @code and @location
    
      {first_line, first_column, last_line, last_column} = @location
      last_line ?= first_line
      last_column ?= first_column
    
      filename = @filename or '[stdin]'
      codeLine = @code.split('\n')[first_line]
      start    = first_column
  • Show only the first line on multi-line errors.

      end      = if first_line is last_line then last_column + 1 else codeLine.length
      marker   = codeLine[...start].replace(/[^\s]/g, ' ') + repeat('^', end - start)
  • Check to see if we’re running on a color-enabled TTY.

      if process?
        colorsEnabled = process.stdout?.isTTY and not process.env?.NODE_DISABLE_COLORS
    
      if @colorful ? colorsEnabled
        colorize = (str) -> "\x1B[1;31m#{str}\x1B[0m"
        codeLine = codeLine[...start] + colorize(codeLine[start...end]) + codeLine[end..]
        marker   = colorize marker
    
      """
        #{filename}:#{first_line + 1}:#{first_column + 1}: error: #{@message}
        #{codeLine}
        #{marker}
      """
    
    exports.nameWhitespaceCharacter = (string) ->
      switch string
        when ' ' then 'space'
        when '\n' then 'newline'
        when '\r' then 'carriage return'
        when '\t' then 'tab'
        else string
coffeescript-1.12.7/docs/v1/annotated-source/index.html000066400000000000000000000072171313305734200230140ustar00rootroot00000000000000 index.coffee coffeescript-1.12.7/docs/v1/annotated-source/lexer.html000066400000000000000000003646151313305734200230340ustar00rootroot00000000000000 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, locationData]
    

    where locationData is {first_line, first_column, last_line, last_column}, which is a format that can be fed directly into Jison. These are read by jison in the parser.lexer function defined in coffee-script.coffee.

    {Rewriter, INVERSES} = require './rewriter'
  • Import the helpers we need.

    {count, starts, compact, repeat, invertLiterate,
    locationDataToString,  throwSyntaxError} = 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.

      tokenize: (code, opts = {}) ->
        @literate   = opts.literate  # Are we lexing literate CoffeeScript?
        @indent     = 0              # The current indentation level.
        @baseIndent = 0              # The overall minimum 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, location data]`.
        @seenFor    = no             # Used to recognize FORIN, FOROF and FORFROM tokens.
        @seenImport = no             # Used to recognize IMPORT FROM? AS? tokens.
        @seenExport = no             # Used to recognize EXPORT FROM? AS? tokens.
        @importSpecifierList = no    # Used to identify when in an IMPORT {...} FROM? ...
        @exportSpecifierList = no    # Used to identify when in an EXPORT {...} FROM? ...
    
        @chunkLine =
          opts.line or 0             # The start line for the current @chunk.
        @chunkColumn =
          opts.column or 0           # The start column of the current @chunk.
        code = @clean code           # The stripped, cleaned original source code.
  • 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..]
          consumed = \
               @identifierToken() or
               @commentToken()    or
               @whitespaceToken() or
               @lineToken()       or
               @stringToken()     or
               @numberToken()     or
               @regexToken()      or
               @jsToken()         or
               @literalToken()
  • Update position

          [@chunkLine, @chunkColumn] = @getLineAndColumnFromChunk consumed
    
          i += consumed
    
          return {@tokens, index: i} if opts.untilBalanced and @ends.length is 0
    
        @closeIndentation()
        @error "missing #{end.tag}", end.origin[2] if end = @ends.pop()
        return @tokens if opts.rewrite is off
        (new Rewriter).rewrite @tokens
  • Preprocess the code to remove leading and trailing whitespace, carriage returns, etc. If we’re lexing literate CoffeeScript, strip external Markdown by removing all lines that aren’t indented by at least four spaces or a tab.

      clean: (code) ->
        code = code.slice(1) if code.charCodeAt(0) is BOM
        code = code.replace(/\r/g, '').replace TRAILING_SPACES, ''
        if WHITESPACE.test code
          code = "\n#{code}"
          @chunkLine--
        code = invertLiterate code if @literate
        code
  • 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
  • Preserve length of id for location data

        idLength = id.length
        poppedToken = undefined
    
        if id is 'own' and @tag() is 'FOR'
          @token 'OWN', id
          return id.length
        if id is 'from' and @tag() is 'YIELD'
          @token 'FROM', id
          return id.length
        if id is 'as' and @seenImport
          if @value() is '*'
            @tokens[@tokens.length - 1][0] = 'IMPORT_ALL'
          else if @value() in COFFEE_KEYWORDS
            @tokens[@tokens.length - 1][0] = 'IDENTIFIER'
          if @tag() in ['DEFAULT', 'IMPORT_ALL', 'IDENTIFIER']
            @token 'AS', id
            return id.length
        if id is 'as' and @seenExport and @tag() in ['IDENTIFIER', 'DEFAULT']
          @token 'AS', id
          return id.length
        if id is 'default' and @seenExport and @tag() in ['EXPORT', 'AS']
          @token 'DEFAULT', id
          return id.length
    
        [..., prev] = @tokens
    
        tag =
          if colon or prev? and
             (prev[0] in ['.', '?.', '::', '?::'] or
             not prev.spaced and prev[0] is '@')
            'PROPERTY'
          else
            'IDENTIFIER'
    
        if tag is 'IDENTIFIER' and (id in JS_KEYWORDS or id in COFFEE_KEYWORDS) and
           not (@exportSpecifierList and 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 is 'IMPORT'
            @seenImport = yes
          else if tag is 'EXPORT'
            @seenExport = yes
          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 '!'
                poppedToken = @tokens.pop()
                id = '!' + id
        else if tag is 'IDENTIFIER' and @seenFor and id is 'from' and
           isForFrom(prev)
          tag = 'FORFROM'
          @seenFor = no
    
        if tag is 'IDENTIFIER' and id in RESERVED
          @error "reserved word '#{id}'", length: id.length
    
        unless tag is 'PROPERTY'
          if id in COFFEE_ALIASES
            alias = id
            id = COFFEE_ALIAS_MAP[id]
          tag = switch id
            when '!'                 then 'UNARY'
            when '==', '!='          then 'COMPARE'
            when 'true', 'false'     then 'BOOL'
            when 'break', 'continue', \
                 'debugger'          then 'STATEMENT'
            when '&&', '||'          then id
            else  tag
    
        tagToken = @token tag, id, 0, idLength
        tagToken.origin = [tag, alias, tagToken[2]] if alias
        if poppedToken
          [tagToken[2].first_line, tagToken[2].first_column] =
            [poppedToken[2].first_line, poppedToken[2].first_column]
        if colon
          colonOffset = input.lastIndexOf ':'
          @token ':', ':', colonOffset, colon.length
    
        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]
        lexedLength = number.length
    
        switch
          when /^0[BOX]/.test number
            @error "radix prefix in '#{number}' must be lowercase", offset: 1
          when /^(?!0x).*E/.test number
            @error "exponential notation in '#{number}' must be indicated with a lowercase 'e'",
              offset: number.indexOf('E')
          when /^0\d*[89]/.test number
            @error "decimal literal '#{number}' must not be prefixed with '0'", length: lexedLength
          when /^0\d+/.test number
            @error "octal literal '#{number}' must be prefixed with '0o'", length: lexedLength
    
        base = switch number.charAt 1
          when 'b' then 2
          when 'o' then 8
          when 'x' then 16
          else null
        numberValue = if base? then parseInt(number[2..], base) else parseFloat(number)
        if number.charAt(1) in ['b', 'o']
          number = "0x#{numberValue.toString 16}"
    
        tag = if numberValue is Infinity then 'INFINITY' else 'NUMBER'
        @token tag, number, 0, lexedLength
        lexedLength
  • Matches strings, including multi-line strings, as well as heredocs, with or without interpolation.

      stringToken: ->
        [quote] = STRING_START.exec(@chunk) || []
        return 0 unless quote
  • If the preceding token is from and this is an import or export statement, properly tag the from.

        if @tokens.length and @value() is 'from' and (@seenImport or @seenExport)
          @tokens[@tokens.length - 1][0] = 'FROM'
    
        regex = switch quote
          when "'"   then STRING_SINGLE
          when '"'   then STRING_DOUBLE
          when "'''" then HEREDOC_SINGLE
          when '"""' then HEREDOC_DOUBLE
        heredoc = quote.length is 3
    
        {tokens, index: end} = @matchWithInterpolations regex, quote
        $ = tokens.length - 1
    
        delimiter = quote.charAt(0)
        if heredoc
  • Find the smallest indentation. It will be removed from all lines later.

          indent = null
          doc = (token[1] for token, i in tokens when token[0] is 'NEOSTRING').join '#{}'
          while match = HEREDOC_INDENT.exec doc
            attempt = match[1]
            indent = attempt if indent is null or 0 < attempt.length < indent.length
          indentRegex = /// \n#{indent} ///g if indent
          @mergeInterpolationTokens tokens, {delimiter}, (value, i) =>
            value = @formatString value, delimiter: quote
            value = value.replace indentRegex, '\n' if indentRegex
            value = value.replace LEADING_BLANK_LINE,  '' if i is 0
            value = value.replace TRAILING_BLANK_LINE, '' if i is $
            value
        else
          @mergeInterpolationTokens tokens, {delimiter}, (value, i) =>
            value = @formatString value, delimiter: quote
            value = value.replace SIMPLE_STRING_OMIT, (match, offset) ->
              if (i is 0 and offset is 0) or
                 (i is $ and offset + match.length is value.length)
                ''
              else
                ' '
            value
    
        end
  • Matches and consumes comments.

      commentToken: ->
        return 0 unless match = @chunk.match COMMENT
        [comment, here] = match
        if here
          if match = HERECOMMENT_ILLEGAL.exec comment
            @error "block comments cannot contain #{match[0]}",
              offset: match.index, length: match[0].length
          if here.indexOf('\n') >= 0
            here = here.replace /// \n #{repeat ' ', @indent} ///g, '\n'
          @token 'HERECOMMENT', here, 0, comment.length
        comment.length
  • Matches JavaScript interpolated directly into the source via backticks.

      jsToken: ->
        return 0 unless @chunk.charAt(0) is '`' and
          (match = HERE_JSTOKEN.exec(@chunk) or JSTOKEN.exec(@chunk))
  • Convert escaped backticks to backticks, and escaped backslashes just before escaped backticks to backslashes

        script = match[1].replace /\\+(`|$)/g, (string) ->
  • string is always a value like ‘`‘, ‘\`‘, ‘\\`‘, etc. By reducing it to its latter half, we turn ‘`‘ to ‘', '\\\‘ to ‘`‘, etc.

          string[-Math.ceil(string.length / 2)..]
        @token 'JS', script, 0, match[0].length
        match[0].length
  • Matches regular expression literals, as well as multiline extended ones. Lexing regular expressions is difficult to distinguish from division, so we borrow some basic heuristics from JavaScript and Ruby.

      regexToken: ->
        switch
          when match = REGEX_ILLEGAL.exec @chunk
            @error "regular expressions cannot begin with #{match[2]}",
              offset: match.index + match[1].length
          when match = @matchWithInterpolations HEREGEX, '///'
            {tokens, index} = match
          when match = REGEX.exec @chunk
            [regex, body, closed] = match
            @validateEscapes body, isRegex: yes, offsetInChunk: 1
            body = @formatRegex body, delimiter: '/'
            index = regex.length
            [..., prev] = @tokens
            if prev
              if prev.spaced and prev[0] in CALLABLE
                return 0 if not closed or POSSIBLY_DIVISION.test regex
              else if prev[0] in NOT_REGEX
                return 0
            @error 'missing / (unclosed regex)' unless closed
          else
            return 0
    
        [flags] = REGEX_FLAGS.exec @chunk[index..]
        end = index + flags.length
        origin = @makeToken 'REGEX', null, 0, end
        switch
          when not VALID_FLAGS.test flags
            @error "invalid regular expression flags #{flags}", offset: index, length: flags.length
          when regex or tokens.length is 1
            body ?= @formatHeregex tokens[0][1]
            @token 'REGEX', "#{@makeDelimitedLiteral body, delimiter: '/'}#{flags}", 0, end, origin
          else
            @token 'REGEX_START', '(', 0, 0, origin
            @token 'IDENTIFIER', 'RegExp', 0, 0
            @token 'CALL_START', '(', 0, 0
            @mergeInterpolationTokens tokens, {delimiter: '"', double: yes}, @formatHeregex
            if flags
              @token ',', ',', index - 1, 0
              @token 'STRING', '"' + flags + '"', index - 1, flags.length
            @token ')', ')', end - 1, 0
            @token 'REGEX_END', ')', end - 1, 0
    
        end
  • Matches newlines, indents, and outdents, and determines which is which. If we can detect that the current line is continued onto 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]
    
        @seenFor = no
        @seenImport = no unless @importSpecifierList
        @seenExport = no unless @exportSpecifierList
    
        size = indent.length - 1 - indent.lastIndexOf '\n'
        noNewlines = @unfinished()
    
        if size - @indebt is @indent
          if noNewlines then @suppressNewlines() else @newlineToken 0
          return indent.length
    
        if size > @indent
          if noNewlines
            @indebt = size - @indent
            @suppressNewlines()
            return indent.length
          unless @tokens.length
            @baseIndent = @indent = size
            return indent.length
          diff = size - @indent + @outdebt
          @token 'INDENT', diff, indent.length - size, size
          @indents.push diff
          @ends.push {tag: 'OUTDENT'}
          @outdebt = @indebt = 0
          @indent = size
        else if size < @baseIndent
          @error 'missing indentation', offset: indent.length
        else
          @indebt = 0
          @outdentToken @indent - size, noNewlines, indent.length
        indent.length
  • Record an outdent token or multiple tokens, if we happen to be moving back inwards past several recorded indents. Sets new @indent value.

      outdentToken: (moveOut, noNewlines, outdentLength) ->
        decreasedIndent = @indent - moveOut
        while moveOut > 0
          lastIndent = @indents[@indents.length - 1]
          if not lastIndent
            moveOut = 0
          else if lastIndent is @outdebt
            moveOut -= @outdebt
            @outdebt = 0
          else if lastIndent < @outdebt
            @outdebt -= lastIndent
            moveOut  -= lastIndent
          else
            dent = @indents.pop() + @outdebt
            if outdentLength and @chunk[outdentLength] in INDENTABLE_CLOSERS
              decreasedIndent -= dent - moveOut
              moveOut = dent
            @outdebt = 0
  • pair might call outdentToken, so preserve decreasedIndent

            @pair 'OUTDENT'
            @token 'OUTDENT', moveOut, 0, outdentLength
            moveOut -= dent
        @outdebt -= moveOut if dent
        @tokens.pop() while @value() is ';'
    
        @token 'TERMINATOR', '\n', outdentLength, 0 unless @tag() is 'TERMINATOR' or noNewlines
        @indent = decreasedIndent
        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] = @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: (offset) ->
        @tokens.pop() while @value() is ';'
        @token 'TERMINATOR', '\n', offset, 0 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] = @tokens
    
        if prev and value in ['=', COMPOUND_ASSIGN...]
          skipToken = false
          if value is '=' and prev[1] in ['||', '&&'] and not prev.spaced
            prev[0] = 'COMPOUND_ASSIGN'
            prev[1] += '='
            prev = @tokens[@tokens.length - 2]
            skipToken = true
          if prev and prev[0] isnt 'PROPERTY'
            origin = prev.origin ? prev
            message = isUnassignable prev[1], origin[1]
            @error message, origin[2] if message
          return value.length if skipToken
    
        if value is '{' and @seenImport
          @importSpecifierList = yes
        else if @importSpecifierList and value is '}'
          @importSpecifierList = no
        else if value is '{' and prev?[0] is 'EXPORT'
          @exportSpecifierList = yes
        else if @exportSpecifierList and value is '}'
          @exportSpecifierList = no
    
        if value is ';'
          @seenFor = @seenImport = @seenExport = no
          tag = 'TERMINATOR'
        else if value is '*' and prev[0] is 'EXPORT'
          tag = 'EXPORT_ALL'
        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 UNARY_MATH      then tag = 'UNARY_MATH'
        else if value in SHIFT           then tag = 'SHIFT'
        else if value is '?' and prev?.spaced then tag = 'BIN?'
        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'
        token = @makeToken tag, value
        switch value
          when '(', '{', '[' then @ends.push {tag: INVERSES[value], origin: token}
          when ')', '}', ']' then @pair value
        @tokens.push token
        value.length
  • Token Manipulators

  • 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
  • Match the contents of a delimited token and expand variables and expressions inside it 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 and tokenize until the { of #{ is balanced with a }.

    • regex matches the contents of a token (but not delimiter, and not #{ if interpolations are desired).
    • delimiter is the delimiter of the token. Examples are ', ", ''', """ and ///.

    This method allows us to have strings within interpolations within strings, ad infinitum.

      matchWithInterpolations: (regex, delimiter) ->
        tokens = []
        offsetInChunk = delimiter.length
        return null unless @chunk[...offsetInChunk] is delimiter
        str = @chunk[offsetInChunk..]
        loop
          [strPart] = regex.exec str
    
          @validateEscapes strPart, {isRegex: delimiter.charAt(0) is '/', offsetInChunk}
  • Push a fake ‘NEOSTRING’ token, which will get turned into a real string later.

          tokens.push @makeToken 'NEOSTRING', strPart, offsetInChunk
    
          str = str[strPart.length..]
          offsetInChunk += strPart.length
    
          break unless str[...2] is '#{'
  • The 1s are to remove the # in #{.

          [line, column] = @getLineAndColumnFromChunk offsetInChunk + 1
          {tokens: nested, index} =
            new Lexer().tokenize str[1..], line: line, column: column, untilBalanced: on
  • Skip the trailing }.

          index += 1
  • Turn the leading and trailing { and } into parentheses. Unnecessary parentheses will be removed later.

          [open, ..., close] = nested
          open[0]  = open[1]  = '('
          close[0] = close[1] = ')'
          close.origin = ['', 'end of interpolation', close[2]]
  • Remove leading ‘TERMINATOR’ (if any).

          nested.splice 1, 1 if nested[1]?[0] is 'TERMINATOR'
  • Push a fake ‘TOKENS’ token, which will get turned into real tokens later.

          tokens.push ['TOKENS', nested]
    
          str = str[index..]
          offsetInChunk += index
    
        unless str[...delimiter.length] is delimiter
          @error "missing #{delimiter}", length: delimiter.length
    
        [firstToken, ..., lastToken] = tokens
        firstToken[2].first_column -= delimiter.length
        if lastToken[1].substr(-1) is '\n'
          lastToken[2].last_line += 1
          lastToken[2].last_column = delimiter.length - 1
        else
          lastToken[2].last_column += delimiter.length
        lastToken[2].last_column -= 1 if lastToken[1].length is 0
    
        {tokens, index: offsetInChunk + delimiter.length}
  • Merge the array tokens of the fake token types ‘TOKENS’ and ‘NEOSTRING’ (as returned by matchWithInterpolations) into the token stream. The value of ‘NEOSTRING’s are converted using fn and turned into strings using options first.

      mergeInterpolationTokens: (tokens, options, fn) ->
        if tokens.length > 1
          lparen = @token 'STRING_START', '(', 0, 0
    
        firstIndex = @tokens.length
        for token, i in tokens
          [tag, value] = token
          switch tag
            when 'TOKENS'
  • Optimize out empty interpolations (an empty pair of parentheses).

              continue if value.length is 2
  • Push all the tokens in the fake ‘TOKENS’ token. These already have sane location data.

              locationToken = value[0]
              tokensToPush = value
            when 'NEOSTRING'
  • Convert ‘NEOSTRING’ into ‘STRING’.

              converted = fn.call this, token[1], i
  • Optimize out empty strings. We ensure that the tokens stream always starts with a string token, though, to make sure that the result really is a string.

              if converted.length is 0
                if i is 0
                  firstEmptyStringIndex = @tokens.length
                else
                  continue
  • However, there is one case where we can optimize away a starting empty string.

              if i is 2 and firstEmptyStringIndex?
                @tokens.splice firstEmptyStringIndex, 2 # Remove empty string and the plus.
              token[0] = 'STRING'
              token[1] = @makeDelimitedLiteral converted, options
              locationToken = token
              tokensToPush = [token]
          if @tokens.length > firstIndex
  • Create a 0-length “+” token.

            plusToken = @token '+', '+'
            plusToken[2] =
              first_line:   locationToken[2].first_line
              first_column: locationToken[2].first_column
              last_line:    locationToken[2].first_line
              last_column:  locationToken[2].first_column
          @tokens.push tokensToPush...
    
        if lparen
          [..., lastToken] = tokens
          lparen.origin = ['STRING', null,
            first_line:   lparen[2].first_line
            first_column: lparen[2].first_column
            last_line:    lastToken[2].last_line
            last_column:  lastToken[2].last_column
          ]
          rparen = @token 'STRING_END', ')'
          rparen[2] =
            first_line:   lastToken[2].last_line
            first_column: lastToken[2].last_column
            last_line:    lastToken[2].last_line
            last_column:  lastToken[2].last_column
  • Pairs up a closing token, ensuring that all listed pairs of tokens are correctly balanced throughout the course of the token stream.

      pair: (tag) ->
        [..., prev] = @ends
        unless tag is wanted = prev?.tag
          @error "unmatched #{tag}" unless 'OUTDENT' is wanted
  • Auto-close INDENT to support syntax like this:

    el.click((event) ->
      el.hide())
    
          [..., lastIndent] = @indents
          @outdentToken lastIndent, true
          return @pair tag
        @ends.pop()
  • Helpers

  • Returns the line and column number from an offset into the current chunk.

    offset is a number of characters into @chunk.

      getLineAndColumnFromChunk: (offset) ->
        if offset is 0
          return [@chunkLine, @chunkColumn]
    
        if offset >= @chunk.length
          string = @chunk
        else
          string = @chunk[..offset-1]
    
        lineCount = count string, '\n'
    
        column = @chunkColumn
        if lineCount > 0
          [..., lastLine] = string.split '\n'
          column = lastLine.length
        else
          column += string.length
    
        [@chunkLine + lineCount, column]
  • Same as “token”, exception this just returns the token without adding it to the results.

      makeToken: (tag, value, offsetInChunk = 0, length = value.length) ->
        locationData = {}
        [locationData.first_line, locationData.first_column] =
          @getLineAndColumnFromChunk offsetInChunk
  • Use length - 1 for the final offset - we’re supplying the last_line and the last_column, so if last_column == first_column, then we’re looking at a character of length 1.

        lastCharacter = if length > 0 then (length - 1) else 0
        [locationData.last_line, locationData.last_column] =
          @getLineAndColumnFromChunk offsetInChunk + lastCharacter
    
        token = [tag, value, locationData]
    
        token
  • Add a token to the results. offset is the offset into the current @chunk where the token starts. length is the length of the token in the @chunk, after the offset. If not specified, the length of value will be used.

    Returns the new token.

      token: (tag, value, offsetInChunk, length, origin) ->
        token = @makeToken tag, value, offsetInChunk, length
        token.origin = origin if origin
        @tokens.push token
        token
  • Peek at the last tag in the token stream.

      tag: ->
        [..., token] = @tokens
        token?[0]
  • Peek at the last value in the token stream.

      value: ->
        [..., token] = @tokens
        token?[1]
  • Are we in the midst of an unfinished expression?

      unfinished: ->
        LINE_CONTINUER.test(@chunk) or
        @tag() in UNFINISHED
    
      formatString: (str, options) ->
        @replaceUnicodeCodePointEscapes str.replace(STRING_OMIT, '$1'), options
    
      formatHeregex: (str) ->
        @formatRegex str.replace(HEREGEX_OMIT, '$1$2'), delimiter: '///'
    
      formatRegex: (str, options) ->
        @replaceUnicodeCodePointEscapes str, options
    
      unicodeCodePointToUnicodeEscapes: (codePoint) ->
        toUnicodeEscape = (val) ->
          str = val.toString 16
          "\\u#{repeat '0', 4 - str.length}#{str}"
        return toUnicodeEscape(codePoint) if codePoint < 0x10000
  • surrogate pair

        high = Math.floor((codePoint - 0x10000) / 0x400) + 0xD800
        low = (codePoint - 0x10000) % 0x400 + 0xDC00
        "#{toUnicodeEscape(high)}#{toUnicodeEscape(low)}"
  • Replace \u{…} with \uxxxx[\uxxxx] in strings and regexes

      replaceUnicodeCodePointEscapes: (str, options) ->
        str.replace UNICODE_CODE_POINT_ESCAPE, (match, escapedBackslash, codePointHex, offset) =>
          return escapedBackslash if escapedBackslash
    
          codePointDecimal = parseInt codePointHex, 16
          if codePointDecimal > 0x10ffff
            @error "unicode code point escapes greater than \\u{10ffff} are not allowed",
              offset: offset + options.delimiter.length
              length: codePointHex.length + 4
    
          @unicodeCodePointToUnicodeEscapes codePointDecimal
  • Validates escapes in strings and regexes.

      validateEscapes: (str, options = {}) ->
        invalidEscapeRegex =
          if options.isRegex
            REGEX_INVALID_ESCAPE
          else
            STRING_INVALID_ESCAPE
        match = invalidEscapeRegex.exec str
        return unless match
        [[], before, octal, hex, unicodeCodePoint, unicode] = match
        message =
          if octal
            "octal escape sequences are not allowed"
          else
            "invalid escape sequence"
        invalidEscape = "\\#{octal or hex or unicodeCodePoint or unicode}"
        @error "#{message} #{invalidEscape}",
          offset: (options.offsetInChunk ? 0) + match.index + before.length
          length: invalidEscape.length
  • Constructs a string or regex by escaping certain characters.

      makeDelimitedLiteral: (body, options = {}) ->
        body = '(?:)' if body is '' and options.delimiter is '/'
        regex = ///
            (\\\\)                               # escaped backslash
          | (\\0(?=[1-7]))                       # nul character mistaken as octal escape
          | \\?(#{options.delimiter})            # (possibly escaped) delimiter
          | \\?(?: (\n)|(\r)|(\u2028)|(\u2029) ) # (possibly escaped) newlines
          | (\\.)                                # other escapes
        ///g
        body = body.replace regex, (match, backslash, nul, delimiter, lf, cr, ls, ps, other) -> switch
  • Ignore escaped backslashes.

          when backslash then (if options.double then backslash + backslash else backslash)
          when nul       then '\\x00'
          when delimiter then "\\#{delimiter}"
          when lf        then '\\n'
          when cr        then '\\r'
          when ls        then '\\u2028'
          when ps        then '\\u2029'
          when other     then (if options.double then "\\#{other}" else other)
        "#{options.delimiter}#{body}#{options.delimiter}"
  • Throws an error at either a given offset from the current chunk or at the location of a token (token[2]).

      error: (message, options = {}) ->
        location =
          if 'first_line' of options
            options
          else
            [first_line, first_column] = @getLineAndColumnFromChunk options.offset ? 0
            {first_line, first_column, last_column: first_column + (options.length ? 1) - 1}
        throwSyntaxError message, location
  • Helper functions

  • 
    isUnassignable = (name, displayName = name) -> switch
      when name in [JS_KEYWORDS..., COFFEE_KEYWORDS...]
        "keyword '#{displayName}' can't be assigned"
      when name in STRICT_PROSCRIBED
        "'#{displayName}' can't be assigned"
      when name in RESERVED
        "reserved word '#{displayName}' can't be assigned"
      else
        false
    
    exports.isUnassignable = isUnassignable
  • from isn’t a CoffeeScript keyword, but it behaves like one in import and export statements (handled above) and in the declaration line of a for loop. Try to detect when from is a variable identifier and when it is this “sometimes” keyword.

    isForFrom = (prev) ->
      if prev[0] is 'IDENTIFIER'
  • for i from from, for from from iterable

        if prev[1] is 'from'
          prev[1][0] = 'IDENTIFIER'
          yes
  • for i from iterable

        yes
  • for from…

      else if prev[0] is 'FOR'
        no
  • for {from}…, for [from]…, for {a, from}…, for {a: from}…

      else if prev[1] in ['{', '[', ',', ':']
        no
      else
        yes
  • 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', 'yield'
      'if', 'else', 'switch', 'for', 'while', 'do', 'try', 'catch', 'finally'
      'class', 'extends', 'super'
      'import', 'export', 'default'
    ]
  • CoffeeScript-only keywords.

    COFFEE_KEYWORDS = [
      'undefined', 'Infinity', 'NaN'
      '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', 'function', 'var', 'void', 'with', 'const', 'let', 'enum'
      'native', 'implements', 'interface', 'package', 'private'
      'protected', 'public', 'static'
    ]
    
    STRICT_PROSCRIBED = ['arguments', 'eval']
  • The superset of both JavaScript keywords and reserved words, none of which may be used as identifiers or properties.

    exports.JS_FORBIDDEN = JS_KEYWORDS.concat(RESERVED).concat(STRICT_PROSCRIBED)
  • The character code of the nasty Microsoft madness otherwise known as the BOM.

    BOM = 65279
  • Token matching regexes.

    IDENTIFIER = /// ^
      (?!\d)
      ( (?: (?!\s)[$\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
    
    OPERATOR   = /// ^ (
      ?: [-=]>             # function
       | [-+*/%<>&|^!?=]=  # compound assign / compare
       | >>>=?             # zero-fill right shift
       | ([-+:])\1         # doubles
       | ([&|<>*/%])\2=?   # logic / shift / power / floor division / modulo
       | \?(\.|::)         # soak access
       | \.{2,3}           # range or splat
    ) ///
    
    WHITESPACE = /^[^\n\S]+/
    
    COMMENT    = /^###([^#][\s\S]*?)(?:###[^\n\S]*|###$)|^(?:\s*#(?!##[^#]).*)+/
    
    CODE       = /^[-=]>/
    
    MULTI_DENT = /^(?:\n[^\n\S]*)+/
    
    JSTOKEN      = ///^ `(?!``) ((?: [^`\\] | \\[\s\S]           )*) `   ///
    HERE_JSTOKEN = ///^ ```     ((?: [^`\\] | \\[\s\S] | `(?!``) )*) ``` ///
  • String-matching-regexes.

    STRING_START   = /^(?:'''|"""|'|")/
    
    STRING_SINGLE  = /// ^(?: [^\\']  | \\[\s\S]                      )* ///
    STRING_DOUBLE  = /// ^(?: [^\\"#] | \\[\s\S] |           \#(?!\{) )* ///
    HEREDOC_SINGLE = /// ^(?: [^\\']  | \\[\s\S] | '(?!'')            )* ///
    HEREDOC_DOUBLE = /// ^(?: [^\\"#] | \\[\s\S] | "(?!"") | \#(?!\{) )* ///
    
    STRING_OMIT    = ///
        ((?:\\\\)+)      # consume (and preserve) an even number of backslashes
      | \\[^\S\n]*\n\s*  # remove escaped newlines
    ///g
    SIMPLE_STRING_OMIT = /\s*\n\s*/g
    HEREDOC_INDENT     = /\n+([^\n\S]*)(?=\S)/g
  • Regex-matching-regexes.

    REGEX = /// ^
      / (?!/) ((
      ?: [^ [ / \n \\ ]  # every other thing
       | \\[^\n]         # anything but newlines escaped
       | \[              # character class
           (?: \\[^\n] | [^ \] \n \\ ] )*
         \]
      )*) (/)?
    ///
    
    REGEX_FLAGS  = /^\w*/
    VALID_FLAGS  = /^(?!.*(.).*\1)[imguy]*$/
    
    HEREGEX      = /// ^(?: [^\\/#] | \\[\s\S] | /(?!//) | \#(?!\{) )* ///
    
    HEREGEX_OMIT = ///
        ((?:\\\\)+)     # consume (and preserve) an even number of backslashes
      | \\(\s)          # preserve escaped whitespace
      | \s+(?:#.*)?     # remove whitespace and comments
    ///g
    
    REGEX_ILLEGAL = /// ^ ( / | /{3}\s*) (\*) ///
    
    POSSIBLY_DIVISION   = /// ^ /=?\s ///
  • Other regexes.

    HERECOMMENT_ILLEGAL = /\*\//
    
    LINE_CONTINUER      = /// ^ \s* (?: , | \??\.(?![.\d]) | :: ) ///
    
    STRING_INVALID_ESCAPE = ///
      ( (?:^|[^\\]) (?:\\\\)* )        # make sure the escape isn’t escaped
      \\ (
         ?: (0[0-7]|[1-7])             # octal escape
          | (x(?![\da-fA-F]{2}).{0,2}) # hex escape
          | (u\{(?![\da-fA-F]{1,}\})[^}]*\}?) # unicode code point escape
          | (u(?!\{|[\da-fA-F]{4}).{0,4}) # unicode escape
      )
    ///
    REGEX_INVALID_ESCAPE = ///
      ( (?:^|[^\\]) (?:\\\\)* )        # make sure the escape isn’t escaped
      \\ (
         ?: (0[0-7])                   # octal escape
          | (x(?![\da-fA-F]{2}).{0,2}) # hex escape
          | (u\{(?![\da-fA-F]{1,}\})[^}]*\}?) # unicode code point escape
          | (u(?!\{|[\da-fA-F]{4}).{0,4}) # unicode escape
      )
    ///
    
    UNICODE_CODE_POINT_ESCAPE = ///
      ( \\\\ )        # make sure the escape isn’t escaped
      |
      \\u\{ ( [\da-fA-F]+ ) \}
    ///g
    
    LEADING_BLANK_LINE  = /^[^\n\S]*\n/
    TRAILING_BLANK_LINE = /\n[^\n\S]*$/
    
    TRAILING_SPACES     = /\s+$/
  • Compound assignment tokens.

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

    UNARY = ['NEW', 'TYPEOF', 'DELETE', 'DO']
    
    UNARY_MATH = ['!', '~']
  • 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 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', 'PROPERTY', ')', ']', '?', '@', 'THIS', 'SUPER']
    INDEXABLE = CALLABLE.concat [
      'NUMBER', 'INFINITY', 'NAN', 'STRING', 'STRING_END', 'REGEX', 'REGEX_END'
      'BOOL', 'NULL', 'UNDEFINED', '}', '::'
    ]
  • Tokens which a regular expression will never immediately follow (except spaced CALLABLEs in some cases), but which a division operator can.

    See: http://www-archive.mozilla.org/js/language/js20-2002-04/rationale/syntax.html#regular-expressions

    NOT_REGEX = INDEXABLE.concat ['++', '--']
  • 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']
  • Additional indent in front of these is ignored.

    INDENTABLE_CLOSERS = [')', '}', ']']
  • Tokens that, when appearing at the end of a line, suppress a following TERMINATOR/INDENT token

    UNFINISHED = ['\\', '.', '?.', '?::', 'UNARY', 'MATH', 'UNARY_MATH', '+', '-',
               '**', 'SHIFT', 'RELATION', 'COMPARE', '&', '^', '|', '&&', '||',
               'BIN?', 'THROW', 'EXTENDS', 'DEFAULT']
coffeescript-1.12.7/docs/v1/annotated-source/nodes.html000066400000000000000000010754131313305734200230210ustar00rootroot00000000000000 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.

    Error.stackTraceLimit = Infinity
    
    {Scope} = require './scope'
    {isUnassignable, JS_FORBIDDEN} = require './lexer'
  • Import the helpers we plan to use.

    {compact, flatten, extend, merge, del, starts, ends, some,
    addLocationDataFn, locationDataToString, throwSyntaxError} = require './helpers'
  • Functions required by parser

    exports.extend = extend
    exports.addLocationDataFn = addLocationDataFn
  • Constant functions for nodes that don’t need customization.

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

  • The various nodes defined below all compile to a collection of CodeFragment objects. A CodeFragments is a block of generated code, and the location in the source file where the code came from. CodeFragments can be assembled together into working code just by catting together all the CodeFragments’ code snippets, in order.

    exports.CodeFragment = class CodeFragment
      constructor: (parent, code) ->
        @code = "#{code}"
        @locationData = parent?.locationData
        @type = parent?.constructor?.name or 'unknown'
    
      toString:   ->
        "#{@code}#{if @locationData then ": " + locationDataToString(@locationData) else ''}"
  • Convert an array of CodeFragments into a string.

    fragmentsToText = (fragments) ->
      (fragment.code for fragment in fragments).join('')
  • 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
    
      compile: (o, lvl) ->
        fragmentsToText @compileToFragments o, lvl
  • 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).

      compileToFragments: (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 jumpNode = @jumps()
          jumpNode.error 'cannot use a pure statement in an expression'
        o.sharedScope = yes
        func = new Code [], Block.wrap [this]
        args = []
        if (argumentsNode = @contains isLiteralArguments) or @contains isLiteralThis
          args = [new ThisLiteral]
          if argumentsNode
            meth = 'apply'
            args.push new IdentifierLiteral 'arguments'
          else
            meth = 'call'
          func = new Value func, [new Access new PropertyName meth]
        parts = (new Call func, args).compileNode o
        if func.isGenerator or func.base?.isGenerator
          parts.unshift @makeCode "(yield* "
          parts.push    @makeCode ")"
        parts
  • 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.

    If level is passed, then returns [val, ref], where val is the compiled value, and ref is the compiled reference. If level is not passed, this returns [val, ref] where the two values are raw nodes which have not been compiled.

      cache: (o, level, isComplex) ->
        complex = if isComplex? then isComplex this else @isComplex()
        if complex
          ref = new IdentifierLiteral o.scope.freeVariable 'ref'
          sub = new Assign ref, this
          if level then [sub.compileToFragments(o, level), [@makeCode(ref.value)]] else [sub, ref]
        else
          ref = if level then @compileToFragments o, level else this
          [ref, ref]
    
      cacheToCodeFragments: (cacheValues) ->
        [fragmentsToText(cacheValues[0]), fragmentsToText(cacheValues[1])]
  • 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 nodes and returns the first one that verifies pred. Otherwise return undefined. contains does not cross scope boundaries.

      contains: (pred) ->
        node = undefined
        @traverseChildren no, (n) ->
          if pred n
            node = n
            return no
        node
  • 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) ->
          recur = func(child)
          child.traverseChildren(crossScope, func) unless recur is no
    
      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
      isNumber        : NO
    
      unwrap     : THIS
      unfoldSoak : NO
  • Is this node used to assign a certain variable?

      assigns: NO
  • For this node and all descendents, set the location data to locationData if the location data is not already set.

      updateLocationDataIfMissing: (locationData) ->
        return this if @locationData
        @locationData = locationData
    
        @eachChild (child) ->
          child.updateLocationDataIfMissing locationData
  • Throw a SyntaxError associated with this node’s location.

      error: (message) ->
        throwSyntaxError message, @locationData
    
      makeCode: (code) ->
        new CodeFragment this, code
    
      wrapInBraces: (fragments) ->
        [].concat @makeCode('('), fragments, @makeCode(')')
  • fragmentsList is an array of arrays of fragments. Each array in fragmentsList will be concatonated together, with joinStr added in between each, to produce a final flat array of fragments.

      joinFragmentArrays: (fragmentsList, joinStr) ->
        answer = []
        for fragments,i in fragmentsList
          if i then answer.push @makeCode joinStr
          answer = answer.concat fragments
        answer
  • 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 jumpNode if jumpNode = 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.

      compileToFragments: (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
        compiledNodes = []
    
        for node, index 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

            compiledNodes.push node.compileNode o
          else if top
            node.front = true
            fragments = node.compileToFragments o
            unless node.isStatement o
              fragments.unshift @makeCode "#{@tab}"
              fragments.push @makeCode ";"
            compiledNodes.push fragments
          else
            compiledNodes.push node.compileToFragments o, LEVEL_LIST
        if top
          if @spaced
            return [].concat @joinFragmentArrays(compiledNodes, '\n\n'), @makeCode("\n")
          else
            return @joinFragmentArrays(compiledNodes, '\n')
        if compiledNodes.length
          answer = @joinFragmentArrays(compiledNodes, ', ')
        else
          answer = [@makeCode "void 0"]
        if compiledNodes.length > 1 and o.level >= LEVEL_LIST then @wrapInBraces answer else answer
  • 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.level   = LEVEL_TOP
        @spaced   = yes
        o.scope   = new Scope null, this, null, o.referencedVars ? []
  • Mark given local variables in the root scope as parameters so they don’t end up being declared on this block.

        o.scope.parameter name for name in o.locals or []
        prelude   = []
        unless o.bare
          preludeExps = for exp, i in @expressions
            break unless exp.unwrap() instanceof Comment
            exp
          rest = @expressions[preludeExps.length...]
          @expressions = preludeExps
          if preludeExps.length
            prelude = @compileNode merge(o, indent: '')
            prelude.push @makeCode "\n"
          @expressions = rest
        fragments = @compileWithDeclarations o
        return fragments if o.bare
        [].concat prelude, @makeCode("(function() {\n"), fragments, @makeCode("\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) ->
        fragments = []
        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]
          [fragments, @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
            fragments.push @makeCode '\n' if i
            fragments.push @makeCode "#{@tab}var "
            if declars
              fragments.push @makeCode scope.declaredVariables().join(', ')
            if assigns
              fragments.push @makeCode ",\n#{@tab + TAB}" if declars
              fragments.push @makeCode scope.assignedVariables().join(",\n#{@tab + TAB}")
            fragments.push @makeCode ";\n#{if @spaced then '\n' else ''}"
          else if fragments.length and post.length
            fragments.push @makeCode "\n"
        fragments.concat 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

  • Literal is a base class for 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) ->
    
      isComplex: NO
    
      assigns: (name) ->
        name is @value
    
      compileNode: (o) ->
        [@makeCode @value]
    
      toString: ->
        " #{if @isStatement() then super else @constructor.name}: #{@value}"
    
    exports.NumberLiteral = class NumberLiteral extends Literal
    
    exports.InfinityLiteral = class InfinityLiteral extends NumberLiteral
      compileNode: ->
        [@makeCode '2e308']
    
    exports.NaNLiteral = class NaNLiteral extends NumberLiteral
      constructor: ->
        super 'NaN'
    
      compileNode: (o) ->
        code = [@makeCode '0/0']
        if o.level >= LEVEL_OP then @wrapInBraces code else code
    
    exports.StringLiteral = class StringLiteral extends Literal
    
    exports.RegexLiteral = class RegexLiteral extends Literal
    
    exports.PassthroughLiteral = class PassthroughLiteral extends Literal
    
    exports.IdentifierLiteral = class IdentifierLiteral extends Literal
      isAssignable: YES
    
    exports.PropertyName = class PropertyName extends Literal
      isAssignable: YES
    
    exports.StatementLiteral = class StatementLiteral extends Literal
      isStatement: YES
    
      makeReturn: THIS
    
      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) ->
        [@makeCode "#{@tab}#{@value};"]
    
    exports.ThisLiteral = class ThisLiteral extends Literal
      constructor: ->
        super 'this'
    
      compileNode: (o) ->
        code = if o.scope.method?.bound then o.scope.method.context else @value
        [@makeCode code]
    
    exports.UndefinedLiteral = class UndefinedLiteral extends Literal
      constructor: ->
        super 'undefined'
    
      compileNode: (o) ->
        [@makeCode if o.level >= LEVEL_ACCESS then '(void 0)' else 'void 0']
    
    exports.NullLiteral = class NullLiteral extends Literal
      constructor: ->
        super 'null'
    
    exports.BooleanLiteral = class BooleanLiteral extends Literal
  • Return

  • A return is a pureStatement – wrapping it in a closure wouldn’t make sense.

    exports.Return = class Return extends Base
      constructor: (@expression) ->
    
      children: ['expression']
    
      isStatement:     YES
      makeReturn:      THIS
      jumps:           THIS
    
      compileToFragments: (o, level) ->
        expr = @expression?.makeReturn()
        if expr and expr not instanceof Return then expr.compileToFragments o, level else super o, level
    
      compileNode: (o) ->
        answer = []
  • TODO: If we call expression.compile() here twice, we’ll sometimes get back different results!

        answer.push @makeCode @tab + "return#{if @expression then " " else ""}"
        if @expression
          answer = answer.concat @expression.compileToFragments o, LEVEL_PAREN
        answer.push @makeCode ";"
        return answer
  • yield return works exactly like return, except that it turns the function into a generator.

    exports.YieldReturn = class YieldReturn extends Return
      compileNode: (o) ->
        unless o.scope.parent?
          @error 'yield can only occur inside functions'
        super
  • 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
    
      bareLiteral: (type) ->
        not @properties.length and @base instanceof type
  • Some boolean checks for the benefit of other nodes.

      isArray        : -> @bareLiteral(Arr)
      isRange        : -> @bareLiteral(Range)
      isComplex      : -> @hasProperties() or @base.isComplex()
      isAssignable   : -> @hasProperties() or @base.isAssignable()
      isNumber       : -> @bareLiteral(NumberLiteral)
      isString       : -> @bareLiteral(StringLiteral)
      isRegex        : -> @bareLiteral(RegexLiteral)
      isUndefined    : -> @bareLiteral(UndefinedLiteral)
      isNull         : -> @bareLiteral(NullLiteral)
      isBoolean      : -> @bareLiteral(BooleanLiteral)
      isAtomic       : ->
        for node in @properties.concat @base
          return no if node.soak or node instanceof Call
        yes
    
      isNotCallable  : -> @isNumber() or @isString() or @isRegex() or
                          @isArray() or @isRange() or @isSplice() or @isObject() or
                          @isUndefined() or @isNull() or @isBoolean()
    
      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: ->
        [..., lastProp] = @properties
        lastProp instanceof Slice
    
      looksStatic: (className) ->
        @base.value is className and @properties.length is 1 and
          @properties[0].name?.value isnt 'prototype'
  • 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] = @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 IdentifierLiteral 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 IdentifierLiteral 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
        fragments = @base.compileToFragments o, (if props.length then LEVEL_ACCESS else null)
        if props.length and SIMPLENUM.test fragmentsToText fragments
          fragments.push @makeCode '.'
        for prop in props
          fragments.push (prop.compileToFragments o)...
        fragments
  • Unfold a soak into an If: a?.b -> a.b if a?

      unfoldSoak: (o) ->
        @unfoldedSoak ?= do =>
          if ifn = @base.unfoldSoak o
            ifn.body.properties.push @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 IdentifierLiteral o.scope.freeVariable 'ref'
              fst = new Parens new Assign ref, fst
              snd.base = ref
            return new If new Existence(fst), snd, soak: on
          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) ->
        comment = @comment.replace /^(\s*)#(?=\s)/gm, "$1 *"
        code = "/*#{multident comment, @tab}#{if '\n' in comment then "\n#{@tab}" else ''} */"
        code = o.indent + code if (level or o.level) is LEVEL_TOP
        [@makeCode("\n"), @makeCode(code)]
  • Call

  • Node for a function invocation.

    exports.Call = class Call extends Base
      constructor: (@variable, @args = [], @soak) ->
        @isNew    = false
        if @variable instanceof Value and @variable.isNotCallable()
          @variable.error "literal is not a function"
    
      children: ['variable', 'args']
  • When setting the location, we sometimes need to update the start location to account for a newly-discovered new operator to the left of us. This expands the range on the left, but not the right.

      updateLocationDataIfMissing: (locationData) ->
        if @locationData and @needsUpdatedStartLocation
          @locationData.first_line = locationData.first_line
          @locationData.first_column = locationData.first_column
          base = @variable?.base or @variable
          if base.needsUpdatedStartLocation
            @variable.locationData.first_line = locationData.first_line
            @variable.locationData.first_column = locationData.first_column
            base.updateLocationDataIfMissing locationData
          delete @needsUpdatedStartLocation
        super
  • 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
        @needsUpdatedStartLocation = true
        this
  • Soaked chained invocations unfold into if/else ternary structures.

      unfoldSoak: (o) ->
        if @soak
          if this instanceof SuperCall
            left = new Literal @superReference o
            rite = new Value left
          else
            return ifn if ifn = unfoldSoak o, this, 'variable'
            [left, rite] = new Value(@variable).cacheReference o
          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
  • Compile a vanilla function call.

      compileNode: (o) ->
        @variable?.front = @front
        compiledArray = Splat.compileSplattedArray o, @args, true
        if compiledArray.length
          return @compileSplat o, compiledArray
        compiledArgs = []
        for arg, argIndex in @args
          if argIndex then compiledArgs.push @makeCode ", "
          compiledArgs.push (arg.compileToFragments o, LEVEL_LIST)...
    
        fragments = []
        if this instanceof SuperCall
          preface = @superReference(o) + ".call(#{@superThis(o)}"
          if compiledArgs.length then preface += ", "
          fragments.push @makeCode preface
        else
          if @isNew then fragments.push @makeCode 'new '
          fragments.push @variable.compileToFragments(o, LEVEL_ACCESS)...
          fragments.push @makeCode "("
        fragments.push compiledArgs...
        fragments.push @makeCode ")"
        fragments
  • 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.

    splatArgs is an array of CodeFragments to put into the ‘apply’.

      compileSplat: (o, splatArgs) ->
        if this instanceof SuperCall
          return [].concat @makeCode("#{ @superReference o }.apply(#{@superThis(o)}, "),
            splatArgs, @makeCode(")")
    
        if @isNew
          idt = @tab + TAB
          return [].concat @makeCode("""
            (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.compileToFragments o, LEVEL_LIST),
            @makeCode(", "), splatArgs, @makeCode(", function(){})")
    
        answer = []
        base = new Value @variable
        if (name = base.properties.pop()) and base.isComplex()
          ref = o.scope.freeVariable 'ref'
          answer = answer.concat @makeCode("(#{ref} = "),
            (base.compileToFragments o, LEVEL_LIST),
            @makeCode(")"),
            name.compileToFragments(o)
        else
          fun = base.compileToFragments o, LEVEL_ACCESS
          fun = @wrapInBraces fun if SIMPLENUM.test fragmentsToText fun
          if name
            ref = fragmentsToText fun
            fun.push (name.compileToFragments o)...
          else
            ref = 'null'
          answer = answer.concat fun
        answer = answer.concat @makeCode(".apply(#{ref}, "), splatArgs, @makeCode(")")
  • Super

  • Takes care of converting super() calls into calls against the prototype’s function of the same name.

    exports.SuperCall = class SuperCall extends Call
      constructor: (args) ->
        super null, args ? [new Splat new IdentifierLiteral 'arguments']
  • Allow to recognize a bare super call without parentheses and arguments.

        @isBare = args?
  • Grab the reference to the superclass’s implementation of the current method.

      superReference: (o) ->
        method = o.scope.namedMethod()
        if method?.klass
          {klass, name, variable} = method
          if klass.isComplex()
            bref = new IdentifierLiteral o.scope.parent.freeVariable 'base'
            base = new Value new Parens new Assign bref, klass
            variable.base = base
            variable.properties.splice 0, klass.properties.length
          if name.isComplex() or (name instanceof Index and name.index.isAssignable())
            nref = new IdentifierLiteral o.scope.parent.freeVariable 'name'
            name = new Index new Assign nref, name.index
            variable.properties.pop()
            variable.properties.push name
          accesses = [new Access new PropertyName '__super__']
          accesses.push new Access new PropertyName 'constructor' if method.static
          accesses.push if nref? then new Index nref else name
          (new Value bref ? klass, accesses).compile o
        else if method?.ctor
          "#{method.name}.__super__.constructor"
        else
          @error 'cannot call super outside of an instance method.'
  • The appropriate this value for a super call.

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

  • Regexes with interpolations are in fact just a variation of a Call (a RegExp() call to be precise) with a StringWithInterpolations inside.

    exports.RegexWithInterpolations = class RegexWithInterpolations extends Call
      constructor: (args = []) ->
        super (new Value new IdentifierLiteral 'RegExp'), args, false
  • TaggedTemplateCall

    exports.TaggedTemplateCall = class TaggedTemplateCall extends Call
      constructor: (variable, arg, soak) ->
        arg = new StringWithInterpolations Block.wrap([ new Value arg ]) if arg instanceof StringLiteral
        super variable, [ arg ], soak
    
      compileNode: (o) ->
  • Tell StringWithInterpolations whether to compile as ES2015 or not; will be removed in CoffeeScript 2.

        o.inTaggedTemplateCall = yes
        @variable.compileToFragments(o, LEVEL_ACCESS).concat @args[0].compileToFragments(o, LEVEL_LIST)
  • 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.

      compileToFragments: (o) ->
        new Call(new Value(new Literal utility 'extend', o), [@child, @parent]).compileToFragments 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) ->
        @soak  = tag is 'soak'
    
      children: ['name']
    
      compileToFragments: (o) ->
        name = @name.compileToFragments o
        node = @name.unwrap()
        if node instanceof PropertyName
          if node.value in JS_FORBIDDEN
            [@makeCode('["'), name..., @makeCode('"]')]
          else
            [@makeCode('.'), name...]
        else
          [@makeCode('['), name..., @makeCode(']')]
    
      isComplex: NO
  • Index

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

    exports.Index = class Index extends Base
      constructor: (@index) ->
    
      children: ['index']
    
      compileToFragments: (o) ->
        [].concat @makeCode("["), @index.compileToFragments(o, LEVEL_PAREN), @makeCode("]")
    
      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
        isComplex = del o, 'isComplex'
        [@fromC, @fromVar]  =  @cacheToCodeFragments @from.cache o, LEVEL_LIST, isComplex
        [@toC, @toVar]      =  @cacheToCodeFragments @to.cache o, LEVEL_LIST, isComplex
        [@step, @stepVar]   =  @cacheToCodeFragments step.cache o, LEVEL_LIST, isComplex if step = del o, 'step'
        @fromNum = if @from.isNumber() then Number @fromVar else null
        @toNum   = if @to.isNumber()   then Number @toVar   else null
        @stepNum = if step?.isNumber() then Number @stepVar else null
  • 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 = if @stepVar then "#{@stepVar} > 0" else "#{@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.

        [@makeCode "#{varPart}; #{condPart}; #{stepPart}"]
  • When used as a value, expand the range into the equivalent array.

      compileArray: (o) ->
        known = @fromNum? and @toNum?
        if known and Math.abs(@fromNum - @toNum) <= 20
          range = [@fromNum..@toNum]
          range.pop() if @exclusive
          return [@makeCode "[#{ range.join(', ') }]"]
        idt    = @tab + TAB
        i      = o.scope.freeVariable 'i', single: true
        result = o.scope.freeVariable 'results'
        pre    = "\n#{idt}#{result} = [];"
        if known
          o.index = i
          body    = fragmentsToText @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 isLiteralArguments
        args   = ', arguments' if hasArgs(@from) or hasArgs(@to)
        [@makeCode "(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
        fromCompiled = from and from.compileToFragments(o, LEVEL_PAREN) or [@makeCode '0']
  • TODO: jwalton - move this into the ‘if’?

        if to
          compiled     = to.compileToFragments o, LEVEL_PAREN
          compiledText = fragmentsToText compiled
          if not (not @range.exclusive and +compiledText is -1)
            toStr = ', ' + if @range.exclusive
              compiledText
            else if to.isNumber()
              "#{+compiledText + 1}"
            else
              compiled = to.compileToFragments o, LEVEL_ACCESS
              "+#{fragmentsToText compiled} + 1 || 9e9"
        [@makeCode ".slice(#{ fragmentsToText fromCompiled }#{ 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
        if @generated
          for node in props when node instanceof Value
            node.error 'cannot have an implicit value in an implicit object'
        break for prop, dynamicIndex in props when (prop.variable or prop).base instanceof Parens
        hasDynamic  = dynamicIndex < props.length
        idt         = o.indent += TAB
        lastNoncom  = @lastNonComment @properties
        answer = []
        if hasDynamic
          oref = o.scope.freeVariable 'obj'
          answer.push @makeCode "(\n#{idt}#{oref} = "
        answer.push @makeCode "{#{if props.length is 0 or dynamicIndex is 0 then '}' else '\n'}"
        for prop, i in props
          if i is dynamicIndex
            answer.push @makeCode "\n#{idt}}" unless i is 0
            answer.push @makeCode ',\n'
          join = if i is props.length - 1 or i is dynamicIndex - 1
            ''
          else if prop is lastNoncom or prop instanceof Comment
            '\n'
          else
            ',\n'
          indent = if prop instanceof Comment then '' else idt
          indent += TAB if hasDynamic and i < dynamicIndex
          if prop instanceof Assign
            if prop.context isnt 'object'
              prop.operatorToken.error "unexpected #{prop.operatorToken.value}"
            if prop.variable instanceof Value and prop.variable.hasProperties()
              prop.variable.error 'invalid object key'
          if prop instanceof Value and prop.this
            prop = new Assign prop.properties[0].name, prop, 'object'
          if prop not instanceof Comment
            if i < dynamicIndex
              if prop not instanceof Assign
                prop = new Assign prop, prop, 'object'
            else
              if prop instanceof Assign
                key = prop.variable
                value = prop.value
              else
                [key, value] = prop.base.cache o
                key = new PropertyName key.value if key instanceof IdentifierLiteral
              prop = new Assign (new Value (new IdentifierLiteral oref), [new Access key]), value
          if indent then answer.push @makeCode indent
          answer.push prop.compileToFragments(o, LEVEL_TOP)...
          if join then answer.push @makeCode join
        if hasDynamic
          answer.push @makeCode ",\n#{idt}#{oref}\n#{@tab})"
        else
          answer.push @makeCode "\n#{@tab}}" unless props.length is 0
        if @front and not hasDynamic then @wrapInBraces answer else answer
    
      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']
    
      compileNode: (o) ->
        return [@makeCode '[]'] unless @objects.length
        o.indent += TAB
        answer = Splat.compileSplattedArray o, @objects
        return answer if answer.length
    
        answer = []
        compiledObjs = (obj.compileToFragments o, LEVEL_LIST for obj in @objects)
        for fragments, index in compiledObjs
          if index
            answer.push @makeCode ", "
          answer.push fragments...
        if fragmentsToText(answer).indexOf('\n') >= 0
          answer.unshift @makeCode "[\n#{o.indent}"
          answer.push @makeCode "\n#{@tab}]"
        else
          answer.unshift @makeCode "["
          answer.push @makeCode "]"
        answer
    
      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']
    
      defaultClassVariableName: '_Class'
  • Figure out the appropriate name for the constructor function of this class.

      determineName: ->
        return @defaultClassVariableName unless @variable
        [..., tail] = @variable.properties
        node = if tail
          tail instanceof Access and tail.name
        else
          @variable.base
        unless node instanceof IdentifierLiteral or node instanceof PropertyName
          return @defaultClassVariableName
        name = node.value
        unless tail
          message = isUnassignable name
          @variable.error message if message
        if name in JS_FORBIDDEN then "_#{name}" else name
  • 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 ThisLiteral
            node.value    = name
          else if node instanceof Code
            node.context  = name if node.bound
  • Ensure that all functions bound to the instance are proxied in the constructor.

      addBoundFunctions: (o) ->
        for bvar in @boundFuncs
          lhs = (new Value (new ThisLiteral), [new Access bvar]).compile o
          @ctor.body.unshift new Literal "#{lhs} = #{utility 'bind', o}(#{lhs}, this)"
        return
  • 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
                assign.error 'cannot define more than one constructor in a class'
              if func.bound
                assign.error 'cannot define a constructor as a bound function'
              if func instanceof Code
                assign = @ctor = func
              else
                @externalCtor = o.classScope.freeVariable 'ctor'
                assign = new Assign new IdentifierLiteral(@externalCtor), func
            else
              if assign.variable.this
                func.static = yes
              else
                acc = if base.isComplex() then new Index base else new Access base
                assign.variable = new Value(new IdentifierLiteral(name), [(new Access new PropertyName 'prototype'), acc])
                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 and tagging static assignments.

      walkBody: (name, o) ->
        @traverseChildren false, (child) =>
          cont = true
          return false if child instanceof Class
          if child instanceof Block
            for node, i in exps = child.expressions
              if node instanceof Assign and node.variable.looksStatic name
                node.value.static = yes
              else if node instanceof Value and node.isObject(true)
                cont = false
                exps[i] = @addProperties node, name, o
            child.expressions = exps = flatten exps
          cont and child not instanceof Class
  • 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
          if @externalCtor
            @ctor.body.push new Literal "#{@externalCtor}.apply(this, arguments)"
          else if @parent
            @ctor.body.push new Literal "#{name}.__super__.constructor.apply(this, arguments)"
          @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) ->
        if jumpNode = @body.jumps()
          jumpNode.error 'Class bodies cannot contain pure statements'
        if argumentsNode = @body.contains isLiteralArguments
          argumentsNode.error "Class bodies shouldn't reference arguments"
    
        name  = @determineName()
        lname = new IdentifierLiteral name
        func  = new Code [], Block.wrap [@body]
        args  = []
        o.classScope = func.makeScope o.scope
    
        @hoistDirectivePrologue()
        @setContext name
        @walkBody name, o
        @ensureConstructor name
        @addBoundFunctions o
        @body.spaced = yes
        @body.expressions.push lname
    
        if @parent
          superClass = new IdentifierLiteral o.classScope.freeVariable 'superClass', reserve: no
          @body.expressions.unshift new Extends lname, superClass
          func.params.push new Param superClass
          args.push @parent
    
        @body.expressions.unshift @directives...
    
        klass = new Parens new Call func, args
        klass = new Assign @variable, klass, null, { @moduleDeclaration } if @variable
        klass.compileToFragments o
  • Import and Export

    exports.ModuleDeclaration = class ModuleDeclaration extends Base
      constructor: (@clause, @source) ->
        @checkSource()
    
      children: ['clause', 'source']
    
      isStatement: YES
      jumps:       THIS
      makeReturn:  THIS
    
      checkSource: ->
        if @source? and @source instanceof StringWithInterpolations
          @source.error 'the name of the module to be imported from must be an uninterpolated string'
    
      checkScope: (o, moduleDeclarationType) ->
        if o.indent.length isnt 0
          @error "#{moduleDeclarationType} statements must be at top-level scope"
    
    exports.ImportDeclaration = class ImportDeclaration extends ModuleDeclaration
      compileNode: (o) ->
        @checkScope o, 'import'
        o.importedSymbols = []
    
        code = []
        code.push @makeCode "#{@tab}import "
        code.push @clause.compileNode(o)... if @clause?
    
        if @source?.value?
          code.push @makeCode ' from ' unless @clause is null
          code.push @makeCode @source.value
    
        code.push @makeCode ';'
        code
    
    exports.ImportClause = class ImportClause extends Base
      constructor: (@defaultBinding, @namedImports) ->
    
      children: ['defaultBinding', 'namedImports']
    
      compileNode: (o) ->
        code = []
    
        if @defaultBinding?
          code.push @defaultBinding.compileNode(o)...
          code.push @makeCode ', ' if @namedImports?
    
        if @namedImports?
          code.push @namedImports.compileNode(o)...
    
        code
    
    exports.ExportDeclaration = class ExportDeclaration extends ModuleDeclaration
      compileNode: (o) ->
        @checkScope o, 'export'
    
        code = []
        code.push @makeCode "#{@tab}export "
        code.push @makeCode 'default ' if @ instanceof ExportDefaultDeclaration
    
        if @ not instanceof ExportDefaultDeclaration and
           (@clause instanceof Assign or @clause instanceof Class)
  • Prevent exporting an anonymous class; all exported members must be named

          if @clause instanceof Class and not @clause.variable
            @clause.error 'anonymous classes cannot be exported'
  • When the ES2015 class keyword is supported, don’t add a var here

          code.push @makeCode 'var '
          @clause.moduleDeclaration = 'export'
    
        if @clause.body? and @clause.body instanceof Block
          code = code.concat @clause.compileToFragments o, LEVEL_TOP
        else
          code = code.concat @clause.compileNode o
    
        code.push @makeCode " from #{@source.value}" if @source?.value?
        code.push @makeCode ';'
        code
    
    exports.ExportNamedDeclaration = class ExportNamedDeclaration extends ExportDeclaration
    
    exports.ExportDefaultDeclaration = class ExportDefaultDeclaration extends ExportDeclaration
    
    exports.ExportAllDeclaration = class ExportAllDeclaration extends ExportDeclaration
    
    exports.ModuleSpecifierList = class ModuleSpecifierList extends Base
      constructor: (@specifiers) ->
    
      children: ['specifiers']
    
      compileNode: (o) ->
        code = []
        o.indent += TAB
        compiledList = (specifier.compileToFragments o, LEVEL_LIST for specifier in @specifiers)
    
        if @specifiers.length isnt 0
          code.push @makeCode "{\n#{o.indent}"
          for fragments, index in compiledList
            code.push @makeCode(",\n#{o.indent}") if index
            code.push fragments...
          code.push @makeCode "\n}"
        else
          code.push @makeCode '{}'
        code
    
    exports.ImportSpecifierList = class ImportSpecifierList extends ModuleSpecifierList
    
    exports.ExportSpecifierList = class ExportSpecifierList extends ModuleSpecifierList
    
    exports.ModuleSpecifier = class ModuleSpecifier extends Base
      constructor: (@original, @alias, @moduleDeclarationType) ->
  • The name of the variable entering the local scope

        @identifier = if @alias? then @alias.value else @original.value
    
      children: ['original', 'alias']
    
      compileNode: (o) ->
        o.scope.find @identifier, @moduleDeclarationType
        code = []
        code.push @makeCode @original.value
        code.push @makeCode " as #{@alias.value}" if @alias?
        code
    
    exports.ImportSpecifier = class ImportSpecifier extends ModuleSpecifier
      constructor: (imported, local) ->
        super imported, local, 'import'
    
      compileNode: (o) ->
  • Per the spec, symbols can’t be imported multiple times (e.g. import { foo, foo } from 'lib' is invalid)

        if @identifier in o.importedSymbols or o.scope.check(@identifier)
          @error "'#{@identifier}' has already been declared"
        else
          o.importedSymbols.push @identifier
        super o
    
    exports.ImportDefaultSpecifier = class ImportDefaultSpecifier extends ImportSpecifier
    
    exports.ImportNamespaceSpecifier = class ImportNamespaceSpecifier extends ImportSpecifier
    
    exports.ExportSpecifier = class ExportSpecifier extends ModuleSpecifier
      constructor: (local, exported) ->
        super local, exported, 'export'
  • 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, @subpattern, @operatorToken, @moduleDeclaration} = options
    
      children: ['variable', 'value']
    
      isStatement: (o) ->
        o?.level is LEVEL_TOP and @context? and (@moduleDeclaration or "?" in @context)
    
      checkAssignability: (o, varBase) ->
        if Object::hasOwnProperty.call(o.scope.positions, varBase.value) and
           o.scope.variables[o.scope.positions[varBase.value]].type is 'import'
          varBase.error "'#{varBase.value}' is read-only"
    
      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 ['||=', '&&=', '?=']
          return @compileSpecialMath  o if @context in ['**=', '//=', '%%=']
        if @value instanceof Code
          if @value.static
            @value.klass = @variable.base
            @value.name  = @variable.properties[0]
            @value.variable = @variable
          else if @variable.properties?.length >= 2
            [properties..., prototype, name] = @variable.properties
            if prototype.name?.value is 'prototype'
              @value.klass = new Value @variable.base, properties
              @value.name  = name
              @value.variable = @variable
        unless @context
          varBase = @variable.unwrapAll()
          unless varBase.isAssignable()
            @variable.error "'#{@variable.compile o}' can't be assigned"
          unless varBase.hasProperties?()
  • moduleDeclaration can be 'import' or 'export'

            if @moduleDeclaration
              @checkAssignability o, varBase
              o.scope.add varBase.value, @moduleDeclaration
            else if @param
              o.scope.add varBase.value, 'var'
            else
              @checkAssignability o, varBase
              o.scope.find varBase.value
    
        val = @value.compileToFragments o, LEVEL_LIST
        @variable.front = true if isValue and @variable.base instanceof Obj
        compiledName = @variable.compileToFragments o, LEVEL_LIST
    
        if @context is 'object'
          if fragmentsToText(compiledName) in JS_FORBIDDEN
            compiledName.unshift @makeCode '"'
            compiledName.push @makeCode '"'
          return compiledName.concat @makeCode(": "), val
    
        answer = compiledName.concat @makeCode(" #{ @context or '=' } "), val
        if o.level <= LEVEL_LIST then answer else @wrapInBraces answer
  • Brief implementation of recursive pattern matching, when assigning array or object literals to a value. Peeks at their properties to assign inner names.

      compilePatternMatch: (o) ->
        top       = o.level is LEVEL_TOP
        {value}   = this
        {objects} = @variable.base
        unless olen = objects.length
          code = value.compileToFragments o
          return if o.level >= LEVEL_OP then @wrapInBraces code else code
        [obj] = objects
        if olen is 1 and obj instanceof Expansion
          obj.error 'Destructuring assignment has no target'
        isObject = @variable.isObject()
        if top and olen is 1 and obj not instanceof Splat
  • Pick the property straight off the value when there’s just one to pick (no need to cache the value into a variable).

          defaultValue = null
          if obj instanceof Assign and obj.context is 'object'
  • A regular object pattern-match.

            {variable: {base: idx}, value: obj} = obj
            if obj instanceof Assign
              defaultValue = obj.value
              obj = obj.variable
          else
            if obj instanceof Assign
              defaultValue = obj.value
              obj = obj.variable
            idx = if isObject
  • A shorthand {a, b, @c} = val pattern-match.

              if obj.this
                obj.properties[0].name
              else
                new PropertyName obj.unwrap().value
            else
  • A regular array pattern-match.

              new NumberLiteral 0
          acc   = idx.unwrap() instanceof PropertyName
          value = new Value value
          value.properties.push new (if acc then Access else Index) idx
          message = isUnassignable obj.unwrap().value
          obj.error message if message
          value = new Op '?', value, defaultValue if defaultValue
          return new Assign(obj, value, null, param: @param).compileToFragments o, LEVEL_TOP
        vvar     = value.compileToFragments o, LEVEL_LIST
        vvarText = fragmentsToText vvar
        assigns  = []
        expandedIdx = false
  • Make vvar into a simple variable if it isn’t already.

        if value.unwrap() not instanceof IdentifierLiteral or @variable.assigns(vvarText)
          assigns.push [@makeCode("#{ ref = o.scope.freeVariable 'ref' } = "), vvar...]
          vvar = [@makeCode ref]
          vvarText = ref
        for obj, i in objects
          idx = i
          if not expandedIdx and obj instanceof Splat
            name = obj.name.unwrap().value
            obj = obj.unwrap()
            val = "#{olen} <= #{vvarText}.length ? #{ utility 'slice', o }.call(#{vvarText}, #{i}"
            if rest = olen - i - 1
              ivar = o.scope.freeVariable 'i', single: true
              val += ", #{ivar} = #{vvarText}.length - #{rest}) : (#{ivar} = #{i}, [])"
            else
              val += ") : []"
            val   = new Literal val
            expandedIdx = "#{ivar}++"
          else if not expandedIdx and obj instanceof Expansion
            if rest = olen - i - 1
              if rest is 1
                expandedIdx = "#{vvarText}.length - 1"
              else
                ivar = o.scope.freeVariable 'i', single: true
                val = new Literal "#{ivar} = #{vvarText}.length - #{rest}"
                expandedIdx = "#{ivar}++"
                assigns.push val.compileToFragments o, LEVEL_LIST
            continue
          else
            if obj instanceof Splat or obj instanceof Expansion
              obj.error "multiple splats/expansions are disallowed in an assignment"
            defaultValue = null
            if obj instanceof Assign and obj.context is 'object'
  • A regular object pattern-match.

              {variable: {base: idx}, value: obj} = obj
              if obj instanceof Assign
                defaultValue = obj.value
                obj = obj.variable
            else
              if obj instanceof Assign
                defaultValue = obj.value
                obj = obj.variable
              idx = if isObject
  • A shorthand {a, b, @c} = val pattern-match.

                if obj.this
                  obj.properties[0].name
                else
                  new PropertyName obj.unwrap().value
              else
  • A regular array pattern-match.

                new Literal expandedIdx or idx
            name = obj.unwrap().value
            acc = idx.unwrap() instanceof PropertyName
            val = new Value new Literal(vvarText), [new (if acc then Access else Index) idx]
            val = new Op '?', val, defaultValue if defaultValue
          if name?
            message = isUnassignable name
            obj.error message if message
          assigns.push new Assign(obj, val, null, param: @param, subpattern: yes).compileToFragments o, LEVEL_LIST
        assigns.push vvar unless top or @subpattern
        fragments = @joinFragmentArrays assigns, ', '
        if o.level < LEVEL_LIST then fragments else @wrapInBraces fragments
  • 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 not instanceof ThisLiteral and not o.scope.check left.base.value
          @variable.error "the variable \"#{left.base.value}\" can't be assigned with #{@context} because it has not been declared before"
        if "?" in @context
          o.isExistentialEquals = true
          new If(new Existence(left), right, type: 'if').addElse(new Assign(right, @value, '=')).compileToFragments o
        else
          fragments = new Op(@context[...-1], left, new Assign(right, @value, '=')).compileToFragments o
          if o.level <= LEVEL_LIST then fragments else @wrapInBraces fragments
  • Convert special math assignment operators like a **= b to the equivalent extended form a = a ** b and then compiles that.

      compileSpecialMath: (o) ->
        [left, right] = @variable.cacheReference o
        new Assign(left, new Op(@context[...-1], right, @value)).compileToFragments 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
        if from
          [fromDecl, fromRef] = @cacheToCodeFragments from.cache o, LEVEL_OP
        else
          fromDecl = fromRef = '0'
        if to
          if from?.isNumber() and to.isNumber()
            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
        answer = [].concat @makeCode("[].splice.apply(#{name}, [#{fromDecl}, #{to}].concat("), valDef, @makeCode(")), "), valRef
        if o.level > LEVEL_TOP then @wrapInBraces answer else answer
  • 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'
        @isGenerator = !!@body.contains (node) ->
          (node instanceof Op and node.isYield()) or node instanceof YieldReturn
    
      children: ['params', 'body']
    
      isStatement: -> !!@ctor
    
      jumps: NO
    
      makeScope: (parentScope) -> new Scope parentScope, @body, this
  • 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) ->
    
        if @bound and o.scope.method?.bound
          @context = o.scope.method.context
  • Handle bound functions early.

        if @bound and not @context
          @context = '_this'
          wrapper = new Code [new Param new IdentifierLiteral @context], new Block [this]
          boundfunc = new Call(wrapper, [new ThisLiteral])
          boundfunc.updateLocationDataIfMissing @locationData
          return boundfunc.compileNode(o)
    
        o.scope         = del(o, 'classScope') or @makeScope o.scope
        o.scope.shared  = del(o, 'sharedScope')
        o.indent        += TAB
        delete o.bare
        delete o.isExistentialEquals
        params = []
        exprs  = []
        for param in @params when param not instanceof Expansion
          o.scope.parameter param.asReference o
        for param in @params when param.splat or param instanceof Expansion
          for p in @params when p not instanceof Expansion and p.name.value
            o.scope.add p.name.value, 'var', yes
          splats = new Assign new Value(new Arr(p.asReference o for p in @params)),
                              new Value new IdentifierLiteral '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
        for p, i in params
          params[i] = p.compileToFragments o
          o.scope.parameter fragmentsToText params[i]
        uniqs = []
        @eachParamName (name, node) ->
          node.error "multiple parameters named #{name}" if name in uniqs
          uniqs.push name
        @body.makeReturn() unless wasEmpty or @noReturn
        code = 'function'
        code += '*' if @isGenerator
        code += ' ' + @name if @ctor
        code += '('
        answer = [@makeCode(code)]
        for p, i in params
          if i then answer.push @makeCode ", "
          answer.push p...
        answer.push @makeCode ') {'
        answer = answer.concat(@makeCode("\n"), @body.compileWithDeclarations(o), @makeCode("\n#{@tab}")) unless @body.isEmpty()
        answer.push @makeCode '}'
    
        return [@makeCode(@tab), answer...] if @ctor
        if @front or (o.level >= LEVEL_ACCESS) then @wrapInBraces answer else answer
    
      eachParamName: (iterator) ->
        param.eachName iterator for param in @params
  • 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) ->
        message = isUnassignable @name.unwrapAll().value
        @name.error message if message
        if @name instanceof Obj and @name.generated
          token = @name.objects[0].operatorToken
          token.error "unexpected #{token.value}"
    
      children: ['name', 'value']
    
      compileToFragments: (o) ->
        @name.compileToFragments o, LEVEL_LIST
    
      asReference: (o) ->
        return @reference if @reference
        node = @name
        if node.this
          name = node.properties[0].name.value
          name = "_#{name}" if name in JS_FORBIDDEN
          node = new IdentifierLiteral o.scope.freeVariable name
        else if node.isComplex()
          node = new IdentifierLiteral o.scope.freeVariable 'arg'
        node = new Value node
        node = new Splat node if @splat
        node.updateLocationDataIfMissing @locationData
        @reference = node
    
      isComplex: ->
        @name.isComplex()
  • Iterates the name or names of a Param. In a sense, a destructured parameter represents multiple JS parameters. This method allows to iterate them all. The iterator function will be called as iterator(name, node) where name is the name of the parameter and node is the AST node corresponding to that name.

      eachName: (iterator, name = @name)->
        atParam = (obj) -> iterator "@#{obj.properties[0].name.value}", obj
    • simple literals foo
        return iterator name.value, name if name instanceof Literal
    • at-params @foo
        return atParam name if name instanceof Value
        for obj in name.objects ? []
    • destructured parameter with default value
          if obj instanceof Assign and not obj.context?
            obj = obj.variable
    • assignments within destructured parameters {foo:bar}
          if obj instanceof Assign
  • … possibly with a default value

            if obj.value instanceof Assign
              obj = obj.value
            @eachName iterator, obj.value.unwrap()
    • splats within destructured parameters [xs...]
          else if obj instanceof Splat
            node = obj.name.unwrap()
            iterator node.value, node
          else if obj instanceof Value
    • destructured parameters within destructured parameters [{a}]
            if obj.isArray() or obj.isObject()
              @eachName iterator, obj.base
    • at-params within destructured parameters {@foo}
            else if obj.this
              atParam obj
    • simple destructured parameters {foo}
            else iterator obj.base.value, obj.base
          else if obj not instanceof Expansion
            obj.error "illegal parameter #{obj.compile()}"
        return
  • 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
    
      compileToFragments: (o) ->
        @name.compileToFragments 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
          node = list[0]
          fragments = node.compileToFragments o, LEVEL_LIST
          return fragments if apply
          return [].concat node.makeCode("#{ utility 'slice', o }.call("), fragments, node.makeCode(")")
        args = list[index..]
        for node, i in args
          compiledNode = node.compileToFragments o, LEVEL_LIST
          args[i] = if node instanceof Splat
          then [].concat node.makeCode("#{ utility 'slice', o }.call("), compiledNode, node.makeCode(")")
          else [].concat node.makeCode("["), compiledNode, node.makeCode("]")
        if index is 0
          node = list[0]
          concatPart = (node.joinFragmentArrays args[1..], ', ')
          return args[0].concat node.makeCode(".concat("), concatPart, node.makeCode(")")
        base = (node.compileToFragments o, LEVEL_LIST for node in list[...index])
        base = list[0].joinFragmentArrays base, ', '
        concatPart = list[index].joinFragmentArrays args, ', '
        [..., last] = list
        [].concat list[0].makeCode("["), base, list[index].makeCode("].concat("), concatPart, last.makeCode(")")
  • Expansion

  • Used to skip values inside an array destructuring (pattern matching) or parameter list.

    exports.Expansion = class Expansion extends Base
    
      isComplex: NO
    
      compileNode: (o) ->
        @error 'Expansion must be used inside a destructuring assignment or parameter list'
    
      asReference: (o) ->
        this
    
      eachName: (iterator) ->
  • 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 jumpNode if jumpNode = 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 = @makeCode ''
        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 StatementLiteral "continue"
            else
              body = Block.wrap [new If @guard, body] if @guard
          body = [].concat @makeCode("\n"), (body.compileToFragments o, LEVEL_TOP), @makeCode("\n#{@tab}")
        answer = [].concat @makeCode(set + @tab + "while ("), @condition.compileToFragments(o, LEVEL_PAREN),
          @makeCode(") {"), body, @makeCode("}")
        if @returns
          answer.push @makeCode "\n#{@tab}return #{rvar};"
        answer
  • 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'
        'yieldfrom': 'yield*'
  • The map of invertible operators.

      INVERSIONS =
        '!==': '==='
        '===': '!=='
    
      children: ['first', 'second']
    
      isNumber: ->
        @isUnary() and @operator in ['+', '-'] and
          @first instanceof Value and @first.isNumber()
    
      isYield: ->
        @operator in ['yield', 'yield*']
    
      isUnary: ->
        not @second
    
      isComplex: ->
        not @isNumber()
  •   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)
          @error 'delete operand may not be argument or var'
        if @operator in ['--', '++']
          message = isUnassignable @first.unwrapAll().value
          @first.error message if message
        return @compileYield     o if @isYield()
        return @compileUnary     o if @isUnary()
        return @compileChain     o if isChain
        switch @operator
          when '?'  then @compileExistence o
          when '**' then @compilePower o
          when '//' then @compileFloorDivision o
          when '%%' then @compileModulo o
          else
            lhs = @first.compileToFragments o, LEVEL_OP
            rhs = @second.compileToFragments o, LEVEL_OP
            answer = [].concat lhs, @makeCode(" #{@operator} "), rhs
            if o.level <= LEVEL_OP then answer else @wrapInBraces answer
  • 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.compileToFragments o, LEVEL_OP
        fragments = fst.concat @makeCode(" #{if @invert then '&&' else '||'} "),
          (shared.compileToFragments o), @makeCode(" #{@operator} "), (@second.compileToFragments o, LEVEL_OP)
        @wrapInBraces fragments
  • Keep reference to the left expression, unless this an existential assignment

      compileExistence: (o) ->
        if @first.isComplex()
          ref = new IdentifierLiteral 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).compileToFragments o
  • Compile a unary Op.

      compileUnary: (o) ->
        parts = []
        op = @operator
        parts.push [@makeCode op]
        if op is '!' and @first instanceof Existence
          @first.negated = not @first.negated
          return @first.compileToFragments o
        if o.level >= LEVEL_ACCESS
          return (new Parens this).compileToFragments o
        plusMinus = op in ['+', '-']
        parts.push [@makeCode(' ')] if op in ['new', 'typeof', 'delete'] or
                          plusMinus and @first instanceof Op and @first.operator is op
        if (plusMinus and @first instanceof Op) or (op is 'new' and @first.isStatement o)
          @first = new Parens @first
        parts.push @first.compileToFragments o, LEVEL_OP
        parts.reverse() if @flip
        @joinFragmentArrays parts, ''
    
      compileYield: (o) ->
        parts = []
        op = @operator
        unless o.scope.parent?
          @error 'yield can only occur inside functions'
        if 'expression' in Object.keys(@first) and not (@first instanceof Throw)
          parts.push @first.expression.compileToFragments o, LEVEL_OP if @first.expression?
        else
          parts.push [@makeCode "("] if o.level >= LEVEL_PAREN
          parts.push [@makeCode op]
          parts.push [@makeCode " "] if @first.base?.value isnt ''
          parts.push @first.compileToFragments o, LEVEL_OP
          parts.push [@makeCode ")"] if o.level >= LEVEL_PAREN
        @joinFragmentArrays parts, ''
    
      compilePower: (o) ->
  • Make a Math.pow call

        pow = new Value new IdentifierLiteral('Math'), [new Access new PropertyName 'pow']
        new Call(pow, [@first, @second]).compileToFragments o
    
      compileFloorDivision: (o) ->
        floor = new Value new IdentifierLiteral('Math'), [new Access new PropertyName 'floor']
        second = if @second.isComplex() then new Parens @second else @second
        div = new Op '/', @first, second
        new Call(floor, [div]).compileToFragments o
    
      compileModulo: (o) ->
        mod = new Value new Literal utility 'modulo', o
        new Call(mod, [@first, @second]).compileToFragments o
    
      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() and @array.base.objects.length
          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) ->
        [sub, ref] = @object.cache o, LEVEL_OP
        [cmp, cnj] = if @negated then [' !== ', ' && '] else [' === ', ' || ']
        tests = []
        for item, i in @array.base.objects
          if i then tests.push @makeCode cnj
          tests = tests.concat (if i then ref else sub), @makeCode(cmp), item.compileToFragments(o, LEVEL_ACCESS)
        if o.level < LEVEL_OP then tests else @wrapInBraces tests
    
      compileLoopTest: (o) ->
        [sub, ref] = @object.cache o, LEVEL_LIST
        fragments = [].concat @makeCode(utility('indexOf', o) + ".call("), @array.compileToFragments(o, LEVEL_LIST),
          @makeCode(", "), ref, @makeCode(") " + if @negated then '< 0' else '>= 0')
        return fragments if fragmentsToText(sub) is fragmentsToText(ref)
        fragments = sub.concat @makeCode(', '), fragments
        if o.level < LEVEL_LIST then fragments else @wrapInBraces fragments
    
      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, @errorVariable, @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
        tryPart   = @attempt.compileToFragments o, LEVEL_TOP
    
        catchPart = if @recovery
          generatedErrorVariableName = o.scope.freeVariable 'error', reserve: no
          placeholder = new IdentifierLiteral generatedErrorVariableName
          if @errorVariable
            message = isUnassignable @errorVariable.unwrapAll().value
            @errorVariable.error message if message
            @recovery.unshift new Assign @errorVariable, placeholder
          [].concat @makeCode(" catch ("), placeholder.compileToFragments(o), @makeCode(") {\n"),
            @recovery.compileToFragments(o, LEVEL_TOP), @makeCode("\n#{@tab}}")
        else unless @ensure or @recovery
          generatedErrorVariableName = o.scope.freeVariable 'error', reserve: no
          [@makeCode(" catch (#{generatedErrorVariableName}) {}")]
        else
          []
    
        ensurePart = if @ensure then ([].concat @makeCode(" finally {\n"), @ensure.compileToFragments(o, LEVEL_TOP),
          @makeCode("\n#{@tab}}")) else []
    
        [].concat @makeCode("#{@tab}try {\n"),
          tryPart,
          @makeCode("\n#{@tab}}"), catchPart, 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) ->
        [].concat @makeCode(@tab + "throw "), @expression.compileToFragments(o), @makeCode(";")
  • 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 @expression.unwrap() instanceof IdentifierLiteral 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"
        [@makeCode(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.compileToFragments o
        fragments = expr.compileToFragments o, LEVEL_PAREN
        bare = o.level < LEVEL_OP and (expr instanceof Op or expr instanceof Call or
          (expr instanceof For and expr.returns)) and (o.level < LEVEL_COND or
            fragments.length <= 3)
        if bare then fragments else @wrapInBraces fragments
  • StringWithInterpolations

  • Strings with interpolations are in fact just a variation of Parens with string concatenation inside.

    exports.StringWithInterpolations = class StringWithInterpolations extends Parens
  • Uncomment the following line in CoffeeScript 2, to allow all interpolated strings to be output using the ES2015 syntax: unwrap: -> this

      compileNode: (o) ->
  • This method produces an interpolated string using the new ES2015 syntax, which is opt-in by using tagged template literals. If this StringWithInterpolations isn’t inside a tagged template literal, fall back to the CoffeeScript 1.x output. (Remove this check in CoffeeScript 2.)

        unless o.inTaggedTemplateCall
          return super
  • Assumption: expr is Value>StringLiteral or Op

        expr = @body.unwrap()
    
        elements = []
        expr.traverseChildren no, (node) ->
          if node instanceof StringLiteral
            elements.push node
            return yes
          else if node instanceof Parens
            elements.push node
            return no
          return yes
    
        fragments = []
        fragments.push @makeCode '`'
        for element in elements
          if element instanceof StringLiteral
            value = element.value[1...-1]
  • Backticks and ${ inside template literals must be escaped.

            value = value.replace /(\\*)(`|\$\{)/g, (match, backslashes, toBeEscaped) ->
              if backslashes.length % 2 is 0
                "#{backslashes}\\#{toBeEscaped}"
              else
                match
            fragments.push @makeCode value
          else
            fragments.push @makeCode '${'
            fragments.push element.compileToFragments(o, LEVEL_PAREN)...
            fragments.push @makeCode '}'
        fragments.push @makeCode '`'
    
        fragments
  • 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
        @from    = !!source.from
        @index.error 'cannot use index with for-from' if @from and @index
        source.ownTag.error "cannot use own with for-#{if @from then 'from' else 'in'}" if @own and not @object
        [@name, @index] = [@index, @name] if @object
        @index.error 'index cannot be a pattern matching expression' if @index instanceof Value and not @index.isAssignable()
        @range   = @source instanceof Value and @source.base instanceof Range and not @source.properties.length and not @from
        @pattern = @name instanceof Value
        @index.error 'indexes do not apply to range loops' if @range and @index
        @name.error '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]
        [..., last] = body.expressions
        @returns    = no if last?.jumps() instanceof Return
        source      = if @range then @source.base else @source
        scope       = o.scope
        name        = @name  and (@name.compile o, LEVEL_LIST) if not @pattern
        index       = @index and (@index.compile o, LEVEL_LIST)
        scope.find(name)  if name and not @pattern
        scope.find(index) if index and @index not instanceof Value
        rvar        = scope.freeVariable 'results' if @returns
        if @from
          ivar = scope.freeVariable 'x', single: true if @pattern
        else
          ivar = (@object and index) or scope.freeVariable 'i', single: true
        kvar        = ((@range or @from) and name) or index or ivar
        kvarAssign  = if kvar isnt ivar then "#{kvar} = " else ""
        if @step and not @range
          [step, stepVar] = @cacheToCodeFragments @step.cache o, LEVEL_LIST, isComplexOrAssignable
          stepNum   = Number stepVar if @step.isNumber()
        name        = ivar if @pattern
        varPart     = ''
        guardPart   = ''
        defPart     = ''
        idt1        = @tab + TAB
        if @range
          forPartFragments = source.compileToFragments merge o,
            {index: ivar, name, @step, isComplex: isComplexOrAssignable}
        else
          svar    = @source.compile o, LEVEL_LIST
          if (name or @own) and @source.unwrap() not instanceof IdentifierLiteral
            defPart    += "#{@tab}#{ref = scope.freeVariable 'ref'} = #{svar};\n"
            svar       = ref
          if name and not @pattern and not @from
            namePart   = "#{name} = #{svar}[#{kvar}]"
          if not @object and not @from
            defPart += "#{@tab}#{step};\n" if step isnt stepVar
            down = stepNum < 0
            lvar = scope.freeVariable 'len' unless @step and stepNum? and down
            declare = "#{kvarAssign}#{ivar} = 0, #{lvar} = #{svar}.length"
            declareDown = "#{kvarAssign}#{ivar} = #{svar}.length - 1"
            compare = "#{ivar} < #{lvar}"
            compareDown = "#{ivar} >= 0"
            if @step
              if stepNum?
                if down
                  compare = compareDown
                  declare = declareDown
              else
                compare = "#{stepVar} > 0 ? #{compare} : #{compareDown}"
                declare = "(#{stepVar} > 0 ? (#{declare}) : #{declareDown})"
              increment = "#{ivar} += #{stepVar}"
            else
              increment = "#{if kvar isnt ivar then "++#{ivar}" else "#{ivar}++"}"
            forPartFragments = [@makeCode("#{declare}; #{compare}; #{kvarAssign}#{increment}")]
        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 StatementLiteral "continue"
          else
            body = Block.wrap [new If @guard, body] if @guard
        if @pattern
          body.expressions.unshift new Assign @name, if @from then new IdentifierLiteral kvar else new Literal "#{svar}[#{kvar}]"
        defPartFragments = [].concat @makeCode(defPart), @pluckDirectCall(o, body)
        varPart = "\n#{idt1}#{namePart};" if namePart
        if @object
          forPartFragments = [@makeCode("#{kvar} in #{svar}")]
          guardPart = "\n#{idt1}if (!#{utility 'hasProp', o}.call(#{svar}, #{kvar})) continue;" if @own
        else if @from
          forPartFragments = [@makeCode("#{kvar} of #{svar}")]
        bodyFragments = body.compileToFragments merge(o, indent: idt1), LEVEL_TOP
        if bodyFragments and bodyFragments.length > 0
          bodyFragments = [].concat @makeCode("\n"), bodyFragments, @makeCode("\n")
        [].concat defPartFragments, @makeCode("#{resultPart or ''}#{@tab}for ("),
          forPartFragments, @makeCode(") {#{guardPart}#{varPart}"), bodyFragments,
          @makeCode("#{@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 IdentifierLiteral 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 = defs.concat @makeCode(@tab), (new Assign(ref, fn).compileToFragments(o, LEVEL_TOP)), @makeCode(';\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 jumpNode if jumpNode = 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
        fragments = [].concat @makeCode(@tab + "switch ("),
          (if @subject then @subject.compileToFragments(o, LEVEL_PAREN) else @makeCode "false"),
          @makeCode(") {\n")
        for [conditions, block], i in @cases
          for cond in flatten [conditions]
            cond  = cond.invert() unless @subject
            fragments = fragments.concat @makeCode(idt1 + "case "), cond.compileToFragments(o, LEVEL_PAREN), @makeCode(":\n")
          fragments = fragments.concat body, @makeCode('\n') if (body = block.compileToFragments o, LEVEL_TOP).length > 0
          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')
          fragments.push cond.makeCode(idt2 + 'break;\n')
        if @otherwise and @otherwise.expressions.length
          fragments.push @makeCode(idt1 + "default:\n"), (@otherwise.compileToFragments o, LEVEL_TOP)..., @makeCode("\n")
        fragments.push @makeCode @tab + '}'
        fragments
  • 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
          @elseBody.updateLocationDataIfMissing elseBody.locationData
        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').compileToFragments o
    
        indent   = o.indent + TAB
        cond     = @condition.compileToFragments o, LEVEL_PAREN
        body     = @ensureBlock(@body).compileToFragments merge o, {indent}
        ifPart   = [].concat @makeCode("if ("), cond, @makeCode(") {\n"), body, @makeCode("\n#{@tab}}")
        ifPart.unshift @makeCode @tab unless child
        return ifPart unless @elseBody
        answer = ifPart.concat @makeCode(' else ')
        if @isChain
          o.chainChild = yes
          answer = answer.concat @elseBody.unwrap().compileToFragments o, LEVEL_TOP
        else
          answer = answer.concat @makeCode("{\n"), @elseBody.compileToFragments(merge(o, {indent}), LEVEL_TOP), @makeCode("\n#{@tab}}")
        answer
  • Compile the If as a conditional operator.

      compileExpression: (o) ->
        cond = @condition.compileToFragments o, LEVEL_COND
        body = @bodyNode().compileToFragments o, LEVEL_LIST
        alt  = if @elseBodyNode() then @elseBodyNode().compileToFragments(o, LEVEL_LIST) else [@makeCode('void 0')]
        fragments = cond.concat @makeCode(" ? "), body, @makeCode(" : "), alt
        if o.level >= LEVEL_COND then @wrapInBraces fragments else fragments
    
      unfoldSoak: ->
        @soak and this
  • 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.

      extend: (o) -> "
        function(child, parent) {
          for (var key in parent) {
            if (#{utility 'hasProp', o}.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;
        }
      "
    
      modulo: -> """
        function(a, b) { return (+a % (b = +b) + b) % b; }
      """
  • 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 = '  '
    
    SIMPLENUM = /^[+-]?\d+$/
  • Helper Functions

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

    utility = (name, o) ->
      {root} = o.scope
      if name of root.utilities
        root.utilities[name]
      else
        ref = root.freeVariable name
        root.assign ref, UTILITIES[name] o
        root.utilities[name] = ref
    
    multident = (code, tab) ->
      code = code.replace /\n/g, '$&' + tab
      code.replace /\s+$/, ''
    
    isLiteralArguments = (node) ->
      node instanceof IdentifierLiteral and node.value is 'arguments'
    
    isLiteralThis = (node) ->
      node instanceof ThisLiteral or
        (node instanceof Code and node.bound) or
        node instanceof SuperCall
    
    isComplexOrAssignable = (node) -> node.isComplex() or node.isAssignable?()
  • 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
coffeescript-1.12.7/docs/v1/annotated-source/optparse.html000066400000000000000000000356031313305734200235420ustar00rootroot00000000000000 optparse.coffee
  • optparse.coffee

  • {repeat} = require './helpers'
  • 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 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 repeat ' ', spaces 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
coffeescript-1.12.7/docs/v1/annotated-source/public/000077500000000000000000000000001313305734200222665ustar00rootroot00000000000000coffeescript-1.12.7/docs/v1/annotated-source/public/stylesheets/000077500000000000000000000000001313305734200246425ustar00rootroot00000000000000coffeescript-1.12.7/docs/v1/annotated-source/public/stylesheets/normalize.css000066400000000000000000000153321313305734200273600ustar00rootroot00000000000000/*! normalize.css v2.0.1 | MIT License | git.io/normalize */ /* ========================================================================== HTML5 display definitions ========================================================================== */ /* * Corrects `block` display not defined in IE 8/9. */ article, aside, details, figcaption, figure, footer, header, hgroup, nav, section, summary { display: block; } /* * Corrects `inline-block` display not defined in IE 8/9. */ audio, canvas, video { display: inline-block; } /* * Prevents modern browsers from displaying `audio` without controls. * Remove excess height in iOS 5 devices. */ audio:not([controls]) { display: none; height: 0; } /* * Addresses styling for `hidden` attribute not present in IE 8/9. */ [hidden] { display: none; } /* ========================================================================== Base ========================================================================== */ /* * 1. Sets default font family to sans-serif. * 2. Prevents iOS text size adjust after orientation change, without disabling * user zoom. */ html { font-family: sans-serif; /* 1 */ -webkit-text-size-adjust: 100%; /* 2 */ -ms-text-size-adjust: 100%; /* 2 */ } /* * Removes default margin. */ body { margin: 0; } /* ========================================================================== Links ========================================================================== */ /* * Addresses `outline` inconsistency between Chrome and other browsers. */ a:focus { outline: thin dotted; } /* * Improves readability when focused and also mouse hovered in all browsers. */ a:active, a:hover { outline: 0; } /* ========================================================================== Typography ========================================================================== */ /* * Addresses `h1` font sizes within `section` and `article` in Firefox 4+, * Safari 5, and Chrome. */ h1 { font-size: 2em; } /* * Addresses styling not present in IE 8/9, Safari 5, and Chrome. */ abbr[title] { border-bottom: 1px dotted; } /* * Addresses style set to `bolder` in Firefox 4+, Safari 5, and Chrome. */ b, strong { font-weight: bold; } /* * Addresses styling not present in Safari 5 and Chrome. */ dfn { font-style: italic; } /* * Addresses styling not present in IE 8/9. */ mark { background: #ff0; color: #000; } /* * Corrects font family set oddly in Safari 5 and Chrome. */ code, kbd, pre, samp { font-family: monospace, serif; font-size: 1em; } /* * Improves readability of pre-formatted text in all browsers. */ pre { white-space: pre; white-space: pre-wrap; word-wrap: break-word; } /* * Sets consistent quote types. */ q { quotes: "\201C" "\201D" "\2018" "\2019"; } /* * Addresses inconsistent and variable font size in all browsers. */ small { font-size: 80%; } /* * Prevents `sub` and `sup` affecting `line-height` in all browsers. */ sub, sup { font-size: 75%; line-height: 0; position: relative; vertical-align: baseline; } sup { top: -0.5em; } sub { bottom: -0.25em; } /* ========================================================================== Embedded content ========================================================================== */ /* * Removes border when inside `a` element in IE 8/9. */ img { border: 0; } /* * Corrects overflow displayed oddly in IE 9. */ svg:not(:root) { overflow: hidden; } /* ========================================================================== Figures ========================================================================== */ /* * Addresses margin not present in IE 8/9 and Safari 5. */ figure { margin: 0; } /* ========================================================================== Forms ========================================================================== */ /* * Define consistent border, margin, and padding. */ fieldset { border: 1px solid #c0c0c0; margin: 0 2px; padding: 0.35em 0.625em 0.75em; } /* * 1. Corrects color not being inherited in IE 8/9. * 2. Remove padding so people aren't caught out if they zero out fieldsets. */ legend { border: 0; /* 1 */ padding: 0; /* 2 */ } /* * 1. Corrects font family not being inherited in all browsers. * 2. Corrects font size not being inherited in all browsers. * 3. Addresses margins set differently in Firefox 4+, Safari 5, and Chrome */ button, input, select, textarea { font-family: inherit; /* 1 */ font-size: 100%; /* 2 */ margin: 0; /* 3 */ } /* * Addresses Firefox 4+ setting `line-height` on `input` using `!important` in * the UA stylesheet. */ button, input { line-height: normal; } /* * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio` * and `video` controls. * 2. Corrects inability to style clickable `input` types in iOS. * 3. Improves usability and consistency of cursor style between image-type * `input` and others. */ button, html input[type="button"], /* 1 */ input[type="reset"], input[type="submit"] { -webkit-appearance: button; /* 2 */ cursor: pointer; /* 3 */ } /* * Re-set default cursor for disabled elements. */ button[disabled], input[disabled] { cursor: default; } /* * 1. Addresses box sizing set to `content-box` in IE 8/9. * 2. Removes excess padding in IE 8/9. */ input[type="checkbox"], input[type="radio"] { box-sizing: border-box; /* 1 */ padding: 0; /* 2 */ } /* * 1. Addresses `appearance` set to `searchfield` in Safari 5 and Chrome. * 2. Addresses `box-sizing` set to `border-box` in Safari 5 and Chrome * (include `-moz` to future-proof). */ input[type="search"] { -webkit-appearance: textfield; /* 1 */ -moz-box-sizing: content-box; -webkit-box-sizing: content-box; /* 2 */ box-sizing: content-box; } /* * Removes inner padding and search cancel button in Safari 5 and Chrome * on OS X. */ input[type="search"]::-webkit-search-cancel-button, input[type="search"]::-webkit-search-decoration { -webkit-appearance: none; } /* * Removes inner padding and border in Firefox 4+. */ button::-moz-focus-inner, input::-moz-focus-inner { border: 0; padding: 0; } /* * 1. Removes default vertical scrollbar in IE 8/9. * 2. Improves readability and alignment in all browsers. */ textarea { overflow: auto; /* 1 */ vertical-align: top; /* 2 */ } /* ========================================================================== Tables ========================================================================== */ /* * Remove most spacing between table cells. */ table { border-collapse: collapse; border-spacing: 0; }coffeescript-1.12.7/docs/v1/annotated-source/register.html000066400000000000000000000217731313305734200235340ustar00rootroot00000000000000 register.coffee
  • register.coffee

  • CoffeeScript  = require './coffee-script'
    child_process = require 'child_process'
    helpers       = require './helpers'
    path          = require 'path'
  • Load and run a CoffeeScript file for Node, stripping any BOMs.

    loadFile = (module, filename) ->
      answer = CoffeeScript._compileFile filename, no, yes
      module._compile answer, filename
  • If the installed version of Node supports require.extensions, register CoffeeScript as an extension.

    if require.extensions
      for ext in CoffeeScript.FILE_EXTENSIONS
        require.extensions[ext] = loadFile
  • Patch Node’s module loader to be able to handle multi-dot extensions. This is a horrible thing that should not be required.

      Module = require 'module'
    
      findExtension = (filename) ->
        extensions = path.basename(filename).split '.'
  • Remove the initial dot from dotfiles.

        extensions.shift() if extensions[0] is ''
  • Start with the longest possible extension and work our way shortwards.

        while extensions.shift()
          curExtension = '.' + extensions.join '.'
          return curExtension if Module._extensions[curExtension]
        '.js'
    
      Module::load = (filename) ->
        @filename = filename
        @paths = Module._nodeModulePaths path.dirname filename
        extension = findExtension filename
        Module._extensions[extension](this, filename)
        @loaded = true
  • If we’re on Node, patch child_process.fork so that Coffee scripts are able to fork both CoffeeScript files, and JavaScript files, directly.

    if child_process
      {fork} = child_process
      binary = require.resolve '../../bin/coffee'
      child_process.fork = (path, args, options) ->
        if helpers.isCoffee path
          unless Array.isArray args
            options = args or {}
            args = []
          args = [path].concat args
          path = binary
        fork path, args, options
coffeescript-1.12.7/docs/v1/annotated-source/repl.html000066400000000000000000000622271313305734200226510ustar00rootroot00000000000000 repl.coffee
  • repl.coffee

  • fs = require 'fs'
    path = require 'path'
    vm = require 'vm'
    nodeREPL = require 'repl'
    CoffeeScript = require './coffee-script'
    {merge, updateSyntaxError} = require './helpers'
    
    replDefaults =
      prompt: 'coffee> ',
      historyFile: path.join process.env.HOME, '.coffee_history' if process.env.HOME
      historyMaxInputSize: 10240
      eval: (input, context, filename, cb) ->
  • XXX: multiline hack.

        input = input.replace /\uFF00/g, '\n'
  • Node’s REPL sends the input ending with a newline and then wrapped in parens. Unwrap all that.

        input = input.replace /^\(([\s\S]*)\n\)$/m, '$1'
  • Node’s REPL v6.9.1+ sends the input wrapped in a try/catch statement. Unwrap that too.

        input = input.replace /^\s*try\s*{([\s\S]*)}\s*catch.*$/m, '$1'
  • Require AST nodes to do some AST manipulation.

        {Block, Assign, Value, Literal} = require './nodes'
    
        try
  • Tokenize the clean input.

          tokens = CoffeeScript.tokens input
  • Collect referenced variable names just like in CoffeeScript.compile.

          referencedVars = (
            token[1] for token in tokens when token[0] is 'IDENTIFIER'
          )
  • Generate the AST of the tokens.

          ast = CoffeeScript.nodes tokens
  • Add assignment to _ variable to force the input to be an expression.

          ast = new Block [
            new Assign (new Value new Literal '__'), ast, '='
          ]
          js = ast.compile {bare: yes, locals: Object.keys(context), referencedVars}
          cb null, runInContext js, context, filename
        catch err
  • AST’s compile does not add source code information to syntax errors.

          updateSyntaxError err, input
          cb err
    
    runInContext = (js, context, filename) ->
      if context is global
        vm.runInThisContext js, filename
      else
        vm.runInContext js, context, filename
    
    addMultilineHandler = (repl) ->
      {rli, inputStream, outputStream} = repl
  • Node 0.11.12 changed API, prompt is now _prompt.

      origPrompt = repl._prompt ? repl.prompt
    
      multiline =
        enabled: off
        initialPrompt: origPrompt.replace /^[^> ]*/, (x) -> x.replace /./g, '-'
        prompt: origPrompt.replace /^[^> ]*>?/, (x) -> x.replace /./g, '.'
        buffer: ''
  • Proxy node’s line listener

      nodeLineListener = rli.listeners('line')[0]
      rli.removeListener 'line', nodeLineListener
      rli.on 'line', (cmd) ->
        if multiline.enabled
          multiline.buffer += "#{cmd}\n"
          rli.setPrompt multiline.prompt
          rli.prompt true
        else
          rli.setPrompt origPrompt
          nodeLineListener cmd
        return
  • Handle Ctrl-v

      inputStream.on 'keypress', (char, key) ->
        return unless key and key.ctrl and not key.meta and not key.shift and key.name is 'v'
        if multiline.enabled
  • allow arbitrarily switching between modes any time before multiple lines are entered

          unless multiline.buffer.match /\n/
            multiline.enabled = not multiline.enabled
            rli.setPrompt origPrompt
            rli.prompt true
            return
  • no-op unless the current line is empty

          return if rli.line? and not rli.line.match /^\s*$/
  • eval, print, loop

          multiline.enabled = not multiline.enabled
          rli.line = ''
          rli.cursor = 0
          rli.output.cursorTo 0
          rli.output.clearLine 1
  • XXX: multiline hack

          multiline.buffer = multiline.buffer.replace /\n/g, '\uFF00'
          rli.emit 'line', multiline.buffer
          multiline.buffer = ''
        else
          multiline.enabled = not multiline.enabled
          rli.setPrompt multiline.initialPrompt
          rli.prompt true
        return
  • Store and load command history from a file

    addHistory = (repl, filename, maxSize) ->
      lastLine = null
      try
  • Get file info and at most maxSize of command history

        stat = fs.statSync filename
        size = Math.min maxSize, stat.size
  • Read last size bytes from the file

        readFd = fs.openSync filename, 'r'
        buffer = new Buffer(size)
        fs.readSync readFd, buffer, 0, size, stat.size - size
        fs.closeSync readFd
  • Set the history on the interpreter

        repl.rli.history = buffer.toString().split('\n').reverse()
  • If the history file was truncated we should pop off a potential partial line

        repl.rli.history.pop() if stat.size > maxSize
  • Shift off the final blank newline

        repl.rli.history.shift() if repl.rli.history[0] is ''
        repl.rli.historyIndex = -1
        lastLine = repl.rli.history[0]
    
      fd = fs.openSync filename, 'a'
    
      repl.rli.addListener 'line', (code) ->
        if code and code.length and code isnt '.history' and code isnt '.exit' and lastLine isnt code
  • Save the latest command in the file

          fs.writeSync fd, "#{code}\n"
          lastLine = code
    
      repl.on 'exit', -> fs.closeSync fd
  • Add a command to show the history stack

      repl.commands[getCommandId(repl, 'history')] =
        help: 'Show command history'
        action: ->
          repl.outputStream.write "#{repl.rli.history[..].reverse().join '\n'}\n"
          repl.displayPrompt()
    
    getCommandId = (repl, commandName) ->
  • Node 0.11 changed API, a command such as ‘.help’ is now stored as ‘help’

      commandsHaveLeadingDot = repl.commands['.help']?
      if commandsHaveLeadingDot then ".#{commandName}" else commandName
    
    module.exports =
      start: (opts = {}) ->
        [major, minor, build] = process.versions.node.split('.').map (n) -> parseInt(n, 10)
    
        if major is 0 and minor < 8
          console.warn "Node 0.8.0+ required for CoffeeScript REPL"
          process.exit 1
    
        CoffeeScript.register()
        process.argv = ['coffee'].concat process.argv[2..]
        opts = merge replDefaults, opts
        repl = nodeREPL.start opts
        runInContext opts.prelude, repl.context, 'prelude' if opts.prelude
        repl.on 'exit', -> repl.outputStream.write '\n' if not repl.rli.closed
        addMultilineHandler repl
        addHistory repl, opts.historyFile, opts.historyMaxInputSize if opts.historyFile
  • Adapt help inherited from the node REPL

        repl.commands[getCommandId(repl, 'load')].help = 'Load code from a file into this REPL session'
        repl
coffeescript-1.12.7/docs/v1/annotated-source/rewriter.html000066400000000000000000002100021313305734200235340ustar00rootroot00000000000000 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.

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

    generate = (tag, value, origin) ->
      tok = [tag, value]
      tok.generated = yes
      tok.origin = origin if origin
      tok
  • The Rewriter class is used by the Lexer, directly against its internal array of tokens.

    exports.Rewriter = class Rewriter
  • Rewrite the token stream in multiple passes, one logical filter at a time. This could certainly be changed into a single pass through the stream, with a big ol’ efficient switch, but it’s much nicer to work with like this. The order of these passes matters – indentation must be corrected before implicit parentheses can be wrapped around blocks of code.

      rewrite: (@tokens) ->
  • Helpful snippet for debugging: console.log (t[0] + ‘/‘ + t[1] for t in @tokens).join ‘ ‘

        @removeLeadingNewlines()
        @closeOpenCalls()
        @closeOpenIndexes()
        @normalizeLines()
        @tagPostfixConditionals()
        @addImplicitBracesAndParens()
        @addLocationDataToGeneratedTokens()
        @fixOutdentLocationData()
        @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
  • 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
  • Match tags in token stream starting at i with pattern, skipping ‘HERECOMMENT’s. pattern may consist of strings (equality), an array of strings (one of) or null (wildcard). Returns the index of the match or -1 if no match.

      indexOfTag: (i, pattern...) ->
        fuzz = 0
        for j in [0 ... pattern.length]
          fuzz += 2 while @tag(i + j + fuzz) is 'HERECOMMENT'
          continue if not pattern[j]?
          pattern[j] = [pattern[j]] if typeof pattern[j] is 'string'
          return -1 if @tag(i + j + fuzz) not in pattern[j]
        i + j + fuzz - 1
  • Returns yes if standing in front of something looking like @<x>:, <x>: or <EXPRESSION_START><x>...<EXPRESSION_END>:, skipping over ‘HERECOMMENT’s.

      looksObjectish: (j) ->
        return yes if @indexOfTag(j, '@', null, ':') > -1 or @indexOfTag(j, null, ':') > -1
        index = @indexOfTag(j, EXPRESSION_START)
        if index > -1
          end = null
          @detectEnd index + 1, ((token) -> token[0] in EXPRESSION_END), ((token, i) -> end = i)
          return yes if @tag(end + 1) is ':'
        no
  • Returns yes if current line of tokens contain an element of tags on same expression level. Stop searching at LINEBREAKS or explicit start of containing balanced expression.

      findTagsBackwards: (i, tags) ->
        backStack = []
        while i >= 0 and (backStack.length or
              @tag(i) not in tags and
              (@tag(i) not in EXPRESSION_START or @tokens[i].generated) and
              @tag(i) not in LINEBREAKS)
          backStack.push @tag(i) if @tag(i) in EXPRESSION_END
          backStack.pop() if @tag(i) in EXPRESSION_START and backStack.length
          i -= 1
        @tag(i) in tags
  • Look for signs of implicit calls and objects in the token stream and add them.

      addImplicitBracesAndParens: ->
  • Track current balancing depth (both implicit and explicit) on stack.

        stack = []
        start = null
    
        @scanTokens (token, i, tokens) ->
          [tag]     = token
          [prevTag] = prevToken = if i > 0 then tokens[i - 1] else []
          [nextTag] = if i < tokens.length - 1 then tokens[i + 1] else []
          stackTop  = -> stack[stack.length - 1]
          startIdx  = i
  • Helper function, used for keeping track of the number of tokens consumed and spliced, when returning for getting a new token.

          forward   = (n) -> i - startIdx + n
  • Helper functions

          isImplicit        = (stackItem) -> stackItem?[2]?.ours
          isImplicitObject  = (stackItem) -> isImplicit(stackItem) and stackItem?[0] is '{'
          isImplicitCall    = (stackItem) -> isImplicit(stackItem) and stackItem?[0] is '('
          inImplicit        = -> isImplicit stackTop()
          inImplicitCall    = -> isImplicitCall stackTop()
          inImplicitObject  = -> isImplicitObject stackTop()
  • Unclosed control statement inside implicit parens (like class declaration or if-conditionals)

          inImplicitControl = -> inImplicit and stackTop()?[0] is 'CONTROL'
    
          startImplicitCall = (j) ->
            idx = j ? i
            stack.push ['(', idx, ours: yes]
            tokens.splice idx, 0, generate 'CALL_START', '(', ['', 'implicit function call', token[2]]
            i += 1 if not j?
    
          endImplicitCall = ->
            stack.pop()
            tokens.splice i, 0, generate 'CALL_END', ')', ['', 'end of input', token[2]]
            i += 1
    
          startImplicitObject = (j, startsLine = yes) ->
            idx = j ? i
            stack.push ['{', idx, sameLine: yes, startsLine: startsLine, ours: yes]
            val = new String '{'
            val.generated = yes
            tokens.splice idx, 0, generate '{', val, token
            i += 1 if not j?
    
          endImplicitObject = (j) ->
            j = j ? i
            stack.pop()
            tokens.splice j, 0, generate '}', '}', token
            i += 1
  • Don’t end an implicit call on next indent if any of these are in an argument

          if inImplicitCall() and tag in ['IF', 'TRY', 'FINALLY', 'CATCH',
            'CLASS', 'SWITCH']
            stack.push ['CONTROL', i, ours: yes]
            return forward(1)
    
          if tag is 'INDENT' and inImplicit()
  • An INDENT closes an implicit call unless

    1. We have seen a CONTROL argument on the line.
    2. The last token before the indent is part of the list below
            if prevTag not in ['=>', '->', '[', '(', ',', '{', 'TRY', 'ELSE', '=']
              endImplicitCall() while inImplicitCall()
            stack.pop() if inImplicitControl()
            stack.push [tag, i]
            return forward(1)
  • Straightforward start of explicit expression

          if tag in EXPRESSION_START
            stack.push [tag, i]
            return forward(1)
  • Close all implicit expressions inside of explicitly closed expressions.

          if tag in EXPRESSION_END
            while inImplicit()
              if inImplicitCall()
                endImplicitCall()
              else if inImplicitObject()
                endImplicitObject()
              else
                stack.pop()
            start = stack.pop()
  • Recognize standard implicit calls like f a, f() b, f? c, h[0] d etc.

          if (tag in IMPLICIT_FUNC and token.spaced or
              tag is '?' and i > 0 and not tokens[i - 1].spaced) and
             (nextTag in IMPLICIT_CALL or
              nextTag in IMPLICIT_UNSPACED_CALL and
              not tokens[i + 1]?.spaced and not tokens[i + 1]?.newLine)
            tag = token[0] = 'FUNC_EXIST' if tag is '?'
            startImplicitCall i + 1
            return forward(2)
  • Implicit call taking an implicit indented object as first argument.

    f
      a: b
      c: d
    

    and

    f
      1
      a: b
      b: c
    

    Don’t accept implicit calls of this type, when on the same line as the control structures below as that may misinterpret constructs like:

    if f
       a: 1
    

    as

    if f(a: 1)
    

    which is probably always unintended. Furthermore don’t allow this in literal arrays, as that creates grammatical ambiguities.

          if tag in IMPLICIT_FUNC and
             @indexOfTag(i + 1, 'INDENT') > -1 and @looksObjectish(i + 2) and
             not @findTagsBackwards(i, ['CLASS', 'EXTENDS', 'IF', 'CATCH',
              'SWITCH', 'LEADING_WHEN', 'FOR', 'WHILE', 'UNTIL'])
            startImplicitCall i + 1
            stack.push ['INDENT', i + 2]
            return forward(3)
  • Implicit objects start here

          if tag is ':'
  • Go back to the (implicit) start of the object

            s = switch
              when @tag(i - 1) in EXPRESSION_END then start[1]
              when @tag(i - 2) is '@' then i - 2
              else i - 1
            s -= 2 while @tag(s - 2) is 'HERECOMMENT'
  • Mark if the value is a for loop

            @insideForDeclaration = nextTag is 'FOR'
    
            startsLine = s is 0 or @tag(s - 1) in LINEBREAKS or tokens[s - 1].newLine
  • Are we just continuing an already declared object?

            if stackTop()
              [stackTag, stackIdx] = stackTop()
              if (stackTag is '{' or stackTag is 'INDENT' and @tag(stackIdx - 1) is '{') and
                 (startsLine or @tag(s - 1) is ',' or @tag(s - 1) is '{')
                return forward(1)
    
            startImplicitObject(s, !!startsLine)
            return forward(2)
  • End implicit calls when chaining method calls like e.g.:

    f ->
      a
    .g b, ->
      c
    .h a
    

    and also

    f a
    .g b
    .h a
    
  • Mark all enclosing objects as not sameLine

          if tag in LINEBREAKS
            for stackItem in stack by -1
              break unless isImplicit stackItem
              stackItem[2].sameLine = no if isImplicitObject stackItem
    
          newLine = prevTag is 'OUTDENT' or prevToken.newLine
          if tag in IMPLICIT_END or tag in CALL_CLOSERS and newLine
            while inImplicit()
              [stackTag, stackIdx, {sameLine, startsLine}] = stackTop()
  • Close implicit calls when reached end of argument list

              if inImplicitCall() and prevTag isnt ','
                endImplicitCall()
  • Close implicit objects such as: return a: 1, b: 2 unless true

              else if inImplicitObject() and not @insideForDeclaration and sameLine and
                      tag isnt 'TERMINATOR' and prevTag isnt ':'
                endImplicitObject()
  • Close implicit objects when at end of line, line didn’t end with a comma and the implicit object didn’t start the line or the next line doesn’t look like the continuation of an object.

              else if inImplicitObject() and tag is 'TERMINATOR' and prevTag isnt ',' and
                      not (startsLine and @looksObjectish(i + 1))
                return forward 1 if nextTag is 'HERECOMMENT'
                endImplicitObject()
              else
                break
  • Close implicit object if comma is the last character and what comes after doesn’t look like it belongs. This is used for trailing commas and calls, like:

    x =
        a: b,
        c: d,
    e = 2
    

    and

    f a, b: c, d: e, f, g: h: i, j
    
          if tag is ',' and not @looksObjectish(i + 1) and inImplicitObject() and
             not @insideForDeclaration and
             (nextTag isnt 'TERMINATOR' or not @looksObjectish(i + 2))
  • When nextTag is OUTDENT the comma is insignificant and should just be ignored so embed it in the implicit object.

    When it isn’t the comma go on to play a role in a call or array further up the stack, so give it a chance.

            offset = if nextTag is 'OUTDENT' then 1 else 0
            while inImplicitObject()
              endImplicitObject i + offset
          return forward(1)
  • Add location data to all tokens generated by the rewriter.

      addLocationDataToGeneratedTokens: ->
        @scanTokens (token, i, tokens) ->
          return 1 if     token[2]
          return 1 unless token.generated or token.explicit
          if token[0] is '{' and nextLocation=tokens[i + 1]?[2]
            {first_line: line, first_column: column} = nextLocation
          else if prevLocation = tokens[i - 1]?[2]
            {last_line: line, last_column: column} = prevLocation
          else
            line = column = 0
          token[2] =
            first_line:   line
            first_column: column
            last_line:    line
            last_column:  column
          return 1
  • OUTDENT tokens should always be positioned at the last character of the previous token, so that AST nodes ending in an OUTDENT token end up with a location corresponding to the last “real” token under the node.

      fixOutdentLocationData: ->
        @scanTokens (token, i, tokens) ->
          return 1 unless token[0] is 'OUTDENT' or
            (token.generated and token[0] is 'CALL_END') or
            (token.generated and token[0] is '}')
          prevLocationData = tokens[i - 1][2]
          token[2] =
            first_line:   prevLocationData.last_line
            first_column: prevLocationData.last_column
            last_line:    prevLocationData.last_line
            last_column:  prevLocationData.last_column
          return 1
  • 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. To keep the grammar clean and tidy, trailing newlines within expressions are removed and the indentation tokens of empty blocks are added.

      normalizeLines: ->
        starter = indent = outdent = null
    
        condition = (token, i) ->
          token[1] isnt ';' and token[0] in SINGLE_CLOSERS and
          not (token[0] is 'TERMINATOR' and @tag(i + 1) in EXPRESSION_CLOSE) and
          not (token[0] is 'ELSE' and starter isnt 'THEN') and
          not (token[0] in ['CATCH', 'FINALLY'] and starter in ['->', '=>']) or
          token[0] in CALL_CLOSERS and
          (@tokens[i - 1].newLine or @tokens[i - 1][0] is 'OUTDENT')
    
        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'
            if @tag(i + 1) is 'ELSE' and @tag(i - 1) isnt 'OUTDENT'
              tokens.splice i, 1, @indentation()...
              return 1
            if @tag(i + 1) in EXPRESSION_CLOSE
              tokens.splice i, 1
              return 0
          if tag is 'CATCH'
            for j in [1..2] when @tag(i + j) in ['OUTDENT', 'TERMINATOR', 'FINALLY']
              tokens.splice i + j, 0, @indentation()...
              return 2 + j
          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 tokens[i]
            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) ->
          [tag] = token
          [prevTag] = @tokens[i - 1]
          tag is 'TERMINATOR' or (tag is 'INDENT' and prevTag not in SINGLE_LINERS)
    
        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
          return 1
  • Generate the indentation tokens, based on another token on the same line.

      indentation: (origin) ->
        indent  = ['INDENT', 2]
        outdent = ['OUTDENT', 2]
        if origin
          indent.generated = outdent.generated = yes
          indent.origin = outdent.origin = origin
        else
          indent.explicit = outdent.explicit = yes
        [indent, outdent]
    
      generate: generate
  • 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']
      ['STRING_START', 'STRING_END']
      ['REGEX_START', 'REGEX_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', 'THEN', 'ELSE', 'FINALLY'].concat EXPRESSION_END
  • Tokens that, if followed by an IMPLICIT_CALL, indicate a function invocation.

    IMPLICIT_FUNC    = ['IDENTIFIER', 'PROPERTY', 'SUPER', ')', 'CALL_END', ']', 'INDEX_END', '@', 'THIS']
  • If preceded by an IMPLICIT_FUNC, indicates a function invocation.

    IMPLICIT_CALL    = [
      'IDENTIFIER', 'PROPERTY', 'NUMBER', 'INFINITY', 'NAN'
      'STRING', 'STRING_START', 'REGEX', 'REGEX_START', 'JS'
      'NEW', 'PARAM_START', 'CLASS', 'IF', 'TRY', 'SWITCH', 'THIS'
      'UNDEFINED', 'NULL', 'BOOL'
      'UNARY', 'YIELD', 'UNARY_MATH', 'SUPER', 'THROW'
      '@', '->', '=>', '[', '(', '{', '--', '++'
    ]
    
    IMPLICIT_UNSPACED_CALL = ['+', '-']
  • 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']
  • Tokens that close open calls when they follow a newline.

    CALL_CLOSERS     = ['.', '?.', '::', '?::']
coffeescript-1.12.7/docs/v1/annotated-source/scope.html000066400000000000000000000375351313305734200230240ustar00rootroot00000000000000 scope.litcoffee
  • scope.litcoffee

  • 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 external scopes.

    exports.Scope = class Scope
  • 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, a reference to the function that it belongs to, and a list of variables referenced in the source code and therefore should be avoided when generating variables.

      constructor: (@parent, @expressions, @method, @referencedVars) ->
        @variables = [{name: 'arguments', type: 'arguments'}]
        @positions = {}
        @utilities = {} unless @parent
  • The @root is the top-level Scope object for a given file.

        @root = @parent?.root ? this
  • 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, type = 'var') ->
        return yes if @check name
        @add name, type
        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, single=false) ->
        if single
          startCode = name.charCodeAt(0)
          endCode = 'z'.charCodeAt(0)
          diff = endCode - startCode
          newCode = startCode + index % (diff + 1)
          letter = String.fromCharCode(newCode)
          num = index // (diff + 1)
          "#{letter}#{num or ''}"
        else
          "#{name}#{index or ''}"
  • 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, options={}) ->
        index = 0
        loop
          temp = @temporary name, index, options.single
          break unless @check(temp) or temp in @root.referencedVars
          index++
        @add temp, 'var', yes if options.reserve ? true
        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: ->
        (v.name for v in @variables when v.type is 'var').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
coffeescript-1.12.7/docs/v1/annotated-source/sourcemap.html000066400000000000000000000474261313305734200237110ustar00rootroot00000000000000 sourcemap.litcoffee
  • sourcemap.litcoffee

  • Source maps allow JavaScript runtimes to match running JavaScript back to the original source code that corresponds to it. This can be minified JavaScript, but in our case, we’re concerned with mapping pretty-printed JavaScript back to CoffeeScript.

    In order to produce maps, we must keep track of positions (line number, column number) that originated every node in the syntax tree, and be able to generate a map file — which is a compact, VLQ-encoded representation of the JSON serialization of this information — to write out alongside the generated JavaScript.

    LineMap

  • A LineMap object keeps track of information about original line and column positions for a single line of output JavaScript code. SourceMaps are implemented in terms of LineMaps.

    class LineMap
      constructor: (@line) ->
        @columns = []
    
      add: (column, [sourceLine, sourceColumn], options={}) ->
        return if @columns[column] and options.noReplace
        @columns[column] = {line: @line, column, sourceLine, sourceColumn}
    
      sourceLocation: (column) ->
        column-- until (mapping = @columns[column]) or (column <= 0)
        mapping and [mapping.sourceLine, mapping.sourceColumn]
  • SourceMap

  • Maps locations in a single generated JavaScript file back to locations in the original CoffeeScript source file.

    This is intentionally agnostic towards how a source map might be represented on disk. Once the compiler is ready to produce a “v3”-style source map, we can walk through the arrays of line and column buffer to produce it.

    class SourceMap
      constructor: ->
        @lines = []
  • Adds a mapping to this SourceMap. sourceLocation and generatedLocation are both [line, column] arrays. If options.noReplace is true, then if there is already a mapping for the specified line and column, this will have no effect.

      add: (sourceLocation, generatedLocation, options = {}) ->
        [line, column] = generatedLocation
        lineMap = (@lines[line] or= new LineMap(line))
        lineMap.add column, sourceLocation, options
  • Look up the original position of a given line and column in the generated code.

      sourceLocation: ([line, column]) ->
        line-- until (lineMap = @lines[line]) or (line <= 0)
        lineMap and lineMap.sourceLocation column
  • V3 SourceMap Generation

  • Builds up a V3 source map, returning the generated JSON as a string. options.sourceRoot may be used to specify the sourceRoot written to the source map. Also, options.sourceFiles and options.generatedFile may be passed to set “sources” and “file”, respectively.

      generate: (options = {}, code = null) ->
        writingline       = 0
        lastColumn        = 0
        lastSourceLine    = 0
        lastSourceColumn  = 0
        needComma         = no
        buffer            = ""
    
        for lineMap, lineNumber in @lines when lineMap
          for mapping in lineMap.columns when mapping
            while writingline < mapping.line
              lastColumn = 0
              needComma = no
              buffer += ";"
              writingline++
  • Write a comma if we’ve already written a segment on this line.

            if needComma
              buffer += ","
              needComma = no
  • Write the next segment. Segments can be 1, 4, or 5 values. If just one, then it is a generated column which doesn’t match anything in the source code.

    The starting column in the generated source, relative to any previous recorded column for the current line:

            buffer += @encodeVlq mapping.column - lastColumn
            lastColumn = mapping.column
  • The index into the list of sources:

            buffer += @encodeVlq 0
  • The starting line in the original source, relative to the previous source line.

            buffer += @encodeVlq mapping.sourceLine - lastSourceLine
            lastSourceLine = mapping.sourceLine
  • The starting column in the original source, relative to the previous column.

            buffer += @encodeVlq mapping.sourceColumn - lastSourceColumn
            lastSourceColumn = mapping.sourceColumn
            needComma = yes
  • Produce the canonical JSON object format for a “v3” source map.

        v3 =
          version:    3
          file:       options.generatedFile or ''
          sourceRoot: options.sourceRoot or ''
          sources:    options.sourceFiles or ['']
          names:      []
          mappings:   buffer
    
        v3.sourcesContent = [code] if options.inlineMap
    
        v3
  • Base64 VLQ Encoding

  • Note that SourceMap VLQ encoding is “backwards”. MIDI-style VLQ encoding puts the most-significant-bit (MSB) from the original value into the MSB of the VLQ encoded value (see Wikipedia). SourceMap VLQ does things the other way around, with the least significat four bits of the original value encoded into the first byte of the VLQ encoded value.

      VLQ_SHIFT            = 5
      VLQ_CONTINUATION_BIT = 1 << VLQ_SHIFT             # 0010 0000
      VLQ_VALUE_MASK       = VLQ_CONTINUATION_BIT - 1   # 0001 1111
    
      encodeVlq: (value) ->
        answer = ''
  • Least significant bit represents the sign.

        signBit = if value < 0 then 1 else 0
  • The next bits are the actual value.

        valueToEncode = (Math.abs(value) << 1) + signBit
  • Make sure we encode at least one character, even if valueToEncode is 0.

        while valueToEncode or not answer
          nextChunk = valueToEncode & VLQ_VALUE_MASK
          valueToEncode = valueToEncode >> VLQ_SHIFT
          nextChunk |= VLQ_CONTINUATION_BIT if valueToEncode
          answer += @encodeBase64 nextChunk
    
        answer
  • Regular Base64 Encoding

  •   BASE64_CHARS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
    
      encodeBase64: (value) ->
        BASE64_CHARS[value] or throw new Error "Cannot Base64 encode value: #{value}"
  • Our API for source maps is just the SourceMap class.

    module.exports = SourceMap
coffeescript-1.12.7/docs/v1/index.html000066400000000000000000006676131313305734200175550ustar00rootroot00000000000000 CoffeeScript

CoffeeScript is a little language that compiles into JavaScript. Underneath that awkward Java-esque patina, JavaScript has always had a gorgeous 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, pretty-printed, and tends to run as fast or faster than the equivalent handwritten JavaScript.

The CoffeeScript compiler goes to great lengths to generate output JavaScript that runs in every JavaScript runtime, but there are exceptions. Use generator functions, for…from, or tagged template literals only if you know that your target runtimes can support them. If you use modules, you will need to use an additional tool to resolve them.

Latest Version: 1.12.7

npm install -g coffeescript

CoffeeScript 2 is coming! It adds support for ES2015 classes, async/await, JSX, object rest/spread syntax, and JavaScript generated using ES2015+ syntax. Learn more.

Overview

CoffeeScript on the left, compiled JavaScript output on the right.

# 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)
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;
})();
run: cubes

Installation

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

To install, first make sure you have a working copy of the latest stable version of Node.js. You can then install CoffeeScript globally with npm:

npm install --global coffeescript

This will make the coffee and cake commands available globally.

When you need CoffeeScript as a dependency of a project, within that project’s folder you can install it locally:

npm install --save coffeescript

The coffee and cake commands will first look in the current folder to see if CoffeeScript is installed locally, and use that version if so. This allows different versions of CoffeeScript to be installed globally and locally.

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:

Option Description
-c, --compile Compile a .coffee script into a .js JavaScript file of the same name.
-m, --map Generate source maps alongside the compiled JavaScript files. Adds sourceMappingURL directives to the JavaScript as well.
-M, --inline-map Just like --map, but include the source map directly in the compiled JavaScript files, rather than in a separate file.
-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.
-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.
-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
-l, --literate Parses the code as Literate CoffeeScript. You only need to specify this when passing in code directly over stdio, or using some sort of extension-less file name.
-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 [MODULE] require() the given module before starting the REPL or evaluating the code given with the --eval flag.
-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. Used for debugging the compiler.
-n, --nodes Instead of compiling the CoffeeScript, just lex and parse it, and print out the parse tree. Used for debugging the compiler.
--nodejs The node executable has some useful options you can set, such as --debug, --debug-brk, --max-stack-size, and --expose-gc. Use this flag to forward options directly to Node.js. To pass multiple flags, use --nodejs multiple times.
--no-header Suppress the “Generated by CoffeeScript” header.

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

Literate CoffeeScript

Besides being used as an ordinary programming language, CoffeeScript may also be written in “literate” mode. If you name your file with a .litcoffee extension, you can write it as a Markdown document — a document that also happens to be executable CoffeeScript code. The compiler will treat any indented blocks (Markdown’s way of indicating source code) as code, and ignore the rest as comments.

Just for kicks, a little bit of the compiler is currently implemented in this fashion: See it as a document, raw, and properly highlighted in a text editor.

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, which will be used if the incoming argument is missing (null or undefined).

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

CoffeeScript has a shortcut for creating objects when you want the key to be set with a variable of the same name.

name = "Michelangelo"
mask = "orange"
weapon = "nunchuks"
turtle = {name, mask, weapon}
output = "#{turtle.name} wears an #{turtle.mask} mask. Watch out for his #{turtle.weapon}!"
var mask, name, output, turtle, weapon;

name = "Michelangelo";

mask = "orange";

weapon = "nunchuks";

turtle = {
  name: name,
  mask: mask,
  weapon: weapon
};

output = turtle.name + " wears an " + turtle.mask + " mask. Watch out for his " + turtle.weapon + "!";
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; attach them as properties on the exports object in CommonJS; or use an export statement. If you’re targeting both CommonJS and the browser, the existential operator (covered below), gives you a reliable way to figure out where to add them: 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, j, k, l, len, len1, len2, ref;

ref = ['toast', 'cheese', 'wine'];
for (j = 0, len = ref.length; j < len; j++) {
  food = ref[j];
  eat(food);
}

courses = ['greens', 'caviar', 'truffles', 'roast', 'cake'];

for (i = k = 0, len1 = courses.length; k < len1; i = ++k) {
  dish = courses[i];
  menu(i + 1, dish);
}

foods = ['broccoli', 'spinach', 'chocolate'];

for (l = 0, len2 = foods.length; l < len2; l++) {
  food = foods[l];
  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)

If you don’t need the current iteration value you may omit it: browser.closeCurrentTab() for [0...count]

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.

To iterate a generator function, use from. See Generator Functions.

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...-2]

end     = numbers[-2..]

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, -2);

end = numbers.slice(-2);

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}"
)
var error;

alert((function() {
  try {
    return nonexistent / void 0;
  } catch (error1) {
    error = error1;
    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.

To simplify math expressions, ** can be used for exponentiation and // performs integer division. % works just like in JavaScript, while %% provides “dividend dependent modulo”:

-7 % 5 == -2 # The remainder of 7 / 5
-7 %% 5 == 3 # n %% 5 is always between 0 and 4

tabs.selectTabAtIndex((tabs.currentIndex - count) %% tabs.length)
var modulo = function(a, b) { return (+a % (b = +b) + b) % b; };

-7 % 5 === -2;

modulo(-7, 5) === 3;

tabs.selectTabAtIndex(modulo(tabs.currentIndex - count, tabs.length));
load

All together now:

CoffeeScript JavaScript
is ===
isnt !==
not !
and &&
or ||
true, yes, on true
false, no, off false
@, this this
of in
in no JS equivalent
a ** b Math.pow(a, b)
a // b Math.floor(a / b)
a %% b (a % b + b) % b
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 ref, zip;

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,
  extend = 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; },
  hasProp = {}.hasOwnProperty;

Animal = (function() {
  function Animal(name) {
    this.name = name;
  }

  Animal.prototype.move = function(meters) {
    return alert(this.name + (" moved " + meters + "m."));
  };

  return Animal;

})();

Snake = (function(superClass) {
  extend(Snake, superClass);

  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(superClass) {
  extend(Horse, superClass);

  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

Just like JavaScript (since ES2015), CoffeeScript has 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 ref, theBait, theSwitch;

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, ref, temp, weatherReport;

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

{sculptor} = futurists

{poet: {name, address: [street, city]}} = futurists
var city, futurists, name, ref, ref1, sculptor, street;

futurists = {
  sculptor: "Umberto Boccioni",
  painter: "Vladimir Burliuk",
  poet: {
    name: "F.T. Marinetti",
    address: ["Via Roma 42R", "Bellagio, Italy 22021"]
  }
};

sculptor = futurists.sculptor;

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, i, open, ref, tag,
  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("")

Expansion can be used to retrieve elements from the end of an array without having to assign the rest of its values. It works in function parameter lists as well.

text = "Every literary critic believes he will
        outwit history and have the last word"

[first, ..., last] = text.split " "
var first, last, ref, text;

text = "Every literary critic believes he will outwit history and have the last word";

ref = text.split(" "), first = ref[0], last = ref[ref.length - 1];
load
run: first + " " + last

Destructuring assignment is also useful when combined with class constructors to assign properties to your instance from an options object passed to the constructor.

class Person
  constructor: (options) ->
    {@name, @age, @height = 'average'} = options

tim = new Person name: 'Tim', age: 4
var Person, tim;

Person = (function() {
  function Person(options) {
    var ref;
    this.name = options.name, this.age = options.age, this.height = (ref = options.height) != null ? ref : 'average';
  }

  return Person;

})();

tim = new Person({
  name: 'Tim',
  age: 4
});
load
run: tim.age + " " + tim.height

The above example also demonstrates that if properties are missing in the destructured object or array, you can, just like in JavaScript, provide defaults. The difference with JavaScript is that CoffeeScript, as always, treats both null and undefined the same.

Bound Functions, Generator Functions

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 on. 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').on 'click', (event) =>
    @customer.purchase @cart
var Account;

Account = function(customer, cart) {
  this.customer = customer;
  this.cart = cart;
  return $('.shopping_cart').on('click', (function(_this) {
    return function(event) {
      return _this.customer.purchase(_this.cart);
    };
  })(this));
};
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.

CoffeeScript functions also support ES2015 generator functions through the yield keyword. There’s no function*(){} nonsense — a generator in CoffeeScript is simply a function that yields.

perfectSquares = ->
  num = 0
  loop
    num += 1
    yield num * num
  return

window.ps or= perfectSquares()
var perfectSquares;

perfectSquares = function*() {
  var num;
  num = 0;
  while (true) {
    num += 1;
    yield num * num;
  }
};

window.ps || (window.ps = perfectSquares());
load
run: ps.next().value

yield* is called yield from, and yield return may be used if you need to force a generator that doesn’t yield.

You can iterate over a generator function using for…from.

fibonacci = ->
  [previous, current] = [1, 1]
  loop
    [previous, current] = [current, previous + current]
    yield current
  return

getFibonacciNumbers = (length) ->
  results = [1]
  for n from fibonacci()
    results.push n
    break if results.length is length
  results
var fibonacci, getFibonacciNumbers;

fibonacci = function*() {
  var current, previous, ref, ref1;
  ref = [1, 1], previous = ref[0], current = ref[1];
  while (true) {
    ref1 = [current, previous + current], previous = ref1[0], current = ref1[1];
    yield current;
  }
};

getFibonacciNumbers = function(length) {
  var n, ref, results;
  results = [1];
  ref = fibonacci();
  for (n of ref) {
    results.push(n);
    if (results.length === length) {
      break;
    }
  }
  return results;
};
load
run: getFibonacciNumbers(10)

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

Escape backticks with backslashes: \`​ becomes `​.

Escape backslashes before backticks with more backslashes: \\\`​ becomes \`​.

markdown = `function () {
  return \`In Markdown, write code like \\\`this\\\`\`;
}`
var markdown;

markdown = function () {
  return `In Markdown, write code like \`this\``;
};
load
run: markdown()

You can also embed blocks of JavaScript using triple backticks. That’s easier than escaping backticks, if you need them inside your JavaScript block.

```
function time() {
  return `The time is ${new Date().toLocaleTimeString()}`;
}
```

function time() {
  return `The time is ${new Date().toLocaleTimeString()}`;
}
;

load
run: time()

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

Switch statements can also be used without a control expression, turning them in to a cleaner alternative to if/else chains.

score = 76
grade = switch
  when score < 60 then 'F'
  when score < 70 then 'D'
  when score < 80 then 'C'
  when score < 90 then 'B'
  else 'A'
# grade == 'C'
var grade, score;

score = 76;

grade = (function() {
  switch (false) {
    case !(score < 60):
      return 'F';
    case !(score < 70):
      return 'D';
    case !(score < 80):
      return 'C';
    case !(score < 90):
      return 'B';
    default:
      return 'A';
  }
})();
load

Try/Catch/Finally

Try-expressions have the same semantics as try-statements in JavaScript, though in CoffeeScript, you may omit both the catch and finally parts. The catch part may also omit the error parameter if it is not needed.

try
  allHellBreaksLoose()
  catsAndDogsLivingTogether()
catch error
  print error
finally
  cleanUp()
var error;

try {
  allHellBreaksLoose();
  catsAndDogsLivingTogether();
} catch (error1) {
  error = error1;
  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. You may even use interpolation in object keys.

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. Lines are joined by a single space unless they end with a backslash. Indentation is ignored.

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.

###
SkinnyMochaHalfCaffScript Compiler v1.0
Released under the MIT License
###

/*
SkinnyMochaHalfCaffScript Compiler v1.0
Released under the MIT License
 */

load

Tagged Template Literals

CoffeeScript supports ES2015 tagged template literals, which enable customized string interpolation. If you immediately prefix a string with a function name (no space between the two), CoffeeScript will output this “function plus string” combination as an ES2015 tagged template literal, which will behave accordingly: the function is called, with the parameters being the input text and expression parts that make up the interpolated string. The function can then assemble these parts into an output string, providing custom string interpolation.

Be aware that the CoffeeScript compiler is outputting ES2015 syntax for this feature, so your target JavaScript runtime(s) must support this syntax for your code to work; or you could use tools like Babel or Traceur Compiler to convert this ES2015 syntax into compatible JavaScript.

upperCaseExpr = (textParts, expressions...) ->
  textParts.reduce (text, textPart, i) ->
    text + expressions[i - 1].toUpperCase() + textPart

greet = (name, adjective) ->
  upperCaseExpr"""
               Hi #{name}. You look #{adjective}!
               """
var greet, upperCaseExpr,
  slice = [].slice;

upperCaseExpr = function() {
  var expressions, textParts;
  textParts = arguments[0], expressions = 2 <= arguments.length ? slice.call(arguments, 1) : [];
  return textParts.reduce(function(text, textPart, i) {
    return text + expressions[i - 1].toUpperCase() + textPart;
  });
};

greet = function(name, adjective) {
  return upperCaseExpr`Hi ${name}. You look ${adjective}!`;
};
load
run: greet("greg", "awesome")

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, CoffeeScript’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

Modules

ES2015 modules are supported in CoffeeScript, with very similar import and export syntax:

import 'local-file.coffee'
import 'coffeescript'

import _ from 'underscore'
import * as underscore from 'underscore'

import { now } from 'underscore'
import { now as currentTimestamp } from 'underscore'
import { first, last } from 'underscore'
import utilityBelt, { each } from 'underscore'

export default Math
export square = (x) -> x * x
export class Mathematics
  least: (x, y) -> if x < y then x else y

export { sqrt }
export { sqrt as squareRoot }
export { Mathematics as default, sqrt as squareRoot }

export * from 'underscore'
export { max, min } from 'underscore'
import 'local-file.coffee';

import 'coffeescript';

import _ from 'underscore';

import * as underscore from 'underscore';

import {
  now
} from 'underscore';

import {
  now as currentTimestamp
} from 'underscore';

import {
  first,
  last
} from 'underscore';

import utilityBelt, {
  each
} from 'underscore';

export default Math;

export var square = function(x) {
  return x * x;
};

export var Mathematics = (function() {
  function Mathematics() {}

  Mathematics.prototype.least = function(x, y) {
    if (x < y) {
      return x;
    } else {
      return y;
    }
  };

  return Mathematics;

})();

export {
  sqrt
};

export {
  sqrt as squareRoot
};

export {
  Mathematics as default,
  sqrt as squareRoot
};

export * from 'underscore';

export {
  max,
  min
} from 'underscore';
load

Note that the CoffeeScript compiler does not resolve modules; writing an import or export statement in CoffeeScript will produce an import or export statement in the resulting output. It is your responsibility attach another transpiler, such as Traceur Compiler, Babel or Rollup, to convert this ES2015 syntax into code that will work in your target runtimes.

Also note that any file with an import or export statement will be output without a top-level function safety wrapper; in other words, importing or exporting modules will automatically trigger bare mode for that file. This is because per the ES2015 spec, import or export statements must occur at the topmost scope.

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.

Source Maps

CoffeeScript 1.6.1 and above include support for generating source maps, a way to tell your JavaScript engine what part of your CoffeeScript program matches up with the code being evaluated. Browsers that support it can automatically use source maps to show your original source code in the debugger. To generate source maps alongside your JavaScript files, pass the --map or -m flag to the compiler.

For a full introduction to source maps, how they work, and how to hook them up in your browser, read the HTML5 Tutorial.

“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, 51k when gzipped) as v1/browser-compiler/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, now PluralSight. 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 a 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.
  • technoweenie’s Coffee-Resque, a port of Resque for Node.js.
  • stephank’s Orona, a remake of the Bolo tank game for modern browsers.
  • GitHub’s Atom, a hackable text editor built on web technologies.
  • Basecamp’s Trix, a rich text editor for web apps.

Resources

  • Source Code
    Use bin/coffee to test your changes,
    bin/cake test to run the test suite,
    bin/cake build to rebuild the full CoffeeScript compiler, and
    bin/cake build:except-parser to recompile much faster if you’re not editing grammar.coffee.

    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 folder (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.

  • Browser Tests
    Run CoffeeScript’s test suite in your current browser.

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

  • JS2Coffee
    Is a very well done reverse JavaScript-to-CoffeeScript compiler. It’s not going to be perfect (infer what your JavaScript classes are, when you need bound functions, and so on…) — but it’s a great starting point for converting simple scripts.

  • High-Rez Logo
    The CoffeeScript logo is available in SVG 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.12.7

  • Fix regressions in 1.12.6 related to chained function calls and indented return and throw arguments.
  • The REPL no longer warns about assigning to _.

1.12.6

  • The return and export keywords can now accept implicit objects (defined by indentation, without needing braces).
  • Support Unicode code point escapes (e.g. \u{1F4A9}).
  • The coffee command now first looks to see if CoffeeScript is installed under node_modules in the current folder, and executes the coffee binary there if so; or otherwise it runs the globally installed one. This allows you to have one version of CoffeeScript installed globally and a different one installed locally for a particular project. (Likewise for the cake command.)
  • Bugfixes for chained function calls not closing implicit objects or ternaries.
  • Bugfixes for incorrect code generated by the ? operator within a termary if statement.
  • Fixed some tests, and failing tests now result in a nonzero exit code.

1.12.5

  • Better handling of default, from, as and * within import and export statements. You can now import or export a member named default and the compiler won’t interpret it as the default keyword.
  • Fixed a bug where invalid octal escape sequences weren’t throwing errors in the compiler.

1.12.4

  • The cake commands have been updated, with new watch options for most tasks. Clone the CoffeeScript repo and run cake at the root of the repo to see the options.
  • Fixed a bug where exporting a referenced variable was preventing the variable from being declared.
  • Fixed a bug where the coffee command wasn’t working for a .litcoffee file.
  • Bugfixes related to tokens and location data, for better source maps and improved compatibility with downstream tools.

1.12.3

  • @ values can now be used as indices in for expressions. This loosens the compilation of for expressions to allow the index variable to be an @ value, e.g. do @visit for @node, @index in nodes. Within @visit, the index of the current node (@node) would be available as @index.
  • CoffeeScript’s patched Error.prepareStackTrace has been restored, with some revisions that should prevent the erroneous exceptions that were making life difficult for some downstream projects. This fixes the incorrect line numbers in stack traces since 1.12.2.
  • The //= operator’s output now wraps parentheses around the right operand, like the other assignment operators.

1.12.2

  • The browser compiler can once again be built unminified via MINIFY=false cake build:browser.
  • The error-prone patched version of Error.prepareStackTrace has been removed.
  • Command completion in the REPL (pressing tab to get suggestions) has been fixed for Node 6.9.1+.
  • The browser-based tests now include all the tests as the Node-based version.

1.12.1

  • You can now import a module member named default, e.g. import { default } from 'lib'. Though like in ES2015, you cannot import an entire module and name it default (so import default from 'lib' is not allowed).
  • Fix regression where from as a variable name was breaking for loop declarations. For the record, from is not a reserved word in CoffeeScript; you may use it for variable names. from behaves like a keyword within the context of import and export statements, and in the declaration of a for loop; though you should also be able to use variables named from in those contexts, and the compiler should be able to tell the difference.

1.12.0

  • CoffeeScript now supports ES2015 tagged template literals. Note that using tagged template literals in your code makes you responsible for ensuring that either your runtime supports tagged template literals or that you transpile the output JavaScript further to a version your target runtime(s) support.
  • CoffeeScript now provides a for…from syntax for outputting ES2015 for…of. (Sorry they couldn’t match, but we came up with for…of first for something else.) This allows iterating over generators or any other iterable object. Note that using for…from in your code makes you responsible for ensuring that either your runtime supports for…of or that you transpile the output JavaScript further to a version your target runtime(s) support.
  • Triple backticks (```​) allow the creation of embedded JavaScript blocks where escaping single backticks is not required, which should improve interoperability with ES2015 template literals and with Markdown.
  • Within single-backtick embedded JavaScript, backticks can now be escaped via \`​.
  • The browser tests now run in the browser again, and are accessible here if you would like to test your browser.
  • CoffeeScript-only keywords in ES2015 imports and exports are now ignored.
  • The compiler now throws an error on trying to export an anonymous class.
  • Bugfixes related to tokens and location data, for better source maps and improved compatibility with downstream tools.

1.11.1

  • Bugfix for shorthand object syntax after interpolated keys.
  • Bugfix for indentation-stripping in """ strings.
  • Bugfix for not being able to use the name “arguments” for a prototype property of class.
  • Correctly compile large hexadecimal numbers literals to 2e308 (just like all other large number literals do).

1.11.0

  • CoffeeScript now supports ES2015 import and export syntax.

  • Added the -M, --inline-map flag to the compiler, allowing you embed the source map directly into the output JavaScript, rather than as a separate file.

  • A bunch of fixes for yield:

    • yield return can no longer mistakenly be used as an expression.

    • yield now mirrors return in that it can be used stand-alone as well as with expressions. Where you previously wrote yield undefined, you may now write simply yield. However, this means also inheriting the same syntax limitations that return has, so these examples no longer compile:

      doubles = ->
        yield for i in [1..3]
          i * 2
      six = ->
        yield
          2 * 3
      
    • The JavaScript output is a bit nicer, with unnecessary parentheses and spaces, double indentation and double semicolons around yield no longer present.

  • &&=, ||=, and= and or= no longer accidentally allow a space before the equals sign.

  • Improved several error messages.

  • Just like undefined compiles to void 0, NaN now compiles into 0/0 and Infinity into 2e308.

  • Bugfix for renamed destructured parameters with defaults. ({a: b = 1}) -> no longer crashes the compiler.

  • Improved the internal representation of a CoffeeScript program. This is only noticeable to tools that use CoffeeScript.tokens or CoffeeScript.nodes. Such tools need to update to take account for changed or added tokens and nodes.

  • Several minor bug fixes, including:

    • The caught error in catch blocks is no longer declared unnecessarily, and no longer mistakenly named undefined for catch-less try blocks.
    • Unassignable parameter destructuring no longer crashes the compiler.
    • Source maps are now used correctly for errors thrown from .coffee.md files.
    • coffee -e 'throw null' no longer crashes.
    • The REPL no longer crashes when using .exit to exit it.
    • Invalid JavaScript is no longer output when lots of for loops are used in the same scope.
    • A unicode issue when using stdin with the CLI.

1.10.0

  • CoffeeScript now supports ES2015-style destructuring defaults.

  • (offsetHeight: height) -> no longer compiles. That syntax was accidental and partly broken. Use ({offsetHeight: height}) -> instead. Object destructuring always requires braces.

  • Several minor bug fixes, including:

    • A bug where the REPL would sometimes report valid code as invalid, based on what you had typed earlier.
    • A problem with multiple JS contexts in the jest test framework.
    • An error in io.js where strict mode is set on internal modules.
    • A variable name clash for the caught error in catch blocks.

1.9.3

  • Bugfix for interpolation in the first key of an object literal in an implicit call.
  • Fixed broken error messages in the REPL, as well as a few minor bugs with the REPL.
  • Fixed source mappings for tokens at the beginning of lines when compiling with the --bare option. This has the nice side effect of generating smaller source maps.
  • Slight formatting improvement of compiled block comments.
  • Better error messages for on, off, yes and no.

1.9.2

  • Fixed a watch mode error introduced in 1.9.1 when compiling multiple files with the same filename.
  • Bugfix for yield around expressions containing this.
  • Added a Ruby-style -r option to the REPL, which allows requiring a module before execution with --eval or --interactive.
  • In <script type="text/coffeescript"> tags, to avoid possible duplicate browser requests for .coffee files, you can now use the data-src attribute instead of src.
  • Minor bug fixes for IE8, strict ES5 regular expressions and Browserify.

1.9.1

  • Interpolation now works in object literal keys (again). You can use this to dynamically name properties.
  • Internal compiler variable names no longer start with underscores. This makes the generated JavaScript a bit prettier, and also fixes an issue with the completely broken and ungodly way that AngularJS “parses” function arguments.
  • Fixed a few yield-related edge cases with yield return and yield throw.
  • Minor bug fixes and various improvements to compiler error messages.

1.9.0

  • CoffeeScript now supports ES2015 generators. A generator is simply a function that yields.
  • More robust parsing and improved error messages for strings and regexes — especially with respect to interpolation.
  • Changed strategy for the generation of internal compiler variable names. Note that this means that @example function parameters are no longer available as naked example variables within the function body.
  • Fixed REPL compatibility with latest versions of Node and Io.js.
  • Various minor bug fixes.

1.8.0

  • The --join option of the CLI is now deprecated.
  • Source maps now use .js.map as file extension, instead of just .map.
  • The CLI now exits with the exit code 1 when it fails to write a file to disk.
  • The compiler no longer crashes on unterminated, single-quoted strings.
  • Fixed location data for string interpolations, which made source maps out of sync.
  • The error marker in error messages is now correctly positioned if the code is indented with tabs.
  • Fixed a slight formatting error in CoffeeScript’s source map-patched stack traces.
  • The %% operator now coerces its right operand only once.
  • It is now possible to require CoffeeScript files from Cakefiles without having to register the compiler first.
  • The CoffeeScript REPL is now exported and can be required using require 'coffee-script/repl'.
  • Fixes for the REPL in Node 0.11.

1.7.1

  • Fixed a typo that broke node module lookup when running a script directly with the coffee binary.

1.7.0

  • When requiring CoffeeScript files in Node you must now explicitly register the compiler. This can be done with require 'coffee-script/register' or CoffeeScript.register(). Also for configuration such as Mocha’s, use coffee-script/register.
  • Improved error messages, source maps and stack traces. Source maps now use the updated //# syntax.
  • Leading . now closes all open calls, allowing for simpler chaining syntax.
$ 'body'
.click (e) ->
  $ '.box'
  .fadeIn 'fast'
  .addClass '.active'
.css 'background', 'white'
$('body').click(function(e) {
  return $('.box').fadeIn('fast').addClass('.active');
}).css('background', 'white');
load

  • Added **, // and %% operators and ... expansion in parameter lists and destructuring expressions.
  • Multiline strings are now joined by a single space and ignore all indentation. A backslash at the end of a line can denote the amount of whitespace between lines, in both strings and heredocs. Backslashes correctly escape whitespace in block regexes.
  • Closing brackets can now be indented and therefore no longer cause unexpected error.
  • Several breaking compilation fixes. Non-callable literals (strings, numbers etc.) don’t compile in a call now and multiple postfix conditionals compile properly. Postfix conditionals and loops always bind object literals. Conditional assignment compiles properly in subexpressions. super is disallowed outside of methods and works correctly inside for loops.
  • Formatting of compiled block comments has been improved.
  • No more -p folders on Windows.
  • The options object passed to CoffeeScript is no longer mutated.

1.6.3

  • The CoffeeScript REPL now remembers your history between sessions. Just like a proper REPL should.
  • You can now use require in Node to load .coffee.md Literate CoffeeScript files. In the browser, text/literate-coffeescript script tags.
  • The old coffee --lint command has been removed. It was useful while originally working on the compiler, but has been surpassed by JSHint. You may now use -l to pass literate files in over stdio.
  • Bugfixes for Windows path separators, catch without naming the error, and executable-class-bodies-with- prototypal-property-attachment.

1.6.2

  • Source maps have been used to provide automatic line-mapping when running CoffeeScript directly via the coffee command, and for automatic line-mapping when running CoffeeScript directly in the browser. Also, to provide better error messages for semantic errors thrown by the compiler — with colors, even.
  • Improved support for mixed literate/vanilla-style CoffeeScript projects, and generating source maps for both at the same time.
  • Fixes for 1.6.x regressions with overriding inherited bound functions, and for Windows file path management.
  • The coffee command can now correctly fork() both .coffee and .js files. (Requires Node.js 0.9+)

1.6.1

  • First release of source maps. Pass the --map flag to the compiler, and off you go. Direct all your thanks over to Jason Walton.
  • Fixed a 1.5.0 regression with multiple implicit calls against an indented implicit object. Combinations of implicit function calls and implicit objects should generally be parsed better now — but it still isn’t good style to nest them too heavily.
  • .coffee.md is now also supported as a Literate CoffeeScript file extension, for existing tooling. .litcoffee remains the canonical one.
  • Several minor fixes surrounding member properties, bound methods and super in class declarations.

1.5.0

  • First release of Literate CoffeeScript.
  • The CoffeeScript REPL is now based on the Node.js REPL, and should work better and more familiarly.
  • Returning explicit values from constructors is now forbidden. If you want to return an arbitrary value, use a function, not a constructor.
  • You can now loop over an array backwards, without having to manually deal with the indexes: for item in list by -1
  • Source locations are now preserved in the CoffeeScript AST, although source maps are not yet being emitted.

1.4.0

  • 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

  • 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

  • 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 improvements 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

  • 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

  • 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

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

Bugfix release for classes with external constructor functions, see issue #1182.

1.1.0

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Upgraded CoffeeScript for compatibility with the new Node.js v0.1.90 series.

0.6.0

Trailing commas are now allowed, a-la Python. Static properties may be assigned directly within class definitions, using @property notation.

0.5.6

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

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

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

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

Added a compressed version of the compiler for inclusion in web pages as /v1/browser-compiler/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

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

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

@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

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

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

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

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

Axed the unsatisfactory ino keyword, replacing it with of for object comprehensions. They now look like: for prop, value of object.

0.2.2

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

Arguments objects are now converted into real arrays when referenced.

0.2.0

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

Bugfix for running coffee --interactive and --run from outside of the CoffeeScript directory. Bugfix for nested function/if-statements.

0.1.5

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

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

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

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

Added instanceof and typeof as operators.

0.1.0

Initial CoffeeScript release.

coffeescript-1.12.7/docs/v1/test.html000066400000000000000000007715461313305734200174260ustar00rootroot00000000000000 CoffeeScript Test Suite

CoffeeScript Test Suite















































coffeescript-1.12.7/docs/v2/000077500000000000000000000000001313305734200155365ustar00rootroot00000000000000coffeescript-1.12.7/docs/v2/annotated-source/000077500000000000000000000000001313305734200210115ustar00rootroot00000000000000coffeescript-1.12.7/docs/v2/annotated-source/browser.html000066400000000000000000000335061313305734200233710ustar00rootroot00000000000000



  browser.coffee
  
  
  


  
  • browser.coffee

  • This Browser compatibility layer extends core CoffeeScript functions to make things work smoothly when compiling code directly in the browser. We add support for loading remote Coffee scripts via XHR, and text/coffeescript script tags, source maps via data-URLs, and so on.

    CoffeeScript = require './coffeescript'
    compile = CoffeeScript.compile
  • Use standard JavaScript eval to eval code.

    CoffeeScript.eval = (code, options = {}) ->
      options.bare ?= on
      eval compile code, options
  • Running code does not provide access to this scope.

    CoffeeScript.run = (code, options = {}) ->
      options.bare      = on
      options.shiftLine = on
      Function(compile code, options)()
  • Export this more limited CoffeeScript than what is exported by index.coffee, which is intended for a Node environment.

    module.exports = CoffeeScript
  • If we’re not in a browser environment, we’re finished with the public API.

    return unless window?
  • Include source maps where possible. If we’ve got a base64 encoder, a JSON serializer, and tools for escaping unicode characters, we’re good to go. Ported from https://developer.mozilla.org/en-US/docs/DOM/window.btoa

    if btoa? and JSON?
      compile = (code, options = {}) ->
        options.inlineMap = true
        CoffeeScript.compile code, options
  • Load a remote script from the current domain via XHR.

    CoffeeScript.load = (url, callback, options = {}, hold = false) ->
      options.sourceFiles = [url]
      xhr = if window.ActiveXObject
        new window.ActiveXObject('Microsoft.XMLHTTP')
      else
        new window.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]
            param = [xhr.responseText, options]
            CoffeeScript.run param... unless hold
          else
            throw new Error "Could not load #{url}"
          callback param 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 = window.document.getElementsByTagName 'script'
      coffeetypes = ['text/coffeescript', 'text/literate-coffeescript']
      coffees = (s for s in scripts when s.type in coffeetypes)
      index = 0
    
      execute = ->
        param = coffees[index]
        if param instanceof Array
          CoffeeScript.run param...
          index++
          execute()
    
      for script, i in coffees
        do (script, i) ->
          options = literate: script.type is coffeetypes[1]
          source = script.src or script.getAttribute('data-src')
          if source
            options.filename = source
            CoffeeScript.load source,
              (param) ->
                coffees[i] = param
                execute()
              options
              true
          else
  • options.filename defines the filename the source map appears as in Developer Tools. If a script tag has an id, use that as the filename; otherwise use coffeescript, or coffeescript1 etc., leaving the first one unnumbered for the common case that there’s only one CoffeeScript script block to parse.

            options.filename = if script.id and script.id isnt '' then script.id else "coffeescript#{if i isnt 0 then i else ''}"
            options.sourceFiles = ['embedded']
            coffees[i] = [script.innerHTML, options]
    
      execute()
  • Listen for window load, both in decent browsers and in IE.

    if window.addEventListener
      window.addEventListener 'DOMContentLoaded', runScripts, no
    else
      window.attachEvent 'onload', runScripts
coffeescript-1.12.7/docs/v2/annotated-source/cake.html000066400000000000000000000336751313305734200226200ustar00rootroot00000000000000 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 './'
  • Register .coffee extension

    CoffeeScript.register()
  • 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 fs.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()}"
coffeescript-1.12.7/docs/v2/annotated-source/coffeescript.html000066400000000000000000001037071313305734200243630ustar00rootroot00000000000000 coffeescript.coffee
  • coffeescript.coffee

  • CoffeeScript can be used both on the server, as a command-line compiler based on Node.js/V8, or to run CoffeeScript directly in the browser. This module contains the main entry functions for tokenizing, parsing, and compiling source CoffeeScript into JavaScript.

    {Lexer}       = require './lexer'
    {parser}      = require './parser'
    helpers       = require './helpers'
    SourceMap     = require './sourcemap'
  • Require package.json, which is two levels above this file, as this file is evaluated from lib/coffeescript.

    packageJson   = require '../../package.json'
  • The current CoffeeScript version number.

    exports.VERSION = packageJson.version
    
    exports.FILE_EXTENSIONS = ['.coffee', '.litcoffee', '.coffee.md']
  • Expose helpers for testing.

    exports.helpers = helpers
  • Function that allows for btoa in both nodejs and the browser.

    base64encode = (src) -> switch
      when typeof Buffer is 'function'
        Buffer.from(src).toString('base64')
      when typeof btoa is 'function'
  • The contents of a <script> block are encoded via UTF-16, so if any extended characters are used in the block, btoa will fail as it maxes out at UTF-8. See https://developer.mozilla.org/en-US/docs/Web/API/WindowBase64/Base64_encoding_and_decoding#The_Unicode_Problem for the gory details, and for the solution implemented here.

        btoa encodeURIComponent(src).replace /%([0-9A-F]{2})/g, (match, p1) ->
          String.fromCharCode '0x' + p1
      else
        throw new Error('Unable to base64 encode inline sourcemap.')
  • Function wrapper to add source file information to SyntaxErrors thrown by the lexer/parser/compiler.

    withPrettyErrors = (fn) ->
      (code, options = {}) ->
        try
          fn.call @, code, options
        catch err
          throw err if typeof code isnt 'string' # Support `CoffeeScript.nodes(tokens)`.
          throw helpers.updateSyntaxError err, code, options.filename
  • For each compiled file, save its source in memory in case we need to recompile it later. We might need to recompile if the first compilation didn’t create a source map (faster) but something went wrong and we need a stack trace. Assuming that most of the time, code isn’t throwing exceptions, it’s probably more efficient to compile twice only when we need a stack trace, rather than always generating a source map even when it’s not likely to be used. Save in form of filename: (source)

    sources = {}
  • Also save source maps if generated, in form of filename: (source map).

    sourceMaps = {}
  • Compile CoffeeScript code to JavaScript, using the Coffee/Jison compiler.

    If options.sourceMap is specified, then options.filename must also be specified. All options that can be passed to SourceMap#generate may also be passed here.

    This returns a javascript string, unless options.sourceMap is passed, in which case this returns a {js, v3SourceMap, sourceMap} object, where sourceMap is a sourcemap.coffee#SourceMap object, handy for doing programmatic lookups.

    exports.compile = compile = withPrettyErrors (code, options) ->
      {merge, extend} = helpers
      options = extend {}, options
  • Always generate a source map if no filename is passed in, since without a a filename we have no way to retrieve this source later in the event that we need to recompile it to get a source map for prepareStackTrace.

      generateSourceMap = options.sourceMap or options.inlineMap or not options.filename?
      filename = options.filename or '<anonymous>'
    
      sources[filename] = code
      map = new SourceMap if generateSourceMap
    
      tokens = lexer.tokenize code, options
  • Pass a list of referenced variables, so that generated variables won’t get the same name.

      options.referencedVars = (
        token[1] for token in tokens when token[0] is 'IDENTIFIER'
      )
  • Check for import or export; if found, force bare mode.

      unless options.bare? and options.bare is yes
        for token in tokens
          if token[0] in ['IMPORT', 'EXPORT']
            options.bare = yes
            break
    
      fragments = parser.parse(tokens).compileToFragments options
    
      currentLine = 0
      currentLine += 1 if options.header
      currentLine += 1 if options.shiftLine
      currentColumn = 0
      js = ""
      for fragment in fragments
  • Update the sourcemap with data from each fragment.

        if generateSourceMap
  • Do not include empty, whitespace, or semicolon-only fragments.

          if fragment.locationData and not /^[;\s]*$/.test fragment.code
            map.add(
              [fragment.locationData.first_line, fragment.locationData.first_column]
              [currentLine, currentColumn]
              {noReplace: true})
          newLines = helpers.count fragment.code, "\n"
          currentLine += newLines
          if newLines
            currentColumn = fragment.code.length - (fragment.code.lastIndexOf("\n") + 1)
          else
            currentColumn += fragment.code.length
  • Copy the code from each fragment into the final JavaScript.

        js += fragment.code
    
      if options.header
        header = "Generated by CoffeeScript #{@VERSION}"
        js = "// #{header}\n#{js}"
    
      if generateSourceMap
        v3SourceMap = map.generate(options, code)
        sourceMaps[filename] = map
    
      if options.inlineMap
        encoded = base64encode JSON.stringify v3SourceMap
        sourceMapDataURI = "//# sourceMappingURL=data:application/json;base64,#{encoded}"
        sourceURL = "//# sourceURL=#{options.filename ? 'coffeescript'}"
        js = "#{js}\n#{sourceMapDataURI}\n#{sourceURL}"
    
      if options.sourceMap
        {
          js
          sourceMap: map
          v3SourceMap: JSON.stringify v3SourceMap, null, 2
        }
      else
        js
  • Tokenize a string of CoffeeScript code, and return the array of tokens.

    exports.tokens = withPrettyErrors (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 = withPrettyErrors (source, options) ->
      if typeof source is 'string'
        parser.parse lexer.tokenize source, options
      else
        parser.parse source
  • This file used to export these methods; leave stubs that throw warnings instead. These methods have been moved into index.coffee to provide separate entrypoints for Node and non-Node environments, so that static analysis tools don’t choke on Node packages when compiling for a non-Node environment.

    exports.run = exports.eval = exports.register = ->
      throw new Error 'require index.coffee, not this file'
  • 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: ->
        token = parser.tokens[@pos++]
        if token
          [tag, @yytext, @yylloc] = token
          parser.errorToken = token.origin or token
          @yylineno = @yylloc.first_line
        else
          tag = ''
    
        tag
      setInput: (tokens) ->
        parser.tokens = tokens
        @pos = 0
      upcomingInput: ->
        ""
  • Make all the AST nodes visible to the parser.

    parser.yy = require './nodes'
  • Override Jison’s default error handling function.

    parser.yy.parseError = (message, {token}) ->
  • Disregard Jison’s message, it contains redundant line number information. Disregard the token, we take its value directly from the lexer in case the error is caused by a generated token which might refer to its origin.

      {errorToken, tokens} = parser
      [errorTag, errorText, errorLoc] = errorToken
    
      errorText = switch
        when errorToken is tokens[tokens.length - 1]
          'end of input'
        when errorTag in ['INDENT', 'OUTDENT']
          'indentation'
        when errorTag in ['IDENTIFIER', 'NUMBER', 'INFINITY', 'STRING', 'STRING_START', 'REGEX', 'REGEX_START']
          errorTag.replace(/_START$/, '').toLowerCase()
        else
          helpers.nameWhitespaceCharacter errorText
  • The second argument has a loc property, which should have the location data for this token. Unfortunately, Jison seems to send an outdated loc (from the previous token), so we take the location information directly from the lexer.

      helpers.throwSyntaxError "unexpected #{errorText}", errorLoc
  • formatSourcePosition = (frame, getSourceMapping) ->
      filename = undefined
      fileLocation = ''
    
      if frame.isNative()
        fileLocation = "native"
      else
        if frame.isEval()
          filename = frame.getScriptNameOrSourceURL()
          fileLocation = "#{frame.getEvalOrigin()}, " unless filename
        else
          filename = frame.getFileName()
    
        filename or= "<anonymous>"
    
        line = frame.getLineNumber()
        column = frame.getColumnNumber()
  • Check for a sourceMap position

        source = getSourceMapping filename, line, column
        fileLocation =
          if source
            "#{filename}:#{source[0]}:#{source[1]}"
          else
            "#{filename}:#{line}:#{column}"
    
      functionName = frame.getFunctionName()
      isConstructor = frame.isConstructor()
      isMethodCall = not (frame.isToplevel() or isConstructor)
    
      if isMethodCall
        methodName = frame.getMethodName()
        typeName = frame.getTypeName()
    
        if functionName
          tp = as = ''
          if typeName and functionName.indexOf typeName
            tp = "#{typeName}."
          if methodName and functionName.indexOf(".#{methodName}") isnt functionName.length - methodName.length - 1
            as = " [as #{methodName}]"
    
          "#{tp}#{functionName}#{as} (#{fileLocation})"
        else
          "#{typeName}.#{methodName or '<anonymous>'} (#{fileLocation})"
      else if isConstructor
        "new #{functionName or '<anonymous>'} (#{fileLocation})"
      else if functionName
        "#{functionName} (#{fileLocation})"
      else
        fileLocation
    
    getSourceMap = (filename) ->
      if sourceMaps[filename]?
        sourceMaps[filename]
  • CoffeeScript compiled in a browser may get compiled with options.filename of <anonymous>, but the browser may request the stack trace with the filename of the script file.

      else if sourceMaps['<anonymous>']?
        sourceMaps['<anonymous>']
      else if sources[filename]?
        answer = compile sources[filename],
          filename: filename
          sourceMap: yes
          literate: helpers.isLiterate filename
        answer.sourceMap
      else
        null
  • Based on michaelficarra/CoffeeScriptRedux NodeJS / V8 have no support for transforming positions in stack traces using sourceMap, so we must monkey-patch Error to display CoffeeScript source positions.

    Error.prepareStackTrace = (err, stack) ->
      getSourceMapping = (filename, line, column) ->
        sourceMap = getSourceMap filename
        answer = sourceMap.sourceLocation [line - 1, column - 1] if sourceMap?
        if answer? then [answer[0] + 1, answer[1] + 1] else null
    
      frames = for frame in stack
        break if frame.getFunction() is exports.run
        "    at #{formatSourcePosition frame, getSourceMapping}"
    
      "#{err.toString()}\n#{frames.join '\n'}\n"
coffeescript-1.12.7/docs/v2/annotated-source/command.html000066400000000000000000001343751313305734200233320ustar00rootroot00000000000000 command.coffee
  • command.coffee

  • The coffee utility. Handles command-line compilation of CoffeeScript into various forms: saved into .js files or printed to stdout 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 './'
    {spawn, exec}  = require 'child_process'
    {EventEmitter} = require 'events'
    
    useWinPathSep  = path.sep is '\\'
  • 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 in conjunction with -h/--help.

    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']
      ['-m', '--map',             'generate source map and save as .js.map files']
      ['-M', '--inline-map',      'generate source map and include it directly in output']
      ['-n', '--nodes',           'print out the parse tree that the parser produces']
      [      '--nodejs [ARGS]',   'pass options directly to the "node" binary']
      [      '--no-header',       'suppress the "Generated by" header']
      ['-o', '--output [DIR]',    'set the output directory for compiled JavaScript']
      ['-p', '--print',           'print out the compiled JavaScript']
      ['-r', '--require [MODULE*]', 'require the given module before eval or REPL']
      ['-s', '--stdio',           'listen for and compile scripts over stdio']
      ['-l', '--literate',        'treat stdio as literate style coffeescript']
      ['-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   = {}
    watchedDirs  = {}
    optionParser = null
    
    exports.buildCSOptionParser = buildCSOptionParser = ->
      new optparse.OptionParser SWITCHES, BANNER
  • 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 = ->
      optionParser = buildCSOptionParser()
      parseOptions()
  • Make the REPL CLI use the global context so as to (a) be consistent with the node REPL CLI and, therefore, (b) make packages that modify native prototypes (such as ‘colors’ and ‘sugar’) work as expected.

      replCliOpts = useGlobal: yes
      opts.prelude = makePrelude opts.require       if opts.require
      replCliOpts.prelude = opts.prelude
      return forkNode()                             if opts.nodejs
      return usage()                                if opts.help
      return version()                              if opts.version
      return require('./repl').start(replCliOpts)   if opts.interactive
      return compileStdio()                         if opts.stdio
      return compileScript null, opts.arguments[0]  if opts.eval
      return require('./repl').start(replCliOpts)   unless opts.arguments.length
      literals = if opts.run then opts.arguments.splice 1 else []
      process.argv = process.argv[0..1].concat literals
      process.argv[0] = 'coffee'
    
      opts.output = path.resolve opts.output  if opts.output
      if opts.join
        opts.join = path.resolve opts.join
        console.error '''
    
        The --join option is deprecated and will be removed in a future version.
    
        If for some reason it's necessary to share local variables between files,
        replace...
    
            $ coffee --compile --join bundle.js -- a.coffee b.coffee c.coffee
    
        with...
    
            $ cat a.coffee b.coffee c.coffee | coffee --compile --stdio > bundle.js
    
        '''
      for source in opts.arguments
        source = path.resolve source
        compilePath source, yes, source
    
    makePrelude = (requires) ->
      requires.map (module) ->
        [_, name, module] = match if match = module.match(/^(.*)=(.*)$/)
        name ||= helpers.baseFileName module, yes, useWinPathSep
        "#{name} = require('#{module}')"
      .join ';'
  • Compile a path, which could be a script or a directory. If a directory is passed, recursively compile all ‘.coffee’, ‘.litcoffee’, and ‘.coffee.md’ extension source files in it and all subdirectories.

    compilePath = (source, topLevel, base) ->
      return if source in sources   or
                watchedDirs[source] or
                not topLevel and (notSources[source] or hidden source)
      try
        stats = fs.statSync source
      catch err
        if err.code is 'ENOENT'
          console.error "File not found: #{source}"
          process.exit 1
        throw err
      if stats.isDirectory()
        if path.basename(source) is 'node_modules'
          notSources[source] = yes
          return
        if opts.run
          compilePath findDirectoryIndex(source), topLevel, base
          return
        watchDir source, base if opts.watch
        try
          files = fs.readdirSync source
        catch err
          if err.code is 'ENOENT' then return else throw err
        for file in files
          compilePath (path.join source, file), no, base
      else if topLevel or helpers.isCoffee source
        sources.push source
        sourceCode.push null
        delete notSources[source]
        watch source, base if opts.watch
        try
          code = fs.readFileSync source
        catch err
          if err.code is 'ENOENT' then return else throw err
        compileScript(source, code.toString(), base)
      else
        notSources[source] = yes
    
    findDirectoryIndex = (source) ->
      for ext in CoffeeScript.FILE_EXTENSIONS
        index = path.join source, "index#{ext}"
        try
          return index if (fs.statSync index).isFile()
        catch err
          throw err unless err.code is 'ENOENT'
      console.error "Missing index.coffee or index.litcoffee in #{source}"
      process.exit 1
  • 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 = null) ->
      o = opts
      options = compileOptions file, base
      try
        t = task = {file, input, options}
        CoffeeScript.emit 'compile', task
        if o.tokens
          printTokens CoffeeScript.tokens t.input, t.options
        else if o.nodes
          printLine CoffeeScript.nodes(t.input, t.options).toString().trim()
        else if o.run
          CoffeeScript.register()
          CoffeeScript.eval opts.prelude, t.options if opts.prelude
          CoffeeScript.run t.input, t.options
        else if o.join and t.file isnt o.join
          t.input = helpers.invertLiterate t.input if helpers.isLiterate file
          sourceCode[sources.indexOf(t.file)] = t.input
          compileJoin()
        else
          compiled = CoffeeScript.compile t.input, t.options
          t.output = compiled
          if o.map
            t.output = compiled.js
            t.sourceMap = compiled.v3SourceMap
    
          CoffeeScript.emit 'success', task
          if o.print
            printLine t.output.trim()
          else if o.compile or o.map
            writeJs base, t.file, t.output, options.jsPath, t.sourceMap
      catch err
        CoffeeScript.emit 'failure', err, task
        return if CoffeeScript.listeners('failure').length
        message = err?.stack or "#{err}"
        if o.watch
          printLine message + '\x07'
        else
          printWarn message
          process.exit 1
  • Attach the appropriate listeners to compile scripts incoming over stdin, and write them back to stdout.

    compileStdio = ->
      buffers = []
      stdin = process.openStdin()
      stdin.on 'data', (buffer) ->
        buffers.push buffer if buffer
      stdin.on 'end', ->
        compileScript null, Buffer.concat(buffers).toString()
  • 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
  • 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 --print.

    watch = (source, base) ->
      watcher        = null
      prevStats      = null
      compileTimeout = null
    
      watchErr = (err) ->
        throw err unless err.code is 'ENOENT'
        return unless source in sources
        try
          rewatch()
          compile()
        catch
          removeSource source, base
          compileJoin()
    
      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()
    
      startWatcher = ->
        watcher = fs.watch source
        .on 'change', compile
        .on 'error', (err) ->
          throw err unless err.code is 'EPERM'
          removeSource source, base
    
      rewatch = ->
        watcher?.close()
        startWatcher()
    
      try
        startWatcher()
      catch err
        watchErr err
  • Watch a directory of files for new additions.

    watchDir = (source, base) ->
      watcher        = null
      readdirTimeout = null
    
      startWatcher = ->
        watcher = fs.watch source
        .on 'error', (err) ->
          throw err unless err.code is 'EPERM'
          stopWatcher()
        .on 'change', ->
          clearTimeout readdirTimeout
          readdirTimeout = wait 25, ->
            try
              files = fs.readdirSync source
            catch err
              throw err unless err.code is 'ENOENT'
              return stopWatcher()
            for file in files
              compilePath (path.join source, file), no, base
    
      stopWatcher = ->
        watcher.close()
        removeSourceDir source, base
    
      watchedDirs[source] = yes
      try
        startWatcher()
      catch err
        throw err unless err.code is 'ENOENT'
    
    removeSourceDir = (source, base) ->
      delete watchedDirs[source]
      sourcesChanged = no
      for file in sources when source is path.dirname file
        removeSource file, base
        sourcesChanged = yes
      compileJoin() if sourcesChanged
  • Remove a file from our source list, and source code cache. Optionally remove the compiled JS version as well.

    removeSource = (source, base) ->
      index = sources.indexOf source
      sources.splice index, 1
      sourceCode.splice index, 1
      unless opts.join
        silentUnlink outputPath source, base
        silentUnlink outputPath source, base, '.js.map'
        timeLog "removed #{source}"
    
    silentUnlink = (path) ->
      try
        fs.unlinkSync path
      catch err
        throw err unless err.code in ['ENOENT', 'EPERM']
  • Get the corresponding output JavaScript path for a source file.

    outputPath = (source, base, extension=".js") ->
      basename  = helpers.baseFileName source, yes, useWinPathSep
      srcDir    = path.dirname source
      if not opts.output
        dir = srcDir
      else if source is base
        dir = opts.output
      else
        dir = path.join opts.output, path.relative base, srcDir
      path.join dir, basename + extension
  • Recursively mkdir, like mkdir -p.

    mkdirp = (dir, fn) ->
      mode = 0o777 & ~process.umask()
    
      do mkdirs = (p = dir, fn) ->
        fs.exists p, (exists) ->
          if exists
            fn()
          else
            mkdirs path.dirname(p), ->
              fs.mkdir p, mode, (err) ->
                return fn err if err
                fn()
  • 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.

    If generatedSourceMap is provided, this will write a .js.map file into the same directory as the .js file.

    writeJs = (base, sourcePath, js, jsPath, generatedSourceMap = null) ->
      sourceMapPath = outputPath sourcePath, base, ".js.map"
      jsDir  = path.dirname jsPath
      compile = ->
        if opts.compile
          js = ' ' if js.length <= 0
          if generatedSourceMap then js = "#{js}\n//# sourceMappingURL=#{helpers.baseFileName sourceMapPath, no, useWinPathSep}\n"
          fs.writeFile jsPath, js, (err) ->
            if err
              printLine err.message
              process.exit 1
            else if opts.compile and opts.watch
              timeLog "compiled #{sourcePath}"
        if generatedSourceMap
          fs.writeFile sourceMapPath, generatedSourceMap, (err) ->
            if err
              printLine "Could not write source map: #{err.message}"
              process.exit 1
      fs.exists jsDir, (itExists) ->
        if itExists then compile() else mkdirp 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}"
  • Pretty-print a stream of tokens, sans location data.

    printTokens = (tokens) ->
      strings = for token in tokens
        tag = token[0]
        value = 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 = ->
      o = opts      = optionParser.parse process.argv[2..]
      o.compile     or=  !!o.output
      o.run         = not (o.compile or o.print or o.map)
      o.print       = !!  (o.print or (o.eval or o.stdio and o.compile))
  • The compile-time options to pass to the CoffeeScript compiler.

    compileOptions = (filename, base) ->
      answer = {
        filename
        literate: opts.literate or helpers.isLiterate(filename)
        bare: opts.bare
        header: opts.compile and not opts['no-header']
        sourceMap: opts.map
        inlineMap: opts['inline-map']
      }
      if filename
        if base
          cwd = process.cwd()
          jsPath = outputPath filename, base
          jsDir = path.dirname jsPath
          answer = helpers.merge answer, {
            jsPath
            sourceRoot: path.relative jsDir, cwd
            sourceFiles: [path.relative cwd, filename]
            generatedFile: helpers.baseFileName(jsPath, no, useWinPathSep)
          }
        else
          answer = helpers.merge answer,
            sourceRoot: ""
            sourceFiles: [helpers.baseFileName filename, no, useWinPathSep]
            generatedFile: helpers.baseFileName(filename, yes, useWinPathSep) + ".js"
      answer
  • 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
      p = spawn process.execPath, nodeArgs.concat(args),
        cwd:        process.cwd()
        env:        process.env
        stdio:      [0, 1, 2]
      p.on 'exit', (code) -> process.exit code
  • Print the --help usage message and exit. Deprecated switches are not shown.

    usage = ->
      printLine optionParser.help()
  • Print the --version message and exit.

    version = ->
      printLine "CoffeeScript version #{CoffeeScript.VERSION}"
coffeescript-1.12.7/docs/v2/annotated-source/docco.css000066400000000000000000000233011313305734200226110ustar00rootroot00000000000000/*--------------------- Typography ----------------------------*/ @font-face { font-family: 'aller-light'; src: url('public/fonts/aller-light.eot'); src: url('public/fonts/aller-light.eot?#iefix') format('embedded-opentype'), url('public/fonts/aller-light.woff') format('woff'), url('public/fonts/aller-light.ttf') format('truetype'); font-weight: normal; font-style: normal; } @font-face { font-family: 'aller-bold'; src: url('public/fonts/aller-bold.eot'); src: url('public/fonts/aller-bold.eot?#iefix') format('embedded-opentype'), url('public/fonts/aller-bold.woff') format('woff'), url('public/fonts/aller-bold.ttf') format('truetype'); font-weight: normal; font-style: normal; } @font-face { font-family: 'roboto-black'; src: url('public/fonts/roboto-black.eot'); src: url('public/fonts/roboto-black.eot?#iefix') format('embedded-opentype'), url('public/fonts/roboto-black.woff') format('woff'), url('public/fonts/roboto-black.ttf') format('truetype'); font-weight: normal; font-style: normal; } /*--------------------- Layout ----------------------------*/ html { height: 100%; } body { font-family: "aller-light"; font-size: 14px; line-height: 18px; color: #30404f; margin: 0; padding: 0; height:100%; } #container { min-height: 100%; } a { color: #000; } b, strong { font-weight: normal; font-family: "aller-bold"; } p { margin: 15px 0 0px; } .annotation ul, .annotation ol { margin: 25px 0; } .annotation ul li, .annotation ol li { font-size: 14px; line-height: 18px; margin: 10px 0; } h1, h2, h3, h4, h5, h6 { color: #112233; line-height: 1em; font-weight: normal; font-family: "roboto-black"; text-transform: uppercase; margin: 30px 0 15px 0; } h1 { margin-top: 40px; } h2 { font-size: 1.26em; } hr { border: 0; background: 1px #ddd; height: 1px; margin: 20px 0; } pre, tt, code { font-size: 12px; line-height: 16px; font-family: Menlo, Monaco, Consolas, "Lucida Console", monospace; margin: 0; padding: 0; } .annotation pre { display: block; margin: 0; padding: 7px 10px; background: #fcfcfc; -moz-box-shadow: inset 0 0 10px rgba(0,0,0,0.1); -webkit-box-shadow: inset 0 0 10px rgba(0,0,0,0.1); box-shadow: inset 0 0 10px rgba(0,0,0,0.1); overflow-x: auto; } .annotation pre code { border: 0; padding: 0; background: transparent; } blockquote { border-left: 5px solid #ccc; margin: 0; padding: 1px 0 1px 1em; } .sections blockquote p { font-family: Menlo, Consolas, Monaco, monospace; font-size: 12px; line-height: 16px; color: #999; margin: 10px 0 0; white-space: pre-wrap; } ul.sections { list-style: none; padding:0 0 5px 0;; margin:0; } /* Force border-box so that % widths fit the parent container without overlap because of margin/padding. More Info : http://www.quirksmode.org/css/box.html */ ul.sections > li > div { -moz-box-sizing: border-box; /* firefox */ -ms-box-sizing: border-box; /* ie */ -webkit-box-sizing: border-box; /* webkit */ -khtml-box-sizing: border-box; /* konqueror */ box-sizing: border-box; /* css3 */ } /*---------------------- Jump Page -----------------------------*/ #jump_to, #jump_page { margin: 0; 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: 16px Arial; cursor: pointer; text-align: right; list-style: none; } #jump_to a { text-decoration: none; } #jump_to a.large { display: none; } #jump_to a.small { font-size: 22px; font-weight: bold; color: #676767; } #jump_to, #jump_wrapper { position: fixed; right: 0; top: 0; padding: 10px 15px; margin:0; } #jump_wrapper { display: none; padding:0; } #jump_to:hover #jump_wrapper { display: block; } #jump_page_wrapper{ position: fixed; right: 0; top: 0; bottom: 0; } #jump_page { padding: 5px 0 3px; margin: 0 0 25px 25px; max-height: 100%; overflow: auto; } #jump_page .source { display: block; padding: 15px; text-decoration: none; border-top: 1px solid #eee; } #jump_page .source:hover { background: #f5f5ff; } #jump_page .source:first-child { } /*---------------------- Low resolutions (> 320px) ---------------------*/ @media only screen and (min-width: 320px) { .pilwrap { display: none; } ul.sections > li > div { display: block; padding:5px 10px 0 10px; } ul.sections > li > div.annotation ul, ul.sections > li > div.annotation ol { padding-left: 30px; } ul.sections > li > div.content { overflow-x:auto; -webkit-box-shadow: inset 0 0 5px #e5e5ee; box-shadow: inset 0 0 5px #e5e5ee; border: 1px solid #dedede; margin:5px 10px 5px 10px; padding-bottom: 5px; } ul.sections > li > div.annotation pre { margin: 7px 0 7px; padding-left: 15px; } ul.sections > li > div.annotation p tt, .annotation code { background: #f8f8ff; border: 1px solid #dedede; font-size: 12px; padding: 0 0.2em; } } /*---------------------- (> 481px) ---------------------*/ @media only screen and (min-width: 481px) { #container { position: relative; } body { background-color: #F5F5FF; font-size: 15px; line-height: 21px; } pre, tt, code { line-height: 18px; } p, ul, ol { margin: 0 0 15px; } #jump_to { padding: 5px 10px; } #jump_wrapper { padding: 0; } #jump_to, #jump_page { font: 10px Arial; text-transform: uppercase; } #jump_page .source { padding: 5px 10px; } #jump_to a.large { display: inline-block; } #jump_to a.small { display: none; } #background { position: absolute; top: 0; bottom: 0; width: 350px; background: #fff; border-right: 1px solid #e5e5ee; z-index: -1; } ul.sections > li > div.annotation ul, ul.sections > li > div.annotation ol { padding-left: 40px; } ul.sections > li { white-space: nowrap; } ul.sections > li > div { display: inline-block; } ul.sections > li > div.annotation { max-width: 350px; min-width: 350px; min-height: 5px; padding: 13px; overflow-x: hidden; white-space: normal; vertical-align: top; text-align: left; } ul.sections > li > div.annotation pre { margin: 15px 0 15px; padding-left: 15px; } ul.sections > li > div.content { padding: 13px; vertical-align: top; border: none; -webkit-box-shadow: none; box-shadow: none; } .pilwrap { position: relative; display: inline; } .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; } .for-h1 .pilcrow { top: 47px; } .for-h2 .pilcrow, .for-h3 .pilcrow, .for-h4 .pilcrow { top: 35px; } ul.sections > li > div.annotation:hover .pilcrow { opacity: 1; } } /*---------------------- (> 1025px) ---------------------*/ @media only screen and (min-width: 1025px) { body { font-size: 16px; line-height: 24px; } #background { width: 525px; } ul.sections > li > div.annotation { max-width: 525px; min-width: 525px; padding: 10px 25px 1px 50px; } ul.sections > li > div.content { padding: 9px 15px 16px 25px; } } /*---------------------- Syntax Highlighting -----------------------------*/ td.linenos { background-color: #f0f0f0; padding-right: 10px; } span.lineno { background-color: #f0f0f0; padding: 0 5px 0 5px; } /* github.com style (c) Vasily Polovnyov */ pre code { display: block; padding: 0.5em; color: #000; background: #f8f8ff } pre .hljs-comment, pre .hljs-template_comment, pre .hljs-diff .hljs-header, pre .hljs-javadoc { color: #408080; font-style: italic } pre .hljs-keyword, pre .hljs-assignment, pre .hljs-literal, pre .hljs-css .hljs-rule .hljs-keyword, pre .hljs-winutils, pre .hljs-javascript .hljs-title, pre .hljs-lisp .hljs-title, pre .hljs-subst { color: #954121; /*font-weight: bold*/ } pre .hljs-number, pre .hljs-hexcolor { color: #40a070 } pre .hljs-string, pre .hljs-tag .hljs-value, pre .hljs-phpdoc, pre .hljs-tex .hljs-formula { color: #219161; } pre .hljs-title, pre .hljs-id { color: #19469D; } pre .hljs-params { color: #00F; } pre .hljs-javascript .hljs-title, pre .hljs-lisp .hljs-title, pre .hljs-subst { font-weight: normal } pre .hljs-class .hljs-title, pre .hljs-haskell .hljs-label, pre .hljs-tex .hljs-command { color: #458; font-weight: bold } pre .hljs-tag, pre .hljs-tag .hljs-title, pre .hljs-rules .hljs-property, pre .hljs-django .hljs-tag .hljs-keyword { color: #000080; font-weight: normal } pre .hljs-attribute, pre .hljs-variable, pre .hljs-instancevar, pre .hljs-lisp .hljs-body { color: #008080 } pre .hljs-regexp { color: #B68 } pre .hljs-class { color: #458; font-weight: bold } pre .hljs-symbol, pre .hljs-ruby .hljs-symbol .hljs-string, pre .hljs-ruby .hljs-symbol .hljs-keyword, pre .hljs-ruby .hljs-symbol .hljs-keymethods, pre .hljs-lisp .hljs-keyword, pre .hljs-tex .hljs-special, pre .hljs-input_number { color: #990073 } pre .hljs-builtin, pre .hljs-constructor, pre .hljs-built_in, pre .hljs-lisp .hljs-title { color: #0086b3 } pre .hljs-preprocessor, pre .hljs-pi, pre .hljs-doctype, pre .hljs-shebang, pre .hljs-cdata { color: #999; font-weight: bold } pre .hljs-deletion { background: #fdd } pre .hljs-addition { background: #dfd } pre .hljs-diff .hljs-change { background: #0086b3 } pre .hljs-chunk { color: #aaa } pre .hljs-tex .hljs-formula { opacity: 0.5; } coffeescript-1.12.7/docs/v2/annotated-source/grammar.html000066400000000000000000003307031313305734200233330ustar00rootroot00000000000000 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, ' '
      patternCount = patternString.split(' ').length
      return [patternString, '$$ = $1;', options] unless action
      action = if match = unwrap.exec action then match[1] else "(#{action}())"
  • All runtime functions we need are defined on yy

      action = action.replace /\bnew /g, '$&yy.'
      action = action.replace /\b(?:Block\.wrap|extend)\b/g, 'yy.$&'
  • Returns a function which adds location data to the first parameter passed in, and returns the parameter. If the parameter is not a node, it will just be passed through unaffected.

      addLocationDataFn = (first, last) ->
        if not last
          "yy.addLocationDataFn(@#{first})"
        else
          "yy.addLocationDataFn(@#{first}, @#{last})"
    
      action = action.replace /LOC\(([0-9]*)\)/g, addLocationDataFn('$1')
      action = action.replace /LOC\(([0-9]*),\s*([0-9]*)\)/g, addLocationDataFn('$1', '$2')
    
      [patternString, "$$ = #{addLocationDataFn(1, patternCount)}(#{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'
      ]
  • 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. YieldReturn is a statement, but not included in Statement because that results in an ambiguous grammar.

      Line: [
        o 'Expression'
        o 'Statement'
        o 'FuncDirective'
      ]
    
      FuncDirective: [
        o 'YieldReturn'
        o 'AwaitReturn'
      ]
  • Pure statements which cannot be expressions.

      Statement: [
        o 'Return'
        o 'Comment'
        o 'STATEMENT',                              -> new StatementLiteral $1
        o 'Import'
        o 'Export'
      ]
  • 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'
        o 'Yield'
      ]
    
      Yield: [
        o 'YIELD',                                  -> new Op $1, new Value new Literal ''
        o 'YIELD Expression',                       -> new Op $1, $2
        o 'YIELD FROM Expression',                  -> new Op $1.concat($2), $3
      ]
  • 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
      ]
    
      Identifier: [
        o 'IDENTIFIER',                             -> new IdentifierLiteral $1
        o 'CSX_TAG',                                -> new CSXTag $1
      ]
    
      Property: [
        o 'PROPERTY',                               -> new PropertyName $1
      ]
  • Alphanumerics are separated from the other Literal matchers because they can also serve as keys in object literals.

      AlphaNumeric: [
        o 'NUMBER',                                 -> new NumberLiteral $1
        o 'String'
      ]
    
      String: [
        o 'STRING',                                 -> new StringLiteral $1
        o 'STRING_START Body STRING_END',           -> new StringWithInterpolations $2
      ]
    
      Regex: [
        o 'REGEX',                                  -> new RegexLiteral $1
        o 'REGEX_START Invocation REGEX_END',       -> new RegexWithInterpolations $2.args
      ]
  • All of our immediate values. Generally these can be passed straight through and printed to JavaScript.

      Literal: [
        o 'AlphaNumeric'
        o 'JS',                                     -> new PassthroughLiteral $1
        o 'Regex'
        o 'UNDEFINED',                              -> new UndefinedLiteral
        o 'NULL',                                   -> new NullLiteral
        o 'BOOL',                                   -> new BooleanLiteral $1
        o 'INFINITY',                               -> new InfinityLiteral $1
        o 'NAN',                                    -> new NaNLiteral
      ]
  • 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 'ObjRestValue'
        o 'ObjAssignable : Expression',             -> new Assign LOC(1)(new Value $1), $3, 'object',
                                                                  operatorToken: LOC(2)(new Literal $2)
        o 'ObjAssignable :
           INDENT Expression OUTDENT',              -> new Assign LOC(1)(new Value $1), $4, 'object',
                                                                  operatorToken: LOC(2)(new Literal $2)
        o 'SimpleObjAssignable = Expression',       -> new Assign LOC(1)(new Value $1), $3, null,
                                                                  operatorToken: LOC(2)(new Literal $2)
        o 'SimpleObjAssignable =
           INDENT Expression OUTDENT',              -> new Assign LOC(1)(new Value $1), $4, null,
                                                                  operatorToken: LOC(2)(new Literal $2)
        o 'Comment'
      ]
    
      SimpleObjAssignable: [
        o 'Identifier'
        o 'Property'
        o 'ThisProperty'
      ]
    
      ObjAssignable: [
        o 'SimpleObjAssignable'
        o 'AlphaNumeric'
      ]
  • Object literal spread properties.

      ObjRestValue: [
        o 'SimpleObjAssignable ...', -> new Splat new Value $1
        o 'ObjSpreadExpr ...',       -> new Splat $1
      ]
    
      ObjSpreadExpr: [
        o 'ObjSpreadIdentifier'
        o 'Object'
        o 'Parenthetical'
        o 'Super'
        o 'This'
        o 'SUPER Arguments',               -> new SuperCall LOC(1)(new Super), $2
        o 'SimpleObjAssignable Arguments', -> new Call (new Value $1), $2
        o 'ObjSpreadExpr Arguments',       -> new Call $1, $2
      ]
    
      ObjSpreadIdentifier: [
        o 'SimpleObjAssignable . Property',                             -> (new Value $1).add(new Access $3)
        o 'SimpleObjAssignable INDEX_START IndexValue INDEX_END',       -> (new Value $1).add($3)
      ]
  • A return statement from a function body.

      Return: [
        o 'RETURN Expression',                      -> new Return $2
        o 'RETURN',                                 -> new Return
      ]
    
      YieldReturn: [
        o 'YIELD RETURN Expression',                -> new YieldReturn $3
        o 'YIELD RETURN',                           -> new YieldReturn
      ]
    
      AwaitReturn: [
        o 'AWAIT RETURN Expression',                -> new AwaitReturn $3
        o 'AWAIT RETURN',                           -> new AwaitReturn
      ]
  • 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
        o '...',                                    -> new Expansion
      ]
  • 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'
        o 'Super'
      ]
  • A super-based expression that can be used as a value.

      Super: [
        o 'SUPER . Property',                       -> new Super LOC(3) new Access $3
        o 'SUPER INDEX_START Expression INDEX_END', -> new Super LOC(3) new Index $3
      ]
  • The general group of accessors into an object, by property, by prototype or by array index or slice.

      Accessor: [
        o '.  Property',                            -> new Access $2
        o '?. Property',                            -> new Access $2, 'soak'
        o ':: Property',                            -> [LOC(1)(new Access new PropertyName('prototype')), LOC(2)(new Access $2)]
        o '?:: Property',                           -> [LOC(1)(new Access new PropertyName('prototype'), 'soak'), LOC(2)(new Access $2)]
        o '::',                                     -> new Access new PropertyName '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
      ]
    
      Import: [
        o 'IMPORT String',                                                                -> new ImportDeclaration null, $2
        o 'IMPORT ImportDefaultSpecifier FROM String',                                    -> new ImportDeclaration new ImportClause($2, null), $4
        o 'IMPORT ImportNamespaceSpecifier FROM String',                                  -> new ImportDeclaration new ImportClause(null, $2), $4
        o 'IMPORT { } FROM String',                                                       -> new ImportDeclaration new ImportClause(null, new ImportSpecifierList []), $5
        o 'IMPORT { ImportSpecifierList OptComma } FROM String',                          -> new ImportDeclaration new ImportClause(null, new ImportSpecifierList $3), $7
        o 'IMPORT ImportDefaultSpecifier , ImportNamespaceSpecifier FROM String',         -> new ImportDeclaration new ImportClause($2, $4), $6
        o 'IMPORT ImportDefaultSpecifier , { ImportSpecifierList OptComma } FROM String', -> new ImportDeclaration new ImportClause($2, new ImportSpecifierList $5), $9
      ]
    
      ImportSpecifierList: [
        o 'ImportSpecifier',                                                          -> [$1]
        o 'ImportSpecifierList , ImportSpecifier',                                    -> $1.concat $3
        o 'ImportSpecifierList OptComma TERMINATOR ImportSpecifier',                  -> $1.concat $4
        o 'INDENT ImportSpecifierList OptComma OUTDENT',                              -> $2
        o 'ImportSpecifierList OptComma INDENT ImportSpecifierList OptComma OUTDENT', -> $1.concat $4
      ]
    
      ImportSpecifier: [
        o 'Identifier',                             -> new ImportSpecifier $1
        o 'Identifier AS Identifier',               -> new ImportSpecifier $1, $3
        o 'DEFAULT',                                -> new ImportSpecifier new Literal $1
        o 'DEFAULT AS Identifier',                  -> new ImportSpecifier new Literal($1), $3
      ]
    
      ImportDefaultSpecifier: [
        o 'Identifier',                             -> new ImportDefaultSpecifier $1
      ]
    
      ImportNamespaceSpecifier: [
        o 'IMPORT_ALL AS Identifier',               -> new ImportNamespaceSpecifier new Literal($1), $3
      ]
    
      Export: [
        o 'EXPORT { }',                                          -> new ExportNamedDeclaration new ExportSpecifierList []
        o 'EXPORT { ExportSpecifierList OptComma }',             -> new ExportNamedDeclaration new ExportSpecifierList $3
        o 'EXPORT Class',                                        -> new ExportNamedDeclaration $2
        o 'EXPORT Identifier = Expression',                      -> new ExportNamedDeclaration new Assign $2, $4, null,
                                                                                                          moduleDeclaration: 'export'
        o 'EXPORT Identifier = TERMINATOR Expression',           -> new ExportNamedDeclaration new Assign $2, $5, null,
                                                                                                          moduleDeclaration: 'export'
        o 'EXPORT Identifier = INDENT Expression OUTDENT',       -> new ExportNamedDeclaration new Assign $2, $5, null,
                                                                                                          moduleDeclaration: 'export'
        o 'EXPORT DEFAULT Expression',                           -> new ExportDefaultDeclaration $3
        o 'EXPORT EXPORT_ALL FROM String',                       -> new ExportAllDeclaration new Literal($2), $4
        o 'EXPORT { ExportSpecifierList OptComma } FROM String', -> new ExportNamedDeclaration new ExportSpecifierList($3), $7
      ]
    
      ExportSpecifierList: [
        o 'ExportSpecifier',                                                          -> [$1]
        o 'ExportSpecifierList , ExportSpecifier',                                    -> $1.concat $3
        o 'ExportSpecifierList OptComma TERMINATOR ExportSpecifier',                  -> $1.concat $4
        o 'INDENT ExportSpecifierList OptComma OUTDENT',                              -> $2
        o 'ExportSpecifierList OptComma INDENT ExportSpecifierList OptComma OUTDENT', -> $1.concat $4
      ]
    
      ExportSpecifier: [
        o 'Identifier',                             -> new ExportSpecifier $1
        o 'Identifier AS Identifier',               -> new ExportSpecifier $1, $3
        o 'Identifier AS DEFAULT',                  -> new ExportSpecifier $1, new Literal $3
        o 'DEFAULT',                                -> new ExportSpecifier new Literal $1
        o 'DEFAULT AS Identifier',                  -> new ExportSpecifier new Literal($1), $3
      ]
  • Ordinary function invocation, or a chained series of calls.

      Invocation: [
        o 'Value OptFuncExist String',              -> new TaggedTemplateCall $1, $3, $2
        o 'Value OptFuncExist Arguments',           -> new Call $1, $3, $2
        o 'Invocation OptFuncExist Arguments',      -> new Call $1, $3, $2
        o 'SUPER OptFuncExist Arguments',           -> new SuperCall LOC(1)(new Super), $3, $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 ThisLiteral
        o '@',                                      -> new Value new ThisLiteral
      ]
  • A reference to a property on this.

      ThisProperty: [
        o '@ Property',                             -> new Value LOC(1)(new ThisLiteral), [LOC(2)(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'
        o '...',                                     -> new Expansion
      ]
  • 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]
        o 'CATCH Object Block',                     -> [LOC(2)(new Value($2)), $3]
        o 'CATCH Block',                            -> [null, $2]
      ]
  • 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 LOC(1) Block.wrap([$1])
        o 'Expression WhileSource',                 -> $2.addBody LOC(1) Block.wrap([$1])
        o 'Loop',                                   -> $1
      ]
    
      Loop: [
        o 'LOOP Block',                             -> new While(LOC(1) new BooleanLiteral 'true').addBody $2
        o 'LOOP Expression',                        -> new While(LOC(1) new BooleanLiteral 'true').addBody LOC(2) 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: (LOC(2) new Value($2))
        o 'FOR Range BY Expression',                -> source: (LOC(2) new Value($2)), step: $4
        o 'ForStart ForSource',                     -> $2.own = $1.own; $2.ownTag = $1.ownTag; $2.name = $1[0]; $2.index = $1[1]; $2
      ]
    
      ForStart: [
        o 'FOR ForVariables',                       -> $2
        o 'FOR OWN ForVariables',                   -> $3.own = yes; $3.ownTag = (LOC(2) new Literal($2)); $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
        o 'FORFROM Expression',                             -> source: $2, from: yes
        o 'FORFROM Expression WHEN Expression',             -> source: $2, guard: $4, from: yes
      ]
    
      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 LOC(3,5) 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, LOC(1)(Block.wrap [$1]), type: $2, statement: true
        o 'Expression POST_IF Expression',          -> new If $3, LOC(1)(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 'UNARY_MATH Expression',                  -> new Op $1 , $2
        o '-     Expression',                      (-> new Op '-', $2), prec: 'UNARY_MATH'
        o '+     Expression',                      (-> new Op '+', $2), prec: 'UNARY_MATH'
    
        o 'AWAIT Expression',                       -> new Op $1 , $2
    
        o '-- SimpleAssignable',                    -> new Op '--', $2
        o '++ SimpleAssignable',                    -> new Op '++', $2
        o 'SimpleAssignable --',                    -> new Op '--', $1, null, true
        o 'SimpleAssignable ++',                    -> new Op '++', $1, null, true
  •     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 **       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 &        Expression',         -> new Op $2, $1, $3
        o 'Expression ^        Expression',         -> new Op $2, $1, $3
        o 'Expression |        Expression',         -> new Op $2, $1, $3
        o 'Expression &&       Expression',         -> new Op $2, $1, $3
        o 'Expression ||       Expression',         -> new Op $2, $1, $3
        o 'Expression BIN?     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 COMPOUND_ASSIGN TERMINATOR
           Expression',                             -> new Assign $1, $4, $2
      ]
  • 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']
      ['right',     'AWAIT']
      ['right',     '**']
      ['right',     'UNARY_MATH']
      ['left',      'MATH']
      ['left',      '+', '-']
      ['left',      'SHIFT']
      ['left',      'RELATION']
      ['left',      'COMPARE']
      ['left',      '&']
      ['left',      '^']
      ['left',      '|']
      ['left',      '&&']
      ['left',      '||']
      ['left',      'BIN?']
      ['nonassoc',  'INDENT', 'OUTDENT']
      ['right',     'YIELD']
      ['right',     '=', ':', 'COMPOUND_ASSIGN', 'RETURN', 'THROW', 'EXTENDS']
      ['right',     'FORIN', 'FOROF', 'FORFROM', 'BY', 'WHEN']
      ['right',     'IF', 'ELSE', 'FOR', 'WHILE', 'UNTIL', 'LOOP', 'SUPER', 'CLASS', 'IMPORT', 'EXPORT']
      ['left',      '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'
coffeescript-1.12.7/docs/v2/annotated-source/helpers.html000066400000000000000000000654621313305734200233560ustar00rootroot00000000000000 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
  • Repeat a string n times.

    exports.repeat = repeat = (str, n) ->
  • Use clever algorithm to have O(log(n)) string concatenation operations.

      res = ''
      while n > 0
        res += str if n & 1
        n >>>= 1
        str += str
      res
  • 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 '[object Array]' is Object::toString.call element
          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
  • Typical Array::some

    exports.some = Array::some ? (fn) ->
      return true for e in this when fn e
      false
  • Helper function for extracting code from Literate CoffeeScript by stripping out all non-code blocks, producing a string of CoffeeScript code that can be compiled “normally.”

    exports.invertLiterate = (code) ->
      out = []
      blankLine = /^\s*$/
      indented = /^[\t ]/
      listItemStart = /// ^
        (?:\t?|\ {0,3})   # Up to one tab, or up to three spaces, or neither;
        (?:
          [\*\-\+] |      # followed by `*`, `-` or `+`;
          [0-9]{1,9}\.    # or by an integer up to 9 digits long, followed by a period;
        )
        [\ \t]            # followed by a space or a tab.
      ///
      insideComment = no
      for line in code.split('\n')
        if blankLine.test(line)
          insideComment = no
          out.push line
        else if insideComment or listItemStart.test(line)
          insideComment = yes
          out.push "# #{line}"
        else if not insideComment and indented.test(line)
          out.push line
        else
          insideComment = yes
          out.push "# #{line}"
      out.join '\n'
  • Merge two jison-style location data objects together. If last is not provided, this will simply return first.

    buildLocationData = (first, last) ->
      if not last
        first
      else
        first_line: first.first_line
        first_column: first.first_column
        last_line: last.last_line
        last_column: last.last_column
  • This returns a function which takes an object as a parameter, and if that object is an AST node, updates that object’s locationData. The object is returned either way.

    exports.addLocationDataFn = (first, last) ->
      (obj) ->
        if ((typeof obj) is 'object') and (!!obj['updateLocationDataIfMissing'])
          obj.updateLocationDataIfMissing buildLocationData(first, last)
    
        return obj
  • Convert jison location data to a string. obj can be a token, or a locationData.

    exports.locationDataToString = (obj) ->
      if ("2" of obj) and ("first_line" of obj[2]) then locationData = obj[2]
      else if "first_line" of obj then locationData = obj
    
      if locationData
        "#{locationData.first_line + 1}:#{locationData.first_column + 1}-" +
        "#{locationData.last_line + 1}:#{locationData.last_column + 1}"
      else
        "No location data"
  • A .coffee.md compatible version of basename, that returns the file sans-extension.

    exports.baseFileName = (file, stripExt = no, useWinPathSep = no) ->
      pathSep = if useWinPathSep then /\\|\// else /\//
      parts = file.split(pathSep)
      file = parts[parts.length - 1]
      return file unless stripExt and file.indexOf('.') >= 0
      parts = file.split('.')
      parts.pop()
      parts.pop() if parts[parts.length - 1] is 'coffee' and parts.length > 1
      parts.join('.')
  • Determine if a filename represents a CoffeeScript file.

    exports.isCoffee = (file) -> /\.((lit)?coffee|coffee\.md)$/.test file
  • Determine if a filename represents a Literate CoffeeScript file.

    exports.isLiterate = (file) -> /\.(litcoffee|coffee\.md)$/.test file
  • Throws a SyntaxError from a given location. The error’s toString will return an error message following the “standard” format <filename>:<line>:<col>: <message> plus the line with the error and a marker showing where the error is.

    exports.throwSyntaxError = (message, location) ->
      error = new SyntaxError message
      error.location = location
      error.toString = syntaxErrorToString
  • Instead of showing the compiler’s stacktrace, show our custom error message (this is useful when the error bubbles up in Node.js applications that compile CoffeeScript for example).

      error.stack = error.toString()
    
      throw error
  • Update a compiler SyntaxError with source code information if it didn’t have it already.

    exports.updateSyntaxError = (error, code, filename) ->
  • Avoid screwing up the stack property of other errors (i.e. possible bugs).

      if error.toString is syntaxErrorToString
        error.code or= code
        error.filename or= filename
        error.stack = error.toString()
      error
    
    syntaxErrorToString = ->
      return Error::toString.call @ unless @code and @location
    
      {first_line, first_column, last_line, last_column} = @location
      last_line ?= first_line
      last_column ?= first_column
    
      filename = @filename or '[stdin]'
      codeLine = @code.split('\n')[first_line]
      start    = first_column
  • Show only the first line on multi-line errors.

      end      = if first_line is last_line then last_column + 1 else codeLine.length
      marker   = codeLine[...start].replace(/[^\s]/g, ' ') + repeat('^', end - start)
  • Check to see if we’re running on a color-enabled TTY.

      if process?
        colorsEnabled = process.stdout?.isTTY and not process.env?.NODE_DISABLE_COLORS
    
      if @colorful ? colorsEnabled
        colorize = (str) -> "\x1B[1;31m#{str}\x1B[0m"
        codeLine = codeLine[...start] + colorize(codeLine[start...end]) + codeLine[end..]
        marker   = colorize marker
    
      """
        #{filename}:#{first_line + 1}:#{first_column + 1}: error: #{@message}
        #{codeLine}
        #{marker}
      """
    
    exports.nameWhitespaceCharacter = (string) ->
      switch string
        when ' ' then 'space'
        when '\n' then 'newline'
        when '\r' then 'carriage return'
        when '\t' then 'tab'
        else string
coffeescript-1.12.7/docs/v2/annotated-source/index.html000066400000000000000000000356261313305734200230220ustar00rootroot00000000000000 index.coffee
  • index.coffee

  • Node.js Implementation

    CoffeeScript  = require './coffeescript'
    fs            = require 'fs'
    vm            = require 'vm'
    path          = require 'path'
    
    helpers       = CoffeeScript.helpers
    compile       = CoffeeScript.compile
  • Compile and execute a string of CoffeeScript (on the server), correctly setting __filename, __dirname, and relative require().

    CoffeeScript.run = (code, options = {}) ->
      mainModule = require.main
  • Set the filename.

      mainModule.filename = process.argv[1] =
        if options.filename then fs.realpathSync(options.filename) else '<anonymous>'
  • Clear the module cache.

      mainModule.moduleCache and= {}
  • Assign paths for node_modules loading

      dir = if options.filename?
        path.dirname fs.realpathSync options.filename
      else
        fs.realpathSync '.'
      mainModule.paths = require('module')._nodeModulePaths dir
  • Compile.

      if not helpers.isCoffee(mainModule.filename) or require.extensions
        answer = compile code, options
        code = answer.js ? answer
    
      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.

    CoffeeScript.eval = (code, options = {}) ->
      return unless code = code.trim()
      createContext = vm.Script.createContext ? vm.createContext
    
      isContext = vm.isContext ? (ctx) ->
        options.sandbox instanceof createContext().constructor
    
      if createContext
        if options.sandbox?
          if isContext options.sandbox
            sandbox = options.sandbox
          else
            sandbox = 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
          for r in Object.getOwnPropertyNames require when r not in ['paths', 'arguments', 'caller']
            _require[r] = require[r]
  • 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
    
    CoffeeScript.register = -> require './register'
  • Throw error with deprecation warning when depending upon implicit require.extensions registration

    if require.extensions
      for ext in CoffeeScript.FILE_EXTENSIONS then do (ext) ->
        require.extensions[ext] ?= ->
          throw new Error """
          Use CoffeeScript.register() or require the coffeescript/register module to require #{ext} files.
          """
    
    CoffeeScript._compileFile = (filename, sourceMap = no, inlineMap = no) ->
      raw = fs.readFileSync filename, 'utf8'
  • Strip the Unicode byte order mark, if this file begins with one.

      stripped = if raw.charCodeAt(0) is 0xFEFF then raw.substring 1 else raw
    
      try
        answer = compile stripped, {
          filename, sourceMap, inlineMap
          sourceFiles: [filename]
          literate: helpers.isLiterate filename
        }
      catch err
  • As the filename and code of a dynamically loaded file will be different from the original file compiled with CoffeeScript.run, add that information to error so it can be pretty-printed later.

        throw helpers.updateSyntaxError err, stripped, filename
    
      answer
    
    module.exports = CoffeeScript
coffeescript-1.12.7/docs/v2/annotated-source/lexer.html000066400000000000000000004260541313305734200230310ustar00rootroot00000000000000 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, locationData]
    

    where locationData is {first_line, first_column, last_line, last_column}, which is a format that can be fed directly into Jison. These are read by jison in the parser.lexer function defined in coffeescript.coffee.

    {Rewriter, INVERSES} = require './rewriter'
  • Import the helpers we need.

    {count, starts, compact, repeat, invertLiterate, merge,
    locationDataToString, throwSyntaxError} = 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.

      tokenize: (code, opts = {}) ->
        @literate   = opts.literate  # Are we lexing literate CoffeeScript?
        @indent     = 0              # The current indentation level.
        @baseIndent = 0              # The overall minimum 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.
        @indentLiteral = ''          # The indentation
        @ends       = []             # The stack for pairing up tokens.
        @tokens     = []             # Stream of parsed tokens in the form `['TYPE', value, location data]`.
        @seenFor    = no             # Used to recognize FORIN, FOROF and FORFROM tokens.
        @seenImport = no             # Used to recognize IMPORT FROM? AS? tokens.
        @seenExport = no             # Used to recognize EXPORT FROM? AS? tokens.
        @importSpecifierList = no    # Used to identify when in an IMPORT {...} FROM? ...
        @exportSpecifierList = no    # Used to identify when in an EXPORT {...} FROM? ...
        @csxDepth = 0                # Used to optimize CSX checks, how deep in CSX we are.
    
        @chunkLine =
          opts.line or 0             # The start line for the current @chunk.
        @chunkColumn =
          opts.column or 0           # The start column of the current @chunk.
        code = @clean code           # The stripped, cleaned original source code.
  • 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..]
          consumed = \
               @identifierToken() or
               @commentToken()    or
               @whitespaceToken() or
               @lineToken()       or
               @stringToken()     or
               @numberToken()     or
               @csxToken()        or
               @regexToken()      or
               @jsToken()         or
               @literalToken()
  • Update position

          [@chunkLine, @chunkColumn] = @getLineAndColumnFromChunk consumed
    
          i += consumed
    
          return {@tokens, index: i} if opts.untilBalanced and @ends.length is 0
    
        @closeIndentation()
        @error "missing #{end.tag}", (end.origin ? end)[2] if end = @ends.pop()
        return @tokens if opts.rewrite is off
        (new Rewriter).rewrite @tokens
  • Preprocess the code to remove leading and trailing whitespace, carriage returns, etc. If we’re lexing literate CoffeeScript, strip external Markdown by removing all lines that aren’t indented by at least four spaces or a tab.

      clean: (code) ->
        code = code.slice(1) if code.charCodeAt(0) is BOM
        code = code.replace(/\r/g, '').replace TRAILING_SPACES, ''
        if WHITESPACE.test code
          code = "\n#{code}"
          @chunkLine--
        code = invertLiterate code if @literate
        code
  • 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: ->
        inCSXTag = @atCSXTag()
        regex = if inCSXTag then CSX_ATTRIBUTE else IDENTIFIER
        return 0 unless match = regex.exec @chunk
        [input, id, colon] = match
  • Preserve length of id for location data

        idLength = id.length
        poppedToken = undefined
    
        if id is 'own' and @tag() is 'FOR'
          @token 'OWN', id
          return id.length
        if id is 'from' and @tag() is 'YIELD'
          @token 'FROM', id
          return id.length
        if id is 'as' and @seenImport
          if @value() is '*'
            @tokens[@tokens.length - 1][0] = 'IMPORT_ALL'
          else if @value() in COFFEE_KEYWORDS
            @tokens[@tokens.length - 1][0] = 'IDENTIFIER'
          if @tag() in ['DEFAULT', 'IMPORT_ALL', 'IDENTIFIER']
            @token 'AS', id
            return id.length
        if id is 'as' and @seenExport and @tag() in ['IDENTIFIER', 'DEFAULT']
          @token 'AS', id
          return id.length
        if id is 'default' and @seenExport and @tag() in ['EXPORT', 'AS']
          @token 'DEFAULT', id
          return id.length
    
        prev = @prev()
    
        tag =
          if colon or prev? and
             (prev[0] in ['.', '?.', '::', '?::'] or
             not prev.spaced and prev[0] is '@')
            'PROPERTY'
          else
            'IDENTIFIER'
    
        if tag is 'IDENTIFIER' and (id in JS_KEYWORDS or id in COFFEE_KEYWORDS) and
           not (@exportSpecifierList and 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 is 'IMPORT'
            @seenImport = yes
          else if tag is 'EXPORT'
            @seenExport = yes
          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 '!'
                poppedToken = @tokens.pop()
                id = '!' + id
        else if tag is 'IDENTIFIER' and @seenFor and id is 'from' and
           isForFrom(prev)
          tag = 'FORFROM'
          @seenFor = no
  • Throw an error on attempts to use get or set as keywords, or what CoffeeScript would normally interpret as calls to functions named get or set, i.e. get({foo: function () {}}).

        else if tag is 'PROPERTY' and prev
          if prev.spaced and prev[0] in CALLABLE and /^[gs]et$/.test(prev[1])
            @error "'#{prev[1]}' cannot be used as a keyword, or as a function call without parentheses", prev[2]
          else
            prevprev = @tokens[@tokens.length - 2]
            if prev[0] in ['@', 'THIS'] and prevprev and prevprev.spaced and /^[gs]et$/.test(prevprev[1]) and
            @tokens[@tokens.length - 3][0] isnt '.'
              @error "'#{prevprev[1]}' cannot be used as a keyword, or as a function call without parentheses", prevprev[2]
    
        if tag is 'IDENTIFIER' and id in RESERVED
          @error "reserved word '#{id}'", length: id.length
    
        unless tag is 'PROPERTY'
          if id in COFFEE_ALIASES
            alias = id
            id = COFFEE_ALIAS_MAP[id]
          tag = switch id
            when '!'                 then 'UNARY'
            when '==', '!='          then 'COMPARE'
            when 'true', 'false'     then 'BOOL'
            when 'break', 'continue', \
                 'debugger'          then 'STATEMENT'
            when '&&', '||'          then id
            else  tag
    
        tagToken = @token tag, id, 0, idLength
        tagToken.origin = [tag, alias, tagToken[2]] if alias
        if poppedToken
          [tagToken[2].first_line, tagToken[2].first_column] =
            [poppedToken[2].first_line, poppedToken[2].first_column]
        if colon
          colonOffset = input.lastIndexOf if inCSXTag then '=' else ':'
          colonToken = @token ':', ':', colonOffset, colon.length
          colonToken.csxColon = yes if inCSXTag # used by rewriter
        if inCSXTag and tag is 'IDENTIFIER' and prev[0] isnt ':'
          @token ',', ',', 0, 0, tagToken
    
        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]
        lexedLength = number.length
    
        switch
          when /^0[BOX]/.test number
            @error "radix prefix in '#{number}' must be lowercase", offset: 1
          when /^(?!0x).*E/.test number
            @error "exponential notation in '#{number}' must be indicated with a lowercase 'e'",
              offset: number.indexOf('E')
          when /^0\d*[89]/.test number
            @error "decimal literal '#{number}' must not be prefixed with '0'", length: lexedLength
          when /^0\d+/.test number
            @error "octal literal '#{number}' must be prefixed with '0o'", length: lexedLength
    
        base = switch number.charAt 1
          when 'b' then 2
          when 'o' then 8
          when 'x' then 16
          else null
    
        numberValue = if base? then parseInt(number[2..], base) else parseFloat(number)
    
        tag = if numberValue is Infinity then 'INFINITY' else 'NUMBER'
        @token tag, number, 0, lexedLength
        lexedLength
  • Matches strings, including multiline strings, as well as heredocs, with or without interpolation.

      stringToken: ->
        [quote] = STRING_START.exec(@chunk) || []
        return 0 unless quote
  • If the preceding token is from and this is an import or export statement, properly tag the from.

        prev = @prev()
        if prev and @value() is 'from' and (@seenImport or @seenExport)
          prev[0] = 'FROM'
    
        regex = switch quote
          when "'"   then STRING_SINGLE
          when '"'   then STRING_DOUBLE
          when "'''" then HEREDOC_SINGLE
          when '"""' then HEREDOC_DOUBLE
        heredoc = quote.length is 3
    
        {tokens, index: end} = @matchWithInterpolations regex, quote
        $ = tokens.length - 1
    
        delimiter = quote.charAt(0)
        if heredoc
  • Find the smallest indentation. It will be removed from all lines later.

          indent = null
          doc = (token[1] for token, i in tokens when token[0] is 'NEOSTRING').join '#{}'
          while match = HEREDOC_INDENT.exec doc
            attempt = match[1]
            indent = attempt if indent is null or 0 < attempt.length < indent.length
          indentRegex = /// \n#{indent} ///g if indent
          @mergeInterpolationTokens tokens, {delimiter}, (value, i) =>
            value = @formatString value, delimiter: quote
            value = value.replace indentRegex, '\n' if indentRegex
            value = value.replace LEADING_BLANK_LINE,  '' if i is 0
            value = value.replace TRAILING_BLANK_LINE, '' if i is $
            value
        else
          @mergeInterpolationTokens tokens, {delimiter}, (value, i) =>
            value = @formatString value, delimiter: quote
            value = value.replace SIMPLE_STRING_OMIT, (match, offset) ->
              if (i is 0 and offset is 0) or
                 (i is $ and offset + match.length is value.length)
                ''
              else
                ' '
            value
    
        if @atCSXTag()
          @token ',', ',', 0, 0, @prev
    
        end
  • Matches and consumes comments.

      commentToken: ->
        return 0 unless match = @chunk.match COMMENT
        [comment, here] = match
        if here
          if match = HERECOMMENT_ILLEGAL.exec comment
            @error "block comments cannot contain #{match[0]}",
              offset: match.index, length: match[0].length
          if here.indexOf('\n') >= 0
            here = here.replace /// \n #{repeat ' ', @indent} ///g, '\n'
          @token 'HERECOMMENT', here, 0, comment.length
        comment.length
  • Matches JavaScript interpolated directly into the source via backticks.

      jsToken: ->
        return 0 unless @chunk.charAt(0) is '`' and
          (match = HERE_JSTOKEN.exec(@chunk) or JSTOKEN.exec(@chunk))
  • Convert escaped backticks to backticks, and escaped backslashes just before escaped backticks to backslashes

        script = match[1].replace /\\+(`|$)/g, (string) ->
  • string is always a value like ‘`‘, ‘\`‘, ‘\\`‘, etc. By reducing it to its latter half, we turn ‘`‘ to ‘', '\\\‘ to ‘`‘, etc.

          string[-Math.ceil(string.length / 2)..]
        @token 'JS', script, 0, match[0].length
        match[0].length
  • Matches regular expression literals, as well as multiline extended ones. Lexing regular expressions is difficult to distinguish from division, so we borrow some basic heuristics from JavaScript and Ruby.

      regexToken: ->
        switch
          when match = REGEX_ILLEGAL.exec @chunk
            @error "regular expressions cannot begin with #{match[2]}",
              offset: match.index + match[1].length
          when match = @matchWithInterpolations HEREGEX, '///'
            {tokens, index} = match
          when match = REGEX.exec @chunk
            [regex, body, closed] = match
            @validateEscapes body, isRegex: yes, offsetInChunk: 1
            index = regex.length
            prev = @prev()
            if prev
              if prev.spaced and prev[0] in CALLABLE
                return 0 if not closed or POSSIBLY_DIVISION.test regex
              else if prev[0] in NOT_REGEX
                return 0
            @error 'missing / (unclosed regex)' unless closed
          else
            return 0
    
        [flags] = REGEX_FLAGS.exec @chunk[index..]
        end = index + flags.length
        origin = @makeToken 'REGEX', null, 0, end
        switch
          when not VALID_FLAGS.test flags
            @error "invalid regular expression flags #{flags}", offset: index, length: flags.length
          when regex or tokens.length is 1
            if body
              body = @formatRegex body, { flags, delimiter: '/' }
            else
              body = @formatHeregex tokens[0][1], { flags }
            @token 'REGEX', "#{@makeDelimitedLiteral body, delimiter: '/'}#{flags}", 0, end, origin
          else
            @token 'REGEX_START', '(', 0, 0, origin
            @token 'IDENTIFIER', 'RegExp', 0, 0
            @token 'CALL_START', '(', 0, 0
            @mergeInterpolationTokens tokens, {delimiter: '"', double: yes}, (str) =>
              @formatHeregex str, { flags }
            if flags
              @token ',', ',', index - 1, 0
              @token 'STRING', '"' + flags + '"', index - 1, flags.length
            @token ')', ')', end - 1, 0
            @token 'REGEX_END', ')', end - 1, 0
    
        end
  • Matches newlines, indents, and outdents, and determines which is which. If we can detect that the current line is continued onto 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]
    
        @seenFor = no
        @seenImport = no unless @importSpecifierList
        @seenExport = no unless @exportSpecifierList
    
        size = indent.length - 1 - indent.lastIndexOf '\n'
        noNewlines = @unfinished()
    
        newIndentLiteral = if size > 0 then indent[-size..] else ''
        unless /^(.?)\1*$/.exec newIndentLiteral
          @error 'mixed indentation', offset: indent.length
          return indent.length
    
        minLiteralLength = Math.min newIndentLiteral.length, @indentLiteral.length
        if newIndentLiteral[...minLiteralLength] isnt @indentLiteral[...minLiteralLength]
          @error 'indentation mismatch', offset: indent.length
          return indent.length
    
        if size - @indebt is @indent
          if noNewlines then @suppressNewlines() else @newlineToken 0
          return indent.length
    
        if size > @indent
          if noNewlines or @tag() is 'RETURN'
            @indebt = size - @indent
            @suppressNewlines()
            return indent.length
          unless @tokens.length
            @baseIndent = @indent = size
            @indentLiteral = newIndentLiteral
            return indent.length
          diff = size - @indent + @outdebt
          @token 'INDENT', diff, indent.length - size, size
          @indents.push diff
          @ends.push {tag: 'OUTDENT'}
          @outdebt = @indebt = 0
          @indent = size
          @indentLiteral = newIndentLiteral
        else if size < @baseIndent
          @error 'missing indentation', offset: indent.length
        else
          @indebt = 0
          @outdentToken @indent - size, noNewlines, indent.length
        indent.length
  • Record an outdent token or multiple tokens, if we happen to be moving back inwards past several recorded indents. Sets new @indent value.

      outdentToken: (moveOut, noNewlines, outdentLength) ->
        decreasedIndent = @indent - moveOut
        while moveOut > 0
          lastIndent = @indents[@indents.length - 1]
          if not lastIndent
            @outdebt = moveOut = 0
          else if @outdebt and moveOut <= @outdebt
            @outdebt -= moveOut
            moveOut   = 0
          else
            dent = @indents.pop() + @outdebt
            if outdentLength and @chunk[outdentLength] in INDENTABLE_CLOSERS
              decreasedIndent -= dent - moveOut
              moveOut = dent
            @outdebt = 0
  • pair might call outdentToken, so preserve decreasedIndent

            @pair 'OUTDENT'
            @token 'OUTDENT', moveOut, 0, outdentLength
            moveOut -= dent
        @outdebt -= moveOut if dent
        @tokens.pop() while @value() is ';'
    
        @token 'TERMINATOR', '\n', outdentLength, 0 unless @tag() is 'TERMINATOR' or noNewlines
        @indent = decreasedIndent
        @indentLiteral = @indentLiteral[...decreasedIndent]
        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 = @prev()
        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: (offset) ->
        @tokens.pop() while @value() is ';'
        @token 'TERMINATOR', '\n', offset, 0 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
  • CSX is like JSX but for CoffeeScript.

      csxToken: ->
        firstChar = @chunk[0]
        if firstChar is '<'
          match = CSX_IDENTIFIER.exec @chunk[1...]
          return 0 unless match and (
            @csxDepth > 0 or
  • Not the right hand side of an unspaced comparison (i.e. a<b).

            not (prev = @prev()) or
            prev.spaced or
            prev[0] not in COMPARABLE_LEFT_SIDE
          )
          [input, id, colon] = match
          origin = @token 'CSX_TAG', id, 1, id.length
          @token 'CALL_START', '('
          @token '{', '{'
          @ends.push tag: '/>', origin: origin, name: id
          @csxDepth++
          return id.length + 1
        else if csxTag = @atCSXTag()
          if @chunk[...2] is '/>'
            @pair '/>'
            @token '}', '}', 0, 2
            @token 'CALL_END', ')', 0, 2
            @csxDepth--
            return 2
          else if firstChar is '{'
            token = @token '(', '('
            @ends.push {tag: '}', origin: token}
            return 1
          else if firstChar is '>'
  • Ignore terminators inside a tag.

            @pair '/>' # As if the current tag was self-closing.
            origin = @token '}', '}'
            @token ',', ','
            {tokens, index: end} =
              @matchWithInterpolations INSIDE_CSX, '>', '</', CSX_INTERPOLATION
            @mergeInterpolationTokens tokens, {delimiter: '"'}, (value, i) =>
              @formatString value, delimiter: '>'
            match = CSX_IDENTIFIER.exec @chunk[end...]
            if not match or match[0] isnt csxTag.name
              @error "expected corresponding CSX closing tag for #{csxTag.name}",
                csxTag.origin[2]
            afterTag = end + csxTag.name.length
            if @chunk[afterTag] isnt '>'
              @error "missing closing > after tag name", offset: afterTag, length: 1
  • +1 for the closing >.

            @token 'CALL_END', ')', end, csxTag.name.length + 1
            @csxDepth--
            return afterTag + 1
          else
            return 0
        else if @atCSXTag 1
          if firstChar is '}'
            @pair firstChar
            @token ')', ')'
            @token ',', ','
            return 1
          else
            return 0
        else
          return 0
    
      atCSXTag: (depth = 0) ->
        return no if @csxDepth is 0
        i = @ends.length - 1
        i-- while @ends[i]?.tag is 'OUTDENT' or depth-- > 0 # Ignore indents.
        last = @ends[i]
        last?.tag is '/>' and last
  • 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 = @prev()
    
        if prev and value in ['=', COMPOUND_ASSIGN...]
          skipToken = false
          if value is '=' and prev[1] in ['||', '&&'] and not prev.spaced
            prev[0] = 'COMPOUND_ASSIGN'
            prev[1] += '='
            prev = @tokens[@tokens.length - 2]
            skipToken = true
          if prev and prev[0] isnt 'PROPERTY'
            origin = prev.origin ? prev
            message = isUnassignable prev[1], origin[1]
            @error message, origin[2] if message
          return value.length if skipToken
    
        if value is '{' and @seenImport
          @importSpecifierList = yes
        else if @importSpecifierList and value is '}'
          @importSpecifierList = no
        else if value is '{' and prev?[0] is 'EXPORT'
          @exportSpecifierList = yes
        else if @exportSpecifierList and value is '}'
          @exportSpecifierList = no
    
        if value is ';'
          @seenFor = @seenImport = @seenExport = no
          tag = 'TERMINATOR'
        else if value is '*' and prev[0] is 'EXPORT'
          tag = 'EXPORT_ALL'
        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 UNARY_MATH      then tag = 'UNARY_MATH'
        else if value in SHIFT           then tag = 'SHIFT'
        else if value is '?' and prev?.spaced then tag = 'BIN?'
        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'
        token = @makeToken tag, value
        switch value
          when '(', '{', '[' then @ends.push {tag: INVERSES[value], origin: token}
          when ')', '}', ']' then @pair value
        @tokens.push @makeToken tag, value
        value.length
  • Token Manipulators

  • 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
        paramEndToken = tokens[--i]
        paramEndToken[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
                paramEndToken[0] = 'CALL_END'
                return this
        this
  • Close up all remaining open blocks at the end of the file.

      closeIndentation: ->
        @outdentToken @indent
  • Match the contents of a delimited token and expand variables and expressions inside it 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 and tokenize until the { of #{ is balanced with a }.

    • regex matches the contents of a token (but not delimiter, and not #{ if interpolations are desired).
    • delimiter is the delimiter of the token. Examples are ', ", ''', """ and ///.
    • closingDelimiter is different from delimiter only in CSX
    • interpolators matches the start of an interpolation, for CSX it’s both { and < (i.e. nested CSX tag)

    This method allows us to have strings within interpolations within strings, ad infinitum.

      matchWithInterpolations: (regex, delimiter, closingDelimiter, interpolators) ->
        closingDelimiter ?= delimiter
        interpolators ?= /^#\{/
    
        tokens = []
        offsetInChunk = delimiter.length
        return null unless @chunk[...offsetInChunk] is delimiter
        str = @chunk[offsetInChunk..]
        loop
          [strPart] = regex.exec str
    
          @validateEscapes strPart, {isRegex: delimiter.charAt(0) is '/', offsetInChunk}
  • Push a fake 'NEOSTRING' token, which will get turned into a real string later.

          tokens.push @makeToken 'NEOSTRING', strPart, offsetInChunk
    
          str = str[strPart.length..]
          offsetInChunk += strPart.length
    
          break unless match = interpolators.exec str
          [interpolator] = match
  • To remove the # in #{.

          interpolationOffset = interpolator.length - 1
          [line, column] = @getLineAndColumnFromChunk offsetInChunk + interpolationOffset
          rest = str[interpolationOffset..]
          {tokens: nested, index} =
            new Lexer().tokenize rest, line: line, column: column, untilBalanced: on
  • Account for the # in #{

          index += interpolationOffset
    
          braceInterpolator = str[index - 1] is '}'
          if braceInterpolator
  • Turn the leading and trailing { and } into parentheses. Unnecessary parentheses will be removed later.

            [open, ..., close] = nested
            open[0]  = open[1]  = '('
            close[0] = close[1] = ')'
            close.origin = ['', 'end of interpolation', close[2]]
  • Remove leading 'TERMINATOR' (if any).

          nested.splice 1, 1 if nested[1]?[0] is 'TERMINATOR'
    
          unless braceInterpolator
  • We are not using { and }, so wrap the interpolated tokens instead.

            open = @makeToken '(', '(', offsetInChunk, 0
            close = @makeToken ')', ')', offsetInChunk + index, 0
            nested = [open, nested..., close]
  • Push a fake 'TOKENS' token, which will get turned into real tokens later.

          tokens.push ['TOKENS', nested]
    
          str = str[index..]
          offsetInChunk += index
    
        unless str[...closingDelimiter.length] is closingDelimiter
          @error "missing #{closingDelimiter}", length: delimiter.length
    
        [firstToken, ..., lastToken] = tokens
        firstToken[2].first_column -= delimiter.length
        if lastToken[1].substr(-1) is '\n'
          lastToken[2].last_line += 1
          lastToken[2].last_column = closingDelimiter.length - 1
        else
          lastToken[2].last_column += closingDelimiter.length
        lastToken[2].last_column -= 1 if lastToken[1].length is 0
    
        {tokens, index: offsetInChunk + closingDelimiter.length}
  • Merge the array tokens of the fake token types 'TOKENS' and 'NEOSTRING' (as returned by matchWithInterpolations) into the token stream. The value of 'NEOSTRING's are converted using fn and turned into strings using options first.

      mergeInterpolationTokens: (tokens, options, fn) ->
        if tokens.length > 1
          lparen = @token 'STRING_START', '(', 0, 0
    
        firstIndex = @tokens.length
        for token, i in tokens
          [tag, value] = token
          switch tag
            when 'TOKENS'
  • Optimize out empty interpolations (an empty pair of parentheses).

              continue if value.length is 2
  • Push all the tokens in the fake 'TOKENS' token. These already have sane location data.

              locationToken = value[0]
              tokensToPush = value
            when 'NEOSTRING'
  • Convert 'NEOSTRING' into 'STRING'.

              converted = fn.call this, token[1], i
  • Optimize out empty strings. We ensure that the tokens stream always starts with a string token, though, to make sure that the result really is a string.

              if converted.length is 0
                if i is 0
                  firstEmptyStringIndex = @tokens.length
                else
                  continue
  • However, there is one case where we can optimize away a starting empty string.

              if i is 2 and firstEmptyStringIndex?
                @tokens.splice firstEmptyStringIndex, 2 # Remove empty string and the plus.
              token[0] = 'STRING'
              token[1] = @makeDelimitedLiteral converted, options
              locationToken = token
              tokensToPush = [token]
          if @tokens.length > firstIndex
  • Create a 0-length “+” token.

            plusToken = @token '+', '+'
            plusToken[2] =
              first_line:   locationToken[2].first_line
              first_column: locationToken[2].first_column
              last_line:    locationToken[2].first_line
              last_column:  locationToken[2].first_column
          @tokens.push tokensToPush...
    
        if lparen
          [..., lastToken] = tokens
          lparen.origin = ['STRING', null,
            first_line:   lparen[2].first_line
            first_column: lparen[2].first_column
            last_line:    lastToken[2].last_line
            last_column:  lastToken[2].last_column
          ]
          rparen = @token 'STRING_END', ')'
          rparen[2] =
            first_line:   lastToken[2].last_line
            first_column: lastToken[2].last_column
            last_line:    lastToken[2].last_line
            last_column:  lastToken[2].last_column
  • Pairs up a closing token, ensuring that all listed pairs of tokens are correctly balanced throughout the course of the token stream.

      pair: (tag) ->
        [..., prev] = @ends
        unless tag is wanted = prev?.tag
          @error "unmatched #{tag}" unless 'OUTDENT' is wanted
  • Auto-close INDENT to support syntax like this:

    el.click((event) ->
      el.hide())
    
          [..., lastIndent] = @indents
          @outdentToken lastIndent, true
          return @pair tag
        @ends.pop()
  • Helpers

  • Returns the line and column number from an offset into the current chunk.

    offset is a number of characters into @chunk.

      getLineAndColumnFromChunk: (offset) ->
        if offset is 0
          return [@chunkLine, @chunkColumn]
    
        if offset >= @chunk.length
          string = @chunk
        else
          string = @chunk[..offset-1]
    
        lineCount = count string, '\n'
    
        column = @chunkColumn
        if lineCount > 0
          [..., lastLine] = string.split '\n'
          column = lastLine.length
        else
          column += string.length
    
        [@chunkLine + lineCount, column]
  • Same as token, except this just returns the token without adding it to the results.

      makeToken: (tag, value, offsetInChunk = 0, length = value.length) ->
        locationData = {}
        [locationData.first_line, locationData.first_column] =
          @getLineAndColumnFromChunk offsetInChunk
  • Use length - 1 for the final offset - we’re supplying the last_line and the last_column, so if last_column == first_column, then we’re looking at a character of length 1.

        lastCharacter = if length > 0 then (length - 1) else 0
        [locationData.last_line, locationData.last_column] =
          @getLineAndColumnFromChunk offsetInChunk + lastCharacter
    
        token = [tag, value, locationData]
    
        token
  • Add a token to the results. offset is the offset into the current @chunk where the token starts. length is the length of the token in the @chunk, after the offset. If not specified, the length of value will be used.

    Returns the new token.

      token: (tag, value, offsetInChunk, length, origin) ->
        token = @makeToken tag, value, offsetInChunk, length
        token.origin = origin if origin
        @tokens.push token
        token
  • Peek at the last tag in the token stream.

      tag: ->
        [..., token] = @tokens
        token?[0]
  • Peek at the last value in the token stream.

      value: ->
        [..., token] = @tokens
        token?[1]
  • Get the previous token in the token stream.

      prev: ->
        @tokens[@tokens.length - 1]
  • Are we in the midst of an unfinished expression?

      unfinished: ->
        LINE_CONTINUER.test(@chunk) or
        @tag() in ['\\', '.', '?.', '?::', 'UNARY', 'MATH', 'UNARY_MATH', '+', '-',
                   '**', 'SHIFT', 'RELATION', 'COMPARE', '&', '^', '|', '&&', '||',
                   'BIN?', 'THROW', 'EXTENDS', 'DEFAULT']
    
      formatString: (str, options) ->
        @replaceUnicodeCodePointEscapes str.replace(STRING_OMIT, '$1'), options
    
      formatHeregex: (str, options) ->
        @formatRegex str.replace(HEREGEX_OMIT, '$1$2'), merge(options, delimiter: '///')
    
      formatRegex: (str, options) ->
        @replaceUnicodeCodePointEscapes str, options
    
      unicodeCodePointToUnicodeEscapes: (codePoint) ->
        toUnicodeEscape = (val) ->
          str = val.toString 16
          "\\u#{repeat '0', 4 - str.length}#{str}"
        return toUnicodeEscape(codePoint) if codePoint < 0x10000
  • surrogate pair

        high = Math.floor((codePoint - 0x10000) / 0x400) + 0xD800
        low = (codePoint - 0x10000) % 0x400 + 0xDC00
        "#{toUnicodeEscape(high)}#{toUnicodeEscape(low)}"
  • Replace \u{...} with \uxxxx[\uxxxx] in regexes without u flag

      replaceUnicodeCodePointEscapes: (str, options) ->
        shouldReplace = options.flags? and 'u' not in options.flags
        str.replace UNICODE_CODE_POINT_ESCAPE, (match, escapedBackslash, codePointHex, offset) =>
          return escapedBackslash if escapedBackslash
    
          codePointDecimal = parseInt codePointHex, 16
          if codePointDecimal > 0x10ffff
            @error "unicode code point escapes greater than \\u{10ffff} are not allowed",
              offset: offset + options.delimiter.length
              length: codePointHex.length + 4
          return match unless shouldReplace
    
          @unicodeCodePointToUnicodeEscapes codePointDecimal
  • Validates escapes in strings and regexes.

      validateEscapes: (str, options = {}) ->
        invalidEscapeRegex =
          if options.isRegex
            REGEX_INVALID_ESCAPE
          else
            STRING_INVALID_ESCAPE
        match = invalidEscapeRegex.exec str
        return unless match
        [[], before, octal, hex, unicodeCodePoint, unicode] = match
        message =
          if octal
            "octal escape sequences are not allowed"
          else
            "invalid escape sequence"
        invalidEscape = "\\#{octal or hex or unicodeCodePoint or unicode}"
        @error "#{message} #{invalidEscape}",
          offset: (options.offsetInChunk ? 0) + match.index + before.length
          length: invalidEscape.length
  • Constructs a string or regex by escaping certain characters.

      makeDelimitedLiteral: (body, options = {}) ->
        body = '(?:)' if body is '' and options.delimiter is '/'
        regex = ///
            (\\\\)                               # Escaped backslash.
          | (\\0(?=[1-7]))                       # Null character mistaken as octal escape.
          | \\?(#{options.delimiter})            # (Possibly escaped) delimiter.
          | \\?(?: (\n)|(\r)|(\u2028)|(\u2029) ) # (Possibly escaped) newlines.
          | (\\.)                                # Other escapes.
        ///g
        body = body.replace regex, (match, backslash, nul, delimiter, lf, cr, ls, ps, other) -> switch
  • Ignore escaped backslashes.

          when backslash then (if options.double then backslash + backslash else backslash)
          when nul       then '\\x00'
          when delimiter then "\\#{delimiter}"
          when lf        then '\\n'
          when cr        then '\\r'
          when ls        then '\\u2028'
          when ps        then '\\u2029'
          when other     then (if options.double then "\\#{other}" else other)
        "#{options.delimiter}#{body}#{options.delimiter}"
  • Throws an error at either a given offset from the current chunk or at the location of a token (token[2]).

      error: (message, options = {}) ->
        location =
          if 'first_line' of options
            options
          else
            [first_line, first_column] = @getLineAndColumnFromChunk options.offset ? 0
            {first_line, first_column, last_column: first_column + (options.length ? 1) - 1}
        throwSyntaxError message, location
  • Helper functions

  • 
    isUnassignable = (name, displayName = name) -> switch
      when name in [JS_KEYWORDS..., COFFEE_KEYWORDS...]
        "keyword '#{displayName}' can't be assigned"
      when name in STRICT_PROSCRIBED
        "'#{displayName}' can't be assigned"
      when name in RESERVED
        "reserved word '#{displayName}' can't be assigned"
      else
        false
    
    exports.isUnassignable = isUnassignable
  • from isn’t a CoffeeScript keyword, but it behaves like one in import and export statements (handled above) and in the declaration line of a for loop. Try to detect when from is a variable identifier and when it is this “sometimes” keyword.

    isForFrom = (prev) ->
      if prev[0] is 'IDENTIFIER'
  • for i from from, for from from iterable

        if prev[1] is 'from'
          prev[1][0] = 'IDENTIFIER'
          yes
  • for i from iterable

        yes
  • for from…

      else if prev[0] is 'FOR'
        no
  • for {from}…, for [from]…, for {a, from}…, for {a: from}…

      else if prev[1] in ['{', '[', ',', ':']
        no
      else
        yes
  • 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', 'yield', 'await'
      'if', 'else', 'switch', 'for', 'while', 'do', 'try', 'catch', 'finally'
      'class', 'extends', 'super'
      'import', 'export', 'default'
    ]
  • CoffeeScript-only keywords.

    COFFEE_KEYWORDS = [
      'undefined', 'Infinity', 'NaN'
      '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', 'function', 'var', 'void', 'with', 'const', 'let', 'enum'
      'native', 'implements', 'interface', 'package', 'private'
      'protected', 'public', 'static'
    ]
    
    STRICT_PROSCRIBED = ['arguments', 'eval']
  • The superset of both JavaScript keywords and reserved words, none of which may be used as identifiers or properties.

    exports.JS_FORBIDDEN = JS_KEYWORDS.concat(RESERVED).concat(STRICT_PROSCRIBED)
  • The character code of the nasty Microsoft madness otherwise known as the BOM.

    BOM = 65279
  • Token matching regexes.

    IDENTIFIER = /// ^
      (?!\d)
      ( (?: (?!\s)[$\w\x7f-\uffff] )+ )
      ( [^\n\S]* : (?!:) )?  # Is this a property name?
    ///
    
    CSX_IDENTIFIER = /// ^
      (?![\d<]) # Must not start with `<`.
      ( (?: (?!\s)[\.\-$\w\x7f-\uffff] )+ ) # Like `IDENTIFIER`, but includes `-`s and `.`s.
    ///
    
    CSX_ATTRIBUTE = /// ^
      (?!\d)
      ( (?: (?!\s)[\-$\w\x7f-\uffff] )+ ) # Like `IDENTIFIER`, but includes `-`s.
      ( [^\S]* = (?!=) )?  # Is this an attribute with a value?
    ///
    
    NUMBER     = ///
      ^ 0b[01]+    |              # binary
      ^ 0o[0-7]+   |              # octal
      ^ 0x[\da-f]+ |              # hex
      ^ \d*\.?\d+ (?:e[+-]?\d+)?  # decimal
    ///i
    
    OPERATOR   = /// ^ (
      ?: [-=]>             # function
       | [-+*/%<>&|^!?=]=  # compound assign / compare
       | >>>=?             # zero-fill right shift
       | ([-+:])\1         # doubles
       | ([&|<>*/%])\2=?   # logic / shift / power / floor division / modulo
       | \?(\.|::)         # soak access
       | \.{2,3}           # range or splat
    ) ///
    
    WHITESPACE = /^[^\n\S]+/
    
    COMMENT    = /^###([^#][\s\S]*?)(?:###[^\n\S]*|###$)|^(?:\s*#(?!##[^#]).*)+/
    
    CODE       = /^[-=]>/
    
    MULTI_DENT = /^(?:\n[^\n\S]*)+/
    
    JSTOKEN      = ///^ `(?!``) ((?: [^`\\] | \\[\s\S]           )*) `   ///
    HERE_JSTOKEN = ///^ ```     ((?: [^`\\] | \\[\s\S] | `(?!``) )*) ``` ///
  • String-matching-regexes.

    STRING_START   = /^(?:'''|"""|'|")/
    
    STRING_SINGLE  = /// ^(?: [^\\']  | \\[\s\S]                      )* ///
    STRING_DOUBLE  = /// ^(?: [^\\"#] | \\[\s\S] |           \#(?!\{) )* ///
    HEREDOC_SINGLE = /// ^(?: [^\\']  | \\[\s\S] | '(?!'')            )* ///
    HEREDOC_DOUBLE = /// ^(?: [^\\"#] | \\[\s\S] | "(?!"") | \#(?!\{) )* ///
    
    INSIDE_CSX = /// ^(?:
        [^
          \{ # Start of CoffeeScript interpolation.
          <  # Maybe CSX tag (`<` not allowed even if bare).
        ]
      )* /// # Similar to `HEREDOC_DOUBLE` but there is no escaping.
    CSX_INTERPOLATION = /// ^(?:
          \{       # CoffeeScript interpolation.
        | <(?!/)   # CSX opening tag.
      )///
    
    STRING_OMIT    = ///
        ((?:\\\\)+)      # Consume (and preserve) an even number of backslashes.
      | \\[^\S\n]*\n\s*  # Remove escaped newlines.
    ///g
    SIMPLE_STRING_OMIT = /\s*\n\s*/g
    HEREDOC_INDENT     = /\n+([^\n\S]*)(?=\S)/g
  • Regex-matching-regexes.

    REGEX = /// ^
      / (?!/) ((
      ?: [^ [ / \n \\ ]  # Every other thing.
       | \\[^\n]         # Anything but newlines escaped.
       | \[              # Character class.
           (?: \\[^\n] | [^ \] \n \\ ] )*
         \]
      )*) (/)?
    ///
    
    REGEX_FLAGS  = /^\w*/
    VALID_FLAGS  = /^(?!.*(.).*\1)[imguy]*$/
    
    HEREGEX      = /// ^(?: [^\\/#] | \\[\s\S] | /(?!//) | \#(?!\{) )* ///
    
    HEREGEX_OMIT = ///
        ((?:\\\\)+)     # Consume (and preserve) an even number of backslashes.
      | \\(\s)          # Preserve escaped whitespace.
      | \s+(?:#.*)?     # Remove whitespace and comments.
    ///g
    
    REGEX_ILLEGAL = /// ^ ( / | /{3}\s*) (\*) ///
    
    POSSIBLY_DIVISION   = /// ^ /=?\s ///
  • Other regexes.

    HERECOMMENT_ILLEGAL = /\*\//
    
    LINE_CONTINUER      = /// ^ \s* (?: , | \??\.(?![.\d]) | :: ) ///
    
    STRING_INVALID_ESCAPE = ///
      ( (?:^|[^\\]) (?:\\\\)* )        # Make sure the escape isn’t escaped.
      \\ (
         ?: (0[0-7]|[1-7])             # octal escape
          | (x(?![\da-fA-F]{2}).{0,2}) # hex escape
          | (u\{(?![\da-fA-F]{1,}\})[^}]*\}?) # unicode code point escape
          | (u(?!\{|[\da-fA-F]{4}).{0,4}) # unicode escape
      )
    ///
    REGEX_INVALID_ESCAPE = ///
      ( (?:^|[^\\]) (?:\\\\)* )        # Make sure the escape isn’t escaped.
      \\ (
         ?: (0[0-7])                   # octal escape
          | (x(?![\da-fA-F]{2}).{0,2}) # hex escape
          | (u\{(?![\da-fA-F]{1,}\})[^}]*\}?) # unicode code point escape
          | (u(?!\{|[\da-fA-F]{4}).{0,4}) # unicode escape
      )
    ///
    
    UNICODE_CODE_POINT_ESCAPE = ///
      ( \\\\ )        # Make sure the escape isn’t escaped.
      |
      \\u\{ ( [\da-fA-F]+ ) \}
    ///g
    
    LEADING_BLANK_LINE  = /^[^\n\S]*\n/
    TRAILING_BLANK_LINE = /\n[^\n\S]*$/
    
    TRAILING_SPACES     = /\s+$/
  • Compound assignment tokens.

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

    UNARY = ['NEW', 'TYPEOF', 'DELETE', 'DO']
    
    UNARY_MATH = ['!', '~']
  • 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 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', 'PROPERTY', ')', ']', '?', '@', 'THIS', 'SUPER']
    INDEXABLE = CALLABLE.concat [
      'NUMBER', 'INFINITY', 'NAN', 'STRING', 'STRING_END', 'REGEX', 'REGEX_END'
      'BOOL', 'NULL', 'UNDEFINED', '}', '::'
    ]
  • Tokens which can be the left-hand side of a less-than comparison, i.e. a<b.

    COMPARABLE_LEFT_SIDE = ['IDENTIFIER', ')', ']', 'NUMBER']
  • Tokens which a regular expression will never immediately follow (except spaced CALLABLEs in some cases), but which a division operator can.

    See: http://www-archive.mozilla.org/js/language/js20-2002-04/rationale/syntax.html#regular-expressions

    NOT_REGEX = INDEXABLE.concat ['++', '--']
  • 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']
  • Additional indent in front of these is ignored.

    INDENTABLE_CLOSERS = [')', '}', ']']
coffeescript-1.12.7/docs/v2/annotated-source/nodes.html000066400000000000000000013114751313305734200230230ustar00rootroot00000000000000 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.

    Error.stackTraceLimit = Infinity
    
    {Scope} = require './scope'
    {isUnassignable, JS_FORBIDDEN} = require './lexer'
  • Import the helpers we plan to use.

    {compact, flatten, extend, merge, del, starts, ends, some,
    addLocationDataFn, locationDataToString, throwSyntaxError} = require './helpers'
  • Functions required by parser

    exports.extend = extend
    exports.addLocationDataFn = addLocationDataFn
  • Constant functions for nodes that don’t need customization.

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

  • The various nodes defined below all compile to a collection of CodeFragment objects. A CodeFragments is a block of generated code, and the location in the source file where the code came from. CodeFragments can be assembled together into working code just by catting together all the CodeFragments’ code snippets, in order.

    exports.CodeFragment = class CodeFragment
      constructor: (parent, code) ->
        @code = "#{code}"
        @locationData = parent?.locationData
        @type = parent?.constructor?.name or 'unknown'
    
      toString:   ->
        "#{@code}#{if @locationData then ": " + locationDataToString(@locationData) else ''}"
  • Convert an array of CodeFragments into a string.

    fragmentsToText = (fragments) ->
      (fragment.code for fragment in fragments).join('')
  • 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
    
      compile: (o, lvl) ->
        fragmentsToText @compileToFragments o, lvl
  • 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).

      compileToFragments: (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 jumpNode = @jumps()
          jumpNode.error 'cannot use a pure statement in an expression'
        o.sharedScope = yes
        func = new Code [], Block.wrap [this]
        args = []
        if @contains ((node) -> node instanceof SuperCall)
          func.bound = yes
        else if (argumentsNode = @contains isLiteralArguments) or @contains isLiteralThis
          args = [new ThisLiteral]
          if argumentsNode
            meth = 'apply'
            args.push new IdentifierLiteral 'arguments'
          else
            meth = 'call'
          func = new Value func, [new Access new PropertyName meth]
        parts = (new Call func, args).compileNode o
    
        switch
          when func.isGenerator or func.base?.isGenerator
            parts.unshift @makeCode "(yield* "
            parts.push    @makeCode ")"
          when func.isAsync or func.base?.isAsync
            parts.unshift @makeCode "(await "
            parts.push    @makeCode ")"
        parts
  • 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.

    If level is passed, then returns [val, ref], where val is the compiled value, and ref is the compiled reference. If level is not passed, this returns [val, ref] where the two values are raw nodes which have not been compiled.

      cache: (o, level, shouldCache) ->
        complex = if shouldCache? then shouldCache this else @shouldCache()
        if complex
          ref = new IdentifierLiteral o.scope.freeVariable 'ref'
          sub = new Assign ref, this
          if level then [sub.compileToFragments(o, level), [@makeCode(ref.value)]] else [sub, ref]
        else
          ref = if level then @compileToFragments o, level else this
          [ref, ref]
  • Occasionally it may be useful to make an expression behave as if it was ‘hoisted’, whereby the result of the expression is available before its location in the source, but the expression’s variable scope corresponds the source position. This is used extensively to deal with executable class bodies in classes.

    Calling this method mutates the node, proxying the compileNode and compileToFragments methods to store their result for later replacing the target node, which is returned by the call.

      hoist: ->
        @hoisted = yes
        target   = new HoistTarget @
    
        compileNode        = @compileNode
        compileToFragments = @compileToFragments
    
        @compileNode = (o) ->
          target.update compileNode, o
    
        @compileToFragments = (o) ->
          target.update compileToFragments, o
    
        target
    
      cacheToCodeFragments: (cacheValues) ->
        [fragmentsToText(cacheValues[0]), fragmentsToText(cacheValues[1])]
  • 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 nodes and returns the first one that verifies pred. Otherwise return undefined. contains does not cross scope boundaries.

      contains: (pred) ->
        node = undefined
        @traverseChildren no, (n) ->
          if pred n
            node = n
            return no
        node
  • 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) ->
          recur = func(child)
          child.traverseChildren(crossScope, func) unless recur is no
  • replaceInContext will traverse children looking for a node for which match returns true. Once found, the matching node will be replaced by the result of calling replacement.

      replaceInContext: (match, replacement) ->
        return false unless @children
        for attr in @children when children = @[attr]
          if Array.isArray children
            for child, i in children
              if match child
                children[i..i] = replacement child, @
                return true
              else
                return true if child.replaceInContext match, replacement
          else if match children
            @[attr] = replacement children, @
            return true
          else
            return true if children.replaceInContext match, replacement
    
      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 are the properties to recurse into when tree walking. The children list is the structure of the AST. The parent pointer, and the pointer to the children are how you can traverse the tree.

      children: []
  • isStatement has to do with “everything is an expression”. A few things can’t be expressions, such as break. Things that isStatement returns true for are things that can’t be used as expressions. There are some error messages that come from nodes.coffee due to statements ending up in expression position.

      isStatement: NO
  • jumps tells you if an expression, or an internal part of an expression has a flow control construct (like break, or continue, or return, or throw) that jumps out of the normal flow of control and can’t be used as a value. This is important because things like this make no sense; we have to disallow them.

      jumps: NO
  • If node.shouldCache() is false, it is safe to use node more than once. Otherwise you need to store the value of node in a variable and output that variable several times instead. Kind of like this: 5 need not be cached. returnFive(), however, could have side effects as a result of evaluating it more than once, and therefore we need to cache it. The parameter is named shouldCache rather than mustCache because there are also cases where we might not need to cache but where we want to, for example a long expression that may well be idempotent but we want to cache for brevity.

      shouldCache: YES
    
      isChainable: NO
      isAssignable: NO
      isNumber: NO
    
      unwrap: THIS
      unfoldSoak: NO
  • Is this node used to assign a certain variable?

      assigns: NO
  • For this node and all descendents, set the location data to locationData if the location data is not already set.

      updateLocationDataIfMissing: (locationData) ->
        return this if @locationData
        @locationData = locationData
    
        @eachChild (child) ->
          child.updateLocationDataIfMissing locationData
  • Throw a SyntaxError associated with this node’s location.

      error: (message) ->
        throwSyntaxError message, @locationData
    
      makeCode: (code) ->
        new CodeFragment this, code
    
      wrapInParentheses: (fragments) ->
        [@makeCode('('), fragments..., @makeCode(')')]
    
      wrapInBraces: (fragments) ->
        [@makeCode('{'), fragments..., @makeCode('}')]
  • fragmentsList is an array of arrays of fragments. Each array in fragmentsList will be concatonated together, with joinStr added in between each, to produce a final flat array of fragments.

      joinFragmentArrays: (fragmentsList, joinStr) ->
        answer = []
        for fragments,i in fragmentsList
          if i then answer.push @makeCode joinStr
          answer = answer.concat fragments
        answer
  • HoistTarget

  • A HoistTargetNode represents the output location in the node tree for a hoisted node. See Base#hoist.

    exports.HoistTarget = class HoistTarget extends Base
  • Expands hoisted fragments in the given array

      @expand = (fragments) ->
        for fragment, i in fragments by -1 when fragment.fragments
          fragments[i..i] = @expand fragment.fragments
        fragments
    
      constructor: (@source) ->
        super()
  • Holds presentational options to apply when the source node is compiled

        @options = {}
  • Placeholder fragments to be replaced by the source node’s compilation

        @targetFragments = { fragments: [] }
    
      isStatement: (o) ->
        @source.isStatement o
  • Update the target fragments with the result of compiling the source. Calls the given compile function with the node and options (overriden with the target presentational options).

      update: (compile, o) ->
        @targetFragments.fragments = compile.call @source, merge o, @options
  • Copies the target indent and level, and returns the placeholder fragments

      compileToFragments: (o, level) ->
        @options.indent = o.indent
        @options.level  = level ? o.level
        [ @targetFragments ]
    
      compileNode: (o) ->
        @compileToFragments o
    
      compileClosure: (o) ->
        @compileToFragments o
  • 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) ->
        super()
    
        @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 jumpNode if jumpNode = 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.

      compileToFragments: (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
        compiledNodes = []
    
        for node, index 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

            compiledNodes.push node.compileNode o
          else if node.hoisted
  • This is a hoisted expression. We want to compile this and ignore the result.

            node.compileToFragments o
          else if top
            node.front = true
            fragments = node.compileToFragments o
            unless node.isStatement o
              fragments.unshift @makeCode "#{@tab}"
              fragments.push @makeCode ';'
            compiledNodes.push fragments
          else
            compiledNodes.push node.compileToFragments o, LEVEL_LIST
        if top
          if @spaced
            return [].concat @joinFragmentArrays(compiledNodes, '\n\n'), @makeCode("\n")
          else
            return @joinFragmentArrays(compiledNodes, '\n')
        if compiledNodes.length
          answer = @joinFragmentArrays(compiledNodes, ', ')
        else
          answer = [@makeCode "void 0"]
        if compiledNodes.length > 1 and o.level >= LEVEL_LIST then @wrapInParentheses answer else answer
  • 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.level   = LEVEL_TOP
        @spaced   = yes
        o.scope   = new Scope null, this, null, o.referencedVars ? []
  • Mark given local variables in the root scope as parameters so they don’t end up being declared on this block.

        o.scope.parameter name for name in o.locals or []
        prelude   = []
        unless o.bare
          preludeExps = for exp, i in @expressions
            break unless exp.unwrap() instanceof Comment
            exp
          rest = @expressions[preludeExps.length...]
          @expressions = preludeExps
          if preludeExps.length
            prelude = @compileNode merge(o, indent: '')
            prelude.push @makeCode "\n"
          @expressions = rest
        fragments = @compileWithDeclarations o
        HoistTarget.expand fragments
        return fragments if o.bare
        [].concat prelude, @makeCode("(function() {\n"), fragments, @makeCode("\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) ->
        fragments = []
        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]
          [fragments, @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
            fragments.push @makeCode '\n' if i
            fragments.push @makeCode "#{@tab}var "
            if declars
              fragments.push @makeCode scope.declaredVariables().join(', ')
            if assigns
              fragments.push @makeCode ",\n#{@tab + TAB}" if declars
              fragments.push @makeCode scope.assignedVariables().join(",\n#{@tab + TAB}")
            fragments.push @makeCode ";\n#{if @spaced then '\n' else ''}"
          else if fragments.length and post.length
            fragments.push @makeCode "\n"
        fragments.concat 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

  • Literal is a base class for 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) ->
        super()
    
      shouldCache: NO
    
      assigns: (name) ->
        name is @value
    
      compileNode: (o) ->
        [@makeCode @value]
    
      toString: ->
        " #{if @isStatement() then super() else @constructor.name}: #{@value}"
    
    exports.NumberLiteral = class NumberLiteral extends Literal
    
    exports.InfinityLiteral = class InfinityLiteral extends NumberLiteral
      compileNode: ->
        [@makeCode '2e308']
    
    exports.NaNLiteral = class NaNLiteral extends NumberLiteral
      constructor: ->
        super 'NaN'
    
      compileNode: (o) ->
        code = [@makeCode '0/0']
        if o.level >= LEVEL_OP then @wrapInParentheses code else code
    
    exports.StringLiteral = class StringLiteral extends Literal
      compileNode: (o) ->
        res = if @csx then [@makeCode @unquote yes] else super()
    
      unquote: (literal) ->
        unquoted = @value[1...-1]
        if literal
          unquoted.replace /\\n/g, '\n'
          .replace /\\"/g, '"'
        else
          unquoted
    
    exports.RegexLiteral = class RegexLiteral extends Literal
    
    exports.PassthroughLiteral = class PassthroughLiteral extends Literal
    
    exports.IdentifierLiteral = class IdentifierLiteral extends Literal
      isAssignable: YES
    
      eachName: (iterator) ->
        iterator @
    
    exports.CSXTag = class CSXTag extends IdentifierLiteral
    
    exports.PropertyName = class PropertyName extends Literal
      isAssignable: YES
    
    exports.StatementLiteral = class StatementLiteral extends Literal
      isStatement: YES
    
      makeReturn: THIS
    
      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) ->
        [@makeCode "#{@tab}#{@value};"]
    
    exports.ThisLiteral = class ThisLiteral extends Literal
      constructor: ->
        super 'this'
    
      compileNode: (o) ->
        code = if o.scope.method?.bound then o.scope.method.context else @value
        [@makeCode code]
    
    exports.UndefinedLiteral = class UndefinedLiteral extends Literal
      constructor: ->
        super 'undefined'
    
      compileNode: (o) ->
        [@makeCode if o.level >= LEVEL_ACCESS then '(void 0)' else 'void 0']
    
    exports.NullLiteral = class NullLiteral extends Literal
      constructor: ->
        super 'null'
    
    exports.BooleanLiteral = class BooleanLiteral extends Literal
  • Return

  • A return is a pureStatement—wrapping it in a closure wouldn’t make sense.

    exports.Return = class Return extends Base
      constructor: (@expression) ->
        super()
    
      children: ['expression']
    
      isStatement:     YES
      makeReturn:      THIS
      jumps:           THIS
    
      compileToFragments: (o, level) ->
        expr = @expression?.makeReturn()
        if expr and expr not instanceof Return then expr.compileToFragments o, level else super o, level
    
      compileNode: (o) ->
        answer = []
  • TODO: If we call expression.compile() here twice, we’ll sometimes get back different results!

        answer.push @makeCode @tab + "return#{if @expression then " " else ""}"
        if @expression
          answer = answer.concat @expression.compileToFragments o, LEVEL_PAREN
        answer.push @makeCode ";"
        return answer
  • yield return works exactly like return, except that it turns the function into a generator.

    exports.YieldReturn = class YieldReturn extends Return
      compileNode: (o) ->
        unless o.scope.parent?
          @error 'yield can only occur inside functions'
        super o
    
    
    exports.AwaitReturn = class AwaitReturn extends Return
      compileNode: (o) ->
        unless o.scope.parent?
          @error 'await can only occur inside functions'
        super o
  • Value

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

    exports.Value = class Value extends Base
      constructor: (base, props, tag, isDefaultValue = no) ->
        super()
    
        return base if not props and base instanceof Value
    
        @base           = base
        @properties     = props or []
        @[tag]          = yes if tag
        @isDefaultValue = isDefaultValue
        return this
    
      children: ['base', 'properties']
  • Add a property (or properties ) Access to the list.

      add: (props) ->
        @properties = @properties.concat props
        this
    
      hasProperties: ->
        !!@properties.length
    
      bareLiteral: (type) ->
        not @properties.length and @base instanceof type
  • Some boolean checks for the benefit of other nodes.

      isArray        : -> @bareLiteral(Arr)
      isRange        : -> @bareLiteral(Range)
      shouldCache    : -> @hasProperties() or @base.shouldCache()
      isAssignable   : -> @hasProperties() or @base.isAssignable()
      isNumber       : -> @bareLiteral(NumberLiteral)
      isString       : -> @bareLiteral(StringLiteral)
      isRegex        : -> @bareLiteral(RegexLiteral)
      isUndefined    : -> @bareLiteral(UndefinedLiteral)
      isNull         : -> @bareLiteral(NullLiteral)
      isBoolean      : -> @bareLiteral(BooleanLiteral)
      isAtomic       : ->
        for node in @properties.concat @base
          return no if node.soak or node instanceof Call
        yes
    
      isNotCallable  : -> @isNumber() or @isString() or @isRegex() or
                          @isArray() or @isRange() or @isSplice() or @isObject() or
                          @isUndefined() or @isNull() or @isBoolean()
    
      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: ->
        [..., lastProp] = @properties
        lastProp instanceof Slice
    
      looksStatic: (className) ->
        (@this or @base instanceof ThisLiteral or @base.value is className) and
          @properties.length is 1 and @properties[0].name?.value isnt 'prototype'
  • 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] = @properties
        if @properties.length < 2 and not @base.shouldCache() and not name?.shouldCache()
          return [this, this]  # `a` `a.b`
        base = new Value @base, @properties[...-1]
        if base.shouldCache()  # `a().b`
          bref = new IdentifierLiteral o.scope.freeVariable 'base'
          base = new Value new Parens new Assign bref, base
        return [base, bref] unless name  # `a()`
        if name.shouldCache()  # `a[b()]`
          nref = new IdentifierLiteral 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
        fragments = @base.compileToFragments o, (if props.length then LEVEL_ACCESS else null)
        if props.length and SIMPLENUM.test fragmentsToText fragments
          fragments.push @makeCode '.'
        for prop in props
          fragments.push (prop.compileToFragments o)...
        fragments
  • Unfold a soak into an If: a?.b -> a.b if a?

      unfoldSoak: (o) ->
        @unfoldedSoak ?= do =>
          if ifn = @base.unfoldSoak o
            ifn.body.properties.push @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.shouldCache()
              ref = new IdentifierLiteral o.scope.freeVariable 'ref'
              fst = new Parens new Assign ref, fst
              snd.base = ref
            return new If new Existence(fst), snd, soak: on
          no
    
      eachName: (iterator) ->
        if @hasProperties()
          iterator @
        else if @base.isAssignable()
          @base.eachName iterator
        else
          @error 'tried to assign to unassignable value'
  • Comment

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

    exports.Comment = class Comment extends Base
      constructor: (@comment) ->
        super()
    
      isStatement:     YES
      makeReturn:      THIS
    
      compileNode: (o, level) ->
        comment = @comment.replace /^(\s*)#(?=\s)/gm, "$1 *"
        code = "/*#{multident comment, @tab}#{if '\n' in comment then "\n#{@tab}" else ''} */"
        code = o.indent + code if (level or o.level) is LEVEL_TOP
        [@makeCode("\n"), @makeCode(code)]
  • Call

  • Node for a function invocation.

    exports.Call = class Call extends Base
      constructor: (@variable, @args = [], @soak) ->
        super()
    
        @isNew = no
        if @variable instanceof Value and @variable.isNotCallable()
          @variable.error "literal is not a function"
    
        @csx = @variable.base instanceof CSXTag
    
      children: ['variable', 'args']
  • When setting the location, we sometimes need to update the start location to account for a newly-discovered new operator to the left of us. This expands the range on the left, but not the right.

      updateLocationDataIfMissing: (locationData) ->
        if @locationData and @needsUpdatedStartLocation
          @locationData.first_line = locationData.first_line
          @locationData.first_column = locationData.first_column
          base = @variable?.base or @variable
          if base.needsUpdatedStartLocation
            @variable.locationData.first_line = locationData.first_line
            @variable.locationData.first_column = locationData.first_column
            base.updateLocationDataIfMissing locationData
          delete @needsUpdatedStartLocation
        super locationData
  • 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
        @needsUpdatedStartLocation = true
        this
  • Soaked chained invocations unfold into if/else ternary structures.

      unfoldSoak: (o) ->
        if @soak
          if @variable instanceof Super
            left = new Literal @variable.compile o
            rite = new Value left
            @variable.error "Unsupported reference to 'super'" unless @variable.accessor?
          else
            return ifn if ifn = unfoldSoak o, this, 'variable'
            [left, rite] = new Value(@variable).cacheReference o
          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
  • Compile a vanilla function call.

      compileNode: (o) ->
        return @compileCSX o if @csx
        @variable?.front = @front
        compiledArgs = []
        for arg, argIndex in @args
          if argIndex then compiledArgs.push @makeCode ", "
          compiledArgs.push (arg.compileToFragments o, LEVEL_LIST)...
    
        fragments = []
        if @isNew
          @variable.error "Unsupported reference to 'super'" if @variable instanceof Super
          fragments.push @makeCode 'new '
        fragments.push @variable.compileToFragments(o, LEVEL_ACCESS)...
        fragments.push @makeCode('('), compiledArgs..., @makeCode(')')
        fragments
    
      compileCSX: (o) ->
        [attributes, content] = @args
        attributes.base.csx = yes
        content?.base.csx = yes
        fragments = [@makeCode('<')]
        fragments.push (tag = @variable.compileToFragments(o, LEVEL_ACCESS))...
        fragments.push attributes.compileToFragments(o, LEVEL_PAREN)...
        if content
          fragments.push @makeCode('>')
          fragments.push content.compileNode(o, LEVEL_LIST)...
          fragments.push [@makeCode('</'), tag..., @makeCode('>')]...
        else
          fragments.push @makeCode(' />')
        fragments
  • Super

  • Takes care of converting super() calls into calls against the prototype’s function of the same name. When expressions are set the call will be compiled in such a way that the expressions are evaluated without altering the return value of the SuperCall expression.

    exports.SuperCall = class SuperCall extends Call
      children: Call::children.concat ['expressions']
    
      isStatement: (o) ->
        @expressions?.length and o.level is LEVEL_TOP
    
      compileNode: (o) ->
        return super o unless @expressions?.length
    
        superCall   = new Literal fragmentsToText super o
        replacement = new Block @expressions.slice()
    
        if o.level > LEVEL_TOP
  • If we might be in an expression we need to cache and return the result

          [superCall, ref] = superCall.cache o, null, YES
          replacement.push ref
    
        replacement.unshift superCall
        replacement.compileToFragments o, if o.level is LEVEL_TOP then o.level else LEVEL_LIST
    
    exports.Super = class Super extends Base
      children: ['accessor']
    
      constructor: (@accessor) ->
        super()
    
      compileNode: (o) ->
        method = o.scope.namedMethod()
        @error 'cannot use super outside of an instance method' unless method?.isMethod
    
        @inCtor = !!method.ctor
    
        unless @inCtor or @accessor?
          {name, variable} = method
          if name.shouldCache() or (name instanceof Index and name.index.isAssignable())
            nref = new IdentifierLiteral o.scope.parent.freeVariable 'name'
            name.index = new Assign nref, name.index
          @accessor = if nref? then new Index nref else name
    
        (new Value (new Literal 'super'), if @accessor then [ @accessor ] else []).compileToFragments o
  • RegexWithInterpolations

  • Regexes with interpolations are in fact just a variation of a Call (a RegExp() call to be precise) with a StringWithInterpolations inside.

    exports.RegexWithInterpolations = class RegexWithInterpolations extends Call
      constructor: (args = []) ->
        super (new Value new IdentifierLiteral 'RegExp'), args, false
  • TaggedTemplateCall

    exports.TaggedTemplateCall = class TaggedTemplateCall extends Call
      constructor: (variable, arg, soak) ->
        arg = new StringWithInterpolations Block.wrap([ new Value arg ]) if arg instanceof StringLiteral
        super variable, [ arg ], soak
    
      compileNode: (o) ->
        @variable.compileToFragments(o, LEVEL_ACCESS).concat @args[0].compileToFragments(o, LEVEL_LIST)
  • 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) ->
        super()
    
      children: ['child', 'parent']
  • Hooks one constructor into another’s prototype chain.

      compileToFragments: (o) ->
        new Call(new Value(new Literal utility 'extend', o), [@child, @parent]).compileToFragments 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) ->
        super()
        @soak  = tag is 'soak'
    
      children: ['name']
    
      compileToFragments: (o) ->
        name = @name.compileToFragments o
        node = @name.unwrap()
        if node instanceof PropertyName
          [@makeCode('.'), name...]
        else
          [@makeCode('['), name..., @makeCode(']')]
    
      shouldCache: NO
  • Index

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

    exports.Index = class Index extends Base
      constructor: (@index) ->
        super()
    
      children: ['index']
    
      compileToFragments: (o) ->
        [].concat @makeCode("["), @index.compileToFragments(o, LEVEL_PAREN), @makeCode("]")
    
      shouldCache: ->
        @index.shouldCache()
  • 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) ->
        super()
    
        @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
        shouldCache = del o, 'shouldCache'
        [@fromC, @fromVar] = @cacheToCodeFragments @from.cache o, LEVEL_LIST, shouldCache
        [@toC, @toVar]     = @cacheToCodeFragments @to.cache o, LEVEL_LIST, shouldCache
        [@step, @stepVar]  = @cacheToCodeFragments step.cache o, LEVEL_LIST, shouldCache if step = del o, 'step'
        @fromNum = if @from.isNumber() then Number @fromVar else null
        @toNum   = if @to.isNumber()   then Number @toVar   else null
        @stepNum = if step?.isNumber() then Number @stepVar else null
  • 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 = if @stepVar then "#{@stepVar} > 0" else "#{@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.

        [@makeCode "#{varPart}; #{condPart}; #{stepPart}"]
  • When used as a value, expand the range into the equivalent array.

      compileArray: (o) ->
        known = @fromNum? and @toNum?
        if known and Math.abs(@fromNum - @toNum) <= 20
          range = [@fromNum..@toNum]
          range.pop() if @exclusive
          return [@makeCode "[#{ range.join(', ') }]"]
        idt    = @tab + TAB
        i      = o.scope.freeVariable 'i', single: true
        result = o.scope.freeVariable 'results'
        pre    = "\n#{idt}#{result} = [];"
        if known
          o.index = i
          body    = fragmentsToText @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 isLiteralArguments
        args   = ', arguments' if hasArgs(@from) or hasArgs(@to)
        [@makeCode "(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
        fromCompiled = from and from.compileToFragments(o, LEVEL_PAREN) or [@makeCode '0']
  • TODO: jwalton - move this into the ‘if’?

        if to
          compiled     = to.compileToFragments o, LEVEL_PAREN
          compiledText = fragmentsToText compiled
          if not (not @range.exclusive and +compiledText is -1)
            toStr = ', ' + if @range.exclusive
              compiledText
            else if to.isNumber()
              "#{+compiledText + 1}"
            else
              compiled = to.compileToFragments o, LEVEL_ACCESS
              "+#{fragmentsToText compiled} + 1 || 9e9"
        [@makeCode ".slice(#{ fragmentsToText fromCompiled }#{ toStr or '' })"]
  • Obj

  • An object literal, nothing fancy.

    exports.Obj = class Obj extends Base
      constructor: (props, @generated = no, @lhs = no) ->
        super()
    
        @objects = @properties = props or []
    
      children: ['properties']
    
      isAssignable: ->
        for prop in @properties
  • Check for reserved words.

          message = isUnassignable prop.unwrapAll().value
          prop.error message if message
    
          prop = prop.value if prop instanceof Assign and prop.context is 'object'
          return no unless prop.isAssignable()
        yes
    
      shouldCache: ->
        not @isAssignable()
  • Check if object contains splat.

      hasSplat: ->
        splat = yes for prop in @properties when prop instanceof Splat
        splat ? no
    
      compileNode: (o) ->
        props = @properties
        if @generated
          for node in props when node instanceof Value
            node.error 'cannot have an implicit value in an implicit object'
  •     return @compileSpread o if @hasSplat()
    
        idt        = o.indent += TAB
        lastNoncom = @lastNonComment @properties
  • If this object is the left-hand side of an assignment, all its children are too.

        if @lhs
          for prop in props when prop instanceof Assign
            {value} = prop
            unwrappedVal = value.unwrapAll()
            if unwrappedVal instanceof Arr or unwrappedVal instanceof Obj
              unwrappedVal.lhs = yes
            else if unwrappedVal instanceof Assign
              unwrappedVal.nestedLhs = yes
    
        isCompact = yes
        for prop in @properties
          if prop instanceof Comment or (prop instanceof Assign and prop.context is 'object' and not @csx)
            isCompact = no
    
        answer = []
        answer.push @makeCode if isCompact then '' else '\n'
        for prop, i in props
          join = if i is props.length - 1
            ''
          else if isCompact and @csx
            ' '
          else if isCompact
            ', '
          else if prop is lastNoncom or prop instanceof Comment or @csx
            '\n'
          else
            ',\n'
          indent = if isCompact or prop instanceof Comment then '' else idt
    
          key = if prop instanceof Assign and prop.context is 'object'
            prop.variable
          else if prop instanceof Assign
            prop.operatorToken.error "unexpected #{prop.operatorToken.value}" unless @lhs
            prop.variable
          else if prop not instanceof Comment
            prop
          if key instanceof Value and key.hasProperties()
            key.error 'invalid object key' if prop.context is 'object' or not key.this
            key  = key.properties[0].name
            prop = new Assign key, prop, 'object'
          if key is prop
            if prop.shouldCache()
              [key, value] = prop.base.cache o
              key  = new PropertyName key.value if key instanceof IdentifierLiteral
              prop = new Assign key, value, 'object'
            else if not prop.bareLiteral?(IdentifierLiteral)
              prop = new Assign prop, prop, 'object'
          if indent then answer.push @makeCode indent
          prop.csx = yes if @csx
          answer.push @makeCode ' ' if @csx and i is 0
          answer.push prop.compileToFragments(o, LEVEL_TOP)...
          if join then answer.push @makeCode join
        answer.push @makeCode if isCompact then '' else "\n#{@tab}"
        answer = @wrapInBraces answer if not @csx
        if @front then @wrapInParentheses answer else answer
    
      assigns: (name) ->
        for prop in @properties when prop.assigns name then return yes
        no
    
      eachName: (iterator) ->
        for prop in @properties
          prop = prop.value if prop instanceof Assign and prop.context is 'object'
          prop = prop.unwrapAll()
          prop.eachName iterator if prop.eachName?
  • Object spread properties. https://github.com/tc39/proposal-object-rest-spread/blob/master/Spread.md obj2 = {a: 1, obj..., c: 3, d: 4}obj2 = Object.assign({}, {a: 1}, obj, {c: 3, d: 4})

      compileSpread: (o) ->
        props = @properties
  • Store object spreads.

        splatSlice = []
        propSlices = []
        slices = []
        addSlice = ->
          slices.push new Obj propSlices if propSlices.length
          slices.push splatSlice... if splatSlice.length
          splatSlice = []
          propSlices = []
        for prop in props
          if prop instanceof Splat
            splatSlice.push new Value prop.name
            addSlice()
          else
            propSlices.push prop
        addSlice()
        slices.unshift new Obj unless slices[0] instanceof Obj
        (new Call new Literal('Object.assign'), slices).compileToFragments o
  • Arr

  • An array literal.

    exports.Arr = class Arr extends Base
      constructor: (objs, @lhs = no) ->
        super()
    
        @objects = objs or []
    
      children: ['objects']
    
      isAssignable: ->
        return no unless @objects.length
    
        for obj, i in @objects
          return no if obj instanceof Splat and i + 1 isnt @objects.length
          return no unless obj.isAssignable() and (not obj.isAtomic or obj.isAtomic())
        yes
    
      shouldCache: ->
        not @isAssignable()
    
      compileNode: (o) ->
        return [@makeCode '[]'] unless @objects.length
        o.indent += TAB
    
        answer = []
  • If this array is the left-hand side of an assignment, all its children are too.

        if @lhs
          for obj in @objects
            unwrappedObj = obj.unwrapAll()
            unwrappedObj.lhs = yes if unwrappedObj instanceof Arr or unwrappedObj instanceof Obj
    
        compiledObjs = (obj.compileToFragments o, LEVEL_LIST for obj in @objects)
        for fragments, index in compiledObjs
          if index
            answer.push @makeCode ", "
          answer.push fragments...
        if fragmentsToText(answer).indexOf('\n') >= 0
          answer.unshift @makeCode "[\n#{o.indent}"
          answer.push @makeCode "\n#{@tab}]"
        else
          answer.unshift @makeCode '['
          answer.push @makeCode ']'
        answer
    
      assigns: (name) ->
        for obj in @objects when obj.assigns name then return yes
        no
    
      eachName: (iterator) ->
        for obj in @objects
          obj = obj.unwrapAll()
          obj.eachName iterator
  • Class

  • The CoffeeScript class definition. Initialize a Class with its name, an optional superclass, and a body.

    exports.Class = class Class extends Base
      children: ['variable', 'parent', 'body']
    
      constructor: (@variable, @parent, @body = new Block) ->
        super()
    
      compileNode: (o) ->
        @name          = @determineName()
        executableBody = @walkBody()
  • Special handling to allow class expr.A extends A declarations

        parentName    = @parent.base.value if @parent instanceof Value and not @parent.hasProperties()
        @hasNameClash = @name? and @name is parentName
    
        node = @
    
        if executableBody or @hasNameClash
          node = new ExecutableClassBody node, executableBody
        else if not @name? and o.level is LEVEL_TOP
  • Anonymous classes are only valid in expressions

          node = new Parens node
    
        if @boundMethods.length and @parent
          @variable ?= new IdentifierLiteral o.scope.freeVariable '_class'
          [@variable, @variableRef] = @variable.cache o unless @variableRef?
    
        if @variable
          node = new Assign @variable, node, null, { @moduleDeclaration }
    
        @compileNode = @compileClassDeclaration
        try
          return node.compileToFragments o
        finally
          delete @compileNode
    
      compileClassDeclaration: (o) ->
        @ctor ?= @makeDefaultConstructor() if @externalCtor or @boundMethods.length
        @ctor?.noReturn = true
    
        @proxyBoundMethods() if @boundMethods.length
    
        o.indent += TAB
    
        result = []
        result.push @makeCode "class "
        result.push @makeCode "#{@name} " if @name
        result.push @makeCode('extends '), @parent.compileToFragments(o)..., @makeCode ' ' if @parent
    
        result.push @makeCode '{'
        unless @body.isEmpty()
          @body.spaced = true
          result.push @makeCode '\n'
          result.push @body.compileToFragments(o, LEVEL_TOP)...
          result.push @makeCode "\n#{@tab}"
        result.push @makeCode '}'
    
        result
  • Figure out the appropriate name for this class

      determineName: ->
        return null unless @variable
        [..., tail] = @variable.properties
        node = if tail
          tail instanceof Access and tail.name
        else
          @variable.base
        unless node instanceof IdentifierLiteral or node instanceof PropertyName
          return null
        name = node.value
        unless tail
          message = isUnassignable name
          @variable.error message if message
        if name in JS_FORBIDDEN then "_#{name}" else name
    
      walkBody: ->
        @ctor          = null
        @boundMethods  = []
        executableBody = null
    
        initializer     = []
        { expressions } = @body
    
        i = 0
        for expression in expressions.slice()
          if expression instanceof Value and expression.isObject true
            { properties } = expression.base
            exprs     = []
            end       = 0
            start     = 0
            pushSlice = -> exprs.push new Value new Obj properties[start...end], true if end > start
    
            while assign = properties[end]
              if initializerExpression = @addInitializerExpression assign
                pushSlice()
                exprs.push initializerExpression
                initializer.push initializerExpression
                start = end + 1
              else if initializer[initializer.length - 1] instanceof Comment
  • Try to keep comments with their subsequent assign

                exprs.pop()
                initializer.pop()
                start--
              end++
            pushSlice()
    
            expressions[i..i] = exprs
            i += exprs.length
          else
            if initializerExpression = @addInitializerExpression expression
              initializer.push initializerExpression
              expressions[i] = initializerExpression
            else if initializer[initializer.length - 1] instanceof Comment
  • Try to keep comments with their subsequent assign

              initializer.pop()
            i += 1
    
        for method in initializer when method instanceof Code
          if method.ctor
            method.error 'Cannot define more than one constructor in a class' if @ctor
            @ctor = method
          else if method.isStatic and method.bound
            method.context = @name
          else if method.bound
            @boundMethods.push method
    
        if initializer.length isnt expressions.length
          @body.expressions = (expression.hoist() for expression in initializer)
          new Block expressions
  • Add an expression to the class initializer

    NOTE Currently, only comments, methods and static methods are valid in ES class initializers. When additional expressions become valid, this method should be updated to handle them.

      addInitializerExpression: (node) ->
        switch
          when node instanceof Comment
            node
          when @validInitializerMethod node
            @addInitializerMethod node
          else
            null
  • Checks if the given node is a valid ES class initializer method.

      validInitializerMethod: (node) ->
        return false unless node instanceof Assign and node.value instanceof Code
        return true if node.context is 'object' and not node.variable.hasProperties()
        return node.variable.looksStatic(@name) and (@name or not node.value.bound)
  • Returns a configured class initializer method

      addInitializerMethod: (assign) ->
        { variable, value: method } = assign
        method.isMethod = yes
        method.isStatic = variable.looksStatic @name
    
        if method.isStatic
          method.name = variable.properties[0]
        else
          methodName  = variable.base
          method.name = new (if methodName.shouldCache() then Index else Access) methodName
          method.name.updateLocationDataIfMissing methodName.locationData
          method.ctor = (if @parent then 'derived' else 'base') if methodName.value is 'constructor'
          method.error 'Cannot define a constructor as a bound (fat arrow) function' if method.bound and method.ctor
    
        method
    
      makeDefaultConstructor: ->
        ctor = @addInitializerMethod new Assign (new Value new PropertyName 'constructor'), new Code
        @body.unshift ctor
    
        if @parent
          ctor.body.push new SuperCall new Super, [new Splat new IdentifierLiteral 'arguments']
    
        if @externalCtor
          applyCtor = new Value @externalCtor, [ new Access new PropertyName 'apply' ]
          applyArgs = [ new ThisLiteral, new IdentifierLiteral 'arguments' ]
          ctor.body.push new Call applyCtor, applyArgs
          ctor.body.makeReturn()
    
        ctor
    
      proxyBoundMethods: ->
        @ctor.thisAssignments = for method in @boundMethods
          method.classVariable = @variableRef if @parent
    
          name = new Value(new ThisLiteral, [ method.name ])
          new Assign name, new Call(new Value(name, [new Access new PropertyName 'bind']), [new ThisLiteral])
    
        null
    
    exports.ExecutableClassBody = class ExecutableClassBody extends Base
      children: [ 'class', 'body' ]
    
      defaultClassVariableName: '_Class'
    
      constructor: (@class, @body = new Block) ->
        super()
    
      compileNode: (o) ->
        if jumpNode = @body.jumps()
          jumpNode.error 'Class bodies cannot contain pure statements'
        if argumentsNode = @body.contains isLiteralArguments
          argumentsNode.error "Class bodies shouldn't reference arguments"
    
        @name      = @class.name ? @defaultClassVariableName
        directives = @walkBody()
        @setContext()
    
        ident   = new IdentifierLiteral @name
        params  = []
        args    = []
        wrapper = new Code params, @body
        klass   = new Parens new Call wrapper, args
    
        @body.spaced = true
    
        o.classScope = wrapper.makeScope o.scope
    
        if @class.hasNameClash
          parent = new IdentifierLiteral o.classScope.freeVariable 'superClass'
          wrapper.params.push new Param parent
          args.push @class.parent
          @class.parent = parent
    
        if @externalCtor
          externalCtor = new IdentifierLiteral o.classScope.freeVariable 'ctor', reserve: no
          @class.externalCtor = externalCtor
          @externalCtor.variable.base = externalCtor
    
        if @name isnt @class.name
          @body.expressions.unshift new Assign (new IdentifierLiteral @name), @class
        else
          @body.expressions.unshift @class
        @body.expressions.unshift directives...
        @body.push ident
    
        klass.compileToFragments o
  • Traverse the class’s children and:

    • Hoist valid ES properties into @properties
    • Hoist static assignments into @properties
    • Convert invalid ES properties into class or prototype assignments
      walkBody: ->
        directives  = []
    
        index = 0
        while expr = @body.expressions[index]
          break unless expr instanceof Comment or expr instanceof Value and expr.isString()
          if expr.hoisted
            index++
          else
            directives.push @body.expressions.splice(index, 1)...
    
        @traverseChildren false, (child) =>
          return false if child instanceof Class or child instanceof HoistTarget
    
          cont = true
          if child instanceof Block
            for node, i in child.expressions
              if node instanceof Value and node.isObject(true)
                cont = false
                child.expressions[i] = @addProperties node.base.properties
              else if node instanceof Assign and node.variable.looksStatic @name
                node.value.isStatic = yes
            child.expressions = flatten child.expressions
          cont
    
        directives
    
      setContext: ->
        @body.traverseChildren false, (node) =>
          if node instanceof ThisLiteral
            node.value   = @name
          else if node instanceof Code and node.bound and node.isStatic
            node.context = @name
  • Make class/prototype assignments for invalid ES properties

      addProperties: (assigns) ->
        result = for assign in assigns
          variable = assign.variable
          base     = variable?.base
          value    = assign.value
          delete assign.context
    
          if assign instanceof Comment
  • Passthrough

          else if base.value is 'constructor'
            if value instanceof Code
              base.error 'constructors must be defined at the top level of a class body'
  • The class scope is not available yet, so return the assignment to update later

            assign = @externalCtor = new Assign new Value, value
          else if not assign.variable.this
            name      = new (if base.shouldCache() then Index else Access) base
            prototype = new Access new PropertyName 'prototype'
            variable  = new Value new ThisLiteral(), [ prototype, name ]
    
            assign.variable = variable
          else if assign.value instanceof Code
            assign.value.isStatic = true
    
          assign
        compact result
  • Import and Export

    exports.ModuleDeclaration = class ModuleDeclaration extends Base
      constructor: (@clause, @source) ->
        super()
        @checkSource()
    
      children: ['clause', 'source']
    
      isStatement: YES
      jumps:       THIS
      makeReturn:  THIS
    
      checkSource: ->
        if @source? and @source instanceof StringWithInterpolations
          @source.error 'the name of the module to be imported from must be an uninterpolated string'
    
      checkScope: (o, moduleDeclarationType) ->
        if o.indent.length isnt 0
          @error "#{moduleDeclarationType} statements must be at top-level scope"
    
    exports.ImportDeclaration = class ImportDeclaration extends ModuleDeclaration
      compileNode: (o) ->
        @checkScope o, 'import'
        o.importedSymbols = []
    
        code = []
        code.push @makeCode "#{@tab}import "
        code.push @clause.compileNode(o)... if @clause?
    
        if @source?.value?
          code.push @makeCode ' from ' unless @clause is null
          code.push @makeCode @source.value
    
        code.push @makeCode ';'
        code
    
    exports.ImportClause = class ImportClause extends Base
      constructor: (@defaultBinding, @namedImports) ->
        super()
    
      children: ['defaultBinding', 'namedImports']
    
      compileNode: (o) ->
        code = []
    
        if @defaultBinding?
          code.push @defaultBinding.compileNode(o)...
          code.push @makeCode ', ' if @namedImports?
    
        if @namedImports?
          code.push @namedImports.compileNode(o)...
    
        code
    
    exports.ExportDeclaration = class ExportDeclaration extends ModuleDeclaration
      compileNode: (o) ->
        @checkScope o, 'export'
    
        code = []
        code.push @makeCode "#{@tab}export "
        code.push @makeCode 'default ' if @ instanceof ExportDefaultDeclaration
    
        if @ not instanceof ExportDefaultDeclaration and
           (@clause instanceof Assign or @clause instanceof Class)
  • Prevent exporting an anonymous class; all exported members must be named

          if @clause instanceof Class and not @clause.variable
            @clause.error 'anonymous classes cannot be exported'
    
          code.push @makeCode 'var '
          @clause.moduleDeclaration = 'export'
    
        if @clause.body? and @clause.body instanceof Block
          code = code.concat @clause.compileToFragments o, LEVEL_TOP
        else
          code = code.concat @clause.compileNode o
    
        code.push @makeCode " from #{@source.value}" if @source?.value?
        code.push @makeCode ';'
        code
    
    exports.ExportNamedDeclaration = class ExportNamedDeclaration extends ExportDeclaration
    
    exports.ExportDefaultDeclaration = class ExportDefaultDeclaration extends ExportDeclaration
    
    exports.ExportAllDeclaration = class ExportAllDeclaration extends ExportDeclaration
    
    exports.ModuleSpecifierList = class ModuleSpecifierList extends Base
      constructor: (@specifiers) ->
        super()
    
      children: ['specifiers']
    
      compileNode: (o) ->
        code = []
        o.indent += TAB
        compiledList = (specifier.compileToFragments o, LEVEL_LIST for specifier in @specifiers)
    
        if @specifiers.length isnt 0
          code.push @makeCode "{\n#{o.indent}"
          for fragments, index in compiledList
            code.push @makeCode(",\n#{o.indent}") if index
            code.push fragments...
          code.push @makeCode "\n}"
        else
          code.push @makeCode '{}'
        code
    
    exports.ImportSpecifierList = class ImportSpecifierList extends ModuleSpecifierList
    
    exports.ExportSpecifierList = class ExportSpecifierList extends ModuleSpecifierList
    
    exports.ModuleSpecifier = class ModuleSpecifier extends Base
      constructor: (@original, @alias, @moduleDeclarationType) ->
        super()
  • The name of the variable entering the local scope

        @identifier = if @alias? then @alias.value else @original.value
    
      children: ['original', 'alias']
    
      compileNode: (o) ->
        o.scope.find @identifier, @moduleDeclarationType
        code = []
        code.push @makeCode @original.value
        code.push @makeCode " as #{@alias.value}" if @alias?
        code
    
    exports.ImportSpecifier = class ImportSpecifier extends ModuleSpecifier
      constructor: (imported, local) ->
        super imported, local, 'import'
    
      compileNode: (o) ->
  • Per the spec, symbols can’t be imported multiple times (e.g. import { foo, foo } from 'lib' is invalid)

        if @identifier in o.importedSymbols or o.scope.check(@identifier)
          @error "'#{@identifier}' has already been declared"
        else
          o.importedSymbols.push @identifier
        super o
    
    exports.ImportDefaultSpecifier = class ImportDefaultSpecifier extends ImportSpecifier
    
    exports.ImportNamespaceSpecifier = class ImportNamespaceSpecifier extends ImportSpecifier
    
    exports.ExportSpecifier = class ExportSpecifier extends ModuleSpecifier
      constructor: (local, exported) ->
        super local, exported, 'export'
  • 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 = {}) ->
        super()
        {@param, @subpattern, @operatorToken, @moduleDeclaration} = options
    
      children: ['variable', 'value']
    
      isAssignable: YES
    
      isStatement: (o) ->
        o?.level is LEVEL_TOP and @context? and (@moduleDeclaration or "?" in @context)
    
      checkAssignability: (o, varBase) ->
        if Object::hasOwnProperty.call(o.scope.positions, varBase.value) and
           o.scope.variables[o.scope.positions[varBase.value]].type is 'import'
          varBase.error "'#{varBase.value}' is read-only"
    
      assigns: (name) ->
        @[if @context is 'object' then 'value' else 'variable'].assigns name
    
      unfoldSoak: (o) ->
        unfoldSoak o, this, 'variable'
  • Compile an assignment, delegating to compileDestructuring 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) ->
        isValue = @variable instanceof Value
        if isValue
  • When compiling @variable, remember if it is part of a function parameter.

          @variable.param = @param
  • If @variable is an array or an object, we’re destructuring; if it’s also isAssignable(), the destructuring syntax is supported in ES and we can output it as is; otherwise we @compileDestructuring and convert this ES-unsupported destructuring into acceptable output.

          if @variable.isArray() or @variable.isObject()
  • This is the left-hand side of an assignment; let Arr and Obj know that, so that those nodes know that they’re assignable as destructured variables.

            @variable.base.lhs = yes
            return @compileDestructuring o unless @variable.isAssignable()
  • Object destructuring. Can be removed once ES proposal hits Stage 4.

            return @compileObjectDestruct(o) if @variable.isObject() and @variable.contains (node) ->
              node instanceof Obj and node.hasSplat()
    
          return @compileSplice       o if @variable.isSplice()
          return @compileConditional  o if @context in ['||=', '&&=', '?=']
          return @compileSpecialMath  o if @context in ['**=', '//=', '%%=']
    
        unless @context
          varBase = @variable.unwrapAll()
          unless varBase.isAssignable()
            @variable.error "'#{@variable.compile o}' can't be assigned"
    
          varBase.eachName (name) =>
            return if name.hasProperties?()
    
            message = isUnassignable name.value
            name.error message if message
  • moduleDeclaration can be 'import' or 'export'

            @checkAssignability o, name
            if @moduleDeclaration
              o.scope.add name.value, @moduleDeclaration
            else
              o.scope.find name.value
    
        if @value instanceof Code
          if @value.isStatic
            @value.name = @variable.properties[0]
          else if @variable.properties?.length >= 2
            [properties..., prototype, name] = @variable.properties
            @value.name = name if prototype.name?.value is 'prototype'
    
        @value.base.csxAttribute = yes if @csx
        val = @value.compileToFragments o, LEVEL_LIST
        compiledName = @variable.compileToFragments o, LEVEL_LIST
    
        if @context is 'object'
          if @variable.shouldCache()
            compiledName.unshift @makeCode '['
            compiledName.push @makeCode ']'
          return compiledName.concat @makeCode(if @csx then '=' else ': '), val
    
        answer = compiledName.concat @makeCode(" #{ @context or '=' } "), val
  • Per https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment#Assignment_without_declaration, if we’re destructuring without declaring, the destructuring assignment must be wrapped in parentheses.

        if o.level > LEVEL_LIST or (o.level is LEVEL_TOP and isValue and @variable.base instanceof Obj and not @nestedLhs and not @param)
          @wrapInParentheses answer
        else
          answer
  • Check object destructuring variable for rest elements; can be removed once ES proposal hits Stage 4.

      compileObjectDestruct: (o) ->
  • Per https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment#Assignment_without_declaration, if we’re destructuring without declaring, the destructuring assignment must be wrapped in parentheses: ({a, b} = obj). Helper function setScopeVar() declares variables a and b at the top of the current scope.

        setScopeVar = (prop) ->
          newVar = false
          return if prop instanceof Assign and prop.value.base instanceof Obj
          if prop instanceof Assign
            if prop.value.base instanceof IdentifierLiteral
              newVar = prop.value.base.compile o
            else
              newVar = prop.variable.base.compile o
          else
            newVar = prop.compile o
          o.scope.add(newVar, 'var', true) if newVar
  • Returns a safe (cached) reference to the key for a given property

        getPropKey = (prop) ->
          if prop instanceof Assign
            [prop.variable, key] = prop.variable.cache o
            key
          else
            prop
  • Returns the name of a given property for use with excludeProps Property names are quoted (e.g. a: b -> ‘a’), and everything else uses the key reference (e.g. 'a': b -> 'a', "#{a}": b -> `)

        getPropName = (prop) ->
          key = getPropKey prop
          cached = prop instanceof Assign and prop.variable != key
          if cached or not key.isAssignable()
            key
          else
            new Literal "'#{key.compile o}'"
  • Recursive function for searching and storing rest elements in objects. e.g. {[properties...]} = source.

        traverseRest = (properties, source) =>
          restElements = []
          restIndex = undefined
    
          for prop, index in properties
            setScopeVar prop.unwrap()
            if prop instanceof Assign
  • prop is k: expr, we need to check expr for nested splats

              if prop.value.isObject?()
  • prop is k: {...}

                nestedProperties = prop.value.base.properties
              else if prop.value instanceof Assign and prop.value.variable.isObject()
  • prop is k: {...} = default

                nestedProperties = prop.value.variable.base.properties
                [prop.value.value, nestedSourceDefault] = prop.value.value.cache o
              if nestedProperties
                nestedSource = new Value source.base, source.properties.concat [new Access getPropKey prop]
                nestedSource = new Value new Op '?', nestedSource, nestedSourceDefault if nestedSourceDefault
                restElements = restElements.concat traverseRest nestedProperties, nestedSource
            else if prop instanceof Splat
              prop.error "multiple rest elements are disallowed in object destructuring" if restIndex?
              restIndex = index
              restElements.push {
                name: prop.name.unwrapAll()
                source
                excludeProps: new Arr (getPropName p for p in properties when p isnt prop)
              }
    
          if restIndex?
  • Remove rest element from the properties after iteration

            properties.splice restIndex, 1
    
          restElements
  • Cache the value for reuse with rest elements

        [@value, valueRef] = @value.cache o
  • Find all rest elements.

        restElements = traverseRest @variable.base.properties, valueRef
    
        result = new Block [@]
        for restElement in restElements
          value = new Call new Value(new Literal utility 'objectWithoutKeys', o), [restElement.source, restElement.excludeProps]
          result.push new Assign restElement.name, value
    
        fragments = result.compileToFragments o
        if o.level is LEVEL_TOP
  • Remove leading tab and trailing semicolon

          fragments.shift()
          fragments.pop()
    
        fragments
  • Brief implementation of recursive pattern matching, when assigning array or object literals to a value. Peeks at their properties to assign inner names.

      compileDestructuring: (o) ->
        top       = o.level is LEVEL_TOP
        {value}   = this
        {objects} = @variable.base
        olen      = objects.length
  • Special-case for {} = a and [] = a (empty patterns). Compile to simply a.

        if olen is 0
          code = value.compileToFragments o
          return if o.level >= LEVEL_OP then @wrapInParentheses code else code
        [obj] = objects
  • Disallow [...] = a for some reason. (Could be equivalent to [] = a?)

        if olen is 1 and obj instanceof Expansion
          obj.error 'Destructuring assignment has no target'
    
        isObject = @variable.isObject()
  • Special case for when there’s only one thing destructured off of something. {a} = b, [a] = b, {a: b} = c

        if top and olen is 1 and obj not instanceof Splat
  • Pick the property straight off the value when there’s just one to pick (no need to cache the value into a variable).

          defaultValue = undefined
          if obj instanceof Assign and obj.context is 'object'
  • A regular object pattern-match.

            {variable: {base: idx}, value: obj} = obj
            if obj instanceof Assign
              defaultValue = obj.value
              obj = obj.variable
          else
            if obj instanceof Assign
              defaultValue = obj.value
              obj = obj.variable
            idx = if isObject
  • A shorthand {a, b, @c} = val pattern-match.

              if obj.this
                obj.properties[0].name
              else
                new PropertyName obj.unwrap().value
            else
  • A regular array pattern-match.

              new NumberLiteral 0
          acc   = idx.unwrap() instanceof PropertyName
          value = new Value value
          value.properties.push new (if acc then Access else Index) idx
          message = isUnassignable obj.unwrap().value
          obj.error message if message
          if defaultValue
            defaultValue.isDefaultValue = yes
            value = new Op '?', value, defaultValue
          return new Assign(obj, value, null, param: @param).compileToFragments o, LEVEL_TOP
    
        vvar     = value.compileToFragments o, LEVEL_LIST
        vvarText = fragmentsToText vvar
        assigns  = []
        expandedIdx = false
  • At this point, there are several things to destructure. So the fn() in {a, b} = fn() must be cached, for example. Make vvar into a simple variable if it isn’t already.

        if value.unwrap() not instanceof IdentifierLiteral or @variable.assigns(vvarText)
          ref = o.scope.freeVariable 'ref'
          assigns.push [@makeCode(ref + ' = '), vvar...]
          vvar = [@makeCode ref]
          vvarText = ref
  • And here comes the big loop that handles all of these cases: [a, b] = c [a..., b] = c [..., a, b] = c [@a, b] = c [a = 1, b] = c {a, b} = c {@a, b} = c {a = 1, b} = c etc.

        for obj, i in objects
          idx = i
          if not expandedIdx and obj instanceof Splat
            name = obj.name.unwrap().value
            obj = obj.unwrap()
            val = "#{olen} <= #{vvarText}.length ? #{utility 'slice', o}.call(#{vvarText}, #{i}"
            rest = olen - i - 1
            if rest isnt 0
              ivar = o.scope.freeVariable 'i', single: true
              val += ", #{ivar} = #{vvarText}.length - #{rest}) : (#{ivar} = #{i}, [])"
            else
              val += ") : []"
            val   = new Literal val
            expandedIdx = "#{ivar}++"
          else if not expandedIdx and obj instanceof Expansion
            rest = olen - i - 1
            if rest isnt 0
              if rest is 1
                expandedIdx = "#{vvarText}.length - 1"
              else
                ivar = o.scope.freeVariable 'i', single: true
                val = new Literal "#{ivar} = #{vvarText}.length - #{rest}"
                expandedIdx = "#{ivar}++"
                assigns.push val.compileToFragments o, LEVEL_LIST
            continue
          else
            if obj instanceof Splat or obj instanceof Expansion
              obj.error "multiple splats/expansions are disallowed in an assignment"
            defaultValue = undefined
            if obj instanceof Assign and obj.context is 'object'
  • A regular object pattern-match.

              {variable: {base: idx}, value: obj} = obj
              if obj instanceof Assign
                defaultValue = obj.value
                obj = obj.variable
            else
              if obj instanceof Assign
                defaultValue = obj.value
                obj = obj.variable
              idx = if isObject
  • A shorthand {a, b, @c} = val pattern-match.

                if obj.this
                  obj.properties[0].name
                else
                  new PropertyName obj.unwrap().value
              else
  • A regular array pattern-match.

                new Literal expandedIdx or idx
            name = obj.unwrap().value
            acc = idx.unwrap() instanceof PropertyName
            val = new Value new Literal(vvarText), [new (if acc then Access else Index) idx]
            if defaultValue
              defaultValue.isDefaultValue = yes
              val = new Op '?', val, defaultValue
          if name?
            message = isUnassignable name
            obj.error message if message
          assigns.push new Assign(obj, val, null, param: @param, subpattern: yes).compileToFragments o, LEVEL_LIST
    
        assigns.push vvar unless top or @subpattern
        fragments = @joinFragmentArrays assigns, ', '
        if o.level < LEVEL_LIST then fragments else @wrapInParentheses fragments
  • 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 not instanceof ThisLiteral and not o.scope.check left.base.value
          @variable.error "the variable \"#{left.base.value}\" can't be assigned with #{@context} because it has not been declared before"
        if "?" in @context
          o.isExistentialEquals = true
          new If(new Existence(left), right, type: 'if').addElse(new Assign(right, @value, '=')).compileToFragments o
        else
          fragments = new Op(@context[...-1], left, new Assign(right, @value, '=')).compileToFragments o
          if o.level <= LEVEL_LIST then fragments else @wrapInParentheses fragments
  • Convert special math assignment operators like a **= b to the equivalent extended form a = a ** b and then compiles that.

      compileSpecialMath: (o) ->
        [left, right] = @variable.cacheReference o
        new Assign(left, new Op(@context[...-1], right, @value)).compileToFragments 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
        if from
          [fromDecl, fromRef] = @cacheToCodeFragments from.cache o, LEVEL_OP
        else
          fromDecl = fromRef = '0'
        if to
          if from?.isNumber() and to.isNumber()
            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
        answer = [].concat @makeCode("#{utility 'splice', o}.apply(#{name}, [#{fromDecl}, #{to}].concat("), valDef, @makeCode(")), "), valRef
        if o.level > LEVEL_TOP then @wrapInParentheses answer else answer
    
      eachName: (iterator) ->
        @variable.unwrapAll().eachName iterator
  • 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) ->
        super()
    
        @params      = params or []
        @body        = body or new Block
        @bound       = tag is 'boundfunc'
        @isGenerator = no
        @isAsync     = no
        @isMethod    = no
    
        @body.traverseChildren no, (node) =>
          if (node instanceof Op and node.isYield()) or node instanceof YieldReturn
            @isGenerator = yes
          if (node instanceof Op and node.isAwait()) or node instanceof AwaitReturn
            @isAsync = yes
          if @isGenerator and @isAsync
            node.error "function can't contain both yield and await"
    
      children: ['params', 'body']
    
      isStatement: -> @isMethod
    
      jumps: NO
    
      makeScope: (parentScope) -> new Scope parentScope, @body, this
  • Compilation creates a new scope unless explicitly asked to share with the outer scope. Handles splat parameters in the parameter list by setting such parameters to be the final parameter in the function definition, as required per the ES2015 spec. If the CoffeeScript function definition had parameters after the splat, they are declared via expressions in the function body.

      compileNode: (o) ->
        if @ctor
          @name.error 'Class constructor may not be async'       if @isAsync
          @name.error 'Class constructor may not be a generator' if @isGenerator
    
        if @bound
          @context = o.scope.method.context if o.scope.method?.bound
          @context = 'this' unless @context
    
        o.scope         = del(o, 'classScope') or @makeScope o.scope
        o.scope.shared  = del(o, 'sharedScope')
        o.indent        += TAB
        delete o.bare
        delete o.isExistentialEquals
        params           = []
        exprs            = []
        thisAssignments  = @thisAssignments?.slice() ? []
        paramsAfterSplat = []
        haveSplatParam   = no
        haveBodyParam    = no
  • Check for duplicate parameters and separate this assignments

        paramNames = []
        @eachParamName (name, node, param) ->
          node.error "multiple parameters named '#{name}'" if name in paramNames
          paramNames.push name
          if node.this
            name   = node.properties[0].name.value
            name   = "_#{name}" if name in JS_FORBIDDEN
            target = new IdentifierLiteral o.scope.freeVariable name
            param.renameParam node, target
            thisAssignments.push new Assign node, target
  • Parse the parameters, adding them to the list of parameters to put in the function definition; and dealing with splats or expansions, including adding expressions to the function body to declare all parameter variables that would have been after the splat/expansion parameter. If we encounter a parameter that needs to be declared in the function body for any reason, for example it’s destructured with this, also declare and assign all subsequent parameters in the function body so that any non-idempotent parameters are evaluated in the correct order.

        for param, i in @params
  • Was ... used with this parameter? (Only one such parameter is allowed per function.) Splat/expansion parameters cannot have default values, so we need not worry about that.

          if param.splat or param instanceof Expansion
            if haveSplatParam
              param.error 'only one splat or expansion parameter is allowed per function definition'
            else if param instanceof Expansion and @params.length is 1
              param.error 'an expansion parameter cannot be the only parameter in a function definition'
            haveSplatParam = yes
            if param.splat
              if param.name instanceof Arr
  • Splat arrays are treated oddly by ES; deal with them the legacy way in the function body. TODO: Should this be handled in the function parameter list, and if so, how?

                splatParamName = o.scope.freeVariable 'arg'
                params.push ref = new Value new IdentifierLiteral splatParamName
                exprs.push new Assign new Value(param.name), ref
              else
                params.push ref = param.asReference o
                splatParamName = fragmentsToText ref.compileNode o
              if param.shouldCache()
                exprs.push new Assign new Value(param.name), ref
            else # `param` is an Expansion
              splatParamName = o.scope.freeVariable 'args'
              params.push new Value new IdentifierLiteral splatParamName
    
            o.scope.parameter splatParamName
  • Parse all other parameters; if a splat paramater has not yet been encountered, add these other parameters to the list to be output in the function definition.

          else
            if param.shouldCache() or haveBodyParam
              param.assignedInBody = yes
              haveBodyParam = yes
  • This parameter cannot be declared or assigned in the parameter list. So put a reference in the parameter list and add a statement to the function body assigning it, e.g. (arg) => { var a = arg.a; }, with a default value if it has one.

              if param.value?
                condition = new Op '===', param, new UndefinedLiteral
                ifTrue = new Assign new Value(param.name), param.value
                exprs.push new If condition, ifTrue
              else
                exprs.push new Assign new Value(param.name), param.asReference(o)
  • If this parameter comes before the splat or expansion, it will go in the function definition parameter list.

            unless haveSplatParam
  • If this parameter has a default value, and it hasn’t already been set by the shouldCache() block above, define it as a statement in the function body. This parameter comes after the splat parameter, so we can’t define its default value in the parameter list.

              if param.shouldCache()
                ref = param.asReference o
              else
                if param.value? and not param.assignedInBody
                  ref = new Assign new Value(param.name), param.value, null, param: yes
                else
                  ref = param
  • Add this parameter’s reference(s) to the function scope.

              if param.name instanceof Arr or param.name instanceof Obj
  • This parameter is destructured.

                param.name.lhs = yes
                param.name.eachName (prop) ->
                  o.scope.parameter prop.value
  • Compile foo({a, b...}) -> to foo(arg) -> {a, b...} = arg. Can be removed once ES proposal hits Stage 4.

                if param.name instanceof Obj and param.name.hasSplat()
                  splatParamName = o.scope.freeVariable 'arg'
                  o.scope.parameter splatParamName
                  ref = new Value new IdentifierLiteral splatParamName
                  exprs.push new Assign new Value(param.name), ref
  • Compile foo({a, b...} = {}) -> to foo(arg = {}) -> {a, b...} = arg.

                  if param.value?  and not param.assignedInBody
                    ref = new Assign ref, param.value, null, param: yes
              else
                o.scope.parameter fragmentsToText (if param.value? then param else ref).compileToFragments o
              params.push ref
            else
              paramsAfterSplat.push param
  • If this parameter had a default value, since it’s no longer in the function parameter list we need to assign its default value (if necessary) as an expression in the body.

              if param.value? and not param.shouldCache()
                condition = new Op '===', param, new UndefinedLiteral
                ifTrue = new Assign new Value(param.name), param.value
                exprs.push new If condition, ifTrue
  • Add this parameter to the scope, since it wouldn’t have been added yet since it was skipped earlier.

              o.scope.add param.name.value, 'var', yes if param.name?.value?
  • If there were parameters after the splat or expansion parameter, those parameters need to be assigned in the body of the function.

        if paramsAfterSplat.length isnt 0
  • Create a destructured assignment, e.g. [a, b, c] = [args..., b, c]

          exprs.unshift new Assign new Value(
              new Arr [new Splat(new IdentifierLiteral(splatParamName)), (param.asReference o for param in paramsAfterSplat)...]
            ), new Value new IdentifierLiteral splatParamName
  • Add new expressions to the function body

        wasEmpty = @body.isEmpty()
        @body.expressions.unshift thisAssignments... unless @expandCtorSuper thisAssignments
        @body.expressions.unshift exprs...
        if @isMethod and @bound and not @isStatic and @classVariable
          boundMethodCheck = new Value new Literal utility 'boundMethodCheck', o
          @body.expressions.unshift new Call(boundMethodCheck, [new Value(new ThisLiteral), @classVariable])
        @body.makeReturn() unless wasEmpty or @noReturn
  • Assemble the output

        modifiers = []
        modifiers.push 'static' if @isMethod and @isStatic
        modifiers.push 'async'  if @isAsync
        unless @isMethod or @bound
          modifiers.push "function#{if @isGenerator then '*' else ''}"
        else if @isGenerator
          modifiers.push '*'
    
        signature = [@makeCode '(']
        for param, i in params
          signature.push @makeCode ', ' if i
          signature.push @makeCode '...' if haveSplatParam and i is params.length - 1
          signature.push param.compileToFragments(o)...
        signature.push @makeCode ')'
    
        body = @body.compileWithDeclarations o unless @body.isEmpty()
  • We need to compile the body before method names to ensure super references are handled

        if @isMethod
          [methodScope, o.scope] = [o.scope, o.scope.parent]
          name = @name.compileToFragments o
          name.shift() if name[0].code is '.'
          o.scope = methodScope
    
        answer = @joinFragmentArrays (@makeCode m for m in modifiers), ' '
        answer.push @makeCode ' ' if modifiers.length and name
        answer.push name... if name
        answer.push signature...
        answer.push @makeCode ' =>' if @bound and not @isMethod
        answer.push @makeCode ' {'
        answer.push @makeCode('\n'), body..., @makeCode("\n#{@tab}") if body?.length
        answer.push @makeCode '}'
    
        return [@makeCode(@tab), answer...] if @isMethod
        if @front or (o.level >= LEVEL_ACCESS) then @wrapInParentheses answer else answer
    
      eachParamName: (iterator) ->
        param.eachName iterator for param in @params
  • Short-circuit traverseChildren method to prevent it from crossing scope boundaries unless crossScope is true.

      traverseChildren: (crossScope, func) ->
        super(crossScope, func) if crossScope
  • Short-circuit replaceInContext method to prevent it from crossing context boundaries. Bound functions have the same context.

      replaceInContext: (child, replacement) ->
        if @bound
          super child, replacement
        else
          false
    
      expandCtorSuper: (thisAssignments) ->
        return false unless @ctor
    
        @eachSuperCall Block.wrap(@params), (superCall) ->
          superCall.error "'super' is not allowed in constructor parameter defaults"
    
        seenSuper = @eachSuperCall @body, (superCall) =>
          superCall.error "'super' is only allowed in derived class constructors" if @ctor is 'base'
          superCall.expressions = thisAssignments
    
        haveThisParam = thisAssignments.length and thisAssignments.length isnt @thisAssignments?.length
        if @ctor is 'derived' and not seenSuper and haveThisParam
          param = thisAssignments[0].variable
          param.error "Can't use @params in derived class constructors without calling super"
    
        seenSuper
  • Find all super calls in the given context node Returns true if iterator is called

      eachSuperCall: (context, iterator) ->
        seenSuper = no
    
        context.traverseChildren true, (child) =>
          if child instanceof SuperCall
            seenSuper = yes
            iterator child
          else if child instanceof ThisLiteral and @ctor is 'derived' and not seenSuper
            child.error "Can't reference 'this' before calling super in derived class constructors"
  • super has the same target in bound (arrow) functions, so check them too

          child not instanceof SuperCall and (child not instanceof Code or child.bound)
    
        seenSuper
  • 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) ->
        super()
    
        message = isUnassignable @name.unwrapAll().value
        @name.error message if message
        if @name instanceof Obj and @name.generated
          token = @name.objects[0].operatorToken
          token.error "unexpected #{token.value}"
    
      children: ['name', 'value']
    
      compileToFragments: (o) ->
        @name.compileToFragments o, LEVEL_LIST
    
      asReference: (o) ->
        return @reference if @reference
        node = @name
        if node.this
          name = node.properties[0].name.value
          name = "_#{name}" if name in JS_FORBIDDEN
          node = new IdentifierLiteral o.scope.freeVariable name
        else if node.shouldCache()
          node = new IdentifierLiteral o.scope.freeVariable 'arg'
        node = new Value node
        node.updateLocationDataIfMissing @locationData
        @reference = node
    
      shouldCache: ->
        @name.shouldCache()
  • Iterates the name or names of a Param. In a sense, a destructured parameter represents multiple JS parameters. This method allows to iterate them all. The iterator function will be called as iterator(name, node) where name is the name of the parameter and node is the AST node corresponding to that name.

      eachName: (iterator, name = @name) ->
        atParam = (obj) => iterator "@#{obj.properties[0].name.value}", obj, @
    • simple literals foo
        return iterator name.value, name, @ if name instanceof Literal
    • at-params @foo
        return atParam name if name instanceof Value
        for obj in name.objects ? []
    • destructured parameter with default value
          if obj instanceof Assign and not obj.context?
            obj = obj.variable
    • assignments within destructured parameters {foo:bar}
          if obj instanceof Assign
  • … possibly with a default value

            if obj.value instanceof Assign
              obj = obj.value
            @eachName iterator, obj.value.unwrap()
    • splats within destructured parameters [xs...]
          else if obj instanceof Splat
            node = obj.name.unwrap()
            iterator node.value, node, @
          else if obj instanceof Value
    • destructured parameters within destructured parameters [{a}]
            if obj.isArray() or obj.isObject()
              @eachName iterator, obj.base
    • at-params within destructured parameters {@foo}
            else if obj.this
              atParam obj
    • simple destructured parameters {foo}
            else iterator obj.base.value, obj.base, @
          else if obj not instanceof Expansion
            obj.error "illegal parameter #{obj.compile()}"
        return
  • Rename a param by replacing the given AST node for a name with a new node. This needs to ensure that the the source for object destructuring does not change.

      renameParam: (node, newNode) ->
        isNode      = (candidate) -> candidate is node
        replacement = (node, parent) =>
          if parent instanceof Obj
            key = node
            key = node.properties[0].name if node.this
            new Assign new Value(key), newNode, 'object'
          else
            newNode
    
        @replaceInContext isNode, replacement
  • 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: ->
        @name.isAssignable() and (not @name.isAtomic or @name.isAtomic())
    
      constructor: (name) ->
        super()
        @name = if name.compile then name else new Literal name
    
      assigns: (name) ->
        @name.assigns name
    
      compileToFragments: (o) ->
        [ @makeCode('...')
          @name.compileToFragments(o)... ]
    
      unwrap: -> @name
  • Expansion

  • Used to skip values inside an array destructuring (pattern matching) or parameter list.

    exports.Expansion = class Expansion extends Base
    
      shouldCache: NO
    
      compileNode: (o) ->
        @error 'Expansion must be used inside a destructuring assignment or parameter list'
    
      asReference: (o) ->
        this
    
      eachName: (iterator) ->
  • 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) ->
        super()
    
        @condition = if options?.invert then condition.invert() else condition
        @guard     = options?.guard
    
      children: ['condition', 'guard', 'body']
    
      isStatement: YES
    
      makeReturn: (res) ->
        if res
          super res
        else
          @returns = not @jumps loop: yes
          this
    
      addBody: (@body) ->
        this
    
      jumps: ->
        {expressions} = @body
        return no unless expressions.length
        for node in expressions
          return jumpNode if jumpNode = 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 = @makeCode ''
        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 StatementLiteral "continue"
            else
              body = Block.wrap [new If @guard, body] if @guard
          body = [].concat @makeCode("\n"), (body.compileToFragments o, LEVEL_TOP), @makeCode("\n#{@tab}")
        answer = [].concat @makeCode(set + @tab + "while ("), @condition.compileToFragments(o, LEVEL_PAREN),
          @makeCode(") {"), body, @makeCode("}")
        if @returns
          answer.push @makeCode "\n#{@tab}return #{rvar};"
        answer
  • 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) ->
        super()
    
        return new In first, second if op is 'in'
        if op is 'do'
          return Op::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'
        'yieldfrom': 'yield*'
  • The map of invertible operators.

      INVERSIONS =
        '!==': '==='
        '===': '!=='
    
      children: ['first', 'second']
    
      isNumber: ->
        @isUnary() and @operator in ['+', '-'] and
          @first instanceof Value and @first.isNumber()
    
      isAwait: ->
        @operator is 'await'
    
      isYield: ->
        @operator in ['yield', 'yield*']
    
      isUnary: ->
        not @second
    
      shouldCache: ->
        not @isNumber()
  •   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)
          @error 'delete operand may not be argument or var'
        if @operator in ['--', '++']
          message = isUnassignable @first.unwrapAll().value
          @first.error message if message
        return @compileContinuation o if @isYield() or @isAwait()
        return @compileUnary        o if @isUnary()
        return @compileChain        o if isChain
        switch @operator
          when '?'  then @compileExistence o, @second.isDefaultValue
          when '**' then @compilePower o
          when '//' then @compileFloorDivision o
          when '%%' then @compileModulo o
          else
            lhs = @first.compileToFragments o, LEVEL_OP
            rhs = @second.compileToFragments o, LEVEL_OP
            answer = [].concat lhs, @makeCode(" #{@operator} "), rhs
            if o.level <= LEVEL_OP then answer else @wrapInParentheses answer
  • 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.compileToFragments o, LEVEL_OP
        fragments = fst.concat @makeCode(" #{if @invert then '&&' else '||'} "),
          (shared.compileToFragments o), @makeCode(" #{@operator} "), (@second.compileToFragments o, LEVEL_OP)
        @wrapInParentheses fragments
  • Keep reference to the left expression, unless this an existential assignment

      compileExistence: (o, checkOnlyUndefined) ->
        if @first.shouldCache()
          ref = new IdentifierLiteral o.scope.freeVariable 'ref'
          fst = new Parens new Assign ref, @first
        else
          fst = @first
          ref = fst
        new If(new Existence(fst, checkOnlyUndefined), ref, type: 'if').addElse(@second).compileToFragments o
  • Compile a unary Op.

      compileUnary: (o) ->
        parts = []
        op = @operator
        parts.push [@makeCode op]
        if op is '!' and @first instanceof Existence
          @first.negated = not @first.negated
          return @first.compileToFragments o
        if o.level >= LEVEL_ACCESS
          return (new Parens this).compileToFragments o
        plusMinus = op in ['+', '-']
        parts.push [@makeCode(' ')] if op in ['new', 'typeof', 'delete'] or
                          plusMinus and @first instanceof Op and @first.operator is op
        if (plusMinus and @first instanceof Op) or (op is 'new' and @first.isStatement o)
          @first = new Parens @first
        parts.push @first.compileToFragments o, LEVEL_OP
        parts.reverse() if @flip
        @joinFragmentArrays parts, ''
    
      compileContinuation: (o) ->
        parts = []
        op = @operator
        unless o.scope.parent?
          @error "#{@operator} can only occur inside functions"
        if o.scope.method?.bound and o.scope.method.isGenerator
          @error 'yield cannot occur inside bound (fat arrow) functions'
        if 'expression' in Object.keys(@first) and not (@first instanceof Throw)
          parts.push @first.expression.compileToFragments o, LEVEL_OP if @first.expression?
        else
          parts.push [@makeCode "("] if o.level >= LEVEL_PAREN
          parts.push [@makeCode op]
          parts.push [@makeCode " "] if @first.base?.value isnt ''
          parts.push @first.compileToFragments o, LEVEL_OP
          parts.push [@makeCode ")"] if o.level >= LEVEL_PAREN
        @joinFragmentArrays parts, ''
    
      compilePower: (o) ->
  • Make a Math.pow call

        pow = new Value new IdentifierLiteral('Math'), [new Access new PropertyName 'pow']
        new Call(pow, [@first, @second]).compileToFragments o
    
      compileFloorDivision: (o) ->
        floor = new Value new IdentifierLiteral('Math'), [new Access new PropertyName 'floor']
        second = if @second.shouldCache() then new Parens @second else @second
        div = new Op '/', @first, second
        new Call(floor, [div]).compileToFragments o
    
      compileModulo: (o) ->
        mod = new Value new Literal utility 'modulo', o
        new Call(mod, [@first, @second]).compileToFragments o
    
      toString: (idt) ->
        super idt, @constructor.name + ' ' + @operator
  • In

    exports.In = class In extends Base
      constructor: (@object, @array) ->
        super()
    
      children: ['object', 'array']
    
      invert: NEGATE
    
      compileNode: (o) ->
        if @array instanceof Value and @array.isArray() and @array.base.objects.length
          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) ->
        [sub, ref] = @object.cache o, LEVEL_OP
        [cmp, cnj] = if @negated then [' !== ', ' && '] else [' === ', ' || ']
        tests = []
        for item, i in @array.base.objects
          if i then tests.push @makeCode cnj
          tests = tests.concat (if i then ref else sub), @makeCode(cmp), item.compileToFragments(o, LEVEL_ACCESS)
        if o.level < LEVEL_OP then tests else @wrapInParentheses tests
    
      compileLoopTest: (o) ->
        [sub, ref] = @object.cache o, LEVEL_LIST
        fragments = [].concat @makeCode(utility('indexOf', o) + ".call("), @array.compileToFragments(o, LEVEL_LIST),
          @makeCode(", "), ref, @makeCode(") " + if @negated then '< 0' else '>= 0')
        return fragments if fragmentsToText(sub) is fragmentsToText(ref)
        fragments = sub.concat @makeCode(', '), fragments
        if o.level < LEVEL_LIST then fragments else @wrapInParentheses fragments
    
      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, @errorVariable, @recovery, @ensure) ->
        super()
    
      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
        tryPart   = @attempt.compileToFragments o, LEVEL_TOP
    
        catchPart = if @recovery
          generatedErrorVariableName = o.scope.freeVariable 'error', reserve: no
          placeholder = new IdentifierLiteral generatedErrorVariableName
          if @errorVariable
            message = isUnassignable @errorVariable.unwrapAll().value
            @errorVariable.error message if message
            @recovery.unshift new Assign @errorVariable, placeholder
          [].concat @makeCode(" catch ("), placeholder.compileToFragments(o), @makeCode(") {\n"),
            @recovery.compileToFragments(o, LEVEL_TOP), @makeCode("\n#{@tab}}")
        else unless @ensure or @recovery
          generatedErrorVariableName = o.scope.freeVariable 'error', reserve: no
          [@makeCode(" catch (#{generatedErrorVariableName}) {}")]
        else
          []
    
        ensurePart = if @ensure then ([].concat @makeCode(" finally {\n"), @ensure.compileToFragments(o, LEVEL_TOP),
          @makeCode("\n#{@tab}}")) else []
    
        [].concat @makeCode("#{@tab}try {\n"),
          tryPart,
          @makeCode("\n#{@tab}}"), catchPart, ensurePart
  • Throw

  • Simple node to throw an exception.

    exports.Throw = class Throw extends Base
      constructor: (@expression) ->
        super()
    
      children: ['expression']
    
      isStatement: YES
      jumps:       NO
  • A Throw is already a return, of sorts…

      makeReturn: THIS
    
      compileNode: (o) ->
        [].concat @makeCode(@tab + "throw "), @expression.compileToFragments(o), @makeCode(";")
  • 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. Optionally only check if a variable is not undefined.

    exports.Existence = class Existence extends Base
      constructor: (@expression, onlyNotUndefined = no) ->
        super()
        @comparisonTarget = if onlyNotUndefined then 'undefined' else 'null'
    
      children: ['expression']
    
      invert: NEGATE
    
      compileNode: (o) ->
        @expression.front = @front
        code = @expression.compile o, LEVEL_OP
        if @expression.unwrap() instanceof IdentifierLiteral and not o.scope.check code
          [cmp, cnj] = if @negated then ['===', '||'] else ['!==', '&&']
          code = "typeof #{code} #{cmp} \"undefined\"" + if @comparisonTarget isnt 'undefined' then " #{cnj} #{code} #{cmp} #{@comparisonTarget}" else ''
        else
  • We explicity want to use loose equality (==) when comparing against null, so that an existence check roughly corresponds to a check for truthiness. Do not change this to === for null, as this will break mountains of existing code. When comparing only against undefined, however, we want to use === because this use case is for parity with ES2015+ default values, which only get assigned when the variable is undefined (but not null).

          cmp = if @comparisonTarget is 'null'
            if @negated then '==' else '!='
          else # `undefined`
            if @negated then '===' else '!=='
          code = "#{code} #{cmp} #{@comparisonTarget}"
        [@makeCode(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) ->
        super()
    
      children: ['body']
    
      unwrap: -> @body
    
      shouldCache: -> @body.shouldCache()
    
      compileNode: (o) ->
        expr = @body.unwrap()
        if expr instanceof Value and expr.isAtomic() and not @csxAttribute
          expr.front = @front
          return expr.compileToFragments o
        fragments = expr.compileToFragments o, LEVEL_PAREN
        bare = o.level < LEVEL_OP and (expr instanceof Op or expr instanceof Call or
          (expr instanceof For and expr.returns)) and (o.level < LEVEL_COND or
            fragments.length <= 3)
        return @wrapInBraces fragments if @csxAttribute
        if bare then fragments else @wrapInParentheses fragments
  • StringWithInterpolations

    exports.StringWithInterpolations = class StringWithInterpolations extends Base
      constructor: (@body) ->
        super()
    
      children: ['body']
  • unwrap returns this to stop ancestor nodes reaching in to grab @body, and using @body.compileNode. StringWithInterpolations.compileNode is the custom logic to output interpolated strings as code.

      unwrap: -> this
    
      shouldCache: -> @body.shouldCache()
    
      compileNode: (o) ->
        if @csxAttribute
          wrapped = new Parens new StringWithInterpolations @body
          wrapped.csxAttribute = yes
          return wrapped.compileNode o
  • Assumes that expr is Value » StringLiteral or Op

        expr = @body.unwrap()
    
        elements = []
        expr.traverseChildren no, (node) ->
          if node instanceof StringLiteral
            elements.push node
            return yes
          else if node instanceof Parens
            elements.push node
            return no
          return yes
    
        fragments = []
        fragments.push @makeCode '`' unless @csx
        for element in elements
          if element instanceof StringLiteral
            value = element.unquote @csx
            unless @csx
  • Backticks and ${ inside template literals must be escaped.

              value = value.replace /(\\*)(`|\$\{)/g, (match, backslashes, toBeEscaped) ->
                if backslashes.length % 2 is 0
                  "#{backslashes}\\#{toBeEscaped}"
                else
                  match
            fragments.push @makeCode value
          else
            fragments.push @makeCode '$' unless @csx
            code = element.compileToFragments(o, LEVEL_PAREN)
            code = @wrapInBraces code unless @isNestedTag element
            fragments.push code...
        fragments.push @makeCode '`' unless @csx
        fragments
    
      isNestedTag: (element) ->
        exprs = element?.body?.expressions
        call = exprs?[0]
        @csx and exprs and exprs.length is 1 and call instanceof Call and call.csx
  • 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) ->
        super()
    
        {@source, @guard, @step, @name, @index} = source
        @body    = Block.wrap [body]
        @own     = !!source.own
        @object  = !!source.object
        @from    = !!source.from
        @index.error 'cannot use index with for-from' if @from and @index
        source.ownTag.error "cannot use own with for-#{if @from then 'from' else 'in'}" if @own and not @object
        [@name, @index] = [@index, @name] if @object
        @index.error 'index cannot be a pattern matching expression' if @index?.isArray?() or @index?.isObject?()
        @range   = @source instanceof Value and @source.base instanceof Range and not @source.properties.length and not @from
        @pattern = @name instanceof Value
        @index.error 'indexes do not apply to range loops' if @range and @index
        @name.error '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]
        [..., last] = body.expressions
        @returns    = no if last?.jumps() instanceof Return
        source      = if @range then @source.base else @source
        scope       = o.scope
        name        = @name  and (@name.compile o, LEVEL_LIST) if not @pattern
        index       = @index and (@index.compile o, LEVEL_LIST)
        scope.find(name)  if name and not @pattern
        scope.find(index) if index and @index not instanceof Value
        rvar        = scope.freeVariable 'results' if @returns
        if @from
          ivar = scope.freeVariable 'x', single: true if @pattern
        else
          ivar = (@object and index) or scope.freeVariable 'i', single: true
        kvar        = ((@range or @from) and name) or index or ivar
        kvarAssign  = if kvar isnt ivar then "#{kvar} = " else ""
        if @step and not @range
          [step, stepVar] = @cacheToCodeFragments @step.cache o, LEVEL_LIST, shouldCacheOrIsAssignable
          stepNum   = Number stepVar if @step.isNumber()
        name        = ivar if @pattern
        varPart     = ''
        guardPart   = ''
        defPart     = ''
        idt1        = @tab + TAB
        if @range
          forPartFragments = source.compileToFragments merge o,
            {index: ivar, name, @step, shouldCache: shouldCacheOrIsAssignable}
        else
          svar    = @source.compile o, LEVEL_LIST
          if (name or @own) and @source.unwrap() not instanceof IdentifierLiteral
            defPart    += "#{@tab}#{ref = scope.freeVariable 'ref'} = #{svar};\n"
            svar       = ref
          if name and not @pattern and not @from
            namePart   = "#{name} = #{svar}[#{kvar}]"
          if not @object and not @from
            defPart += "#{@tab}#{step};\n" if step isnt stepVar
            down = stepNum < 0
            lvar = scope.freeVariable 'len' unless @step and stepNum? and down
            declare = "#{kvarAssign}#{ivar} = 0, #{lvar} = #{svar}.length"
            declareDown = "#{kvarAssign}#{ivar} = #{svar}.length - 1"
            compare = "#{ivar} < #{lvar}"
            compareDown = "#{ivar} >= 0"
            if @step
              if stepNum?
                if down
                  compare = compareDown
                  declare = declareDown
              else
                compare = "#{stepVar} > 0 ? #{compare} : #{compareDown}"
                declare = "(#{stepVar} > 0 ? (#{declare}) : #{declareDown})"
              increment = "#{ivar} += #{stepVar}"
            else
              increment = "#{if kvar isnt ivar then "++#{ivar}" else "#{ivar}++"}"
            forPartFragments = [@makeCode("#{declare}; #{compare}; #{kvarAssign}#{increment}")]
        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 StatementLiteral "continue"
          else
            body = Block.wrap [new If @guard, body] if @guard
        if @pattern
          body.expressions.unshift new Assign @name, if @from then new IdentifierLiteral kvar else new Literal "#{svar}[#{kvar}]"
        defPartFragments = [].concat @makeCode(defPart), @pluckDirectCall(o, body)
        varPart = "\n#{idt1}#{namePart};" if namePart
        if @object
          forPartFragments = [@makeCode("#{kvar} in #{svar}")]
          guardPart = "\n#{idt1}if (!#{utility 'hasProp', o}.call(#{svar}, #{kvar})) continue;" if @own
        else if @from
          forPartFragments = [@makeCode("#{kvar} of #{svar}")]
        bodyFragments = body.compileToFragments merge(o, indent: idt1), LEVEL_TOP
        if bodyFragments and bodyFragments.length > 0
          bodyFragments = [].concat @makeCode("\n"), bodyFragments, @makeCode("\n")
        [].concat defPartFragments, @makeCode("#{resultPart or ''}#{@tab}for ("),
          forPartFragments, @makeCode(") {#{guardPart}#{varPart}"), bodyFragments,
          @makeCode("#{@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 IdentifierLiteral 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 = defs.concat @makeCode(@tab), (new Assign(ref, fn).compileToFragments(o, LEVEL_TOP)), @makeCode(';\n')
        defs
  • Switch

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

    exports.Switch = class Switch extends Base
      constructor: (@subject, @cases, @otherwise) ->
        super()
    
      children: ['subject', 'cases', 'otherwise']
    
      isStatement: YES
    
      jumps: (o = {block: yes}) ->
        for [conds, block] in @cases
          return jumpNode if jumpNode = 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
        fragments = [].concat @makeCode(@tab + "switch ("),
          (if @subject then @subject.compileToFragments(o, LEVEL_PAREN) else @makeCode "false"),
          @makeCode(") {\n")
        for [conditions, block], i in @cases
          for cond in flatten [conditions]
            cond  = cond.invert() unless @subject
            fragments = fragments.concat @makeCode(idt1 + "case "), cond.compileToFragments(o, LEVEL_PAREN), @makeCode(":\n")
          fragments = fragments.concat body, @makeCode('\n') if (body = block.compileToFragments o, LEVEL_TOP).length > 0
          break if i is @cases.length - 1 and not @otherwise
          expr = @lastNonComment block.expressions
          continue if expr instanceof Return or expr instanceof Throw or (expr instanceof Literal and expr.jumps() and expr.value isnt 'debugger')
          fragments.push cond.makeCode(idt2 + 'break;\n')
        if @otherwise and @otherwise.expressions.length
          fragments.push @makeCode(idt1 + "default:\n"), (@otherwise.compileToFragments o, LEVEL_TOP)..., @makeCode("\n")
        fragments.push @makeCode @tab + '}'
        fragments
  • 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 = {}) ->
        super()
    
        @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
          @elseBody.updateLocationDataIfMissing elseBody.locationData
        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').compileToFragments o
    
        indent   = o.indent + TAB
        cond     = @condition.compileToFragments o, LEVEL_PAREN
        body     = @ensureBlock(@body).compileToFragments merge o, {indent}
        ifPart   = [].concat @makeCode("if ("), cond, @makeCode(") {\n"), body, @makeCode("\n#{@tab}}")
        ifPart.unshift @makeCode @tab unless child
        return ifPart unless @elseBody
        answer = ifPart.concat @makeCode(' else ')
        if @isChain
          o.chainChild = yes
          answer = answer.concat @elseBody.unwrap().compileToFragments o, LEVEL_TOP
        else
          answer = answer.concat @makeCode("{\n"), @elseBody.compileToFragments(merge(o, {indent}), LEVEL_TOP), @makeCode("\n#{@tab}}")
        answer
  • Compile the If as a conditional operator.

      compileExpression: (o) ->
        cond = @condition.compileToFragments o, LEVEL_COND
        body = @bodyNode().compileToFragments o, LEVEL_LIST
        alt  = if @elseBodyNode() then @elseBodyNode().compileToFragments(o, LEVEL_LIST) else [@makeCode('void 0')]
        fragments = cond.concat @makeCode(" ? "), body, @makeCode(" : "), alt
        if o.level >= LEVEL_COND then @wrapInParentheses fragments else fragments
    
      unfoldSoak: ->
        @soak and this
  • Constants

  • UTILITIES =
      modulo: -> 'function(a, b) { return (+a % (b = +b) + b) % b; }'
      objectWithoutKeys: -> "
          function(o, ks) {
            var res = {};
            for (var k in o) ([].indexOf.call(ks, k) < 0 && {}.hasOwnProperty.call(o, k)) && (res[k] = o[k]);
            return res;
          }
        "
      boundMethodCheck: -> "
        function(instance, Constructor) {
          if (!(instance instanceof Constructor)) {
            throw new Error('Bound instance method accessed before binding');
          }
        }
      "
  • Shortcuts to speed up the lookup time for native functions.

      hasProp: -> '{}.hasOwnProperty'
      indexOf: -> '[].indexOf'
      slice  : -> '[].slice'
      splice : -> '[].splice'
  • 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 = '  '
    
    SIMPLENUM = /^[+-]?\d+$/
  • Helper Functions

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

    utility = (name, o) ->
      {root} = o.scope
      if name of root.utilities
        root.utilities[name]
      else
        ref = root.freeVariable name
        root.assign ref, UTILITIES[name] o
        root.utilities[name] = ref
    
    multident = (code, tab) ->
      code = code.replace /\n/g, '$&' + tab
      code.replace /\s+$/, ''
    
    isLiteralArguments = (node) ->
      node instanceof IdentifierLiteral and node.value is 'arguments'
    
    isLiteralThis = (node) ->
      node instanceof ThisLiteral or (node instanceof Code and node.bound)
    
    shouldCacheOrIsAssignable = (node) -> node.shouldCache() or node.isAssignable?()
  • 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
coffeescript-1.12.7/docs/v2/annotated-source/optparse.html000066400000000000000000000360421313305734200235410ustar00rootroot00000000000000 optparse.coffee
  • optparse.coffee

  • {repeat} = require './helpers'
  • 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.

    The coffee command uses an instance of OptionParser to parse its command-line arguments in src/command.coffee.

    exports.OptionParser = class OptionParser
  • Initialize with a list of valid options, in the form:

    [short-flag, long-flag, description]
    

    Along with 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 repeat ' ', spaces 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
coffeescript-1.12.7/docs/v2/annotated-source/public/000077500000000000000000000000001313305734200222675ustar00rootroot00000000000000coffeescript-1.12.7/docs/v2/annotated-source/public/stylesheets/000077500000000000000000000000001313305734200246435ustar00rootroot00000000000000coffeescript-1.12.7/docs/v2/annotated-source/public/stylesheets/normalize.css000066400000000000000000000153321313305734200273610ustar00rootroot00000000000000/*! normalize.css v2.0.1 | MIT License | git.io/normalize */ /* ========================================================================== HTML5 display definitions ========================================================================== */ /* * Corrects `block` display not defined in IE 8/9. */ article, aside, details, figcaption, figure, footer, header, hgroup, nav, section, summary { display: block; } /* * Corrects `inline-block` display not defined in IE 8/9. */ audio, canvas, video { display: inline-block; } /* * Prevents modern browsers from displaying `audio` without controls. * Remove excess height in iOS 5 devices. */ audio:not([controls]) { display: none; height: 0; } /* * Addresses styling for `hidden` attribute not present in IE 8/9. */ [hidden] { display: none; } /* ========================================================================== Base ========================================================================== */ /* * 1. Sets default font family to sans-serif. * 2. Prevents iOS text size adjust after orientation change, without disabling * user zoom. */ html { font-family: sans-serif; /* 1 */ -webkit-text-size-adjust: 100%; /* 2 */ -ms-text-size-adjust: 100%; /* 2 */ } /* * Removes default margin. */ body { margin: 0; } /* ========================================================================== Links ========================================================================== */ /* * Addresses `outline` inconsistency between Chrome and other browsers. */ a:focus { outline: thin dotted; } /* * Improves readability when focused and also mouse hovered in all browsers. */ a:active, a:hover { outline: 0; } /* ========================================================================== Typography ========================================================================== */ /* * Addresses `h1` font sizes within `section` and `article` in Firefox 4+, * Safari 5, and Chrome. */ h1 { font-size: 2em; } /* * Addresses styling not present in IE 8/9, Safari 5, and Chrome. */ abbr[title] { border-bottom: 1px dotted; } /* * Addresses style set to `bolder` in Firefox 4+, Safari 5, and Chrome. */ b, strong { font-weight: bold; } /* * Addresses styling not present in Safari 5 and Chrome. */ dfn { font-style: italic; } /* * Addresses styling not present in IE 8/9. */ mark { background: #ff0; color: #000; } /* * Corrects font family set oddly in Safari 5 and Chrome. */ code, kbd, pre, samp { font-family: monospace, serif; font-size: 1em; } /* * Improves readability of pre-formatted text in all browsers. */ pre { white-space: pre; white-space: pre-wrap; word-wrap: break-word; } /* * Sets consistent quote types. */ q { quotes: "\201C" "\201D" "\2018" "\2019"; } /* * Addresses inconsistent and variable font size in all browsers. */ small { font-size: 80%; } /* * Prevents `sub` and `sup` affecting `line-height` in all browsers. */ sub, sup { font-size: 75%; line-height: 0; position: relative; vertical-align: baseline; } sup { top: -0.5em; } sub { bottom: -0.25em; } /* ========================================================================== Embedded content ========================================================================== */ /* * Removes border when inside `a` element in IE 8/9. */ img { border: 0; } /* * Corrects overflow displayed oddly in IE 9. */ svg:not(:root) { overflow: hidden; } /* ========================================================================== Figures ========================================================================== */ /* * Addresses margin not present in IE 8/9 and Safari 5. */ figure { margin: 0; } /* ========================================================================== Forms ========================================================================== */ /* * Define consistent border, margin, and padding. */ fieldset { border: 1px solid #c0c0c0; margin: 0 2px; padding: 0.35em 0.625em 0.75em; } /* * 1. Corrects color not being inherited in IE 8/9. * 2. Remove padding so people aren't caught out if they zero out fieldsets. */ legend { border: 0; /* 1 */ padding: 0; /* 2 */ } /* * 1. Corrects font family not being inherited in all browsers. * 2. Corrects font size not being inherited in all browsers. * 3. Addresses margins set differently in Firefox 4+, Safari 5, and Chrome */ button, input, select, textarea { font-family: inherit; /* 1 */ font-size: 100%; /* 2 */ margin: 0; /* 3 */ } /* * Addresses Firefox 4+ setting `line-height` on `input` using `!important` in * the UA stylesheet. */ button, input { line-height: normal; } /* * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio` * and `video` controls. * 2. Corrects inability to style clickable `input` types in iOS. * 3. Improves usability and consistency of cursor style between image-type * `input` and others. */ button, html input[type="button"], /* 1 */ input[type="reset"], input[type="submit"] { -webkit-appearance: button; /* 2 */ cursor: pointer; /* 3 */ } /* * Re-set default cursor for disabled elements. */ button[disabled], input[disabled] { cursor: default; } /* * 1. Addresses box sizing set to `content-box` in IE 8/9. * 2. Removes excess padding in IE 8/9. */ input[type="checkbox"], input[type="radio"] { box-sizing: border-box; /* 1 */ padding: 0; /* 2 */ } /* * 1. Addresses `appearance` set to `searchfield` in Safari 5 and Chrome. * 2. Addresses `box-sizing` set to `border-box` in Safari 5 and Chrome * (include `-moz` to future-proof). */ input[type="search"] { -webkit-appearance: textfield; /* 1 */ -moz-box-sizing: content-box; -webkit-box-sizing: content-box; /* 2 */ box-sizing: content-box; } /* * Removes inner padding and search cancel button in Safari 5 and Chrome * on OS X. */ input[type="search"]::-webkit-search-cancel-button, input[type="search"]::-webkit-search-decoration { -webkit-appearance: none; } /* * Removes inner padding and border in Firefox 4+. */ button::-moz-focus-inner, input::-moz-focus-inner { border: 0; padding: 0; } /* * 1. Removes default vertical scrollbar in IE 8/9. * 2. Improves readability and alignment in all browsers. */ textarea { overflow: auto; /* 1 */ vertical-align: top; /* 2 */ } /* ========================================================================== Tables ========================================================================== */ /* * Remove most spacing between table cells. */ table { border-collapse: collapse; border-spacing: 0; }coffeescript-1.12.7/docs/v2/annotated-source/register.html000066400000000000000000000217541313305734200235340ustar00rootroot00000000000000 register.coffee
  • register.coffee

  • CoffeeScript  = require './'
    child_process = require 'child_process'
    helpers       = require './helpers'
    path          = require 'path'
  • Load and run a CoffeeScript file for Node, stripping any BOMs.

    loadFile = (module, filename) ->
      answer = CoffeeScript._compileFile filename, no, yes
      module._compile answer, filename
  • If the installed version of Node supports require.extensions, register CoffeeScript as an extension.

    if require.extensions
      for ext in CoffeeScript.FILE_EXTENSIONS
        require.extensions[ext] = loadFile
  • Patch Node’s module loader to be able to handle multi-dot extensions. This is a horrible thing that should not be required.

      Module = require 'module'
    
      findExtension = (filename) ->
        extensions = path.basename(filename).split '.'
  • Remove the initial dot from dotfiles.

        extensions.shift() if extensions[0] is ''
  • Start with the longest possible extension and work our way shortwards.

        while extensions.shift()
          curExtension = '.' + extensions.join '.'
          return curExtension if Module._extensions[curExtension]
        '.js'
    
      Module::load = (filename) ->
        @filename = filename
        @paths = Module._nodeModulePaths path.dirname filename
        extension = findExtension filename
        Module._extensions[extension](this, filename)
        @loaded = true
  • If we’re on Node, patch child_process.fork so that Coffee scripts are able to fork both CoffeeScript files, and JavaScript files, directly.

    if child_process
      {fork} = child_process
      binary = require.resolve '../../bin/coffee'
      child_process.fork = (path, args, options) ->
        if helpers.isCoffee path
          unless Array.isArray args
            options = args or {}
            args = []
          args = [path].concat args
          path = binary
        fork path, args, options
coffeescript-1.12.7/docs/v2/annotated-source/repl.html000066400000000000000000000621671313305734200226550ustar00rootroot00000000000000 repl.coffee
  • repl.coffee

  • fs = require 'fs'
    path = require 'path'
    vm = require 'vm'
    nodeREPL = require 'repl'
    CoffeeScript = require './'
    {merge, updateSyntaxError} = require './helpers'
    
    replDefaults =
      prompt: 'coffee> ',
      historyFile: do ->
        historyPath = process.env.XDG_CACHE_HOME or process.env.HOME
        path.join historyPath, '.coffee_history' if historyPath
      historyMaxInputSize: 10240
      eval: (input, context, filename, cb) ->
  • XXX: multiline hack.

        input = input.replace /\uFF00/g, '\n'
  • Node’s REPL sends the input ending with a newline and then wrapped in parens. Unwrap all that.

        input = input.replace /^\(([\s\S]*)\n\)$/m, '$1'
  • Node’s REPL v6.9.1+ sends the input wrapped in a try/catch statement. Unwrap that too.

        input = input.replace /^\s*try\s*{([\s\S]*)}\s*catch.*$/m, '$1'
  • Require AST nodes to do some AST manipulation.

        {Block, Assign, Value, Literal} = require './nodes'
    
        try
  • Tokenize the clean input.

          tokens = CoffeeScript.tokens input
  • Collect referenced variable names just like in CoffeeScript.compile.

          referencedVars = (
            token[1] for token in tokens when token[0] is 'IDENTIFIER'
          )
  • Generate the AST of the tokens.

          ast = CoffeeScript.nodes tokens
  • Add assignment to _ variable to force the input to be an expression.

          ast = new Block [
            new Assign (new Value new Literal '__'), ast, '='
          ]
          js = ast.compile {bare: yes, locals: Object.keys(context), referencedVars}
          cb null, runInContext js, context, filename
        catch err
  • AST’s compile does not add source code information to syntax errors.

          updateSyntaxError err, input
          cb err
    
    runInContext = (js, context, filename) ->
      if context is global
        vm.runInThisContext js, filename
      else
        vm.runInContext js, context, filename
    
    addMultilineHandler = (repl) ->
      {rli, inputStream, outputStream} = repl
  • Node 0.11.12 changed API, prompt is now _prompt.

      origPrompt = repl._prompt ? repl.prompt
    
      multiline =
        enabled: off
        initialPrompt: origPrompt.replace /^[^> ]*/, (x) -> x.replace /./g, '-'
        prompt: origPrompt.replace /^[^> ]*>?/, (x) -> x.replace /./g, '.'
        buffer: ''
  • Proxy node’s line listener

      nodeLineListener = rli.listeners('line')[0]
      rli.removeListener 'line', nodeLineListener
      rli.on 'line', (cmd) ->
        if multiline.enabled
          multiline.buffer += "#{cmd}\n"
          rli.setPrompt multiline.prompt
          rli.prompt true
        else
          rli.setPrompt origPrompt
          nodeLineListener cmd
        return
  • Handle Ctrl-v

      inputStream.on 'keypress', (char, key) ->
        return unless key and key.ctrl and not key.meta and not key.shift and key.name is 'v'
        if multiline.enabled
  • allow arbitrarily switching between modes any time before multiple lines are entered

          unless multiline.buffer.match /\n/
            multiline.enabled = not multiline.enabled
            rli.setPrompt origPrompt
            rli.prompt true
            return
  • no-op unless the current line is empty

          return if rli.line? and not rli.line.match /^\s*$/
  • eval, print, loop

          multiline.enabled = not multiline.enabled
          rli.line = ''
          rli.cursor = 0
          rli.output.cursorTo 0
          rli.output.clearLine 1
  • XXX: multiline hack

          multiline.buffer = multiline.buffer.replace /\n/g, '\uFF00'
          rli.emit 'line', multiline.buffer
          multiline.buffer = ''
        else
          multiline.enabled = not multiline.enabled
          rli.setPrompt multiline.initialPrompt
          rli.prompt true
        return
  • Store and load command history from a file

    addHistory = (repl, filename, maxSize) ->
      lastLine = null
      try
  • Get file info and at most maxSize of command history

        stat = fs.statSync filename
        size = Math.min maxSize, stat.size
  • Read last size bytes from the file

        readFd = fs.openSync filename, 'r'
        buffer = Buffer.alloc size
        fs.readSync readFd, buffer, 0, size, stat.size - size
        fs.closeSync readFd
  • Set the history on the interpreter

        repl.rli.history = buffer.toString().split('\n').reverse()
  • If the history file was truncated we should pop off a potential partial line

        repl.rli.history.pop() if stat.size > maxSize
  • Shift off the final blank newline

        repl.rli.history.shift() if repl.rli.history[0] is ''
        repl.rli.historyIndex = -1
        lastLine = repl.rli.history[0]
    
      fd = fs.openSync filename, 'a'
    
      repl.rli.addListener 'line', (code) ->
        if code and code.length and code isnt '.history' and code isnt '.exit' and lastLine isnt code
  • Save the latest command in the file

          fs.writeSync fd, "#{code}\n"
          lastLine = code
    
      repl.on 'exit', -> fs.closeSync fd
  • Add a command to show the history stack

      repl.commands[getCommandId(repl, 'history')] =
        help: 'Show command history'
        action: ->
          repl.outputStream.write "#{repl.rli.history[..].reverse().join '\n'}\n"
          repl.displayPrompt()
    
    getCommandId = (repl, commandName) ->
  • Node 0.11 changed API, a command such as ‘.help’ is now stored as ‘help’

      commandsHaveLeadingDot = repl.commands['.help']?
      if commandsHaveLeadingDot then ".#{commandName}" else commandName
    
    module.exports =
      start: (opts = {}) ->
        [major, minor, build] = process.versions.node.split('.').map (n) -> parseInt(n, 10)
    
        if major < 6
          console.warn "Node 6+ required for CoffeeScript REPL"
          process.exit 1
    
        CoffeeScript.register()
        process.argv = ['coffee'].concat process.argv[2..]
        opts = merge replDefaults, opts
        repl = nodeREPL.start opts
        runInContext opts.prelude, repl.context, 'prelude' if opts.prelude
        repl.on 'exit', -> repl.outputStream.write '\n' if not repl.rli.closed
        addMultilineHandler repl
        addHistory repl, opts.historyFile, opts.historyMaxInputSize if opts.historyFile
  • Adapt help inherited from the node REPL

        repl.commands[getCommandId(repl, 'load')].help = 'Load code from a file into this REPL session'
        repl
coffeescript-1.12.7/docs/v2/annotated-source/rewriter.html000066400000000000000000002150631313305734200235510ustar00rootroot00000000000000 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.

    {throwSyntaxError} = require './helpers'
  • Create a generated token: one that exists due to a use of implicit syntax.

    generate = (tag, value, origin) ->
      tok = [tag, value]
      tok.generated = yes
      tok.origin = origin if origin
      tok
  • The Rewriter class is used by the Lexer, directly against its internal array of tokens.

    exports.Rewriter = class Rewriter
  • Rewrite the token stream in multiple passes, one logical filter at a time. This could certainly be changed into a single pass through the stream, with a big ol’ efficient switch, but it’s much nicer to work with like this. The order of these passes matters – indentation must be corrected before implicit parentheses can be wrapped around blocks of code.

      rewrite: (@tokens) ->
  • Helpful snippet for debugging: console.log (t[0] + ‘/‘ + t[1] for t in @tokens).join ‘ ‘

        @removeLeadingNewlines()
        @closeOpenCalls()
        @closeOpenIndexes()
        @normalizeLines()
        @tagPostfixConditionals()
        @addImplicitBracesAndParens()
        @addLocationDataToGeneratedTokens()
        @enforceValidCSXAttributes()
        @fixOutdentLocationData()
        @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, opts = {}) ->
        {tokens} = this
        levels = 0
        while token = tokens[i]
          return action.call this, token, i if levels is 0 and condition.call this, token, i
          if token[0] in EXPRESSION_START
            levels += 1
          else if token[0] in EXPRESSION_END
            levels -= 1
          if levels < 0
            return if opts.returnOnNegativeLevel
            return action.call this, token, i
          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
  • The lexer has tagged the opening parenthesis of a method call. Match it with its paired close.

      closeOpenCalls: ->
        condition = (token, i) ->
          token[0] in [')', 'CALL_END']
    
        action = (token, i) ->
          token[0] = 'CALL_END'
    
        @scanTokens (token, i) ->
          @detectEnd i + 1, condition, action if token[0] is 'CALL_START'
          1
  • The lexer has tagged the opening bracket 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
  • Match tags in token stream starting at i with pattern, skipping ‘HERECOMMENT’s. pattern may consist of strings (equality), an array of strings (one of) or null (wildcard). Returns the index of the match or -1 if no match.

      indexOfTag: (i, pattern...) ->
        fuzz = 0
        for j in [0 ... pattern.length]
          fuzz += 2 while @tag(i + j + fuzz) is 'HERECOMMENT'
          continue if not pattern[j]?
          pattern[j] = [pattern[j]] if typeof pattern[j] is 'string'
          return -1 if @tag(i + j + fuzz) not in pattern[j]
        i + j + fuzz - 1
  • Returns yes if standing in front of something looking like @<x>:, <x>: or <EXPRESSION_START><x>...<EXPRESSION_END>:, skipping over ‘HERECOMMENT’s.

      looksObjectish: (j) ->
        return yes if @indexOfTag(j, '@', null, ':') > -1 or @indexOfTag(j, null, ':') > -1
        index = @indexOfTag(j, EXPRESSION_START)
        if index > -1
          end = null
          @detectEnd index + 1, ((token) -> token[0] in EXPRESSION_END), ((token, i) -> end = i)
          return yes if @tag(end + 1) is ':'
        no
  • Returns yes if current line of tokens contain an element of tags on same expression level. Stop searching at LINEBREAKS or explicit start of containing balanced expression.

      findTagsBackwards: (i, tags) ->
        backStack = []
        while i >= 0 and (backStack.length or
              @tag(i) not in tags and
              (@tag(i) not in EXPRESSION_START or @tokens[i].generated) and
              @tag(i) not in LINEBREAKS)
          backStack.push @tag(i) if @tag(i) in EXPRESSION_END
          backStack.pop() if @tag(i) in EXPRESSION_START and backStack.length
          i -= 1
        @tag(i) in tags
  • Look for signs of implicit calls and objects in the token stream and add them.

      addImplicitBracesAndParens: ->
  • Track current balancing depth (both implicit and explicit) on stack.

        stack = []
        start = null
    
        @scanTokens (token, i, tokens) ->
          [tag]     = token
          [prevTag] = prevToken = if i > 0 then tokens[i - 1] else []
          [nextTag] = nextToken = if i < tokens.length - 1 then tokens[i + 1] else []
          stackTop  = -> stack[stack.length - 1]
          startIdx  = i
  • Helper function, used for keeping track of the number of tokens consumed and spliced, when returning for getting a new token.

          forward   = (n) -> i - startIdx + n
  • Helper functions

          isImplicit        = (stackItem) -> stackItem?[2]?.ours
          isImplicitObject  = (stackItem) -> isImplicit(stackItem) and stackItem?[0] is '{'
          isImplicitCall    = (stackItem) -> isImplicit(stackItem) and stackItem?[0] is '('
          inImplicit        = -> isImplicit stackTop()
          inImplicitCall    = -> isImplicitCall stackTop()
          inImplicitObject  = -> isImplicitObject stackTop()
  • Unclosed control statement inside implicit parens (like class declaration or if-conditionals)

          inImplicitControl = -> inImplicit() and stackTop()?[0] is 'CONTROL'
    
          startImplicitCall = (idx) ->
            stack.push ['(', idx, ours: yes]
            tokens.splice idx, 0, generate 'CALL_START', '('
    
          endImplicitCall = ->
            stack.pop()
            tokens.splice i, 0, generate 'CALL_END', ')', ['', 'end of input', token[2]]
            i += 1
    
          startImplicitObject = (idx, startsLine = yes) ->
            stack.push ['{', idx, sameLine: yes, startsLine: startsLine, ours: yes]
            val = new String '{'
            val.generated = yes
            tokens.splice idx, 0, generate '{', val, token
    
          endImplicitObject = (j) ->
            j = j ? i
            stack.pop()
            tokens.splice j, 0, generate '}', '}', token
            i += 1
    
          implicitObjectContinues = (j) =>
            nextTerminatorIdx = null
            @detectEnd j,
              (token) -> token[0] is 'TERMINATOR'
              (token, i) -> nextTerminatorIdx = i
              returnOnNegativeLevel: yes
            return no unless nextTerminatorIdx?
            @looksObjectish nextTerminatorIdx + 1
  • Don’t end an implicit call/object on next indent if any of these are in an argument/value

          if (
            (inImplicitCall() or inImplicitObject()) and tag in CONTROL_IN_IMPLICIT or
            inImplicitObject() and prevTag is ':' and tag is 'FOR'
          )
            stack.push ['CONTROL', i, ours: yes]
            return forward(1)
    
          if tag is 'INDENT' and inImplicit()
  • An INDENT closes an implicit call unless

    1. We have seen a CONTROL argument on the line.
    2. The last token before the indent is part of the list below
            if prevTag not in ['=>', '->', '[', '(', ',', '{', 'ELSE', '=']
              while inImplicitCall() or inImplicitObject() and prevTag isnt ':'
                if inImplicitCall()
                  endImplicitCall()
                else
                  endImplicitObject()
            stack.pop() if inImplicitControl()
            stack.push [tag, i]
            return forward(1)
  • Straightforward start of explicit expression

          if tag in EXPRESSION_START
            stack.push [tag, i]
            return forward(1)
  • Close all implicit expressions inside of explicitly closed expressions.

          if tag in EXPRESSION_END
            while inImplicit()
              if inImplicitCall()
                endImplicitCall()
              else if inImplicitObject()
                endImplicitObject()
              else
                stack.pop()
            start = stack.pop()
  • Recognize standard implicit calls like f a, f() b, f? c, h[0] d etc.

          if (tag in IMPLICIT_FUNC and token.spaced or
              tag is '?' and i > 0 and not tokens[i - 1].spaced) and
             (nextTag in IMPLICIT_CALL or
              nextTag in IMPLICIT_UNSPACED_CALL and
              not nextToken.spaced and not nextToken.newLine)
            tag = token[0] = 'FUNC_EXIST' if tag is '?'
            startImplicitCall i + 1
            return forward(2)
  • Implicit call taking an implicit indented object as first argument.

    f
      a: b
      c: d
    

    Don’t accept implicit calls of this type, when on the same line as the control structures below as that may misinterpret constructs like:

    if f
       a: 1
    

    as

    if f(a: 1)
    

    which is probably always unintended. Furthermore don’t allow this in literal arrays, as that creates grammatical ambiguities.

          if tag in IMPLICIT_FUNC and
             @indexOfTag(i + 1, 'INDENT') > -1 and @looksObjectish(i + 2) and
             not @findTagsBackwards(i, ['CLASS', 'EXTENDS', 'IF', 'CATCH',
              'SWITCH', 'LEADING_WHEN', 'FOR', 'WHILE', 'UNTIL'])
            startImplicitCall i + 1
            stack.push ['INDENT', i + 2]
            return forward(3)
  • Implicit objects start here

          if tag is ':'
  • Go back to the (implicit) start of the object

            s = switch
              when @tag(i - 1) in EXPRESSION_END then start[1]
              when @tag(i - 2) is '@' then i - 2
              else i - 1
            s -= 2 while @tag(s - 2) is 'HERECOMMENT'
    
            startsLine = s is 0 or @tag(s - 1) in LINEBREAKS or tokens[s - 1].newLine
  • Are we just continuing an already declared object?

            if stackTop()
              [stackTag, stackIdx] = stackTop()
              if (stackTag is '{' or stackTag is 'INDENT' and @tag(stackIdx - 1) is '{') and
                 (startsLine or @tag(s - 1) is ',' or @tag(s - 1) is '{')
                return forward(1)
    
            startImplicitObject(s, !!startsLine)
            return forward(2)
  • End implicit calls when chaining method calls like e.g.:

    f ->
      a
    .g b, ->
      c
    .h a
    

    and also

    f a
    .g b
    .h a
    
  • Mark all enclosing objects as not sameLine

          if tag in LINEBREAKS
            for stackItem in stack by -1 when isImplicitObject stackItem
              stackItem[2].sameLine = no
    
          newLine = prevTag is 'OUTDENT' or prevToken.newLine
          if tag in IMPLICIT_END or tag in CALL_CLOSERS and newLine
            while inImplicit()
              [stackTag, stackIdx, {sameLine, startsLine}] = stackTop()
  • Close implicit calls when reached end of argument list

              if inImplicitCall() and prevTag isnt ','
                endImplicitCall()
  • Close implicit objects such as: return a: 1, b: 2 unless true

              else if inImplicitObject() and sameLine and
                      tag isnt 'TERMINATOR' and prevTag isnt ':' and
                      not (tag in ['POST_IF', 'FOR', 'WHILE', 'UNTIL'] and startsLine and implicitObjectContinues(i + 1))
                endImplicitObject()
  • Close implicit objects when at end of line, line didn’t end with a comma and the implicit object didn’t start the line or the next line doesn’t look like the continuation of an object.

              else if inImplicitObject() and tag is 'TERMINATOR' and prevTag isnt ',' and
                      not (startsLine and @looksObjectish(i + 1))
                return forward 1 if nextTag is 'HERECOMMENT'
                endImplicitObject()
              else
                break
  • Close implicit object if comma is the last character and what comes after doesn’t look like it belongs. This is used for trailing commas and calls, like:

    x =
        a: b,
        c: d,
    e = 2
    

    and

    f a, b: c, d: e, f, g: h: i, j
    
          if tag is ',' and not @looksObjectish(i + 1) and inImplicitObject() and
             (nextTag isnt 'TERMINATOR' or not @looksObjectish(i + 2))
  • When nextTag is OUTDENT the comma is insignificant and should just be ignored so embed it in the implicit object.

    When it isn’t the comma go on to play a role in a call or array further up the stack, so give it a chance.

            offset = if nextTag is 'OUTDENT' then 1 else 0
            while inImplicitObject()
              endImplicitObject i + offset
          return forward(1)
  • Make sure only strings and wrapped expressions are used in CSX attributes

      enforceValidCSXAttributes: ->
        @scanTokens (token, i, tokens) ->
          if token.csxColon
            next = tokens[i + 1]
            if next[0] not in ['STRING_START', 'STRING', '(']
              throwSyntaxError 'expected wrapped or quoted CSX attribute', next[2]
          return 1
  • Add location data to all tokens generated by the rewriter.

      addLocationDataToGeneratedTokens: ->
        @scanTokens (token, i, tokens) ->
          return 1 if     token[2]
          return 1 unless token.generated or token.explicit
          if token[0] is '{' and nextLocation=tokens[i + 1]?[2]
            {first_line: line, first_column: column} = nextLocation
          else if prevLocation = tokens[i - 1]?[2]
            {last_line: line, last_column: column} = prevLocation
          else
            line = column = 0
          token[2] =
            first_line:   line
            first_column: column
            last_line:    line
            last_column:  column
          return 1
  • OUTDENT tokens should always be positioned at the last character of the previous token, so that AST nodes ending in an OUTDENT token end up with a location corresponding to the last “real” token under the node.

      fixOutdentLocationData: ->
        @scanTokens (token, i, tokens) ->
          return 1 unless token[0] is 'OUTDENT' or
            (token.generated and token[0] is 'CALL_END') or
            (token.generated and token[0] is '}')
          prevLocationData = tokens[i - 1][2]
          token[2] =
            first_line:   prevLocationData.last_line
            first_column: prevLocationData.last_column
            last_line:    prevLocationData.last_line
            last_column:  prevLocationData.last_column
          return 1
  • 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. To keep the grammar clean and tidy, trailing newlines within expressions are removed and the indentation tokens of empty blocks are added.

      normalizeLines: ->
        starter = indent = outdent = null
    
        condition = (token, i) ->
          token[1] isnt ';' and token[0] in SINGLE_CLOSERS and
          not (token[0] is 'TERMINATOR' and @tag(i + 1) in EXPRESSION_CLOSE) and
          not (token[0] is 'ELSE' and starter isnt 'THEN') and
          not (token[0] in ['CATCH', 'FINALLY'] and starter in ['->', '=>']) or
          token[0] in CALL_CLOSERS and
          (@tokens[i - 1].newLine or @tokens[i - 1][0] is 'OUTDENT')
    
        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'
            if @tag(i + 1) is 'ELSE' and @tag(i - 1) isnt 'OUTDENT'
              tokens.splice i, 1, @indentation()...
              return 1
            if @tag(i + 1) in EXPRESSION_CLOSE
              tokens.splice i, 1
              return 0
          if tag is 'CATCH'
            for j in [1..2] when @tag(i + j) in ['OUTDENT', 'TERMINATOR', 'FINALLY']
              tokens.splice i + j, 0, @indentation()...
              return 2 + j
          if tag in ['->', '=>'] and (@tag(i + 1) is ',' or @tag(i + 1) is '.' and token.newLine)
            [indent, outdent] = @indentation tokens[i]
            tokens.splice i + 1, 0, indent, outdent
            return 1
          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 tokens[i]
            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) ->
          [tag] = token
          [prevTag] = @tokens[i - 1]
          tag is 'TERMINATOR' or (tag is 'INDENT' and prevTag not in SINGLE_LINERS)
    
        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
          return 1
  • Generate the indentation tokens, based on another token on the same line.

      indentation: (origin) ->
        indent  = ['INDENT', 2]
        outdent = ['OUTDENT', 2]
        if origin
          indent.generated = outdent.generated = yes
          indent.origin = outdent.origin = origin
        else
          indent.explicit = outdent.explicit = yes
        [indent, outdent]
    
      generate: generate
  • 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']
      ['STRING_START', 'STRING_END']
      ['REGEX_START', 'REGEX_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', 'THEN', 'ELSE', 'FINALLY'].concat EXPRESSION_END
  • Tokens that, if followed by an IMPLICIT_CALL, indicate a function invocation.

    IMPLICIT_FUNC    = ['IDENTIFIER', 'PROPERTY', 'SUPER', ')', 'CALL_END', ']', 'INDEX_END', '@', 'THIS']
  • If preceded by an IMPLICIT_FUNC, indicates a function invocation.

    IMPLICIT_CALL    = [
      'IDENTIFIER', 'CSX_TAG', 'PROPERTY', 'NUMBER', 'INFINITY', 'NAN'
      'STRING', 'STRING_START', 'REGEX', 'REGEX_START', 'JS'
      'NEW', 'PARAM_START', 'CLASS', 'IF', 'TRY', 'SWITCH', 'THIS'
      'UNDEFINED', 'NULL', 'BOOL'
      'UNARY', 'YIELD', 'AWAIT', 'UNARY_MATH', 'SUPER', 'THROW'
      '@', '->', '=>', '[', '(', '{', '--', '++'
    ]
    
    IMPLICIT_UNSPACED_CALL = ['+', '-']
  • 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']
  • Tokens that close open calls when they follow a newline.

    CALL_CLOSERS     = ['.', '?.', '::', '?::']
  • Tokens that prevent a subsequent indent from ending implicit calls/objects

    CONTROL_IN_IMPLICIT = ['IF', 'TRY', 'FINALLY', 'CATCH', 'CLASS', 'SWITCH']
coffeescript-1.12.7/docs/v2/annotated-source/scope.html000066400000000000000000000375331313305734200230230ustar00rootroot00000000000000 scope.litcoffee
  • scope.litcoffee

  • 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 external scopes.

    exports.Scope = class Scope
  • 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, a reference to the function that it belongs to, and a list of variables referenced in the source code and therefore should be avoided when generating variables.

      constructor: (@parent, @expressions, @method, @referencedVars) ->
        @variables = [{name: 'arguments', type: 'arguments'}]
        @positions = {}
        @utilities = {} unless @parent
  • The @root is the top-level Scope object for a given file.

        @root = @parent?.root ? this
  • 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, type = 'var') ->
        return yes if @check name
        @add name, type
        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, single=false) ->
        if single
          startCode = name.charCodeAt(0)
          endCode = 'z'.charCodeAt(0)
          diff = endCode - startCode
          newCode = startCode + index % (diff + 1)
          letter = String.fromCharCode(newCode)
          num = index // (diff + 1)
          "#{letter}#{num or ''}"
        else
          "#{name}#{index or ''}"
  • 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, options={}) ->
        index = 0
        loop
          temp = @temporary name, index, options.single
          break unless @check(temp) or temp in @root.referencedVars
          index++
        @add temp, 'var', yes if options.reserve ? true
        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: ->
        (v.name for v in @variables when v.type is 'var').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
coffeescript-1.12.7/docs/v2/annotated-source/sourcemap.html000066400000000000000000000474241313305734200237100ustar00rootroot00000000000000 sourcemap.litcoffee
  • sourcemap.litcoffee

  • Source maps allow JavaScript runtimes to match running JavaScript back to the original source code that corresponds to it. This can be minified JavaScript, but in our case, we’re concerned with mapping pretty-printed JavaScript back to CoffeeScript.

    In order to produce maps, we must keep track of positions (line number, column number) that originated every node in the syntax tree, and be able to generate a map file — which is a compact, VLQ-encoded representation of the JSON serialization of this information — to write out alongside the generated JavaScript.

    LineMap

  • A LineMap object keeps track of information about original line and column positions for a single line of output JavaScript code. SourceMaps are implemented in terms of LineMaps.

    class LineMap
      constructor: (@line) ->
        @columns = []
    
      add: (column, [sourceLine, sourceColumn], options={}) ->
        return if @columns[column] and options.noReplace
        @columns[column] = {line: @line, column, sourceLine, sourceColumn}
    
      sourceLocation: (column) ->
        column-- until (mapping = @columns[column]) or (column <= 0)
        mapping and [mapping.sourceLine, mapping.sourceColumn]
  • SourceMap

  • Maps locations in a single generated JavaScript file back to locations in the original CoffeeScript source file.

    This is intentionally agnostic towards how a source map might be represented on disk. Once the compiler is ready to produce a “v3”-style source map, we can walk through the arrays of line and column buffer to produce it.

    class SourceMap
      constructor: ->
        @lines = []
  • Adds a mapping to this SourceMap. sourceLocation and generatedLocation are both [line, column] arrays. If options.noReplace is true, then if there is already a mapping for the specified line and column, this will have no effect.

      add: (sourceLocation, generatedLocation, options = {}) ->
        [line, column] = generatedLocation
        lineMap = (@lines[line] or= new LineMap(line))
        lineMap.add column, sourceLocation, options
  • Look up the original position of a given line and column in the generated code.

      sourceLocation: ([line, column]) ->
        line-- until (lineMap = @lines[line]) or (line <= 0)
        lineMap and lineMap.sourceLocation column
  • V3 SourceMap Generation

  • Builds up a V3 source map, returning the generated JSON as a string. options.sourceRoot may be used to specify the sourceRoot written to the source map. Also, options.sourceFiles and options.generatedFile may be passed to set “sources” and “file”, respectively.

      generate: (options = {}, code = null) ->
        writingline       = 0
        lastColumn        = 0
        lastSourceLine    = 0
        lastSourceColumn  = 0
        needComma         = no
        buffer            = ""
    
        for lineMap, lineNumber in @lines when lineMap
          for mapping in lineMap.columns when mapping
            while writingline < mapping.line
              lastColumn = 0
              needComma = no
              buffer += ";"
              writingline++
  • Write a comma if we’ve already written a segment on this line.

            if needComma
              buffer += ","
              needComma = no
  • Write the next segment. Segments can be 1, 4, or 5 values. If just one, then it is a generated column which doesn’t match anything in the source code.

    The starting column in the generated source, relative to any previous recorded column for the current line:

            buffer += @encodeVlq mapping.column - lastColumn
            lastColumn = mapping.column
  • The index into the list of sources:

            buffer += @encodeVlq 0
  • The starting line in the original source, relative to the previous source line.

            buffer += @encodeVlq mapping.sourceLine - lastSourceLine
            lastSourceLine = mapping.sourceLine
  • The starting column in the original source, relative to the previous column.

            buffer += @encodeVlq mapping.sourceColumn - lastSourceColumn
            lastSourceColumn = mapping.sourceColumn
            needComma = yes
  • Produce the canonical JSON object format for a “v3” source map.

        v3 =
          version:    3
          file:       options.generatedFile or ''
          sourceRoot: options.sourceRoot or ''
          sources:    options.sourceFiles or ['']
          names:      []
          mappings:   buffer
    
        v3.sourcesContent = [code] if options.inlineMap
    
        v3
  • Base64 VLQ Encoding

  • Note that SourceMap VLQ encoding is “backwards”. MIDI-style VLQ encoding puts the most-significant-bit (MSB) from the original value into the MSB of the VLQ encoded value (see Wikipedia). SourceMap VLQ does things the other way around, with the least significat four bits of the original value encoded into the first byte of the VLQ encoded value.

      VLQ_SHIFT            = 5
      VLQ_CONTINUATION_BIT = 1 << VLQ_SHIFT             # 0010 0000
      VLQ_VALUE_MASK       = VLQ_CONTINUATION_BIT - 1   # 0001 1111
    
      encodeVlq: (value) ->
        answer = ''
  • Least significant bit represents the sign.

        signBit = if value < 0 then 1 else 0
  • The next bits are the actual value.

        valueToEncode = (Math.abs(value) << 1) + signBit
  • Make sure we encode at least one character, even if valueToEncode is 0.

        while valueToEncode or not answer
          nextChunk = valueToEncode & VLQ_VALUE_MASK
          valueToEncode = valueToEncode >> VLQ_SHIFT
          nextChunk |= VLQ_CONTINUATION_BIT if valueToEncode
          answer += @encodeBase64 nextChunk
    
        answer
  • Regular Base64 Encoding

  •   BASE64_CHARS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
    
      encodeBase64: (value) ->
        BASE64_CHARS[value] or throw new Error "Cannot Base64 encode value: #{value}"
  • Our API for source maps is just the SourceMap class.

    module.exports = SourceMap
coffeescript-1.12.7/docs/v2/index.html000066400000000000000000007255101313305734200175450ustar00rootroot00000000000000 CoffeeScript

CoffeeScript is a little language that compiles into JavaScript. Underneath that awkward Java-esque patina, JavaScript has always had a gorgeous 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, pretty-printed, and tends to run as fast or faster than the equivalent handwritten JavaScript.

Latest Version: 2.0.0-beta3

npm install -g coffeescript@next

Overview

CoffeeScript on the topleft, compiled JavaScript output on the bottomright. The CoffeeScript is editable!

CoffeeScript 2

What’s New In CoffeeScript 2?

The biggest change in CoffeeScript 2 is that now the CoffeeScript compiler produces modern, ES2015+ JavaScript. A CoffeeScript => becomes an ES =>, a CoffeeScript class becomes an ES class and so on. With the exception of modules (import and export statements), all the ES2015+ features that CoffeeScript supports can run natively in Node 7.6+, meaning that Node can run CoffeeScript’s output without any further processing required. You can run the tests in your browser to see if your browser can do the same; Chrome has supported all features since version 55.

Support for ES2015+ syntax is important to ensure compatibility with frameworks that assume ES2015. Now that CoffeeScript compiles classes to the ES class keyword, it’s possible to extend an ES class; that wasn’t possible in CoffeeScript 1. Parity in how language features work is also important on its own; CoffeeScript “is just JavaScript,” and so things like function parameter default values should behave the same in CoffeeScript as in JavaScript.

Many ES2015+ features have been backported to CoffeeScript 1.11 and 1.12, including modules, for…of, and tagged template literals. Major new features unique to CoffeeScript 2 are support for ES2017’s async functions and for JSX. More details are in the changelog.

There are very few breaking changes from CoffeeScript 1.x to 2; we hope the upgrade process is smooth for most projects.

Why CoffeeScript When There’s ES2015?

CoffeeScript introduced many new features to the JavaScript world, such as => and destructuring and classes. We are happy that ECMA has seen their utility and adopted them into ECMAScript.

CoffeeScript’s intent, however, was never to be a superset of JavaScript. One of the guiding principles of CoffeeScript has been simplicity: not just removing JavaScript’s “bad parts,” but providing an elegant, concise syntax that eschews unnecessary punctuation whenever possible, to make code easier to read and reason about. This benefit of CoffeeScript remains, even in an ES2015 world.

Installation

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

To install, first make sure you have a working copy of the latest stable version of Node.js. You can then install CoffeeScript globally with npm:

npm install --global coffeescript@next

This will make the coffee and cake commands available globally.

When you need CoffeeScript as a dependency of a project, within that project’s folder you can install it locally:

npm install --save coffeescript@next

The coffee and cake commands will first look in the current folder to see if CoffeeScript is installed locally, and use that version if so. This allows different versions of CoffeeScript to be installed globally and locally.

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:

Option Description
-c, --compile Compile a .coffee script into a .js JavaScript file of the same name.
-m, --map Generate source maps alongside the compiled JavaScript files. Adds sourceMappingURL directives to the JavaScript as well.
-M, --inline-map Just like --map, but include the source map directly in the compiled JavaScript files, rather than in a separate file.
-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.
-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.
-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
-l, --literate Parses the code as Literate CoffeeScript. You only need to specify this when passing in code directly over stdio, or using some sort of extension-less file name.
-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 [MODULE] require() the given module before starting the REPL or evaluating the code given with the --eval flag.
-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. Used for debugging the compiler.
-n, --nodes Instead of compiling the CoffeeScript, just lex and parse it, and print out the parse tree. Used for debugging the compiler.
--nodejs The node executable has some useful options you can set, such as --debug, --debug-brk, --max-stack-size, and --expose-gc. Use this flag to forward options directly to Node.js. To pass multiple flags, use --nodejs multiple times.
--no-header Suppress the “Generated by CoffeeScript” header.

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

ES2015+ Output

CoffeeScript 2 outputs the latest ES2015+ syntax. If you’re looking for a single tool that takes CoffeeScript input and generates JavaScript output that runs in any JavaScript runtime, assuming you opt out of certain newer features, stick to CoffeeScript 1.x. CoffeeScript 2 breaks compatibility with certain CoffeeScript 1.x features in order to conform with the ES2015+ specifications, and generate more idiomatic output (a CoffeeScript => becomes an ES =>; a CoffeeScript class becomes an ES class; and so on).

Since the CoffeeScript 2 compiler outputs ES2015+ syntax, it is your responsibility to either ensure that your target JavaScript runtime(s) support all these features, or that you pass the output through another transpiler like Babel, Rollup or Traceur Compiler. In general, CoffeeScript 2’s output is supported as is by Node.js 7.6+, except for modules and JSX which require transpilation.

There are many great task runners for setting up JavaScript build chains, such as Gulp, Webpack, Grunt and Broccoli. If you’re looking for a very minimal solution to get started, you can use babel-preset-env and the command line:

npm install --global coffeescript@next
npm install --save-dev coffeescript@next babel-cli babel-preset-env
coffee --print *.coffee | babel --presets env > app.js

Node.js

If you’d like to use Node.js’ CommonJS to require CoffeeScript files, e.g. require './app.coffee', you must first “register” CoffeeScript as an extension:

require 'coffeescript/register'

App = require './app' # The .coffee extension is optional

If you want to use the compiler’s API, for example to make an app that compiles strings of CoffeeScript on the fly, you can require the full module:

CoffeeScript = require 'coffeescript'

eval CoffeeScript.compile 'console.log "Mmmmm, I could really go for some #{Math.pi}"'

The compile method has the signature compile(code, options) where code is a string of CoffeeScript code, and the optional options is an object with some or all of the following properties:

  • options.sourceMap, boolean: if true, a source map will be generated; and instead of returning a string, compile will return an object of the form {js, v3SourceMap, sourceMap}.
  • options.inlineMap, boolean: if true, output the source map as a base64-encoded string in a comment at the bottom.
  • options.filename, string: the filename to use for the source map.
  • options.bare, boolean: if true, output without the top-level function safety wrapper.
  • options.header, boolean: if true, output the Generated by CoffeeScript header.

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 button on the right. The CoffeeScript on the left is editable, and the JavaScript will update as you edit.

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: ->

Functions may also have default values for arguments, which will be used if the incoming argument is missing (undefined).

Strings

Like JavaScript and many other languages, CoffeeScript supports strings as delimited by the " or ' characters. CoffeeScript also supports string interpolation within "-quoted strings, using #{ … }. Single-quoted strings are literal. You may even use interpolation in object keys.

Multiline strings are allowed in CoffeeScript. Lines are joined by a single space unless they end with a backslash. Indentation is ignored.

Block strings, delimited by """ or ''', 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.

Double-quoted block strings, like other double-quoted strings, allow interpolation.

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.

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

CoffeeScript has a shortcut for creating objects when you want the key to be set with a variable of the same name.

Comments

In CoffeeScript, comments are denoted by the # character. Everything from a # to the end of the line is ignored by the compiler, and will be excluded from the JavaScript output.

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

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.

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.

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 (except in files with import or export statements) 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. (The safety wrapper can be disabled with the bare option, and is unnecessary and automatically disabled when using modules.)

If you’d like to create top-level variables for other scripts to use, attach them as properties on window; attach them as properties on the exports object in CommonJS; or use an export statement. If you’re targeting both CommonJS and the browser, the existential operator (covered below), gives you a reliable way to figure out where to add them: exports ? this.

Since CoffeeScript takes care of all variable declaration, it is not possible to declare variables with ES2015’s let or const. This is intentional; we feel that the simplicity gained by not having to think about variable declaration outweighs the benefit of having three separate ways to declare variables.

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.

Splats, or Rest Parameters/Spread Syntax

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. ES2015 adopted this feature as their rest parameters.

Splats also let us elide array elements…

…and object properties.

In ECMAScript this is called spread syntax, and has been supported for arrays since ES2015 but is coming soon for objects. Until object spread syntax is officially supported, the CoffeeScript compiler outputs the same polyfill as Babel’s rest spread transform; but once it is supported, we will revise the compiler’s output. Note that there are very subtle differences between the polyfill and the current proposal.

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.

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.

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)

If you don’t need the current iteration value you may omit it: browser.closeCurrentTab() for [0...count]

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.

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.

To iterate a generator function, use from. See Generator Functions.

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.

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.

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.

The same syntax can be used with assignment to replace a segment of an array with new values, splicing it.

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.

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:

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:

As well as silly things, like passing a try/catch statement directly into a function call:

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.

In a for loop, from compiles to the ES2015 of. (Yes, it’s unfortunate; the CoffeeScript of predates the ES2015 of.)

To simplify math expressions, ** can be used for exponentiation and // performs integer division. % works just like in JavaScript, while %% provides “dividend dependent modulo”:

All together now:

CoffeeScript JavaScript
is ===
isnt !==
not !
and &&
or ||
true, yes, on true
false, no, off false
@, this this
a in b [].indexOf.call(b, a) >= 0
a of b a in b
for a from b for (a of b)
a ** b Math.pow(a, b)
a // b Math.floor(a / b)
a %% b (a % b + b) % b

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 (to name just the most common cases). CoffeeScript’s existential operator ? returns true unless a variable is null or undefined or undeclared, which makes it analogous to Ruby’s nil?.

It can also be used for safer conditional assignment than the JavaScript pattern a = a || value provides, for cases where you may be handling numbers or strings.

Note that if the compiler knows that a is in scope and therefore declared, a? compiles to a != null, not a !== null. The != makes a loose comparison to null, which does double duty also comparing against undefined. The reverse also holds for not a? or unless a?.

If a variable might be undeclared, the compiler does a thorough check. This is what JavaScript coders should be typing when they want to check if a mystery variable exists.

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.

For completeness:

Example Definition
a? tests that a is in scope and a != null
a ? b returns a if a is in scope and a != null; otherwise, b
a?.b or a?['b'] returns a.b if a is in scope and a != null; otherwise, undefined
a?(b, c) or a? b, c returns the result of calling a (with arguments b and c) if a is in scope and callable; otherwise, undefined
a ?= b assigns the value of b to a if a is not in scope or if a == null; produces the new value of a

Chaining Function Calls

Leading . closes all open calls, allowing for simpler chaining syntax.

Destructuring Assignment

Just like JavaScript (since ES2015), CoffeeScript has 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:

But it’s also helpful for dealing with functions that return multiple values.

Destructuring assignment can be used with any depth of array and object nesting, to help pull out deeply nested properties.

Destructuring assignment can even be combined with splats.

Expansion can be used to retrieve elements from the end of an array without having to assign the rest of its values. It works in function parameter lists as well.

Destructuring assignment is also useful when combined with class constructors to assign properties to your instance from an options object passed to the constructor.

The above example also demonstrates that if properties are missing in the destructured object or array, you can, just like in JavaScript, provide defaults. Note though that unlike with the existential operator, the default is only applied with the value is missing or undefinedpassing null will set a value of null, not the default.

Bound (Fat Arrow) Functions

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 on. Functions created with the fat arrow are able to access properties of the this where they’re defined.

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.

The fat arrow was one of the most popular features of CoffeeScript, and ES2015 adopted it; so CoffeeScript 2 compiles => to ES =>.

Generator Functions

CoffeeScript supports ES2015 generator functions through the yield keyword. There’s no function*(){} nonsense — a generator in CoffeeScript is simply a function that yields.

yield* is called yield from, and yield return may be used if you need to force a generator that doesn’t yield.

You can iterate over a generator function using for…from.

Async Functions

ES2017’s async functions are supported through the await keyword. Like with generators, there’s no need for an async keyword; an async function in CoffeeScript is simply a function that awaits.

Similar to how yield return forces a generator, await return may be used to force a function to be async.

Classes

CoffeeScript 1 provided the class and extends keywords as syntactic sugar for working with prototypal functions. With ES2015, JavaScript has adopted those keywords; so CoffeeScript 2 compiles its class and extends keywords to ES2015 classes.

Static methods can be defined using @ before the method name:

Finally, class definitions are blocks of executable code, which make for interesting metaprogramming possibilities. In the context of a class definition, this is the class object itself; therefore, you can assign static properties by using @property: value.

Prototypal Inheritance

In addition to supporting ES2015 classes, CoffeeScript provides a shortcut for working with prototypes. The :: operator gives you quick access to an object’s prototype:

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 statements can also be used without a control expression, turning them in to a cleaner alternative to if/else chains.

Try/Catch/Finally

try expressions have the same semantics as try statements in JavaScript, though in CoffeeScript, you may omit both the catch and finally parts. The catch part may also omit the error parameter if it is not needed.

Chained Comparisons

CoffeeScript borrows chained comparisons from Python — making it easy to test if a value falls within a certain range.

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, CoffeeScript’s block regexes are delimited by /// and go a long way towards making complex regular expressions readable. To quote from the CoffeeScript source:

Tagged Template Literals

CoffeeScript supports ES2015 tagged template literals, which enable customized string interpolation. If you immediately prefix a string with a function name (no space between the two), CoffeeScript will output this “function plus string” combination as an ES2015 tagged template literal, which will behave accordingly: the function is called, with the parameters being the input text and expression parts that make up the interpolated string. The function can then assemble these parts into an output string, providing custom string interpolation.

Modules

ES2015 modules are supported in CoffeeScript, with very similar import and export syntax:

Note that the CoffeeScript compiler does not resolve modules; writing an import or export statement in CoffeeScript will produce an import or export statement in the resulting output. It is your responsibility attach another transpiler, such as Traceur Compiler, Babel or Rollup, to convert this ES2015 syntax into code that will work in your target runtimes.

Also note that any file with an import or export statement will be output without a top-level function safety wrapper; in other words, importing or exporting modules will automatically trigger bare mode for that file. This is because per the ES2015 spec, import or export statements must occur at the topmost scope.

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.

Escape backticks with backslashes: \`​ becomes `​.

Escape backslashes before backticks with more backslashes: \\\`​ becomes \`​.

You can also embed blocks of JavaScript using triple backticks. That’s easier than escaping backticks, if you need them inside your JavaScript block.

JSX

JSX is JavaScript containing interspersed XML elements. While conceived for React, it is not specific to any particular library or framework.

CoffeeScript supports interspersed XML elements, without the need for separate plugins or special settings. The XML elements will be compiled as such, outputting JSX that could be parsed like any normal JSX file, for example by Babel with the React JSX transform. CoffeeScript does not output React.createElement calls or any code specific to React or any other framework. It is up to you to attach another step in your build chain to convert this JSX to whatever function calls you wish the XML elements to compile to.

Just like in JSX and HTML, denote XML tags using < and >. You can interpolate CoffeeScript code inside a tag using { and }. To avoid compiler errors, when using < and > to mean “less than” or “greater than,” you should wrap the operators in spaces to distinguish them from XML tags. So i < len, not i<len. The compiler tries to be forgiving when it can be sure what you intend, but always putting spaces around the “less than” and “greater than” operators will remove ambiguity.

Older plugins or forks of CoffeeScript supported JSX syntax and referred to it as CSX or CJSX. They also often used a .cjsx file extension, but this is no longer necessary; regalar .coffee will do.

Literate CoffeeScript

Besides being used as an ordinary programming language, CoffeeScript may also be written in “literate” mode. If you name your file with a .litcoffee extension, you can write it as a Markdown document — a document that also happens to be executable CoffeeScript code. The compiler will treat any indented blocks (Markdown’s way of indicating source code) as executable code, and ignore the rest as comments. Code blocks must also be separated from comments by at least one blank line.

Just for kicks, a little bit of the compiler is currently implemented in this fashion: See it as a document, raw, and properly highlighted in a text editor.

A few caveats:

  • Code blocks need to maintain consistent indentation relative to each other. When the compiler parses your Literate CoffeeScript file, it first discards all the non-code block lines and then parses the remainder as a regular CoffeeScript file. Therefore the code blocks need to be written as if the comment lines don’t exist, with consistent indentation (including whether they are indented with tabs or spaces).
  • Along those lines, code blocks within list items or blockquotes are not treated as executable code. Since list items and blockquotes imply their own indentation, it would be ambiguous how to treat indentation between successive code blocks when some are within these other blocks and some are not.
  • List items can be at most only one paragraph long. The second paragraph of a list item would be indented after a blank line, and therefore indistinguishable from a code block.

Source Maps

CoffeeScript includes support for generating source maps, a way to tell your JavaScript engine what part of your CoffeeScript program matches up with the code being evaluated. Browsers that support it can automatically use source maps to show your original source code in the debugger. To generate source maps alongside your JavaScript files, pass the --map or -m flag to the compiler.

For a full introduction to source maps, how they work, and how to hook them up in your browser, read the HTML5 Tutorial.

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:

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, 51k when gzipped) as docs/v2/browser-compiler/coffeescript.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, as well as the code examples and other interactive parts of this site, 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 your JavaScript console 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.

Resources

  • CoffeeScript on GitHub
  • 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.
  • JS2Coffee
    Is a very well done reverse JavaScript-to-CoffeeScript compiler. It’s not going to be perfect (infer what your JavaScript classes are, when you need bound functions, and so on…) — but it’s a great starting point for converting simple scripts.
  • High-Rez Logo
    The CoffeeScript logo is available in SVG for use in presentations.

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, now PluralSight. 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 a 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.
  • technoweenie’s Coffee-Resque, a port of Resque for Node.js.
  • stephank’s Orona, a remake of the Bolo tank game for modern browsers.
  • GitHub’s Atom, a hackable text editor built on web technologies.
  • Basecamp’s Trix, a rich text editor for web apps.

Web Chat (IRC)

Quick help and advice can often be found in the CoffeeScript IRC room #coffeescript on irc.freenode.net, which you can join via your web browser.

Annotated Source

You can browse the CoffeeScript 2.0.0-beta3 source in readable, annotated form here. You can also jump directly to a particular source file:

Contributing

Contributions are welcome! Feel free to fork the repo and submit a pull request.

Some features of ECMAScript are intentionally unsupported. Please review both the open and closed issues on GitHub to see if the feature you’re looking for has already been discussed. As a general rule, we don’t support ECMAScript syntax for features that aren’t yet finalized (at Stage 4 in the proposal approval process).

For more resources on adding to CoffeeScript, please see the Wiki, especially How The Parser Works.

There are several things you can do to increase your odds of having your pull request accepted:

  • Create tests! Any pull request should probably include basic tests to verify you didn’t break anything, or future changes won’t break your code.
  • Follow the style of the rest of the CoffeeScript codebase.
  • Ensure any ECMAScript syntax is mature (at Stage 4), with no further potential changes.
  • Add only features that have broad utility, rather than a feature aimed at a specific use case or framework.

Of course, it’s entirely possible that you have a great addition, but it doesn’t fit within these constraints. Feel free to roll your own solution; you will have plenty of company.

Unsupported ECMAScript Features

There are a few ECMAScript features that CoffeeScript intentionally doesn’t support.

let and const: block-scoped and reassignment-protected variables

When CoffeeScript was designed, var was intentionally omitted. This was to spare developers the mental housekeeping of needing to worry about variable declaration (var foo) as opposed to variable assignment (foo = 1). The CoffeeScript compiler automatically takes care of declaration for you, by generating var statements at the top of every function scope. This makes it impossible to accidentally declare a global variable.

let and const add a useful ability to JavaScript in that you can use them to declare variables within a block scope, for example within an if statement body or a for loop body, whereas var always declares variables in the scope of an entire function. When CoffeeScript 2 was designed, there was much discussion of whether this functionality was useful enough to outweigh the simplicity offered by never needing to consider variable declaration in CoffeeScript. In the end, it was decided that the simplicity was more valued. In CoffeeScript there remains only one type of variable.

Keep in mind that const only protects you from reassigning a variable; it doesn’t prevent the variable’s value from changing, the way constants usually do in other languages:

const obj = {foo: 'bar'};
obj.foo = 'baz'; // Allowed!
obj = {}; // Throws error

Named functions and function declarations

Newcomers to CoffeeScript often wonder how to generate the JavaScript function foo() {}, as opposed to the foo = function() {} that CoffeeScript produces. The first form is a function declaration, and the second is a function expression. As stated above, in CoffeeScript everything is an expression, so naturally we favor the expression form. Supporting only one variant helps avoid confusing bugs that can arise from the subtle differences between the two forms.

Technically, foo = function() {} is creating an anonymous function that gets assigned to a variable named foo. Some very early versions of CoffeeScript named this function, e.g. foo = function foo() {}, but this was dropped because of compatibility issues with Internet Explorer. For a while this annoyed people, as these functions would be unnamed in stack traces; but modern JavaScript runtimes infer the names of such anonymous functions from the names of the variables to which they’re assigned. Given that this is the case, and given that not all functions in function expressions can be named (for example, the functions in first.fn = ->; second.fn = -> can’t both be named fn) it’s simplest to just preserve the current behavior.

get and set keyword shorthand syntax

get and set, as keywords preceding functions or class methods, are intentionally unimplemented in CoffeeScript.

This is to avoid grammatical ambiguity, since in CoffeeScript such a construct looks identical to a function call (e.g. get(function foo() {})); and because there is an alternate syntax that is slightly more verbose but just as effective:

Breaking Changes From CoffeeScript 1.x to 2

CoffeeScript 2 aims to output as much idiomatic ES2015+ syntax as possible with as few breaking changes from CoffeeScript 1.x as possible. Some breaking changes, unfortunately, were unavoidable.

Bound (fat arrow) functions

In CoffeeScript 1.x, => compiled to a regular function but with references to this/@ rewritten to use the outer scope’s this, or with the inner function bound to the outer scope via .bind (hence the name “bound function”). In CoffeeScript 2, => compiles to ES2015’s =>, which behaves slightly differently. The largest difference is that in ES2015, => functions lack an arguments object:

Default values for function parameters and destructured elements

Per the ES2015 spec regarding function default parameters and destructuring default values, default values are only applied when a value is missing or undefined. In CoffeeScript 1.x, the default value would be applied in those cases but also if the value was null.

Bound generator functions

Bound generator functions, a.k.a. generator arrow functions, aren’t allowed in ECMAScript. You can write function* or =>, but not both. Therefore, CoffeeScript code like this:

f = => yield this
# Throws a compiler error

Needs to be rewritten the old-fashioned way:

Classes are compiled to ES2015 classes

ES2015 classes and their methods have some restrictions beyond those on regular functions.

Class constructors can’t be invoked without new:

(class)()
# Throws a TypeError at runtime

Derived (extended) class constructors cannot use this before calling super:

class B extends A
  constructor: -> this  # Throws a compiler error

ES2015 classes don’t allow bound (fat arrow) methods. The CoffeeScript compiler goes through some contortions to preserve support for them, but one thing that can’t be accomodated is calling a bound method before it is bound:

class Base
  constructor: ->
    @onClick()      # This works
    clickHandler = @onClick
    clickHandler()  # This throws a runtime error

class Component extends Base
  onClick: =>
    console.log 'Clicked!', @

Class methods can’t be used with new (uncommon):

class Namespace
  @Klass = ->
new Namespace.Klass  # Throws a TypeError at runtime

Due to the hoisting required to compile to ES2015 classes, dynamic keys in class methods can’t use values from the executable class body unless the methods are assigned in prototype style.

class A
  name = 'method'
  "#{name}": ->   # This method will be named 'undefined'
  @::[name] = ->  # This will work; assigns to `A.prototype.method`

super and extends

Due to a syntax clash with super with accessors, “bare” super (the keyword super without parentheses) no longer compiles to a super call forwarding all arguments.

class B extends A
  foo: -> super
  # Throws a compiler error

Arguments can be forwarded explicitly using splats:

Or if you know that the parent function doesn’t require arguments, just call super():

CoffeeScript 1.x allowed the extends keyword to set up prototypal inheritance between functions, and super could be used manually prototype-assigned functions:

A = ->
B = ->
B extends A
B.prototype.foo = -> super arguments...
# Last two lines each throw compiler errors in CoffeeScript 2

Due to the switch to ES2015 extends and super, using these keywords for prototypal functions are no longer supported. The above case could be refactored to:

or

JSX and the < and > Operators

With the addition of JSX, the < and > characters serve as both the “less than” and “greater than” operators and as the delimiters for XML tags, like <div>. For best results, in general you should always wrap the operators in spaces to distinguish them from XML tags: i < len, not i<len. The compiler tries to be forgiving when it can be sure what you intend, but always putting spaces around the “less than” and “greater than” operators will remove ambiguity.

Literate CoffeeScript parsing

CoffeeScript 2’s parsing of Literate CoffeeScript has been refactored to now be more careful about not treating indented lists as code blocks; but this means that all code blocks (unless they are to be interpreted as comments) must be separated by at least one blank line from lists.

Code blocks should also now maintain a consistent indentation level—so an indentation of one tab (or whatever you consider to be a tab stop, like 2 spaces or 4 spaces) should be treated as your code’s “left margin,” with all code in the file relative to that column.

Code blocks that you want to be part of the commentary, and not executed, must have at least one line (ideally the first line of the block) completely unindented.

Changelog

2.0.0-beta3

  • JSX is now supported.
  • Object rest/spread properties are now supported.
  • Bound (fat arrow) methods are once again supported in classes; though an error will be thrown if you attempt to call the method before it is bound. See breaking changes for classes.
  • The REPL no longer warns about assigning to _.
  • Bugfixes for destructured nested default values and issues related to chaining or continuing expressions across multiple lines.

2.0.0-beta2

  • This release includes all the changes from 1.12.5 to 1.12.6.
  • Bound (fat arrow) methods in classes must be declared in the class constructor, after super() if the class is extending a parent class. See breaking changes for classes.
  • All unnecessary utility helper functions have been removed, including the polyfills for indexOf and bind.
  • The extends keyword now only works in the context of classes; it cannot be used to extend a function prototype. See breaking changes for extends.
  • Literate CoffeeScript is now parsed entirely based on indentation, similar to the 1.x implementation; there is no longer a dependency for parsing Markdown. See breaking changes for Literate CoffeeScript parsing.
  • JavaScript reserved words used as properties are no longer wrapped in quotes.
  • require('coffeescript') should now work in non-Node environments such as the builds created by Webpack or Browserify. This provides a more convenient way to include the browser compiler in builds intending to run in a browser environment.
  • Unreachable break statements are no longer added after switch cases that throw exceptions.
  • The browser compiler is now compiled using Babili and transpiled down to Babel’s env preset (should be safe for use in all browsers in current use, not just evergreen versions).
  • Calling functions @get or @set no longer throws an error about required parentheses. (Bare get or set, not attached to an object or @, still intentionally throws a compiler error.)
  • If $XDG_CACHE_HOME is set, the REPL .coffee_history file is saved there.

1.12.6

  • The return and export keywords can now accept implicit objects (defined by indentation, without needing braces).
  • Support Unicode code point escapes (e.g. \u{1F4A9}).
  • The coffee command now first looks to see if CoffeeScript is installed under node_modules in the current folder, and executes the coffee binary there if so; or otherwise it runs the globally installed one. This allows you to have one version of CoffeeScript installed globally and a different one installed locally for a particular project. (Likewise for the cake command.)
  • Bugfixes for chained function calls not closing implicit objects or ternaries.
  • Bugfixes for incorrect code generated by the ? operator within a termary if statement.
  • Fixed some tests, and failing tests now result in a nonzero exit code.

2.0.0-beta1

  • Initial beta release of CoffeeScript 2. No further breaking changes are anticipated.
  • Destructured objects and arrays now output using ES2015+ syntax whenever possible.
  • Literate CoffeeScript now has much better support for parsing Markdown, thanks to using Markdown-It to detect Markdown sections rather than just looking at indentation.
  • Calling a function named get or set now requires parentheses, to disambiguate from the get or set keywords (which are disallowed).
  • The compiler now requires Node 7.6+, the first version of Node to support asynchronous functions without requiring a flag.

1.12.5

  • Better handling of default, from, as and * within import and export statements. You can now import or export a member named default and the compiler won’t interpret it as the default keyword.
  • Fixed a bug where invalid octal escape sequences weren’t throwing errors in the compiler.

2.0.0-alpha1

  • Initial alpha release of CoffeeScript 2. The CoffeeScript compiler now outputs ES2015+ syntax whenever possible. See breaking changes.
  • Classes are output using ES2015 class and extends keywords.
  • Added support for async/await.
  • Bound (arrow) functions now output as => functions.
  • Function parameters with default values now use ES2015 default values syntax.
  • Splat function parameters now use ES2015 spread syntax.
  • Computed properties now use ES2015 syntax.
  • Interpolated strings (template literals) now use ES2015 backtick syntax.
  • Improved support for recognizing Markdown in Literate CoffeeScript files.
  • Mixing tabs and spaces in indentation is now disallowed.
  • Browser compiler is now minified using the Google Closure Compiler (JavaScript version).
  • Node 7+ required for CoffeeScript 2.

1.12.4

  • The cake commands have been updated, with new watch options for most tasks. Clone the CoffeeScript repo and run cake at the root of the repo to see the options.
  • Fixed a bug where exporting a referenced variable was preventing the variable from being declared.
  • Fixed a bug where the coffee command wasn’t working for a .litcoffee file.
  • Bugfixes related to tokens and location data, for better source maps and improved compatibility with downstream tools.

1.12.3

  • @ values can now be used as indices in for expressions. This loosens the compilation of for expressions to allow the index variable to be an @ value, e.g. do @visit for @node, @index in nodes. Within @visit, the index of the current node (@node) would be available as @index.
  • CoffeeScript’s patched Error.prepareStackTrace has been restored, with some revisions that should prevent the erroneous exceptions that were making life difficult for some downstream projects. This fixes the incorrect line numbers in stack traces since 1.12.2.
  • The //= operator’s output now wraps parentheses around the right operand, like the other assignment operators.

1.12.2

  • The browser compiler can once again be built unminified via MINIFY=false cake build:browser.
  • The error-prone patched version of Error.prepareStackTrace has been removed.
  • Command completion in the REPL (pressing tab to get suggestions) has been fixed for Node 6.9.1+.
  • The browser-based tests now include all the tests as the Node-based version.

1.12.1

  • You can now import a module member named default, e.g. import { default } from 'lib'. Though like in ES2015, you cannot import an entire module and name it default (so import default from 'lib' is not allowed).
  • Fix regression where from as a variable name was breaking for loop declarations. For the record, from is not a reserved word in CoffeeScript; you may use it for variable names. from behaves like a keyword within the context of import and export statements, and in the declaration of a for loop; though you should also be able to use variables named from in those contexts, and the compiler should be able to tell the difference.

1.12.0

  • CoffeeScript now supports ES2015 tagged template literals. Note that using tagged template literals in your code makes you responsible for ensuring that either your runtime supports tagged template literals or that you transpile the output JavaScript further to a version your target runtime(s) support.
  • CoffeeScript now provides a for…from syntax for outputting ES2015 for…of. (Sorry they couldn’t match, but we came up with for…of first for something else.) This allows iterating over generators or any other iterable object. Note that using for…from in your code makes you responsible for ensuring that either your runtime supports for…of or that you transpile the output JavaScript further to a version your target runtime(s) support.
  • Triple backticks (```​) allow the creation of embedded JavaScript blocks where escaping single backticks is not required, which should improve interoperability with ES2015 template literals and with Markdown.
  • Within single-backtick embedded JavaScript, backticks can now be escaped via \`​.
  • The browser tests now run in the browser again, and are accessible here if you would like to test your browser.
  • CoffeeScript-only keywords in ES2015 imports and exports are now ignored.
  • The compiler now throws an error on trying to export an anonymous class.
  • Bugfixes related to tokens and location data, for better source maps and improved compatibility with downstream tools.

1.11.1

  • Bugfix for shorthand object syntax after interpolated keys.
  • Bugfix for indentation-stripping in """ strings.
  • Bugfix for not being able to use the name “arguments” for a prototype property of class.
  • Correctly compile large hexadecimal numbers literals to 2e308 (just like all other large number literals do).

1.11.0

  • CoffeeScript now supports ES2015 import and export syntax.

  • Added the -M, --inline-map flag to the compiler, allowing you embed the source map directly into the output JavaScript, rather than as a separate file.

  • A bunch of fixes for yield:

    • yield return can no longer mistakenly be used as an expression.

    • yield now mirrors return in that it can be used stand-alone as well as with expressions. Where you previously wrote yield undefined, you may now write simply yield. However, this means also inheriting the same syntax limitations that return has, so these examples no longer compile:

      doubles = ->
        yield for i in [1..3]
          i * 2
      six = ->
        yield
          2 * 3
      
    • The JavaScript output is a bit nicer, with unnecessary parentheses and spaces, double indentation and double semicolons around yield no longer present.

  • &&=, ||=, and= and or= no longer accidentally allow a space before the equals sign.

  • Improved several error messages.

  • Just like undefined compiles to void 0, NaN now compiles into 0/0 and Infinity into 2e308.

  • Bugfix for renamed destructured parameters with defaults. ({a: b = 1}) -> no longer crashes the compiler.

  • Improved the internal representation of a CoffeeScript program. This is only noticeable to tools that use CoffeeScript.tokens or CoffeeScript.nodes. Such tools need to update to take account for changed or added tokens and nodes.

  • Several minor bug fixes, including:

    • The caught error in catch blocks is no longer declared unnecessarily, and no longer mistakenly named undefined for catch-less try blocks.
    • Unassignable parameter destructuring no longer crashes the compiler.
    • Source maps are now used correctly for errors thrown from .coffee.md files.
    • coffee -e 'throw null' no longer crashes.
    • The REPL no longer crashes when using .exit to exit it.
    • Invalid JavaScript is no longer output when lots of for loops are used in the same scope.
    • A unicode issue when using stdin with the CLI.

1.10.0

  • CoffeeScript now supports ES2015-style destructuring defaults.

  • (offsetHeight: height) -> no longer compiles. That syntax was accidental and partly broken. Use ({offsetHeight: height}) -> instead. Object destructuring always requires braces.

  • Several minor bug fixes, including:

    • A bug where the REPL would sometimes report valid code as invalid, based on what you had typed earlier.
    • A problem with multiple JS contexts in the jest test framework.
    • An error in io.js where strict mode is set on internal modules.
    • A variable name clash for the caught error in catch blocks.

1.9.3

  • Bugfix for interpolation in the first key of an object literal in an implicit call.
  • Fixed broken error messages in the REPL, as well as a few minor bugs with the REPL.
  • Fixed source mappings for tokens at the beginning of lines when compiling with the --bare option. This has the nice side effect of generating smaller source maps.
  • Slight formatting improvement of compiled block comments.
  • Better error messages for on, off, yes and no.

1.9.2

  • Fixed a watch mode error introduced in 1.9.1 when compiling multiple files with the same filename.
  • Bugfix for yield around expressions containing this.
  • Added a Ruby-style -r option to the REPL, which allows requiring a module before execution with --eval or --interactive.
  • In <script type="text/coffeescript"> tags, to avoid possible duplicate browser requests for .coffee files, you can now use the data-src attribute instead of src.
  • Minor bug fixes for IE8, strict ES5 regular expressions and Browserify.

1.9.1

  • Interpolation now works in object literal keys (again). You can use this to dynamically name properties.
  • Internal compiler variable names no longer start with underscores. This makes the generated JavaScript a bit prettier, and also fixes an issue with the completely broken and ungodly way that AngularJS “parses” function arguments.
  • Fixed a few yield-related edge cases with yield return and yield throw.
  • Minor bug fixes and various improvements to compiler error messages.

1.9.0

  • CoffeeScript now supports ES2015 generators. A generator is simply a function that yields.
  • More robust parsing and improved error messages for strings and regexes — especially with respect to interpolation.
  • Changed strategy for the generation of internal compiler variable names. Note that this means that @example function parameters are no longer available as naked example variables within the function body.
  • Fixed REPL compatibility with latest versions of Node and Io.js.
  • Various minor bug fixes.

1.8.0

  • The --join option of the CLI is now deprecated.
  • Source maps now use .js.map as file extension, instead of just .map.
  • The CLI now exits with the exit code 1 when it fails to write a file to disk.
  • The compiler no longer crashes on unterminated, single-quoted strings.
  • Fixed location data for string interpolations, which made source maps out of sync.
  • The error marker in error messages is now correctly positioned if the code is indented with tabs.
  • Fixed a slight formatting error in CoffeeScript’s source map-patched stack traces.
  • The %% operator now coerces its right operand only once.
  • It is now possible to require CoffeeScript files from Cakefiles without having to register the compiler first.
  • The CoffeeScript REPL is now exported and can be required using require 'coffeescript/repl'.
  • Fixes for the REPL in Node 0.11.

1.7.1

  • Fixed a typo that broke node module lookup when running a script directly with the coffee binary.

1.7.0

  • When requiring CoffeeScript files in Node you must now explicitly register the compiler. This can be done with require 'coffeescript/register' or CoffeeScript.register(). Also for configuration such as Mocha’s, use coffeescript/register.
  • Improved error messages, source maps and stack traces. Source maps now use the updated //# syntax.
  • Leading . now closes all open calls, allowing for simpler chaining syntax.
  • Added **, // and %% operators and ... expansion in parameter lists and destructuring expressions.
  • Multiline strings are now joined by a single space and ignore all indentation. A backslash at the end of a line can denote the amount of whitespace between lines, in both strings and heredocs. Backslashes correctly escape whitespace in block regexes.
  • Closing brackets can now be indented and therefore no longer cause unexpected error.
  • Several breaking compilation fixes. Non-callable literals (strings, numbers etc.) don’t compile in a call now and multiple postfix conditionals compile properly. Postfix conditionals and loops always bind object literals. Conditional assignment compiles properly in subexpressions. super is disallowed outside of methods and works correctly inside for loops.
  • Formatting of compiled block comments has been improved.
  • No more -p folders on Windows.
  • The options object passed to CoffeeScript is no longer mutated.

1.6.3

  • The CoffeeScript REPL now remembers your history between sessions. Just like a proper REPL should.
  • You can now use require in Node to load .coffee.md Literate CoffeeScript files. In the browser, text/literate-coffeescript script tags.
  • The old coffee --lint command has been removed. It was useful while originally working on the compiler, but has been surpassed by JSHint. You may now use -l to pass literate files in over stdio.
  • Bugfixes for Windows path separators, catch without naming the error, and executable-class-bodies-with- prototypal-property-attachment.

1.6.2

  • Source maps have been used to provide automatic line-mapping when running CoffeeScript directly via the coffee command, and for automatic line-mapping when running CoffeeScript directly in the browser. Also, to provide better error messages for semantic errors thrown by the compiler — with colors, even.
  • Improved support for mixed literate/vanilla-style CoffeeScript projects, and generating source maps for both at the same time.
  • Fixes for 1.6.x regressions with overriding inherited bound functions, and for Windows file path management.
  • The coffee command can now correctly fork() both .coffee and .js files. (Requires Node.js 0.9+)

1.6.1

  • First release of source maps. Pass the --map flag to the compiler, and off you go. Direct all your thanks over to Jason Walton.
  • Fixed a 1.5.0 regression with multiple implicit calls against an indented implicit object. Combinations of implicit function calls and implicit objects should generally be parsed better now — but it still isn’t good style to nest them too heavily.
  • .coffee.md is now also supported as a Literate CoffeeScript file extension, for existing tooling. .litcoffee remains the canonical one.
  • Several minor fixes surrounding member properties, bound methods and super in class declarations.

1.5.0

  • First release of Literate CoffeeScript.
  • The CoffeeScript REPL is now based on the Node.js REPL, and should work better and more familiarly.
  • Returning explicit values from constructors is now forbidden. If you want to return an arbitrary value, use a function, not a constructor.
  • You can now loop over an array backwards, without having to manually deal with the indexes: for item in list by -1
  • Source locations are now preserved in the CoffeeScript AST, although source maps are not yet being emitted.

1.4.0

  • 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

  • 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

  • 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 improvements 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

  • 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

  • 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('coffeescript/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

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

Bugfix release for classes with external constructor functions, see issue #1182.

1.1.0

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Upgraded CoffeeScript for compatibility with the new Node.js v0.1.90 series.

0.6.0

Trailing commas are now allowed, a-la Python. Static properties may be assigned directly within class definitions, using @property notation.

0.5.6

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 coffeescript, 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

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

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

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

Added a compressed version of the compiler for inclusion in web pages as /v2/browser-compiler/coffeescript.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

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

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

@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

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

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

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

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

Axed the unsatisfactory ino keyword, replacing it with of for object comprehensions. They now look like: for prop, value of object.

0.2.2

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

Arguments objects are now converted into real arrays when referenced.

0.2.0

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

Bugfix for running coffee --interactive and --run from outside of the CoffeeScript directory. Bugfix for nested function/if-statements.

0.1.5

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 coffeescript command is now called coffee.

0.1.4

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

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

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

Added instanceof and typeof as operators.

0.1.0

Initial CoffeeScript release.

coffeescript-1.12.7/docs/v2/test.html000066400000000000000000011660541313305734200174200ustar00rootroot00000000000000 CoffeeScript Test Suite

CoffeeScript Test Suite



















































coffeescript-1.12.7/documentation/000077500000000000000000000000001313305734200171305ustar00rootroot00000000000000coffeescript-1.12.7/documentation/examples/000077500000000000000000000000001313305734200207465ustar00rootroot00000000000000coffeescript-1.12.7/documentation/examples/aliases.coffee000066400000000000000000000003371313305734200235430ustar00rootroot00000000000000launch() 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}"
coffeescript-1.12.7/documentation/examples/array_comprehensions.coffee000066400000000000000000000004731313305734200263550ustar00rootroot00000000000000# 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'
coffeescript-1.12.7/documentation/examples/block_comment.coffee000066400000000000000000000001171313305734200247320ustar00rootroot00000000000000###
SkinnyMochaHalfCaffScript Compiler v1.0
Released under the MIT License
###
coffeescript-1.12.7/documentation/examples/cake_tasks.coffee000066400000000000000000000004361313305734200242320ustar00rootroot00000000000000fs = 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
coffeescript-1.12.7/documentation/examples/chaining.coffee000066400000000000000000000001441313305734200236760ustar00rootroot00000000000000$ 'body'
.click (e) ->
  $ '.box'
  .fadeIn 'fast'
  .addClass '.active'
.css 'background', 'white'
coffeescript-1.12.7/documentation/examples/classes.coffee000066400000000000000000000005351313305734200235570ustar00rootroot00000000000000class 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()
coffeescript-1.12.7/documentation/examples/comparisons.coffee000066400000000000000000000000641313305734200244540ustar00rootroot00000000000000cholesterol = 127

healthy = 200 > cholesterol > 60
coffeescript-1.12.7/documentation/examples/conditionals.coffee000066400000000000000000000002121313305734200246000ustar00rootroot00000000000000mood = greatlyImproved if singing

if happy and knowsIt
  clapsHands()
  chaChaCha()
else
  showIt()

date = if friday then sue else jill
coffeescript-1.12.7/documentation/examples/constructor_destructuring.coffee000066400000000000000000000002001313305734200274560ustar00rootroot00000000000000class Person
  constructor: (options) ->
    {@name, @age, @height = 'average'} = options

tim = new Person name: 'Tim', age: 4
coffeescript-1.12.7/documentation/examples/default_args.coffee000066400000000000000000000001301313305734200245510ustar00rootroot00000000000000fill = (container, liquid = "coffee") ->
  "Filling the #{container} with #{liquid}..."
coffeescript-1.12.7/documentation/examples/do.coffee000066400000000000000000000002011313305734200225120ustar00rootroot00000000000000for filename in list
  do (filename) ->
    fs.readFile filename, (err, contents) ->
      compile filename, contents.toString()
coffeescript-1.12.7/documentation/examples/embedded.coffee000066400000000000000000000001201313305734200236410ustar00rootroot00000000000000hi = `function() {
  return [document.title, "Hello JavaScript"].join(": ");
}`
coffeescript-1.12.7/documentation/examples/embedded_block.coffee000066400000000000000000000001271313305734200250220ustar00rootroot00000000000000```
function time() {
  return `The time is ${new Date().toLocaleTimeString()}`;
}
```
coffeescript-1.12.7/documentation/examples/embedded_escaped.coffee000066400000000000000000000001251313305734200253320ustar00rootroot00000000000000markdown = `function () {
  return \`In Markdown, write code like \\\`this\\\`\`;
}`
coffeescript-1.12.7/documentation/examples/existence.coffee000066400000000000000000000001341313305734200241040ustar00rootroot00000000000000solipsism = true if mind? and not world?

speed = 0
speed ?= 15

footprints = yeti ? "bear"
coffeescript-1.12.7/documentation/examples/expansion.coffee000066400000000000000000000002031313305734200241160ustar00rootroot00000000000000text = "Every literary critic believes he will
        outwit history and have the last word"

[first, ..., last] = text.split " "
coffeescript-1.12.7/documentation/examples/expressions.coffee000066400000000000000000000002731313305734200245030ustar00rootroot00000000000000grade = (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"
coffeescript-1.12.7/documentation/examples/expressions_assignment.coffee000066400000000000000000000000521313305734200267260ustar00rootroot00000000000000six = (one = 1) + (two = 2) + (three = 3)
coffeescript-1.12.7/documentation/examples/expressions_comprehension.coffee000066400000000000000000000001201313305734200274230ustar00rootroot00000000000000# The first ten global properties.

globals = (name for name of window)[0...10]
coffeescript-1.12.7/documentation/examples/expressions_try.coffee000066400000000000000000000001351313305734200253760ustar00rootroot00000000000000alert(
  try
    nonexistent / undefined
  catch error
    "And the error is ... #{error}"
)
coffeescript-1.12.7/documentation/examples/fat_arrow.coffee000066400000000000000000000002171313305734200241030ustar00rootroot00000000000000Account = (customer, cart) ->
  @customer = customer
  @cart = cart

  $('.shopping_cart').on 'click', (event) =>
    @customer.purchase @cart
coffeescript-1.12.7/documentation/examples/functions.coffee000066400000000000000000000000641313305734200241270ustar00rootroot00000000000000square = (x) -> x * x
cube   = (x) -> square(x) * x
coffeescript-1.12.7/documentation/examples/generator_iteration.coffee000066400000000000000000000004271313305734200261660ustar00rootroot00000000000000fibonacci = ->
  [previous, current] = [1, 1]
  loop
    [previous, current] = [current, previous + current]
    yield current
  return

getFibonacciNumbers = (length) ->
  results = [1]
  for n from fibonacci()
    results.push n
    break if results.length is length
  results
coffeescript-1.12.7/documentation/examples/generators.coffee000066400000000000000000000001571313305734200242730ustar00rootroot00000000000000perfectSquares = ->
  num = 0
  loop
    num += 1
    yield num * num
  return

window.ps or= perfectSquares()
coffeescript-1.12.7/documentation/examples/heredocs.coffee000066400000000000000000000001241313305734200237100ustar00rootroot00000000000000html = """
       
         cup of coffeescript
       
       """
coffeescript-1.12.7/documentation/examples/heregexes.coffee000066400000000000000000000004621313305734200241000ustar00rootroot00000000000000OPERATOR = /// ^ (
  ?: [-=]>             # function
   | [-+*/%<>&|^!?=]=  # compound assign / compare
   | >>>=?             # zero-fill right shift
   | ([-+:])\1         # doubles
   | ([&|<>])\2=?      # logic / shift
   | \?\.              # soak access
   | \.{2,3}           # range or splat
) ///
coffeescript-1.12.7/documentation/examples/interpolation.coffee000066400000000000000000000002011313305734200247770ustar00rootroot00000000000000author = "Wittgenstein"
quote  = "A picture is a fact. -- #{ author }"

sentence = "#{ 22 / 7 } is a decent approximation of π"
coffeescript-1.12.7/documentation/examples/modules.coffee000066400000000000000000000011011313305734200235600ustar00rootroot00000000000000import 'local-file.coffee'
import 'coffeescript'

import _ from 'underscore'
import * as underscore from 'underscore'

import { now } from 'underscore'
import { now as currentTimestamp } from 'underscore'
import { first, last } from 'underscore'
import utilityBelt, { each } from 'underscore'

export default Math
export square = (x) -> x * x
export class Mathematics
  least: (x, y) -> if x < y then x else y

export { sqrt }
export { sqrt as squareRoot }
export { Mathematics as default, sqrt as squareRoot }

export * from 'underscore'
export { max, min } from 'underscore'
coffeescript-1.12.7/documentation/examples/modulo.coffee000066400000000000000000000002311313305734200234120ustar00rootroot00000000000000-7 % 5 == -2 # The remainder of 7 / 5
-7 %% 5 == 3 # n %% 5 is always between 0 and 4

tabs.selectTabAtIndex((tabs.currentIndex - count) %% tabs.length)
coffeescript-1.12.7/documentation/examples/multiple_return_values.coffee000066400000000000000000000002471313305734200267330ustar00rootroot00000000000000weatherReport = (location) ->
  # Make an Ajax request to fetch the weather...
  [location, 72, "Mostly Sunny"]

[city, temp, forecast] = weatherReport "Berkeley, CA"
coffeescript-1.12.7/documentation/examples/object_comprehensions.coffee000066400000000000000000000001361313305734200265010ustar00rootroot00000000000000yearsOld = max: 10, ida: 9, tim: 11

ages = for child, age of yearsOld
  "#{child} is #{age}"
coffeescript-1.12.7/documentation/examples/object_extraction.coffee000066400000000000000000000004041313305734200256230ustar00rootroot00000000000000futurists =
  sculptor: "Umberto Boccioni"
  painter:  "Vladimir Burliuk"
  poet:
    name:   "F.T. Marinetti"
    address: [
      "Via Roma 42R"
      "Bellagio, Italy 22021"
    ]

{sculptor} = futurists

{poet: {name, address: [street, city]}} = futurists
coffeescript-1.12.7/documentation/examples/objects_and_arrays.coffee000066400000000000000000000003241313305734200257520ustar00rootroot00000000000000song = ["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
coffeescript-1.12.7/documentation/examples/objects_reserved.coffee000066400000000000000000000000651313305734200254500ustar00rootroot00000000000000$('.account').attr class: 'active'

log object.class
coffeescript-1.12.7/documentation/examples/objects_shorthand.coffee000066400000000000000000000002641313305734200256240ustar00rootroot00000000000000name = "Michelangelo"
mask = "orange"
weapon = "nunchuks"
turtle = {name, mask, weapon}
output = "#{turtle.name} wears an #{turtle.mask} mask. Watch out for his #{turtle.weapon}!"
coffeescript-1.12.7/documentation/examples/overview.coffee000066400000000000000000000006361313305734200237720ustar00rootroot00000000000000# 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)
coffeescript-1.12.7/documentation/examples/parallel_assignment.coffee000066400000000000000000000001141313305734200261370ustar00rootroot00000000000000theBait   = 1000
theSwitch = 0

[theBait, theSwitch] = [theSwitch, theBait]
coffeescript-1.12.7/documentation/examples/patterns_and_splats.coffee000066400000000000000000000001011313305734200261570ustar00rootroot00000000000000tag = ""

[open, contents..., close] = tag.split("")
coffeescript-1.12.7/documentation/examples/prototypes.coffee000066400000000000000000000000601313305734200243430ustar00rootroot00000000000000String::dasherize = ->
  this.replace /_/g, "-"
coffeescript-1.12.7/documentation/examples/range_comprehensions.coffee000066400000000000000000000000451313305734200263260ustar00rootroot00000000000000countdown = (num for num in [10..1])
coffeescript-1.12.7/documentation/examples/scope.coffee000066400000000000000000000001171313305734200232270ustar00rootroot00000000000000outer = 1
changeNumbers = ->
  inner = -1
  outer = 10
inner = changeNumbers()
coffeescript-1.12.7/documentation/examples/slices.coffee000066400000000000000000000002121313305734200233740ustar00rootroot00000000000000numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9]

start   = numbers[0..2]

middle  = numbers[3...-2]

end     = numbers[-2..]

copy    = numbers[..]
coffeescript-1.12.7/documentation/examples/soaks.coffee000066400000000000000000000000551313305734200232370ustar00rootroot00000000000000zip = lottery.drawWinner?().address?.zipcode
coffeescript-1.12.7/documentation/examples/splats.coffee000066400000000000000000000006361313305734200234320ustar00rootroot00000000000000gold = 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
coffeescript-1.12.7/documentation/examples/splices.coffee000066400000000000000000000001131313305734200235540ustar00rootroot00000000000000numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

numbers[3..6] = [-3, -4, -5, -6]
coffeescript-1.12.7/documentation/examples/strings.coffee000066400000000000000000000004001313305734200236020ustar00rootroot00000000000000mobyDick = "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..."
coffeescript-1.12.7/documentation/examples/switch.coffee000066400000000000000000000003261313305734200234210ustar00rootroot00000000000000switch 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
coffeescript-1.12.7/documentation/examples/switch_with_no_expression.coffee000066400000000000000000000002401313305734200274220ustar00rootroot00000000000000score = 76
grade = switch
  when score < 60 then 'F'
  when score < 70 then 'D'
  when score < 80 then 'C'
  when score < 90 then 'B'
  else 'A'
# grade == 'C'
coffeescript-1.12.7/documentation/examples/tagged_template_literals.coffee000066400000000000000000000004061313305734200271440ustar00rootroot00000000000000upperCaseExpr = (textParts, expressions...) ->
  textParts.reduce (text, textPart, i) ->
    text + expressions[i - 1].toUpperCase() + textPart

greet = (name, adjective) ->
  upperCaseExpr"""
               Hi #{name}. You look #{adjective}!
               """
coffeescript-1.12.7/documentation/examples/try.coffee000066400000000000000000000001471313305734200227370ustar00rootroot00000000000000try
  allHellBreaksLoose()
  catsAndDogsLivingTogether()
catch error
  print error
finally
  cleanUp()
coffeescript-1.12.7/documentation/examples/while.coffee000066400000000000000000000003511313305734200232260ustar00rootroot00000000000000# 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."
coffeescript-1.12.7/documentation/images/000077500000000000000000000000001313305734200203755ustar00rootroot00000000000000coffeescript-1.12.7/documentation/images/icon.svg000066400000000000000000000031571313305734200220540ustar00rootroot00000000000000
    
        CoffeeScript Logo
    
    

coffeescript-1.12.7/documentation/images/logo.svg000066400000000000000000000112631313305734200220610ustar00rootroot00000000000000
	
		CoffeeScript Logo
	
	

coffeescript-1.12.7/documentation/index.html000066400000000000000000000013701313305734200211260ustar00rootroot00000000000000



CoffeeScript










<%= include('styles.html') %>



<%= include('body.html') %>

<%= include('scripts.html') %>


coffeescript-1.12.7/documentation/sections/000077500000000000000000000000001313305734200207575ustar00rootroot00000000000000coffeescript-1.12.7/documentation/sections/books.md000066400000000000000000000051301313305734200224150ustar00rootroot00000000000000## Books

There are a number of excellent resources to help you get started with CoffeeScript, some of which are freely available online.

*   [The Little Book on CoffeeScript](http://arcturo.github.io/library/coffeescript/) is a brief 5-chapter introduction to CoffeeScript, written with great clarity and precision by [Alex MacCaw](http://alexmaccaw.co.uk/).
*   [Smooth CoffeeScript](http://autotelicum.github.io/Smooth-CoffeeScript/) is a reimagination of the excellent book [Eloquent JavaScript](http://eloquentjavascript.net/), as if it had been written in CoffeeScript instead. Covers language features as well as the functional and object oriented programming styles. By [E. Hoigaard](https://github.com/autotelicum).
*   [CoffeeScript: Accelerated JavaScript Development](http://pragprog.com/book/tbcoffee/coffeescript) is [Trevor Burnham](http://trevorburnham.com/)’s thorough introduction to the language. By the end of the book, you’ll have built a fast-paced multiplayer word game, writing both the client-side and Node.js portions in CoffeeScript.
*   [CoffeeScript Programming with jQuery, Rails, and Node.js](https://www.packtpub.com/web-development/coffeescript-programming-jquery-rails-and-nodejs) is a new book by Michael Erasmus that covers CoffeeScript with an eye towards real-world usage both in the browser (jQuery) and on the server-side (Rails, Node).
*   [CoffeeScript Ristretto](https://leanpub.com/coffeescript-ristretto/read) is a deep dive into CoffeeScript’s semantics from simple functions up through closures, higher-order functions, objects, classes, combinators, and decorators. By [Reg Braithwaite](http://braythwayt.com/).
*   [Testing with CoffeeScript](https://efendibooks.com/minibooks/testing-with-coffeescript) is a succinct and freely downloadable guide to building testable applications with CoffeeScript and Jasmine.
*   [CoffeeScript Application Development](https://www.packtpub.com/web-development/coffeescript-application-development) from Packt, introduces CoffeeScript while walking through the process of building a demonstration web application. A [CoffeeScript Application Development Coookbook](https://www.packtpub.com/web-development/coffeescript-application-development-cookbook) with over 90 “recipes” is also available.
*   [CoffeeScript in Action](https://www.manning.com/books/coffeescript-in-action) from Manning Publications, covers CoffeeScript syntax, composition techniques and application development.
*   [CoffeeScript: Die Alternative zu JavaScript](https://www.dpunkt.de/buecher/4021/coffeescript.html) from dpunkt.verlag, is the first CoffeeScript book in Deutsch.
coffeescript-1.12.7/documentation/sections/cake.md000066400000000000000000000025111313305734200222030ustar00rootroot00000000000000## Cake, and Cakefiles

CoffeeScript includes a (very) simple build system similar to [Make](http://www.gnu.org/software/make/) and [Rake](http://rake.rubyforge.org/). 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:

```
codeFor('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](/v<%= majorVersion %>/annotated-source/cake.html). If you need dependencies, or async callbacks, it’s best to put them in your code itself — not the cake task.
coffeescript-1.12.7/documentation/sections/changelog.md000066400000000000000000001130421313305734200232310ustar00rootroot00000000000000## Change Log

```
releaseHeader('2017-07-16', '1.12.7', '1.12.6')
```

*   Fix regressions in 1.12.6 related to chained function calls and indented `return` and `throw` arguments.
*   The REPL no longer warns about assigning to `_`.

```
releaseHeader('2017-05-15', '1.12.6', '1.12.5')
```

*   The `return` and `export` keywords can now accept implicit objects (defined by indentation, without needing braces).
*   Support Unicode code point escapes (e.g. `\u{1F4A9}`).
*   The `coffee` command now first looks to see if CoffeeScript is installed under `node_modules` in the current folder, and executes the `coffee` binary there if so; or otherwise it runs the globally installed one. This allows you to have one version of CoffeeScript installed globally and a different one installed locally for a particular project. (Likewise for the `cake` command.)
*   Bugfixes for chained function calls not closing implicit objects or ternaries.
*   Bugfixes for incorrect code generated by the `?` operator within a termary `if` statement.
*   Fixed some tests, and failing tests now result in a nonzero exit code.

```
releaseHeader('2017-04-10', '1.12.5', '1.12.4')
```

*   Better handling of `default`, `from`, `as` and `*` within `import` and `export` statements. You can now import or export a member named `default` and the compiler won’t interpret it as the `default` keyword.
*   Fixed a bug where invalid octal escape sequences weren’t throwing errors in the compiler.

```
releaseHeader('2017-02-18', '1.12.4', '1.12.3')
```

*   The `cake` commands have been updated, with new `watch` options for most tasks. Clone the [CoffeeScript repo](https://github.com/jashkenas/coffeescript) and run `cake` at the root of the repo to see the options.
*   Fixed a bug where `export`ing a referenced variable was preventing the variable from being declared.
*   Fixed a bug where the `coffee` command wasn’t working for a `.litcoffee` file.
*   Bugfixes related to tokens and location data, for better source maps and improved compatibility with downstream tools.

```
releaseHeader('2017-01-24', '1.12.3', '1.12.2')
```

*   `@` values can now be used as indices in `for` expressions. This loosens the compilation of `for` expressions to allow the index variable to be an `@` value, e.g. `do @visit for @node, @index in nodes`. Within `@visit`, the index of the current node (`@node`) would be available as `@index`.
*   CoffeeScript’s patched `Error.prepareStackTrace` has been restored, with some revisions that should prevent the erroneous exceptions that were making life difficult for some downstream projects. This fixes the incorrect line numbers in stack traces since 1.12.2.
*   The `//=` operator’s output now wraps parentheses around the right operand, like the other assignment operators.

```
releaseHeader('2016-12-16', '1.12.2', '1.12.1')
```

*   The browser compiler can once again be built unminified via `MINIFY=false cake build:browser`.
*   The error-prone patched version of `Error.prepareStackTrace` has been removed.
*   Command completion in the REPL (pressing tab to get suggestions) has been fixed for Node 6.9.1+.
*   The [browser-based tests](/v<%= majorVersion %>/test.html) now include all the tests as the Node-based version.

```
releaseHeader('2016-12-07', '1.12.1', '1.12.0')
```

*   You can now import a module member named `default`, e.g. `import { default } from 'lib'`. Though like in ES2015, you cannot import an entire module and name it `default` (so `import default from 'lib'` is not allowed).
*   Fix regression where `from` as a variable name was breaking `for` loop declarations. For the record, `from` is not a reserved word in CoffeeScript; you may use it for variable names. `from` behaves like a keyword within the context of `import` and `export` statements, and in the declaration of a `for` loop; though you should also be able to use variables named `from` in those contexts, and the compiler should be able to tell the difference.

```
releaseHeader('2016-12-04', '1.12.0', '1.11.1')
```

*   CoffeeScript now supports ES2015 [tagged template literals](#tagged-template-literals). Note that using tagged template literals in your code makes you responsible for ensuring that either your runtime supports tagged template literals or that you transpile the output JavaScript further to a version your target runtime(s) support.
*   CoffeeScript now provides a [`for…from`](#generator-iteration) syntax for outputting ES2015 [`for…of`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...of). (Sorry they couldn’t match, but we came up with `for…of` first for something else.) This allows iterating over generators or any other iterable object. Note that using `for…from` in your code makes you responsible for ensuring that either your runtime supports `for…of` or that you transpile the output JavaScript further to a version your target runtime(s) support.
*   Triple backticks (`` ```​``) allow the creation of embedded JavaScript blocks where escaping single backticks is not required, which should improve interoperability with ES2015 template literals and with Markdown.
*   Within single-backtick embedded JavaScript, backticks can now be escaped via `` \`​``.
*   The browser tests now run in the browser again, and are accessible [here](/v<%= majorVersion %>/test.html) if you would like to test your browser.
*   CoffeeScript-only keywords in ES2015 `import`s and `export`s are now ignored.
*   The compiler now throws an error on trying to export an anonymous class.
*   Bugfixes related to tokens and location data, for better source maps and improved compatibility with downstream tools.

```
releaseHeader('2016-10-02', '1.11.1', '1.11.0')
```

*   Bugfix for shorthand object syntax after interpolated keys.
*   Bugfix for indentation-stripping in `"""` strings.
*   Bugfix for not being able to use the name “arguments” for a prototype property of class.
*   Correctly compile large hexadecimal numbers literals to `2e308` (just like all other large number literals do).

```
releaseHeader('2016-09-24', '1.11.0', '1.10.0')
```

*   CoffeeScript now supports ES2015 [`import` and `export` syntax](#modules).
*   Added the `-M, --inline-map` flag to the compiler, allowing you embed the source map directly into the output JavaScript, rather than as a separate file.
*   A bunch of fixes for `yield`:

    *   `yield return` can no longer mistakenly be used as an expression.
    *   `yield` now mirrors `return` in that it can be used stand-alone as well as with expressions. Where you previously wrote `yield undefined`, you may now write simply `yield`. However, this means also inheriting the same syntax limitations that `return` has, so these examples no longer compile:
        ```
        doubles = ->
          yield for i in [1..3]
            i * 2
        six = ->
          yield
            2 * 3
        ```

    *   The JavaScript output is a bit nicer, with unnecessary parentheses and spaces, double indentation and double semicolons around `yield` no longer present.
*   `&&=`, `||=`, `and=` and `or=` no longer accidentally allow a space before the equals sign.
*   Improved several error messages.
*   Just like `undefined` compiles to `void 0`, `NaN` now compiles into `0/0` and `Infinity` into `2e308`.
*   Bugfix for renamed destructured parameters with defaults. `({a: b = 1}) ->` no longer crashes the compiler.
*   Improved the internal representation of a CoffeeScript program. This is only noticeable to tools that use `CoffeeScript.tokens` or `CoffeeScript.nodes`. Such tools need to update to take account for changed or added tokens and nodes.
*   Several minor bug fixes, including:

    *   The caught error in `catch` blocks is no longer declared unnecessarily, and no longer mistakenly named `undefined` for `catch`-less `try` blocks.
    *   Unassignable parameter destructuring no longer crashes the compiler.
    *   Source maps are now used correctly for errors thrown from .coffee.md files.
    *   `coffee -e 'throw null'` no longer crashes.
    *   The REPL no longer crashes when using `.exit` to exit it.
    *   Invalid JavaScript is no longer output when lots of `for` loops are used in the same scope.
    *   A unicode issue when using stdin with the CLI.

```
releaseHeader('2015-09-03', '1.10.0', '1.9.3')
```

*   CoffeeScript now supports ES2015-style destructuring defaults.
*   `(offsetHeight: height) ->` no longer compiles. That syntax was accidental and partly broken. Use `({offsetHeight: height}) ->` instead. Object destructuring always requires braces.
*   Several minor bug fixes, including:

    *   A bug where the REPL would sometimes report valid code as invalid, based on what you had typed earlier.
    *   A problem with multiple JS contexts in the jest test framework.
    *   An error in io.js where strict mode is set on internal modules.
    *   A variable name clash for the caught error in `catch` blocks.

```
releaseHeader('2015-05-27', '1.9.3', '1.9.2')
```

*   Bugfix for interpolation in the first key of an object literal in an implicit call.
*   Fixed broken error messages in the REPL, as well as a few minor bugs with the REPL.
*   Fixed source mappings for tokens at the beginning of lines when compiling with the `--bare` option. This has the nice side effect of generating smaller source maps.
*   Slight formatting improvement of compiled block comments.
*   Better error messages for `on`, `off`, `yes` and `no`.

```
releaseHeader('2015-04-15', '1.9.2', '1.9.1')
```

*   Fixed a **watch** mode error introduced in 1.9.1 when compiling multiple files with the same filename.
*   Bugfix for `yield` around expressions containing `this`.
*   Added a Ruby-style `-r` option to the REPL, which allows requiring a module before execution with `--eval` or `--interactive`.
*   In `
  
  



CoffeeScript Test Suite





<%= tests %>



coffeescript-1.12.7/documentation/v1/000077500000000000000000000000001313305734200174565ustar00rootroot00000000000000coffeescript-1.12.7/documentation/v1/body.html000066400000000000000000000156761313305734200213200ustar00rootroot00000000000000
<%= htmlFor('introduction') %> <%= htmlFor('overview') %> <%= htmlFor('installation') %> <%= htmlFor('usage') %> <%= htmlFor('literate') %> <%= htmlFor('language') %> <%= htmlFor('functions') %> <%= htmlFor('objects_and_arrays') %> <%= htmlFor('lexical_scope') %> <%= htmlFor('conditionals') %> <%= htmlFor('splats') %> <%= htmlFor('loops') %> <%= htmlFor('slices') %> <%= htmlFor('expressions') %> <%= htmlFor('operators') %> <%= htmlFor('existential_operator') %> <%= htmlFor('classes') %> <%= htmlFor('destructuring') %> <%= htmlFor('fat_arrow') %> <%= htmlFor('embedded') %> <%= htmlFor('switch') %> <%= htmlFor('try') %> <%= htmlFor('comparisons') %> <%= htmlFor('strings') %> <%= htmlFor('tagged_template_literals') %> <%= htmlFor('heregexes') %> <%= htmlFor('modules') %> <%= htmlFor('cake') %> <%= htmlFor('source_maps') %> <%= htmlFor('scripts') %> <%= htmlFor('books') %> <%= htmlFor('screencasts') %> <%= htmlFor('examples') %> <%= htmlFor('resources') %> <%= htmlFor('chat') %> <%= htmlFor('changelog') %>
coffeescript-1.12.7/documentation/v1/code.coffee000066400000000000000000000024261313305734200215450ustar00rootroot00000000000000fs = require 'fs' CoffeeScript = require '../../lib/coffee-script' module.exports = -> counter = 0 hljs = require 'highlight.js' hljs.configure classPrefix: '' (file, executable = no, showLoad = yes) -> counter++ cs = fs.readFileSync "documentation/examples/#{file}.coffee", 'utf-8' js = CoffeeScript.compile cs, bare: yes js = js.replace /^\/\/ generated.*?\n/i, '' cshtml = "
#{hljs.highlight('coffeescript', cs).value}
" jshtml = "
#{hljs.highlight('javascript', js).value}
" append = if executable is yes then '' else "alert(#{executable});".replace /"/g, '"' if executable and executable isnt yes cs.replace /(\S)\s*\Z/m, "$1\n\nalert #{executable}" run = if executable is yes then 'run' else "run: #{executable}" name = "example#{counter}" script = "" load = if showLoad then "
load
" else '' button = if executable then """
#{run}
""" else '' "
#{cshtml}#{jshtml}#{script}#{load}#{button}
" coffeescript-1.12.7/documentation/v1/docs.coffee000066400000000000000000000055041313305734200215630ustar00rootroot00000000000000sourceFragment = "try:" # Set up the compilation function, to run when you stop typing. compileSource = -> source = $('#repl_source').val() results = $('#repl_results') window.compiledJS = '' try window.compiledJS = CoffeeScript.compile source, bare: on el = results[0] if el.innerText el.innerText = window.compiledJS else results.text(window.compiledJS) results.removeClass 'error' $('.minibutton.run').removeClass 'error' catch {location, message} if location? message = "Error on line #{location.first_line + 1}: #{message}" results.text(message).addClass 'error' $('.minibutton.run').addClass 'error' # Update permalink $('#repl_permalink').attr 'href', "##{sourceFragment}#{encodeURIComponent source}" # Listen for keypresses and recompile. $('#repl_source').keyup -> compileSource() # Use tab key to insert tabs $('#repl_source').keydown (e) -> if e.keyCode is 9 e.preventDefault() textbox = e.target # Insert tab character at caret or in selection textbox.value = textbox.value[0...textbox.selectionStart] + "\t" + textbox.value[textbox.selectionEnd...] # Put caret in correct position textbox.selectionEnd = ++textbox.selectionStart # Eval the compiled js. evalJS = -> try eval window.compiledJS catch error then alert error # Load the console with a string of CoffeeScript. window.loadConsole = (coffee) -> $('#repl_source').val coffee compileSource() $('.navigation.try').addClass('active') false # Helper to hide the menus. closeMenus = -> $('.navigation.active').removeClass 'active' $('.minibutton.run').click -> evalJS() # Bind navigation buttons to open the menus. $('.navigation').click (e) -> return if e.target.tagName.toLowerCase() is 'a' return false if $(e.target).closest('.repl_wrapper').length if $(this).hasClass('active') closeMenus() else closeMenus() $(this).addClass 'active' false $(document).on 'click', '[href="#try"]', (e) -> $('.navigation.try').addClass 'active' # Dismiss console if Escape pressed or click falls outside console # Trigger Run button on Ctrl-Enter $(document.body) .keydown (e) -> closeMenus() if e.which == 27 evalJS() if e.which == 13 and (e.metaKey or e.ctrlKey) and $('.minibutton.run:visible').length .click (e) -> return false if $(e.target).hasClass('minibutton') closeMenus() $('#open_webchat').click -> $(this).replaceWith $('') $("#repl_permalink").click (e) -> window.location = $(this).attr("href") false # If source code is included in location.hash, display it. hash = decodeURIComponent location.hash.replace(/^#/, '') if hash.indexOf(sourceFragment) == 0 src = hash.substr sourceFragment.length loadConsole src compileSource() coffeescript-1.12.7/documentation/v1/docs.css000066400000000000000000000417551313305734200211340ustar00rootroot00000000000000body { font-size: 14px; line-height: 21px; color: #333; background: #f6f6f6 url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAADCAIAAABee8vuAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAB1JREFUeNpi/P79O8PgAyzMzMyD0FlMDIMSAAQYAC22AvZUamhbAAAAAElFTkSuQmCC); font-family: "Helvetica Neue", "Lucida Grande", "Lucida Sans Unicode", Helvetica, Arial, sans-serif !important; } .container { width: 950px; margin: 0; padding: 80px 0px 50px 50px; clear: both; } p, li { width: 625px; } a { color: #191933; } h1, h2, h3, h4, h5, h6, b.header { color: #000; margin-top: 40px; margin-bottom: 15px; text-shadow: #fff 0 1px 1px; } h2 { font-size: 18px; } h3 { font-size: 14px; } 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; } tr, td { margin: 0; padding: 0; } td { padding: 9px 15px 9px 0; vertical-align: top; } th { text-align: left; } 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; } blockquote { margin-left: 0; margin-right: 0; } code, pre, pre > code, textarea { font-family: Monaco, Consolas, "Lucida Console", monospace; font-size: 12px; line-height: 18px; color: #155; white-space: pre-wrap; word-wrap: break-word; } p > code, li > code { display: inline-block; background: #fff; border: 1px solid #dedede; padding: 0px 0.2em; } blockquote > pre { margin: 0; border-left: 5px solid rgba(0,0,0,0.2); padding: 3px 0 3px 12px; font-size: 12px; } td code { white-space: nowrap; } .timestamp { font-size: 11px; font-weight: normal; text-transform: uppercase; } .nowrap { white-space: nowrap; } div.anchor { position: relative; top: -90px; margin: 0 0 -20px; } 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: 1px dotted #d0d0d0; border-top-width: 0; border-bottom-width: 0; border-right-width: 0; margin: 15px 3px; padding: 0 0 26px 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; 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; outline: none; float: left; width: 242px; margin-left: 10px; } #logo svg { width: 225px; height: 40px; margin: 5px 0 0 3px; } #logo path { fill: #28334C; } .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 { z-index: 100; 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(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAOCAYAAAAmL5yKAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAACZJREFUeNpi/P//PyMDBYCJgULAAsQD64JRL1ApDP6PeoEyABBgAKOyBSJI2bJcAAAAAElFTkSuQmCC); 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(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAZAAAAEsCAYAAADtt+XCAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAEQZJREFUeNrs3Qly27i6gFGKouwF3DV09r+erOTFmp7oBtMIo5HiAIDnVKXct+t2LGvApx8k5c0///zzv4p3Hds/m83m++v5wl2Sv58/f361X3/8+PHh3sjf5fW5uXzZXl6e2/Zr+MMbGnfBeNHQjeyce19v/btDu/5061C8Jl35d6T6YP/7Am0fy4OYCMgSTiEaB9HIJgrPRuLR4373ze0TcRGb9GPShJDU7iEBGXNBOoYn2kE0kng8zlf++dr/XnKSuRebzY3/vRGY5WMSQtLFxOMhIIPE0TiFJ5p7ZblAvDo15PDzPTPNCMz8Mdm3fy6v/boXEwTk4VaFLaplI3F239wN5UZcZotJux58XdaDNii2uATkuWlDNEYPhUjMM8FcC4qwjDOVdFtcphIB+f1CPISzqBzbEIqS4yIs00wlTTiLq1nrfbnGgJyiaeMoGm/HQijyD4uoDJtKumMl22gqWdX21poCYptKLHgcFlF5PSbdNWH7tW1vrSEgwiEWiMocIem2tw5rCUnJATlUrt14tFCcosXi5C7hhajUUVxqQbkakngiKXKtLfGHEg7TBdM79aZ8U8rfIfk+TtKbSIpac0v6YY7Rg7X2cAgGS08pgnI7JLuqkK2tEgLSHePYrzwcJ8Ego6Cs7mK8Xkh2VQHHSHIOyCl6MNZ4cLx7gZ4Eg4yDUq9tOgkh+epNJFkGtcn0ibgPE8fawmHKoMQ3QKucTnpnbe1CSLIKaW4B6SaOw0rCYcrAdFL4dBJC8qv9VIxoIhGQER3DRwfsVxAO0UBQ/p5Oio9J+8Y4+iDXLA60px6QP45zFP6C6W9PAbe3uoq89iS8Qd73ppFkt/RSDkhb46+CP69KNGBYTKob00lJIemOj7Tr30eqa3WKN+qP03ILfjclGjBuTIrb5mrfQF/Wwv9L9bTf1ALSnV1V2tRxEg2Y5Y1ZPJUUcTZXdNrvMTpbS0B6U0cXj5Ke1KfoKzBvTOqqoC2uMI0cw6f/JnGQPYWAlDR12KKCtCb/qipoiys6yH5KYRppFn5w94Uc6zBtgKlk7mnkFA62L3am1lIB6Q6S535BoGMbkP9UkuWxkujYyCk6yF58QPbh9Nxc36nH72ZMG1DGVJLt9la4APEUgjLrltacATlF8cj1CWebCsqcSrLe3mrfkIfTfWfd0porIMcQjhy3rOJpwzYVlB2S6spUkktE2i/dllZ78eHkZ2nNEZDfV5QLB5DJa/+YcUjaNfc8xxXsUwfkK8TjnNmTRziAbEMSXcHeRuQjt4Cco3gIByAk80fkfFmDf4U38B9T3OYpAvL9IWBVPh+9LhxAkSHpjouE2/5RjXxwfewj9d8Hy9t4ZPKEOIUnxFE8gBdD0sUkB/uwNo96LHrMCeT3mVaZhMN1HMAY60hdZXBB4mVt3kcH10c5Q2usgBzDXlvqZ1rZrgKmCEl3YWLS21rRGVqfY0RkjGLmEg/bVcCUb06z2NYKZ2j9qkbYzno3IIcM4tE+sIfwx5YVMPUb1W69SfaNahSRtw45vBOQYwYXCJ6EA7D23IzIWwfWhwYk9W2rcw7vAoCiJb8OvbudNSQgqU8epg7AmjTDJPJqQE6Jn6pr6gBSn0ZSjMghROSlyNUv3gGpxuNs6gAymkaSe5Mb1vavV27bK9eBpHqFeXfanKkDyCUi3TUj28RuW7vGt9exfI45gXyF8SbFqcN1HUBuuutGkptGwlr/1Hr/TEAOCX6qrgPlQCnTSFJrWbvWh4g8PFzxKCDHxH6fR7LVBnhjXUtqNyV8FPzDM7PuBaT9C/YJna4bfxQJQGmS+iiUcHrv/l7U7h1EbyePfUJ3rAPlQOniD2Zc/AB7aMDNg+q3JpBDKI/RDmD+dS+ZrfrQgsOzATklctzjVOX1C1sAilsDo+Mhp2cCksJxj9x+2xfAlBFZdE0OTdg/CkgKW1eOdwBE63cUksVc28qKA7L01pXjHQC318dFj4tc28qKA7Lk1tW5smUF8MhpyTfZ/a2sLiDt+b5LfUiieABkEpHQimMckHb6OC14R4gHQAZrZ2jFvgvIYaHp4xT9ASCTNTQ049CEjys5r+UHBygsIp16rm8aDqjvmwV+QZR4AOQfkUOzwA8qHgAFRGTOgJzFA2DyiGzCn8nNVSqn6gLME5HZTvGdIyDiAVBgROYIiHgALBORrAMiHgCFRmTKgPj1swDLmnQdniogzrYCSGcSmWQ9niIg3em6PpIdYHmTrclTBMRxD4D0ppDRt7LGDoh4AKwkIvXIN048ANKOyGjr9FgBcdwDIH2jrtVjBcT0AbCyKaQe6ca43gMgH6Mcr343IGeTB0C2k8hbW1n1CDdAQADyDMhb63e95DcHIN+IDA2Is64A8vfWWj40IKYPgJVPIUMC4sA5QHkReXkKGRKQ2X5dIgCz6H5z7KQBcdwDoNyIvLS7JCAATB4QB84ByvbSOv9qQAAoPyKjBsT0AWAKGRwQAEwhLwXE9AFgChkcEABMIS8FxGm7AOv08LTe+om/QEAA1hmQ89CA+MwrgHW7uwtVD/0PAVjFFHIaOoEAICIvBcSpuwDc7UFt+gBgyBRS3/g/mj4AiKeQ87MBMYEAcLcL9Y3SAMDdNtSmDwCGTCECAsAoAbF9BcAtp0cTCADcmkKuBsRHlwDwKCCnawERDwCenkIEBIC3AuLsKwCeDchZQAAYJSAA8GxEBAQAAQFg5oA4/gHAqwE51+IBwJCICAgAAgLAvAEBgJeZQAAYNIFszmf9AGDYBAIAAgKAgAAgIAAICAAICAACAoCAACAgAAgIAAgIAAICgIAAICAACAgACAgAAgKAgAAgIAAICAAICAACAoCAACAgAAgIAAgIAAICgIAAICAACAgACAgAAgKAgAAgIAAICAAICAACAoCAACAgAAiIuwAAAQFAQAAQEAAEBAAEBAABAUBAABAQAAQEAAQEAAEBQEAAEBAABAQABAQAAQFAQAAQEAAEBAAEBAABASAJzY8fPzaXr2d3Bfzp58+f318vrxF3Bvxt004gG/cDAEMCAgAvM4EAMHgCERAABASAeQMiIgA8HY8qOoguIAC8EpBKQAAQEACWCYiIAPBMPAQEgPcDUgkIAE8GpBIQAEYJiIsKAXgUj/paQEwhADw1fVwLiE/nBeCW+l4wnI0FwK3pYyMgAIwekFv/DoB1q5+JhSkEgIdduBUQUwgAcSueCkhlAgHgURPqO7UxhQBwswf1q8UBwPTxKCA+2gRAPOohAXEwHWDd6qETSBcRUwjAOqePzaO6DK4PAEUHpH4nIM/+fwAoS/32/6FySi/AGuMxSkBMIQCmj7cCIiIApo9Bk4WAAJg+BgdERABMH4OmCqf1ApTp5YvHBQSAWQLS2ooIQHHx2L76H9UDv5FjIQDlGLS7VL/xzUQEoIx41EP/w6HjjuMhAHl7ay1/Z4owhQCsdPp4NyAiArDSeIwREAfUAfINyObdv2CMG7H1WABkYzvG+j/W9GArCyCfyaMe6y8ag7OyANI36lo95tRgCgFYyfQxdkBa20pEAFKNx3bsv3BsIgJQeDymCojjIQDpmGxNnmpScDwEIJ3po57qL57KtnJ9CMCSJl2H6xluvEkEYJnJYzv1N5ijgCICUFA85grIRkQAZo/HZo5vNAcRASgoHnMGpIuIs7MAplvPZ72EolngB+ycPN4Ao8Zj1jfo9WazadbwgwKIx3jadtTn83l3+YfNGn5gAPEYJR6bth3tN20u/9Cs5QcHEI/3hGY03Tdup5B6oTvA2VkAmaydoRW7Kvrm24WmkO/bIyIAL8djkQ+sDa3YVr1Fu51ClvrsKhEBSDweoRG7+Mb8/udLWT4WOKAeR6RZ8s4BSFT3JrtZMB7tgfOPuBv9d/ztAfXdwndUN4mICMB/F2Ev+unmoQ1NfxzqW3IrK46ILS1g7eoqgV+N0d+6uheQpbey+neciABrjseia+C1rat7AWmlsJXVjW6OiwBrsvjxjti1ratHAWm1U8gukTvUlhawpqkjid/mGhrwce/G3vxvw8ecbN2xAOt6o9yu/WH62AwJyPcPlMjxkCRHO4CR1rWktuqj4x7bR+/qH2lCRFIb85rKlhaQt+TWsnatD/Fonrnxz/gIf6FqA4yzfiW5mxLW+qfW+1c+/6r9C8+XP/vEHohuz/BY+SVVQB5TR6pvfHfPxuOVCaQr5scCv4DqlWnElhaQejySPIYb1vaPV27bqwtud5Fhk+iD01QOsAPpvslNcu1s1/RbFwuOGZBWd2ZWqqfTOsAOWJOej8f2mTOuxgpIF5HPhCOyMY0A1qGn4vFZDby+7p0ipj6JmEYAa88Ek0fn3f24dt+svebk1+XrMfF3AafoD8BU4Vjk95TPOXmMMYHEk8hn4pNI97N2HxVgWwsY+41qFp/ZN1Y8qhF/0C4ijQcZWOHUkcWb03C21SjxaI254P/+3KzL130GD3j7x7YW8O46ksWb0faTdcOHI462WzT2xNBGpCvwPpMnwCb8aSNy9poAHq3FUThy2Q7fDbnOY+6AdIvy57/B23xdbnQOT4ZtbyIREiD7cEQfjPgxxW1uJryjP8MZWm1Ezpk8OYQEKGHiiD+SfbIPwp36oHf7Kb51iMgxoyeLkABZhiPEY/vsR7KnHJDv7xFNIofMnjxCAsKR143/73OtJr+0Yq7TbrvzjutMjovcC8m5ctYWlKiO4pFjOL6Pd4QzrWY5M6yZ+cH5jLa0cluEu5Cce1MJkH844jMy8xuZNps6TB27Ob/vEhf+7cKW1j6zLa04JJvq760t21uQ5+s464uKw5bVbon1fKkrx9sf+PuBCyHJdfHtnnznyvYW5PKazXabqheO9iyr3ZxbVqkEpHsguy2tfUZnad16N9Pf3jKVQHrTRrbbVL14bEM4dkvejhQ+u2oXppF9CEkpT1RTCZg2xg5HFU0di3+AbSoffvj9QWSXO2VbwDTSn0qqyrESWOJNXFEfmJrK1JFiQPrTyCHzYyPX3gnVUUDEBKaJRhFbVL1wdMc6mhSmjpQD0p9GvgqZRq490fshERN4/bVU1BbVjalj8ivKSwrI79sWHRs5ZHjdyDMvgO7dhJiAaMThaK/raJY8wyr3gFTVf2dqNe2WVhuTcna17sbENhf8PbUXtz11JRztl2QOkucekM73llb7NUwjh5W8YMQE0VjJr6AOFwS2a/Iul9vcZHYfdweSulN+Tyt6IVXV39tcgkJJz/P+830dP/y/21Xd1JFVLJtMn2wfUUgOKwhJJ35hmU4wZeQfjuSPc5QWkHgx/QwhKe20X9MJpoxyw5HsablrCkinO+03nkjWuHhem04EhVSCscop40o4mlwOkK8lIP2QHMJEstaQVFderIKCYCwfjqawNbesHyb6mRohuRuULirxb1n0eV0MmXiLvyZDONYVkH5IjlFILJJ/RmVrSsF0MXo46igc25J/1mYFj2d8jERIXp9SREUsxEI4VhuQfkh2UUiOnvai4vEVizfDsY3Csaqzy5oVPt7tA/wRheR7i8txklGjUglLso+ZWIwTjfa+a6PR7W6s8r5sVv6i6q7+dJxk/KgIi1CUGI7VbVMJyGPx9taxDUn71VQyeVgqcRklEpVQTD5tdNtU22rFF0EKyH3fv/jJVLJYWB7FpVpBYDZXvoqEaUNAMp1KPnox8Q55ubg8mlhymGD6P59AJDZtdNdthGnD4yEgb7/guydUO4nY4ko/MNWDyWXsaaY/NdyaJCoLUprRqGxRCcgM+ltcx3AWl5ikFZhnF+pHcTlFj/szkSC/aPz+XUPuFQGZU7fFVYlJsbH58joRDW77fwEGANUZsxMt/7FyAAAAAElFTkSuQmCC); } .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; -webkit-tab-size: 2; -moz-tab-size: 2; -o-tab-size: 2; tab-size: 2; } #repl_results, #repl_source_wrap { width: auto; height: auto; position: absolute; margin-bottom: 0; top: 10px; left: 10px; right: 10px; bottom: 15px; } #repl_results.error { color: red } #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(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAAWCAIAAACOpGH9AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAACxJREFUeNpifvr0KRMDAwPT////4RjE//fvHxiD+Mjsv3//4uSD2FD1AAEGAHv9O3d7p0bEAAAAAElFTkSuQmCC) 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(data:image/gif;base64,R0lGODlhAQAYALMAADOtbj3BeyqVXDq6dTClZy2gYzKoazu+eDm1cyyaYDaycj7DfAAAAAAAAAAAAAAAACH5BAAAAAAALAAAAAABABgAAAQMcMlJZzgDKWBISUIEADs=); 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(data:image/gif;base64,R0lGODlhAQAYAMQAAFZWVn19fW1tbXd3d3FxcWtra1tbW3V1dWVlZWJiYlJSUnx8fF9fX3l5eWlpaXNzc35+fgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAAAAAAALAAAAAABABgAAAURICSOYrA0w/EQQuEgCWMASggAOw==); text-shadow: none; } .minibutton.error { opacity: 0.5; color: #600; cursor: not-allowed; } @media (max-width: 820px) { .container { width: auto; padding: 1em; } p, li, table { width: auto; } #fadeout { display: none; } #flybar { position: static; height: auto; min-width: 245px; } #logo { float: none; } .navigation { float: none; border: none; } div.code pre, div.code textarea { border-left: none; border-top-width: 1px; width: auto; float: none; margin: 5px; padding: 10px 5px; } div.code pre:first-child { border-top: none; } } coffeescript-1.12.7/documentation/v1/scripts.html000066400000000000000000000003641313305734200220360ustar00rootroot00000000000000 coffeescript-1.12.7/documentation/v1/styles.html000066400000000000000000000001131313305734200216620ustar00rootroot00000000000000 coffeescript-1.12.7/documentation/v1/tomorrow.css000066400000000000000000000030061313305734200220570ustar00rootroot00000000000000/* Highlight.js syntax highlighting */ /* http://jmblog.github.com/color-themes-for-google-code-highlightjs */ /* Forked from http://softwaremaniacs.org/media/soft/highlight/styles/tomorrow.css */ .tomorrow-comment, pre .comment, pre .title { color: #8e908c; } .tomorrow-red, pre .variable, pre .tag, pre .regexp, pre .ruby .constant, pre .xml .tag .title, pre .xml .pi, pre .xml .doctype, pre .html .doctype, pre .css .id, pre .css .class, pre .css .pseudo { color: #c82829; } .tomorrow-orange, pre .number, pre .preprocessor, pre .built_in, pre .params, pre .constant { color: #000000; } .tomorrow-yellow, pre .class, pre .ruby .class .title, pre .css .rules .attribute { color: #eab700; } .tomorrow-green, pre .string, pre .value, pre .inheritance, pre .header, pre .ruby .symbol, pre .xml .cdata { color: #718c00; } .tomorrow-aqua, pre .css .hexcolor { color: #3e999f; } .tomorrow-blue, pre .function, pre .function .title, pre .python .decorator, pre .python .title, pre .ruby .function .title, pre .ruby .title .keyword, pre .perl .sub, pre .javascript .title, pre .coffeescript .title { color: #21439C; } .tomorrow-purple, pre .keyword, pre .reserved, pre .javascript .function { color: #FF5600; } pre .subst { color: #A535AE; } pre .literal { color: #A535AE; } pre .property { color: #A535AE; } pre .class .title { color: #21439C; } pre .coffeescript .javascript, pre .javascript .xml, pre .tex .formula, pre .xml .javascript, pre .xml .vbscript, pre .xml .css, pre .xml .cdata { opacity: 0.5; } coffeescript-1.12.7/lib/000077500000000000000000000000001313305734200150255ustar00rootroot00000000000000coffeescript-1.12.7/lib/coffee-script/000077500000000000000000000000001313305734200175565ustar00rootroot00000000000000coffeescript-1.12.7/lib/coffee-script/browser.js000066400000000000000000000071361313305734200216060ustar00rootroot00000000000000// Generated by CoffeeScript 1.12.7 (function() { var CoffeeScript, compile, runScripts, 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; }; CoffeeScript = require('./coffee-script'); CoffeeScript.require = require; compile = CoffeeScript.compile; CoffeeScript["eval"] = function(code, options) { if (options == null) { options = {}; } if (options.bare == null) { options.bare = true; } return eval(compile(code, options)); }; CoffeeScript.run = function(code, options) { if (options == null) { options = {}; } options.bare = true; options.shiftLine = true; return Function(compile(code, options))(); }; if (typeof window === "undefined" || window === null) { return; } if ((typeof btoa !== "undefined" && btoa !== null) && (typeof JSON !== "undefined" && JSON !== null)) { compile = function(code, options) { if (options == null) { options = {}; } options.inlineMap = true; return CoffeeScript.compile(code, options); }; } CoffeeScript.load = function(url, callback, options, hold) { var xhr; if (options == null) { options = {}; } if (hold == null) { hold = false; } options.sourceFiles = [url]; xhr = window.ActiveXObject ? new window.ActiveXObject('Microsoft.XMLHTTP') : new window.XMLHttpRequest(); xhr.open('GET', url, true); if ('overrideMimeType' in xhr) { xhr.overrideMimeType('text/plain'); } xhr.onreadystatechange = function() { var param, ref; if (xhr.readyState === 4) { if ((ref = xhr.status) === 0 || ref === 200) { param = [xhr.responseText, options]; if (!hold) { CoffeeScript.run.apply(CoffeeScript, param); } } else { throw new Error("Could not load " + url); } if (callback) { return callback(param); } } }; return xhr.send(null); }; runScripts = function() { var coffees, coffeetypes, execute, fn, i, index, j, len, s, script, scripts; scripts = window.document.getElementsByTagName('script'); coffeetypes = ['text/coffeescript', 'text/literate-coffeescript']; coffees = (function() { var j, len, ref, results; results = []; for (j = 0, len = scripts.length; j < len; j++) { s = scripts[j]; if (ref = s.type, indexOf.call(coffeetypes, ref) >= 0) { results.push(s); } } return results; })(); index = 0; execute = function() { var param; param = coffees[index]; if (param instanceof Array) { CoffeeScript.run.apply(CoffeeScript, param); index++; return execute(); } }; fn = function(script, i) { var options, source; options = { literate: script.type === coffeetypes[1] }; source = script.src || script.getAttribute('data-src'); if (source) { return CoffeeScript.load(source, function(param) { coffees[i] = param; return execute(); }, options, true); } else { options.sourceFiles = ['embedded']; return coffees[i] = [script.innerHTML, options]; } }; for (i = j = 0, len = coffees.length; j < len; i = ++j) { script = coffees[i]; fn(script, i); } return execute(); }; if (window.addEventListener) { window.addEventListener('DOMContentLoaded', runScripts, false); } else { window.attachEvent('onload', runScripts); } }).call(this); coffeescript-1.12.7/lib/coffee-script/cake.js000066400000000000000000000056641313305734200210320ustar00rootroot00000000000000// Generated by CoffeeScript 1.12.7 (function() { var CoffeeScript, cakefileDirectory, 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'); CoffeeScript.register(); 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, e, 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 (error) { e = error; 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 (fs.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); coffeescript-1.12.7/lib/coffee-script/coffee-script.js000066400000000000000000000330131313305734200226450ustar00rootroot00000000000000// Generated by CoffeeScript 1.12.7 (function() { var Lexer, SourceMap, base64encode, compile, ext, fn1, formatSourcePosition, fs, getSourceMap, helpers, i, len, lexer, packageJson, parser, path, ref, sourceMaps, sources, vm, withPrettyErrors, hasProp = {}.hasOwnProperty; fs = require('fs'); vm = require('vm'); path = require('path'); Lexer = require('./lexer').Lexer; parser = require('./parser').parser; helpers = require('./helpers'); SourceMap = require('./sourcemap'); packageJson = require('../../package.json'); exports.VERSION = packageJson.version; exports.FILE_EXTENSIONS = ['.coffee', '.litcoffee', '.coffee.md']; exports.helpers = helpers; base64encode = function(src) { switch (false) { case typeof Buffer !== 'function': return new Buffer(src).toString('base64'); case typeof btoa !== 'function': return btoa(encodeURIComponent(src).replace(/%([0-9A-F]{2})/g, function(match, p1) { return String.fromCharCode('0x' + p1); })); default: throw new Error('Unable to base64 encode inline sourcemap.'); } }; withPrettyErrors = function(fn) { return function(code, options) { var err; if (options == null) { options = {}; } try { return fn.call(this, code, options); } catch (error) { err = error; if (typeof code !== 'string') { throw err; } throw helpers.updateSyntaxError(err, code, options.filename); } }; }; sources = {}; sourceMaps = {}; exports.compile = compile = withPrettyErrors(function(code, options) { var currentColumn, currentLine, encoded, extend, filename, fragment, fragments, generateSourceMap, header, i, j, js, len, len1, map, merge, newLines, ref, ref1, sourceMapDataURI, sourceURL, token, tokens, v3SourceMap; merge = helpers.merge, extend = helpers.extend; options = extend({}, options); generateSourceMap = options.sourceMap || options.inlineMap || (options.filename == null); filename = options.filename || ''; sources[filename] = code; if (generateSourceMap) { map = new SourceMap; } tokens = lexer.tokenize(code, options); options.referencedVars = (function() { var i, len, results; results = []; for (i = 0, len = tokens.length; i < len; i++) { token = tokens[i]; if (token[0] === 'IDENTIFIER') { results.push(token[1]); } } return results; })(); if (!((options.bare != null) && options.bare === true)) { for (i = 0, len = tokens.length; i < len; i++) { token = tokens[i]; if ((ref = token[0]) === 'IMPORT' || ref === 'EXPORT') { options.bare = true; break; } } } fragments = parser.parse(tokens).compileToFragments(options); currentLine = 0; if (options.header) { currentLine += 1; } if (options.shiftLine) { currentLine += 1; } currentColumn = 0; js = ""; for (j = 0, len1 = fragments.length; j < len1; j++) { fragment = fragments[j]; if (generateSourceMap) { if (fragment.locationData && !/^[;\s]*$/.test(fragment.code)) { map.add([fragment.locationData.first_line, fragment.locationData.first_column], [currentLine, currentColumn], { noReplace: true }); } newLines = helpers.count(fragment.code, "\n"); currentLine += newLines; if (newLines) { currentColumn = fragment.code.length - (fragment.code.lastIndexOf("\n") + 1); } else { currentColumn += fragment.code.length; } } js += fragment.code; } if (options.header) { header = "Generated by CoffeeScript " + this.VERSION; js = "// " + header + "\n" + js; } if (generateSourceMap) { v3SourceMap = map.generate(options, code); sourceMaps[filename] = map; } if (options.inlineMap) { encoded = base64encode(JSON.stringify(v3SourceMap)); sourceMapDataURI = "//# sourceMappingURL=data:application/json;base64," + encoded; sourceURL = "//# sourceURL=" + ((ref1 = options.filename) != null ? ref1 : 'coffeescript'); js = js + "\n" + sourceMapDataURI + "\n" + sourceURL; } if (options.sourceMap) { return { js: js, sourceMap: map, v3SourceMap: JSON.stringify(v3SourceMap, null, 2) }; } else { return js; } }); exports.tokens = withPrettyErrors(function(code, options) { return lexer.tokenize(code, options); }); exports.nodes = withPrettyErrors(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 answer, dir, mainModule, ref; if (options == null) { options = {}; } mainModule = require.main; mainModule.filename = process.argv[1] = options.filename ? fs.realpathSync(options.filename) : ''; mainModule.moduleCache && (mainModule.moduleCache = {}); dir = options.filename != null ? path.dirname(fs.realpathSync(options.filename)) : fs.realpathSync('.'); mainModule.paths = require('module')._nodeModulePaths(dir); if (!helpers.isCoffee(mainModule.filename) || require.extensions) { answer = compile(code, options); code = (ref = answer.js) != null ? ref : answer; } return mainModule._compile(code, mainModule.filename); }; exports["eval"] = function(code, options) { var Module, _module, _require, createContext, i, isContext, js, k, len, o, r, ref, ref1, ref2, ref3, sandbox, v; if (options == null) { options = {}; } if (!(code = code.trim())) { return; } createContext = (ref = vm.Script.createContext) != null ? ref : vm.createContext; isContext = (ref1 = vm.isContext) != null ? ref1 : function(ctx) { return options.sandbox instanceof createContext().constructor; }; if (createContext) { if (options.sandbox != null) { if (isContext(options.sandbox)) { sandbox = options.sandbox; } else { sandbox = createContext(); ref2 = options.sandbox; for (k in ref2) { if (!hasProp.call(ref2, k)) continue; v = ref2[k]; sandbox[k] = v; } } sandbox.global = sandbox.root = sandbox.GLOBAL = sandbox; } else { sandbox = global; } sandbox.__filename = options.filename || 'eval'; sandbox.__dirname = path.dirname(sandbox.__filename); if (!(sandbox !== global || sandbox.module || sandbox.require)) { Module = require('module'); sandbox.module = _module = new Module(options.modulename || 'eval'); sandbox.require = _require = function(path) { return Module._load(path, _module, true); }; _module.filename = sandbox.__filename; ref3 = Object.getOwnPropertyNames(require); for (i = 0, len = ref3.length; i < len; i++) { r = ref3[i]; if (r !== 'paths' && r !== 'arguments' && r !== 'caller') { _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); } }; exports.register = function() { return require('./register'); }; if (require.extensions) { ref = this.FILE_EXTENSIONS; fn1 = function(ext) { var base; return (base = require.extensions)[ext] != null ? base[ext] : base[ext] = function() { throw new Error("Use CoffeeScript.register() or require the coffee-script/register module to require " + ext + " files."); }; }; for (i = 0, len = ref.length; i < len; i++) { ext = ref[i]; fn1(ext); } } exports._compileFile = function(filename, sourceMap, inlineMap) { var answer, err, raw, stripped; if (sourceMap == null) { sourceMap = false; } if (inlineMap == null) { inlineMap = false; } raw = fs.readFileSync(filename, 'utf8'); stripped = raw.charCodeAt(0) === 0xFEFF ? raw.substring(1) : raw; try { answer = compile(stripped, { filename: filename, sourceMap: sourceMap, inlineMap: inlineMap, sourceFiles: [filename], literate: helpers.isLiterate(filename) }); } catch (error) { err = error; throw helpers.updateSyntaxError(err, stripped, filename); } return answer; }; lexer = new Lexer; parser.lexer = { lex: function() { var tag, token; token = parser.tokens[this.pos++]; if (token) { tag = token[0], this.yytext = token[1], this.yylloc = token[2]; parser.errorToken = token.origin || token; this.yylineno = this.yylloc.first_line; } else { tag = ''; } return tag; }, setInput: function(tokens) { parser.tokens = tokens; return this.pos = 0; }, upcomingInput: function() { return ""; } }; parser.yy = require('./nodes'); parser.yy.parseError = function(message, arg) { var errorLoc, errorTag, errorText, errorToken, token, tokens; token = arg.token; errorToken = parser.errorToken, tokens = parser.tokens; errorTag = errorToken[0], errorText = errorToken[1], errorLoc = errorToken[2]; errorText = (function() { switch (false) { case errorToken !== tokens[tokens.length - 1]: return 'end of input'; case errorTag !== 'INDENT' && errorTag !== 'OUTDENT': return 'indentation'; case errorTag !== 'IDENTIFIER' && errorTag !== 'NUMBER' && errorTag !== 'INFINITY' && errorTag !== 'STRING' && errorTag !== 'STRING_START' && errorTag !== 'REGEX' && errorTag !== 'REGEX_START': return errorTag.replace(/_START$/, '').toLowerCase(); default: return helpers.nameWhitespaceCharacter(errorText); } })(); return helpers.throwSyntaxError("unexpected " + errorText, errorLoc); }; formatSourcePosition = function(frame, getSourceMapping) { var as, column, fileLocation, filename, functionName, isConstructor, isMethodCall, line, methodName, source, tp, typeName; filename = void 0; fileLocation = ''; if (frame.isNative()) { fileLocation = "native"; } else { if (frame.isEval()) { filename = frame.getScriptNameOrSourceURL(); if (!filename) { fileLocation = (frame.getEvalOrigin()) + ", "; } } else { filename = frame.getFileName(); } filename || (filename = ""); line = frame.getLineNumber(); column = frame.getColumnNumber(); source = getSourceMapping(filename, line, column); fileLocation = source ? filename + ":" + source[0] + ":" + source[1] : filename + ":" + line + ":" + column; } functionName = frame.getFunctionName(); isConstructor = frame.isConstructor(); isMethodCall = !(frame.isToplevel() || isConstructor); if (isMethodCall) { methodName = frame.getMethodName(); typeName = frame.getTypeName(); if (functionName) { tp = as = ''; if (typeName && functionName.indexOf(typeName)) { tp = typeName + "."; } if (methodName && functionName.indexOf("." + methodName) !== functionName.length - methodName.length - 1) { as = " [as " + methodName + "]"; } return "" + tp + functionName + as + " (" + fileLocation + ")"; } else { return typeName + "." + (methodName || '') + " (" + fileLocation + ")"; } } else if (isConstructor) { return "new " + (functionName || '') + " (" + fileLocation + ")"; } else if (functionName) { return functionName + " (" + fileLocation + ")"; } else { return fileLocation; } }; getSourceMap = function(filename) { var answer; if (sourceMaps[filename] != null) { return sourceMaps[filename]; } else if (sourceMaps[''] != null) { return sourceMaps['']; } else if (sources[filename] != null) { answer = compile(sources[filename], { filename: filename, sourceMap: true, literate: helpers.isLiterate(filename) }); return answer.sourceMap; } else { return null; } }; Error.prepareStackTrace = function(err, stack) { var frame, frames, getSourceMapping; getSourceMapping = function(filename, line, column) { var answer, sourceMap; sourceMap = getSourceMap(filename); if (sourceMap != null) { answer = sourceMap.sourceLocation([line - 1, column - 1]); } if (answer != null) { return [answer[0] + 1, answer[1] + 1]; } else { return null; } }; frames = (function() { var j, len1, results; results = []; for (j = 0, len1 = stack.length; j < len1; j++) { frame = stack[j]; if (frame.getFunction() === exports.run) { break; } results.push(" at " + (formatSourcePosition(frame, getSourceMapping))); } return results; })(); return (err.toString()) + "\n" + (frames.join('\n')) + "\n"; }; }).call(this); coffeescript-1.12.7/lib/coffee-script/command.js000066400000000000000000000443631313305734200215440ustar00rootroot00000000000000// Generated by CoffeeScript 1.12.7 (function() { var BANNER, CoffeeScript, EventEmitter, SWITCHES, compileJoin, compileOptions, compilePath, compileScript, compileStdio, exec, findDirectoryIndex, forkNode, fs, helpers, hidden, joinTimeout, makePrelude, mkdirp, notSources, optionParser, optparse, opts, outputPath, parseOptions, path, printLine, printTokens, printWarn, ref, removeSource, removeSourceDir, silentUnlink, sourceCode, sources, spawn, timeLog, usage, useWinPathSep, version, wait, watch, watchDir, watchedDirs, writeJs, 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; }; 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; useWinPathSep = path.sep === '\\'; 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'], ['-m', '--map', 'generate source map and save as .js.map files'], ['-M', '--inline-map', 'generate source map and include it directly in output'], ['-n', '--nodes', 'print out the parse tree that the parser produces'], ['--nodejs [ARGS]', 'pass options directly to the "node" binary'], ['--no-header', 'suppress the "Generated by" header'], ['-o', '--output [DIR]', 'set the output directory for compiled JavaScript'], ['-p', '--print', 'print out the compiled JavaScript'], ['-r', '--require [MODULE*]', 'require the given module before eval or REPL'], ['-s', '--stdio', 'listen for and compile scripts over stdio'], ['-l', '--literate', 'treat stdio as literate style coffee-script'], ['-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 = {}; watchedDirs = {}; optionParser = null; exports.run = function() { var i, len, literals, ref1, replCliOpts, results, source; parseOptions(); replCliOpts = { useGlobal: true }; if (opts.require) { opts.prelude = makePrelude(opts.require); } replCliOpts.prelude = opts.prelude; if (opts.nodejs) { return forkNode(); } if (opts.help) { return usage(); } if (opts.version) { return version(); } if (opts.interactive) { return require('./repl').start(replCliOpts); } if (opts.stdio) { return compileStdio(); } if (opts["eval"]) { return compileScript(null, opts["arguments"][0]); } if (!opts["arguments"].length) { return require('./repl').start(replCliOpts); } literals = opts.run ? opts["arguments"].splice(1) : []; process.argv = process.argv.slice(0, 2).concat(literals); process.argv[0] = 'coffee'; if (opts.output) { opts.output = path.resolve(opts.output); } if (opts.join) { opts.join = path.resolve(opts.join); console.error('\nThe --join option is deprecated and will be removed in a future version.\n\nIf for some reason it\'s necessary to share local variables between files,\nreplace...\n\n $ coffee --compile --join bundle.js -- a.coffee b.coffee c.coffee\n\nwith...\n\n $ cat a.coffee b.coffee c.coffee | coffee --compile --stdio > bundle.js\n'); } ref1 = opts["arguments"]; results = []; for (i = 0, len = ref1.length; i < len; i++) { source = ref1[i]; source = path.resolve(source); results.push(compilePath(source, true, source)); } return results; }; makePrelude = function(requires) { return requires.map(function(module) { var _, match, name; if (match = module.match(/^(.*)=(.*)$/)) { _ = match[0], name = match[1], module = match[2]; } name || (name = helpers.baseFileName(module, true, useWinPathSep)); return name + " = require('" + module + "')"; }).join(';'); }; compilePath = function(source, topLevel, base) { var code, err, file, files, i, len, results, stats; if (indexOf.call(sources, source) >= 0 || watchedDirs[source] || !topLevel && (notSources[source] || hidden(source))) { return; } try { stats = fs.statSync(source); } catch (error) { err = error; if (err.code === 'ENOENT') { console.error("File not found: " + source); process.exit(1); } throw err; } if (stats.isDirectory()) { if (path.basename(source) === 'node_modules') { notSources[source] = true; return; } if (opts.run) { compilePath(findDirectoryIndex(source), topLevel, base); return; } if (opts.watch) { watchDir(source, base); } try { files = fs.readdirSync(source); } catch (error) { err = error; if (err.code === 'ENOENT') { return; } else { throw err; } } results = []; for (i = 0, len = files.length; i < len; i++) { file = files[i]; results.push(compilePath(path.join(source, file), false, base)); } return results; } else if (topLevel || helpers.isCoffee(source)) { sources.push(source); sourceCode.push(null); delete notSources[source]; if (opts.watch) { watch(source, base); } try { code = fs.readFileSync(source); } catch (error) { err = error; if (err.code === 'ENOENT') { return; } else { throw err; } } return compileScript(source, code.toString(), base); } else { return notSources[source] = true; } }; findDirectoryIndex = function(source) { var err, ext, i, index, len, ref1; ref1 = CoffeeScript.FILE_EXTENSIONS; for (i = 0, len = ref1.length; i < len; i++) { ext = ref1[i]; index = path.join(source, "index" + ext); try { if ((fs.statSync(index)).isFile()) { return index; } } catch (error) { err = error; if (err.code !== 'ENOENT') { throw err; } } } console.error("Missing index.coffee or index.litcoffee in " + source); return process.exit(1); }; compileScript = function(file, input, base) { var compiled, err, message, o, options, t, task; if (base == null) { base = null; } o = opts; options = compileOptions(file, base); try { t = task = { file: file, input: input, options: options }; CoffeeScript.emit('compile', task); if (o.tokens) { return printTokens(CoffeeScript.tokens(t.input, t.options)); } else if (o.nodes) { return printLine(CoffeeScript.nodes(t.input, t.options).toString().trim()); } else if (o.run) { CoffeeScript.register(); if (opts.prelude) { CoffeeScript["eval"](opts.prelude, t.options); } return CoffeeScript.run(t.input, t.options); } else if (o.join && t.file !== o.join) { if (helpers.isLiterate(file)) { t.input = helpers.invertLiterate(t.input); } sourceCode[sources.indexOf(t.file)] = t.input; return compileJoin(); } else { compiled = CoffeeScript.compile(t.input, t.options); t.output = compiled; if (o.map) { t.output = compiled.js; t.sourceMap = compiled.v3SourceMap; } CoffeeScript.emit('success', task); if (o.print) { return printLine(t.output.trim()); } else if (o.compile || o.map) { return writeJs(base, t.file, t.output, options.jsPath, t.sourceMap); } } } catch (error) { err = error; CoffeeScript.emit('failure', err, task); if (CoffeeScript.listeners('failure').length) { return; } message = (err != null ? err.stack : void 0) || ("" + err); if (o.watch) { return printLine(message + '\x07'); } else { printWarn(message); return process.exit(1); } } }; compileStdio = function() { var buffers, stdin; buffers = []; stdin = process.openStdin(); stdin.on('data', function(buffer) { if (buffer) { return buffers.push(buffer); } }); return stdin.on('end', function() { return compileScript(null, Buffer.concat(buffers).toString()); }); }; 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); }); } }; watch = function(source, base) { var compile, compileTimeout, err, prevStats, rewatch, startWatcher, watchErr, watcher; watcher = null; prevStats = null; compileTimeout = null; watchErr = function(err) { if (err.code !== 'ENOENT') { throw err; } if (indexOf.call(sources, source) < 0) { return; } try { rewatch(); return compile(); } catch (error) { removeSource(source, base); return compileJoin(); } }; 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(); }); }); }); }; startWatcher = function() { return watcher = fs.watch(source).on('change', compile).on('error', function(err) { if (err.code !== 'EPERM') { throw err; } return removeSource(source, base); }); }; rewatch = function() { if (watcher != null) { watcher.close(); } return startWatcher(); }; try { return startWatcher(); } catch (error) { err = error; return watchErr(err); } }; watchDir = function(source, base) { var err, readdirTimeout, startWatcher, stopWatcher, watcher; watcher = null; readdirTimeout = null; startWatcher = function() { return watcher = fs.watch(source).on('error', function(err) { if (err.code !== 'EPERM') { throw err; } return stopWatcher(); }).on('change', function() { clearTimeout(readdirTimeout); return readdirTimeout = wait(25, function() { var err, file, files, i, len, results; try { files = fs.readdirSync(source); } catch (error) { err = error; if (err.code !== 'ENOENT') { throw err; } return stopWatcher(); } results = []; for (i = 0, len = files.length; i < len; i++) { file = files[i]; results.push(compilePath(path.join(source, file), false, base)); } return results; }); }); }; stopWatcher = function() { watcher.close(); return removeSourceDir(source, base); }; watchedDirs[source] = true; try { return startWatcher(); } catch (error) { err = error; if (err.code !== 'ENOENT') { throw err; } } }; removeSourceDir = function(source, base) { var file, i, len, sourcesChanged; delete watchedDirs[source]; sourcesChanged = false; for (i = 0, len = sources.length; i < len; i++) { file = sources[i]; if (!(source === path.dirname(file))) { continue; } removeSource(file, base); sourcesChanged = true; } if (sourcesChanged) { return compileJoin(); } }; removeSource = function(source, base) { var index; index = sources.indexOf(source); sources.splice(index, 1); sourceCode.splice(index, 1); if (!opts.join) { silentUnlink(outputPath(source, base)); silentUnlink(outputPath(source, base, '.js.map')); return timeLog("removed " + source); } }; silentUnlink = function(path) { var err, ref1; try { return fs.unlinkSync(path); } catch (error) { err = error; if ((ref1 = err.code) !== 'ENOENT' && ref1 !== 'EPERM') { throw err; } } }; outputPath = function(source, base, extension) { var basename, dir, srcDir; if (extension == null) { extension = ".js"; } basename = helpers.baseFileName(source, true, useWinPathSep); srcDir = path.dirname(source); if (!opts.output) { dir = srcDir; } else if (source === base) { dir = opts.output; } else { dir = path.join(opts.output, path.relative(base, srcDir)); } return path.join(dir, basename + extension); }; mkdirp = function(dir, fn) { var mkdirs, mode; mode = 0x1ff & ~process.umask(); return (mkdirs = function(p, fn) { return fs.exists(p, function(exists) { if (exists) { return fn(); } else { return mkdirs(path.dirname(p), function() { return fs.mkdir(p, mode, function(err) { if (err) { return fn(err); } return fn(); }); }); } }); })(dir, fn); }; writeJs = function(base, sourcePath, js, jsPath, generatedSourceMap) { var compile, jsDir, sourceMapPath; if (generatedSourceMap == null) { generatedSourceMap = null; } sourceMapPath = outputPath(sourcePath, base, ".js.map"); jsDir = path.dirname(jsPath); compile = function() { if (opts.compile) { if (js.length <= 0) { js = ' '; } if (generatedSourceMap) { js = js + "\n//# sourceMappingURL=" + (helpers.baseFileName(sourceMapPath, false, useWinPathSep)) + "\n"; } fs.writeFile(jsPath, js, function(err) { if (err) { printLine(err.message); return process.exit(1); } else if (opts.compile && opts.watch) { return timeLog("compiled " + sourcePath); } }); } if (generatedSourceMap) { return fs.writeFile(sourceMapPath, generatedSourceMap, function(err) { if (err) { printLine("Could not write source map: " + err.message); return process.exit(1); } }); } }; return fs.exists(jsDir, function(itExists) { if (itExists) { return compile(); } else { return mkdirp(jsDir, compile); } }); }; wait = function(milliseconds, func) { return setTimeout(func, milliseconds); }; timeLog = function(message) { return console.log(((new Date).toLocaleTimeString()) + " - " + message); }; printTokens = function(tokens) { var strings, tag, token, value; strings = (function() { var i, len, results; results = []; for (i = 0, len = tokens.length; i < len; i++) { token = tokens[i]; tag = token[0]; value = token[1].toString().replace(/\n/, '\\n'); results.push("[" + tag + " " + value + "]"); } return results; })(); return printLine(strings.join(' ')); }; parseOptions = function() { var o; 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.map); return o.print = !!(o.print || (o["eval"] || o.stdio && o.compile)); }; compileOptions = function(filename, base) { var answer, cwd, jsDir, jsPath; answer = { filename: filename, literate: opts.literate || helpers.isLiterate(filename), bare: opts.bare, header: opts.compile && !opts['no-header'], sourceMap: opts.map, inlineMap: opts['inline-map'] }; if (filename) { if (base) { cwd = process.cwd(); jsPath = outputPath(filename, base); jsDir = path.dirname(jsPath); answer = helpers.merge(answer, { jsPath: jsPath, sourceRoot: path.relative(jsDir, cwd), sourceFiles: [path.relative(cwd, filename)], generatedFile: helpers.baseFileName(jsPath, false, useWinPathSep) }); } else { answer = helpers.merge(answer, { sourceRoot: "", sourceFiles: [helpers.baseFileName(filename, false, useWinPathSep)], generatedFile: helpers.baseFileName(filename, true, useWinPathSep) + ".js" }); } } return answer; }; forkNode = function() { var args, nodeArgs, p; nodeArgs = opts.nodejs.split(/\s+/); args = process.argv.slice(1); args.splice(args.indexOf('--nodejs'), 2); p = spawn(process.execPath, nodeArgs.concat(args), { cwd: process.cwd(), env: process.env, stdio: [0, 1, 2] }); return p.on('exit', function(code) { return process.exit(code); }); }; usage = function() { return printLine((new optparse.OptionParser(SWITCHES, BANNER)).help()); }; version = function() { return printLine("CoffeeScript version " + CoffeeScript.VERSION); }; }).call(this); coffeescript-1.12.7/lib/coffee-script/grammar.js000066400000000000000000000651411313305734200215510ustar00rootroot00000000000000// Generated by CoffeeScript 1.12.7 (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 addLocationDataFn, match, patternCount; patternString = patternString.replace(/\s{2,}/g, ' '); patternCount = patternString.split(' ').length; 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.$&'); addLocationDataFn = function(first, last) { if (!last) { return "yy.addLocationDataFn(@" + first + ")"; } else { return "yy.addLocationDataFn(@" + first + ", @" + last + ")"; } }; action = action.replace(/LOC\(([0-9]*)\)/g, addLocationDataFn('$1')); action = action.replace(/LOC\(([0-9]*),\s*([0-9]*)\)/g, addLocationDataFn('$1', '$2')); return [patternString, "$$ = " + (addLocationDataFn(1, patternCount)) + "(" + action + ");", options]; }; grammar = { Root: [ o('', function() { return new Block; }), o('Body') ], 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'), o('YieldReturn')], Statement: [ o('Return'), o('Comment'), o('STATEMENT', function() { return new StatementLiteral($1); }), o('Import'), o('Export') ], 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'), o('Yield')], Yield: [ o('YIELD', function() { return new Op($1, new Value(new Literal(''))); }), o('YIELD Expression', function() { return new Op($1, $2); }), o('YIELD FROM Expression', function() { return new Op($1.concat($2), $3); }) ], Block: [ o('INDENT OUTDENT', function() { return new Block; }), o('INDENT Body OUTDENT', function() { return $2; }) ], Identifier: [ o('IDENTIFIER', function() { return new IdentifierLiteral($1); }) ], Property: [ o('PROPERTY', function() { return new PropertyName($1); }) ], AlphaNumeric: [ o('NUMBER', function() { return new NumberLiteral($1); }), o('String') ], String: [ o('STRING', function() { return new StringLiteral($1); }), o('STRING_START Body STRING_END', function() { return new StringWithInterpolations($2); }) ], Regex: [ o('REGEX', function() { return new RegexLiteral($1); }), o('REGEX_START Invocation REGEX_END', function() { return new RegexWithInterpolations($2.args); }) ], Literal: [ o('AlphaNumeric'), o('JS', function() { return new PassthroughLiteral($1); }), o('Regex'), o('UNDEFINED', function() { return new UndefinedLiteral; }), o('NULL', function() { return new NullLiteral; }), o('BOOL', function() { return new BooleanLiteral($1); }), o('INFINITY', function() { return new InfinityLiteral($1); }), o('NAN', function() { return new NaNLiteral; }) ], 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(LOC(1)(new Value($1)), $3, 'object', { operatorToken: LOC(2)(new Literal($2)) }); }), o('ObjAssignable : INDENT Expression OUTDENT', function() { return new Assign(LOC(1)(new Value($1)), $4, 'object', { operatorToken: LOC(2)(new Literal($2)) }); }), o('SimpleObjAssignable = Expression', function() { return new Assign(LOC(1)(new Value($1)), $3, null, { operatorToken: LOC(2)(new Literal($2)) }); }), o('SimpleObjAssignable = INDENT Expression OUTDENT', function() { return new Assign(LOC(1)(new Value($1)), $4, null, { operatorToken: LOC(2)(new Literal($2)) }); }), o('Comment') ], SimpleObjAssignable: [o('Identifier'), o('Property'), o('ThisProperty')], ObjAssignable: [o('SimpleObjAssignable'), o('AlphaNumeric')], Return: [ o('RETURN Expression', function() { return new Return($2); }), o('RETURN INDENT Object OUTDENT', function() { return new Return(new Value($3)); }), o('RETURN', function() { return new Return; }) ], YieldReturn: [ o('YIELD RETURN Expression', function() { return new YieldReturn($3); }), o('YIELD RETURN', function() { return new YieldReturn; }) ], 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); }), o('...', function() { return new Expansion; }) ], 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('. Property', function() { return new Access($2); }), o('?. Property', function() { return new Access($2, 'soak'); }), o(':: Property', function() { return [LOC(1)(new Access(new PropertyName('prototype'))), LOC(2)(new Access($2))]; }), o('?:: Property', function() { return [LOC(1)(new Access(new PropertyName('prototype'), 'soak')), LOC(2)(new Access($2))]; }), o('::', function() { return new Access(new PropertyName('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); }) ], Import: [ o('IMPORT String', function() { return new ImportDeclaration(null, $2); }), o('IMPORT ImportDefaultSpecifier FROM String', function() { return new ImportDeclaration(new ImportClause($2, null), $4); }), o('IMPORT ImportNamespaceSpecifier FROM String', function() { return new ImportDeclaration(new ImportClause(null, $2), $4); }), o('IMPORT { } FROM String', function() { return new ImportDeclaration(new ImportClause(null, new ImportSpecifierList([])), $5); }), o('IMPORT { ImportSpecifierList OptComma } FROM String', function() { return new ImportDeclaration(new ImportClause(null, new ImportSpecifierList($3)), $7); }), o('IMPORT ImportDefaultSpecifier , ImportNamespaceSpecifier FROM String', function() { return new ImportDeclaration(new ImportClause($2, $4), $6); }), o('IMPORT ImportDefaultSpecifier , { ImportSpecifierList OptComma } FROM String', function() { return new ImportDeclaration(new ImportClause($2, new ImportSpecifierList($5)), $9); }) ], ImportSpecifierList: [ o('ImportSpecifier', function() { return [$1]; }), o('ImportSpecifierList , ImportSpecifier', function() { return $1.concat($3); }), o('ImportSpecifierList OptComma TERMINATOR ImportSpecifier', function() { return $1.concat($4); }), o('INDENT ImportSpecifierList OptComma OUTDENT', function() { return $2; }), o('ImportSpecifierList OptComma INDENT ImportSpecifierList OptComma OUTDENT', function() { return $1.concat($4); }) ], ImportSpecifier: [ o('Identifier', function() { return new ImportSpecifier($1); }), o('Identifier AS Identifier', function() { return new ImportSpecifier($1, $3); }), o('DEFAULT', function() { return new ImportSpecifier(new Literal($1)); }), o('DEFAULT AS Identifier', function() { return new ImportSpecifier(new Literal($1), $3); }) ], ImportDefaultSpecifier: [ o('Identifier', function() { return new ImportDefaultSpecifier($1); }) ], ImportNamespaceSpecifier: [ o('IMPORT_ALL AS Identifier', function() { return new ImportNamespaceSpecifier(new Literal($1), $3); }) ], Export: [ o('EXPORT { }', function() { return new ExportNamedDeclaration(new ExportSpecifierList([])); }), o('EXPORT { ExportSpecifierList OptComma }', function() { return new ExportNamedDeclaration(new ExportSpecifierList($3)); }), o('EXPORT Class', function() { return new ExportNamedDeclaration($2); }), o('EXPORT Identifier = Expression', function() { return new ExportNamedDeclaration(new Assign($2, $4, null, { moduleDeclaration: 'export' })); }), o('EXPORT Identifier = TERMINATOR Expression', function() { return new ExportNamedDeclaration(new Assign($2, $5, null, { moduleDeclaration: 'export' })); }), o('EXPORT Identifier = INDENT Expression OUTDENT', function() { return new ExportNamedDeclaration(new Assign($2, $5, null, { moduleDeclaration: 'export' })); }), o('EXPORT DEFAULT Expression', function() { return new ExportDefaultDeclaration($3); }), o('EXPORT EXPORT_ALL FROM String', function() { return new ExportAllDeclaration(new Literal($2), $4); }), o('EXPORT { ExportSpecifierList OptComma } FROM String', function() { return new ExportNamedDeclaration(new ExportSpecifierList($3), $7); }) ], ExportSpecifierList: [ o('ExportSpecifier', function() { return [$1]; }), o('ExportSpecifierList , ExportSpecifier', function() { return $1.concat($3); }), o('ExportSpecifierList OptComma TERMINATOR ExportSpecifier', function() { return $1.concat($4); }), o('INDENT ExportSpecifierList OptComma OUTDENT', function() { return $2; }), o('ExportSpecifierList OptComma INDENT ExportSpecifierList OptComma OUTDENT', function() { return $1.concat($4); }) ], ExportSpecifier: [ o('Identifier', function() { return new ExportSpecifier($1); }), o('Identifier AS Identifier', function() { return new ExportSpecifier($1, $3); }), o('Identifier AS DEFAULT', function() { return new ExportSpecifier($1, new Literal($3)); }), o('DEFAULT', function() { return new ExportSpecifier(new Literal($1)); }), o('DEFAULT AS Identifier', function() { return new ExportSpecifier(new Literal($1), $3); }) ], Invocation: [ o('Value OptFuncExist String', function() { return new TaggedTemplateCall($1, $3, $2); }), o('Value OptFuncExist Arguments', function() { return new Call($1, $3, $2); }), o('Invocation OptFuncExist Arguments', function() { return new Call($1, $3, $2); }), o('Super') ], Super: [ o('SUPER', function() { return new SuperCall; }), o('SUPER Arguments', function() { return new SuperCall($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 ThisLiteral); }), o('@', function() { return new Value(new ThisLiteral); }) ], ThisProperty: [ o('@ Property', function() { return new Value(LOC(1)(new ThisLiteral), [LOC(2)(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'), o('...', function() { return new Expansion; }) ], 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]; }), o('CATCH Object Block', function() { return [LOC(2)(new Value($2)), $3]; }), o('CATCH Block', function() { return [null, $2]; }) ], 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(LOC(1)(Block.wrap([$1]))); }), o('Expression WhileSource', function() { return $2.addBody(LOC(1)(Block.wrap([$1]))); }), o('Loop', function() { return $1; }) ], Loop: [ o('LOOP Block', function() { return new While(LOC(1)(new BooleanLiteral('true'))).addBody($2); }), o('LOOP Expression', function() { return new While(LOC(1)(new BooleanLiteral('true'))).addBody(LOC(2)(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: LOC(2)(new Value($2)) }; }), o('FOR Range BY Expression', function() { return { source: LOC(2)(new Value($2)), step: $4 }; }), o('ForStart ForSource', function() { $2.own = $1.own; $2.ownTag = $1.ownTag; $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; $3.ownTag = LOC(2)(new Literal($2)); 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 }; }), o('FORFROM Expression', function() { return { source: $2, from: true }; }), o('FORFROM Expression WHEN Expression', function() { return { source: $2, guard: $4, from: true }; }) ], 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(LOC(3, 5)(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, LOC(1)(Block.wrap([$1])), { type: $2, statement: true }); }), o('Expression POST_IF Expression', function() { return new If($3, LOC(1)(Block.wrap([$1])), { type: $2, statement: true }); }) ], Operation: [ o('UNARY Expression', function() { return new Op($1, $2); }), o('UNARY_MATH Expression', function() { return new Op($1, $2); }), o('- Expression', (function() { return new Op('-', $2); }), { prec: 'UNARY_MATH' }), o('+ Expression', (function() { return new Op('+', $2); }), { prec: 'UNARY_MATH' }), 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 ** 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 & Expression', function() { return new Op($2, $1, $3); }), o('Expression ^ Expression', function() { return new Op($2, $1, $3); }), o('Expression | Expression', function() { return new Op($2, $1, $3); }), o('Expression && Expression', function() { return new Op($2, $1, $3); }), o('Expression || Expression', function() { return new Op($2, $1, $3); }), o('Expression BIN? 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 COMPOUND_ASSIGN TERMINATOR Expression', 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'], ['right', '**'], ['right', 'UNARY_MATH'], ['left', 'MATH'], ['left', '+', '-'], ['left', 'SHIFT'], ['left', 'RELATION'], ['left', 'COMPARE'], ['left', '&'], ['left', '^'], ['left', '|'], ['left', '&&'], ['left', '||'], ['left', 'BIN?'], ['nonassoc', 'INDENT', 'OUTDENT'], ['right', 'YIELD'], ['right', '=', ':', 'COMPOUND_ASSIGN', 'RETURN', 'THROW', 'EXTENDS'], ['right', 'FORIN', 'FOROF', 'FORFROM', 'BY', 'WHEN'], ['right', 'IF', 'ELSE', 'FOR', 'WHILE', 'UNTIL', 'LOOP', 'SUPER', 'CLASS', 'IMPORT', 'EXPORT'], ['left', '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); coffeescript-1.12.7/lib/coffee-script/helpers.js000066400000000000000000000154311313305734200215620ustar00rootroot00000000000000// Generated by CoffeeScript 1.12.7 (function() { var buildLocationData, extend, flatten, ref, repeat, syntaxErrorToString; 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.repeat = repeat = function(str, n) { var res; res = ''; while (n > 0) { if (n & 1) { res += str; } n >>>= 1; str += str; } return res; }; exports.compact = function(array) { var i, item, len1, results; results = []; for (i = 0, len1 = array.length; i < len1; 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, len1; flattened = []; for (i = 0, len1 = array.length; i < len1; i++) { element = array[i]; if ('[object Array]' === Object.prototype.toString.call(element)) { 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.some = (ref = Array.prototype.some) != null ? ref : function(fn) { var e, i, len1, ref1; ref1 = this; for (i = 0, len1 = ref1.length; i < len1; i++) { e = ref1[i]; if (fn(e)) { return true; } } return false; }; exports.invertLiterate = function(code) { var line, lines, maybe_code; maybe_code = true; lines = (function() { var i, len1, ref1, results; ref1 = code.split('\n'); results = []; for (i = 0, len1 = ref1.length; i < len1; i++) { line = ref1[i]; if (maybe_code && /^([ ]{4}|[ ]{0,3}\t)/.test(line)) { results.push(line); } else if (maybe_code = /^\s*$/.test(line)) { results.push(line); } else { results.push('# ' + line); } } return results; })(); return lines.join('\n'); }; buildLocationData = function(first, last) { if (!last) { return first; } else { return { first_line: first.first_line, first_column: first.first_column, last_line: last.last_line, last_column: last.last_column }; } }; exports.addLocationDataFn = function(first, last) { return function(obj) { if (((typeof obj) === 'object') && (!!obj['updateLocationDataIfMissing'])) { obj.updateLocationDataIfMissing(buildLocationData(first, last)); } return obj; }; }; exports.locationDataToString = function(obj) { var locationData; if (("2" in obj) && ("first_line" in obj[2])) { locationData = obj[2]; } else if ("first_line" in obj) { locationData = obj; } if (locationData) { return ((locationData.first_line + 1) + ":" + (locationData.first_column + 1) + "-") + ((locationData.last_line + 1) + ":" + (locationData.last_column + 1)); } else { return "No location data"; } }; exports.baseFileName = function(file, stripExt, useWinPathSep) { var parts, pathSep; if (stripExt == null) { stripExt = false; } if (useWinPathSep == null) { useWinPathSep = false; } pathSep = useWinPathSep ? /\\|\// : /\//; parts = file.split(pathSep); file = parts[parts.length - 1]; if (!(stripExt && file.indexOf('.') >= 0)) { return file; } parts = file.split('.'); parts.pop(); if (parts[parts.length - 1] === 'coffee' && parts.length > 1) { parts.pop(); } return parts.join('.'); }; exports.isCoffee = function(file) { return /\.((lit)?coffee|coffee\.md)$/.test(file); }; exports.isLiterate = function(file) { return /\.(litcoffee|coffee\.md)$/.test(file); }; exports.throwSyntaxError = function(message, location) { var error; error = new SyntaxError(message); error.location = location; error.toString = syntaxErrorToString; error.stack = error.toString(); throw error; }; exports.updateSyntaxError = function(error, code, filename) { if (error.toString === syntaxErrorToString) { error.code || (error.code = code); error.filename || (error.filename = filename); error.stack = error.toString(); } return error; }; syntaxErrorToString = function() { var codeLine, colorize, colorsEnabled, end, filename, first_column, first_line, last_column, last_line, marker, ref1, ref2, ref3, ref4, start; if (!(this.code && this.location)) { return Error.prototype.toString.call(this); } ref1 = this.location, first_line = ref1.first_line, first_column = ref1.first_column, last_line = ref1.last_line, last_column = ref1.last_column; if (last_line == null) { last_line = first_line; } if (last_column == null) { last_column = first_column; } filename = this.filename || '[stdin]'; codeLine = this.code.split('\n')[first_line]; start = first_column; end = first_line === last_line ? last_column + 1 : codeLine.length; marker = codeLine.slice(0, start).replace(/[^\s]/g, ' ') + repeat('^', end - start); if (typeof process !== "undefined" && process !== null) { colorsEnabled = ((ref2 = process.stdout) != null ? ref2.isTTY : void 0) && !((ref3 = process.env) != null ? ref3.NODE_DISABLE_COLORS : void 0); } if ((ref4 = this.colorful) != null ? ref4 : colorsEnabled) { colorize = function(str) { return "\x1B[1;31m" + str + "\x1B[0m"; }; codeLine = codeLine.slice(0, start) + colorize(codeLine.slice(start, end)) + codeLine.slice(end); marker = colorize(marker); } return filename + ":" + (first_line + 1) + ":" + (first_column + 1) + ": error: " + this.message + "\n" + codeLine + "\n" + marker; }; exports.nameWhitespaceCharacter = function(string) { switch (string) { case ' ': return 'space'; case '\n': return 'newline'; case '\r': return 'carriage return'; case '\t': return 'tab'; default: return string; } }; }).call(this); coffeescript-1.12.7/lib/coffee-script/index.js000066400000000000000000000003011313305734200212150ustar00rootroot00000000000000// Generated by CoffeeScript 1.12.7 (function() { var key, ref, val; ref = require('./coffee-script'); for (key in ref) { val = ref[key]; exports[key] = val; } }).call(this); coffeescript-1.12.7/lib/coffee-script/lexer.js000066400000000000000000001166361313305734200212500ustar00rootroot00000000000000// Generated by CoffeeScript 1.12.7 (function() { var BOM, BOOL, CALLABLE, CODE, COFFEE_ALIASES, COFFEE_ALIAS_MAP, COFFEE_KEYWORDS, COMMENT, COMPARE, COMPOUND_ASSIGN, HERECOMMENT_ILLEGAL, HEREDOC_DOUBLE, HEREDOC_INDENT, HEREDOC_SINGLE, HEREGEX, HEREGEX_OMIT, HERE_JSTOKEN, IDENTIFIER, INDENTABLE_CLOSERS, INDEXABLE, INVERSES, JSTOKEN, JS_KEYWORDS, LEADING_BLANK_LINE, LINE_BREAK, LINE_CONTINUER, Lexer, MATH, MULTI_DENT, NOT_REGEX, NUMBER, OPERATOR, POSSIBLY_DIVISION, REGEX, REGEX_FLAGS, REGEX_ILLEGAL, REGEX_INVALID_ESCAPE, RELATION, RESERVED, Rewriter, SHIFT, SIMPLE_STRING_OMIT, STRICT_PROSCRIBED, STRING_DOUBLE, STRING_INVALID_ESCAPE, STRING_OMIT, STRING_SINGLE, STRING_START, TRAILING_BLANK_LINE, TRAILING_SPACES, UNARY, UNARY_MATH, UNFINISHED, UNICODE_CODE_POINT_ESCAPE, VALID_FLAGS, WHITESPACE, compact, count, invertLiterate, isForFrom, isUnassignable, key, locationDataToString, ref, ref1, repeat, starts, throwSyntaxError, 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; ref = require('./rewriter'), Rewriter = ref.Rewriter, INVERSES = ref.INVERSES; ref1 = require('./helpers'), count = ref1.count, starts = ref1.starts, compact = ref1.compact, repeat = ref1.repeat, invertLiterate = ref1.invertLiterate, locationDataToString = ref1.locationDataToString, throwSyntaxError = ref1.throwSyntaxError; exports.Lexer = Lexer = (function() { function Lexer() {} Lexer.prototype.tokenize = function(code, opts) { var consumed, end, i, ref2; if (opts == null) { opts = {}; } this.literate = opts.literate; this.indent = 0; this.baseIndent = 0; this.indebt = 0; this.outdebt = 0; this.indents = []; this.ends = []; this.tokens = []; this.seenFor = false; this.seenImport = false; this.seenExport = false; this.importSpecifierList = false; this.exportSpecifierList = false; this.chunkLine = opts.line || 0; this.chunkColumn = opts.column || 0; code = this.clean(code); i = 0; while (this.chunk = code.slice(i)) { consumed = this.identifierToken() || this.commentToken() || this.whitespaceToken() || this.lineToken() || this.stringToken() || this.numberToken() || this.regexToken() || this.jsToken() || this.literalToken(); ref2 = this.getLineAndColumnFromChunk(consumed), this.chunkLine = ref2[0], this.chunkColumn = ref2[1]; i += consumed; if (opts.untilBalanced && this.ends.length === 0) { return { tokens: this.tokens, index: i }; } } this.closeIndentation(); if (end = this.ends.pop()) { this.error("missing " + end.tag, end.origin[2]); } if (opts.rewrite === false) { return this.tokens; } return (new Rewriter).rewrite(this.tokens); }; Lexer.prototype.clean = function(code) { if (code.charCodeAt(0) === BOM) { code = code.slice(1); } code = code.replace(/\r/g, '').replace(TRAILING_SPACES, ''); if (WHITESPACE.test(code)) { code = "\n" + code; this.chunkLine--; } if (this.literate) { code = invertLiterate(code); } return code; }; Lexer.prototype.identifierToken = function() { var alias, colon, colonOffset, id, idLength, input, match, poppedToken, prev, ref2, ref3, ref4, ref5, ref6, ref7, ref8, ref9, tag, tagToken; if (!(match = IDENTIFIER.exec(this.chunk))) { return 0; } input = match[0], id = match[1], colon = match[2]; idLength = id.length; poppedToken = void 0; if (id === 'own' && this.tag() === 'FOR') { this.token('OWN', id); return id.length; } if (id === 'from' && this.tag() === 'YIELD') { this.token('FROM', id); return id.length; } if (id === 'as' && this.seenImport) { if (this.value() === '*') { this.tokens[this.tokens.length - 1][0] = 'IMPORT_ALL'; } else if (ref2 = this.value(), indexOf.call(COFFEE_KEYWORDS, ref2) >= 0) { this.tokens[this.tokens.length - 1][0] = 'IDENTIFIER'; } if ((ref3 = this.tag()) === 'DEFAULT' || ref3 === 'IMPORT_ALL' || ref3 === 'IDENTIFIER') { this.token('AS', id); return id.length; } } if (id === 'as' && this.seenExport && ((ref4 = this.tag()) === 'IDENTIFIER' || ref4 === 'DEFAULT')) { this.token('AS', id); return id.length; } if (id === 'default' && this.seenExport && ((ref5 = this.tag()) === 'EXPORT' || ref5 === 'AS')) { this.token('DEFAULT', id); return id.length; } ref6 = this.tokens, prev = ref6[ref6.length - 1]; tag = colon || (prev != null) && (((ref7 = prev[0]) === '.' || ref7 === '?.' || ref7 === '::' || ref7 === '?::') || !prev.spaced && prev[0] === '@') ? 'PROPERTY' : 'IDENTIFIER'; if (tag === 'IDENTIFIER' && (indexOf.call(JS_KEYWORDS, id) >= 0 || indexOf.call(COFFEE_KEYWORDS, id) >= 0) && !(this.exportSpecifierList && indexOf.call(COFFEE_KEYWORDS, id) >= 0)) { tag = id.toUpperCase(); if (tag === 'WHEN' && (ref8 = this.tag(), indexOf.call(LINE_BREAK, ref8) >= 0)) { tag = 'LEADING_WHEN'; } else if (tag === 'FOR') { this.seenFor = true; } else if (tag === 'UNLESS') { tag = 'IF'; } else if (tag === 'IMPORT') { this.seenImport = true; } else if (tag === 'EXPORT') { this.seenExport = true; } 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() === '!') { poppedToken = this.tokens.pop(); id = '!' + id; } } } } else if (tag === 'IDENTIFIER' && this.seenFor && id === 'from' && isForFrom(prev)) { tag = 'FORFROM'; this.seenFor = false; } if (tag === 'IDENTIFIER' && indexOf.call(RESERVED, id) >= 0) { this.error("reserved word '" + id + "'", { length: id.length }); } if (tag !== 'PROPERTY') { if (indexOf.call(COFFEE_ALIASES, id) >= 0) { alias = id; id = COFFEE_ALIAS_MAP[id]; } tag = (function() { switch (id) { case '!': return 'UNARY'; case '==': case '!=': return 'COMPARE'; case 'true': case 'false': return 'BOOL'; case 'break': case 'continue': case 'debugger': return 'STATEMENT'; case '&&': case '||': return id; default: return tag; } })(); } tagToken = this.token(tag, id, 0, idLength); if (alias) { tagToken.origin = [tag, alias, tagToken[2]]; } if (poppedToken) { ref9 = [poppedToken[2].first_line, poppedToken[2].first_column], tagToken[2].first_line = ref9[0], tagToken[2].first_column = ref9[1]; } if (colon) { colonOffset = input.lastIndexOf(':'); this.token(':', ':', colonOffset, colon.length); } return input.length; }; Lexer.prototype.numberToken = function() { var base, lexedLength, match, number, numberValue, ref2, tag; if (!(match = NUMBER.exec(this.chunk))) { return 0; } number = match[0]; lexedLength = number.length; switch (false) { case !/^0[BOX]/.test(number): this.error("radix prefix in '" + number + "' must be lowercase", { offset: 1 }); break; case !/^(?!0x).*E/.test(number): this.error("exponential notation in '" + number + "' must be indicated with a lowercase 'e'", { offset: number.indexOf('E') }); break; case !/^0\d*[89]/.test(number): this.error("decimal literal '" + number + "' must not be prefixed with '0'", { length: lexedLength }); break; case !/^0\d+/.test(number): this.error("octal literal '" + number + "' must be prefixed with '0o'", { length: lexedLength }); } base = (function() { switch (number.charAt(1)) { case 'b': return 2; case 'o': return 8; case 'x': return 16; default: return null; } })(); numberValue = base != null ? parseInt(number.slice(2), base) : parseFloat(number); if ((ref2 = number.charAt(1)) === 'b' || ref2 === 'o') { number = "0x" + (numberValue.toString(16)); } tag = numberValue === 2e308 ? 'INFINITY' : 'NUMBER'; this.token(tag, number, 0, lexedLength); return lexedLength; }; Lexer.prototype.stringToken = function() { var $, attempt, delimiter, doc, end, heredoc, i, indent, indentRegex, match, quote, ref2, ref3, regex, token, tokens; quote = (STRING_START.exec(this.chunk) || [])[0]; if (!quote) { return 0; } if (this.tokens.length && this.value() === 'from' && (this.seenImport || this.seenExport)) { this.tokens[this.tokens.length - 1][0] = 'FROM'; } regex = (function() { switch (quote) { case "'": return STRING_SINGLE; case '"': return STRING_DOUBLE; case "'''": return HEREDOC_SINGLE; case '"""': return HEREDOC_DOUBLE; } })(); heredoc = quote.length === 3; ref2 = this.matchWithInterpolations(regex, quote), tokens = ref2.tokens, end = ref2.index; $ = tokens.length - 1; delimiter = quote.charAt(0); if (heredoc) { indent = null; doc = ((function() { var j, len, results; results = []; for (i = j = 0, len = tokens.length; j < len; i = ++j) { token = tokens[i]; if (token[0] === 'NEOSTRING') { results.push(token[1]); } } return results; })()).join('#{}'); while (match = HEREDOC_INDENT.exec(doc)) { attempt = match[1]; if (indent === null || (0 < (ref3 = attempt.length) && ref3 < indent.length)) { indent = attempt; } } if (indent) { indentRegex = RegExp("\\n" + indent, "g"); } this.mergeInterpolationTokens(tokens, { delimiter: delimiter }, (function(_this) { return function(value, i) { value = _this.formatString(value, { delimiter: quote }); if (indentRegex) { value = value.replace(indentRegex, '\n'); } if (i === 0) { value = value.replace(LEADING_BLANK_LINE, ''); } if (i === $) { value = value.replace(TRAILING_BLANK_LINE, ''); } return value; }; })(this)); } else { this.mergeInterpolationTokens(tokens, { delimiter: delimiter }, (function(_this) { return function(value, i) { value = _this.formatString(value, { delimiter: quote }); value = value.replace(SIMPLE_STRING_OMIT, function(match, offset) { if ((i === 0 && offset === 0) || (i === $ && offset + match.length === value.length)) { return ''; } else { return ' '; } }); return value; }; })(this)); } return end; }; Lexer.prototype.commentToken = function() { var comment, here, match; if (!(match = this.chunk.match(COMMENT))) { return 0; } comment = match[0], here = match[1]; if (here) { if (match = HERECOMMENT_ILLEGAL.exec(comment)) { this.error("block comments cannot contain " + match[0], { offset: match.index, length: match[0].length }); } if (here.indexOf('\n') >= 0) { here = here.replace(RegExp("\\n" + (repeat(' ', this.indent)), "g"), '\n'); } this.token('HERECOMMENT', here, 0, comment.length); } return comment.length; }; Lexer.prototype.jsToken = function() { var match, script; if (!(this.chunk.charAt(0) === '`' && (match = HERE_JSTOKEN.exec(this.chunk) || JSTOKEN.exec(this.chunk)))) { return 0; } script = match[1].replace(/\\+(`|$)/g, function(string) { return string.slice(-Math.ceil(string.length / 2)); }); this.token('JS', script, 0, match[0].length); return match[0].length; }; Lexer.prototype.regexToken = function() { var body, closed, end, flags, index, match, origin, prev, ref2, ref3, ref4, regex, tokens; switch (false) { case !(match = REGEX_ILLEGAL.exec(this.chunk)): this.error("regular expressions cannot begin with " + match[2], { offset: match.index + match[1].length }); break; case !(match = this.matchWithInterpolations(HEREGEX, '///')): tokens = match.tokens, index = match.index; break; case !(match = REGEX.exec(this.chunk)): regex = match[0], body = match[1], closed = match[2]; this.validateEscapes(body, { isRegex: true, offsetInChunk: 1 }); body = this.formatRegex(body, { delimiter: '/' }); index = regex.length; ref2 = this.tokens, prev = ref2[ref2.length - 1]; if (prev) { if (prev.spaced && (ref3 = prev[0], indexOf.call(CALLABLE, ref3) >= 0)) { if (!closed || POSSIBLY_DIVISION.test(regex)) { return 0; } } else if (ref4 = prev[0], indexOf.call(NOT_REGEX, ref4) >= 0) { return 0; } } if (!closed) { this.error('missing / (unclosed regex)'); } break; default: return 0; } flags = REGEX_FLAGS.exec(this.chunk.slice(index))[0]; end = index + flags.length; origin = this.makeToken('REGEX', null, 0, end); switch (false) { case !!VALID_FLAGS.test(flags): this.error("invalid regular expression flags " + flags, { offset: index, length: flags.length }); break; case !(regex || tokens.length === 1): if (body == null) { body = this.formatHeregex(tokens[0][1]); } this.token('REGEX', "" + (this.makeDelimitedLiteral(body, { delimiter: '/' })) + flags, 0, end, origin); break; default: this.token('REGEX_START', '(', 0, 0, origin); this.token('IDENTIFIER', 'RegExp', 0, 0); this.token('CALL_START', '(', 0, 0); this.mergeInterpolationTokens(tokens, { delimiter: '"', double: true }, this.formatHeregex); if (flags) { this.token(',', ',', index - 1, 0); this.token('STRING', '"' + flags + '"', index - 1, flags.length); } this.token(')', ')', end - 1, 0); this.token('REGEX_END', ')', end - 1, 0); } return end; }; Lexer.prototype.lineToken = function() { var diff, indent, match, noNewlines, size; if (!(match = MULTI_DENT.exec(this.chunk))) { return 0; } indent = match[0]; this.seenFor = false; if (!this.importSpecifierList) { this.seenImport = false; } if (!this.exportSpecifierList) { this.seenExport = false; } size = indent.length - 1 - indent.lastIndexOf('\n'); noNewlines = this.unfinished(); if (size - this.indebt === this.indent) { if (noNewlines) { this.suppressNewlines(); } else { this.newlineToken(0); } return indent.length; } if (size > this.indent) { if (noNewlines) { this.indebt = size - this.indent; this.suppressNewlines(); return indent.length; } if (!this.tokens.length) { this.baseIndent = this.indent = size; return indent.length; } diff = size - this.indent + this.outdebt; this.token('INDENT', diff, indent.length - size, size); this.indents.push(diff); this.ends.push({ tag: 'OUTDENT' }); this.outdebt = this.indebt = 0; this.indent = size; } else if (size < this.baseIndent) { this.error('missing indentation', { offset: indent.length }); } else { this.indebt = 0; this.outdentToken(this.indent - size, noNewlines, indent.length); } return indent.length; }; Lexer.prototype.outdentToken = function(moveOut, noNewlines, outdentLength) { var decreasedIndent, dent, lastIndent, ref2; decreasedIndent = this.indent - moveOut; while (moveOut > 0) { lastIndent = this.indents[this.indents.length - 1]; if (!lastIndent) { moveOut = 0; } else if (lastIndent === this.outdebt) { moveOut -= this.outdebt; this.outdebt = 0; } else if (lastIndent < this.outdebt) { this.outdebt -= lastIndent; moveOut -= lastIndent; } else { dent = this.indents.pop() + this.outdebt; if (outdentLength && (ref2 = this.chunk[outdentLength], indexOf.call(INDENTABLE_CLOSERS, ref2) >= 0)) { decreasedIndent -= dent - moveOut; moveOut = dent; } this.outdebt = 0; this.pair('OUTDENT'); this.token('OUTDENT', moveOut, 0, outdentLength); moveOut -= dent; } } if (dent) { this.outdebt -= moveOut; } while (this.value() === ';') { this.tokens.pop(); } if (!(this.tag() === 'TERMINATOR' || noNewlines)) { this.token('TERMINATOR', '\n', outdentLength, 0); } this.indent = decreasedIndent; return this; }; Lexer.prototype.whitespaceToken = function() { var match, nline, prev, ref2; if (!((match = WHITESPACE.exec(this.chunk)) || (nline = this.chunk.charAt(0) === '\n'))) { return 0; } ref2 = this.tokens, prev = ref2[ref2.length - 1]; if (prev) { prev[match ? 'spaced' : 'newLine'] = true; } if (match) { return match[0].length; } else { return 0; } }; Lexer.prototype.newlineToken = function(offset) { while (this.value() === ';') { this.tokens.pop(); } if (this.tag() !== 'TERMINATOR') { this.token('TERMINATOR', '\n', offset, 0); } return this; }; Lexer.prototype.suppressNewlines = function() { if (this.value() === '\\') { this.tokens.pop(); } return this; }; Lexer.prototype.literalToken = function() { var match, message, origin, prev, ref2, ref3, ref4, ref5, ref6, skipToken, tag, token, value; if (match = OPERATOR.exec(this.chunk)) { value = match[0]; if (CODE.test(value)) { this.tagParameters(); } } else { value = this.chunk.charAt(0); } tag = value; ref2 = this.tokens, prev = ref2[ref2.length - 1]; if (prev && indexOf.call(['='].concat(slice.call(COMPOUND_ASSIGN)), value) >= 0) { skipToken = false; if (value === '=' && ((ref3 = prev[1]) === '||' || ref3 === '&&') && !prev.spaced) { prev[0] = 'COMPOUND_ASSIGN'; prev[1] += '='; prev = this.tokens[this.tokens.length - 2]; skipToken = true; } if (prev && prev[0] !== 'PROPERTY') { origin = (ref4 = prev.origin) != null ? ref4 : prev; message = isUnassignable(prev[1], origin[1]); if (message) { this.error(message, origin[2]); } } if (skipToken) { return value.length; } } if (value === '{' && this.seenImport) { this.importSpecifierList = true; } else if (this.importSpecifierList && value === '}') { this.importSpecifierList = false; } else if (value === '{' && (prev != null ? prev[0] : void 0) === 'EXPORT') { this.exportSpecifierList = true; } else if (this.exportSpecifierList && value === '}') { this.exportSpecifierList = false; } if (value === ';') { this.seenFor = this.seenImport = this.seenExport = false; tag = 'TERMINATOR'; } else if (value === '*' && prev[0] === 'EXPORT') { tag = 'EXPORT_ALL'; } 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(UNARY_MATH, value) >= 0) { tag = 'UNARY_MATH'; } else if (indexOf.call(SHIFT, value) >= 0) { tag = 'SHIFT'; } else if (value === '?' && (prev != null ? prev.spaced : void 0)) { tag = 'BIN?'; } else if (prev && !prev.spaced) { if (value === '(' && (ref5 = prev[0], indexOf.call(CALLABLE, ref5) >= 0)) { if (prev[0] === '?') { prev[0] = 'FUNC_EXIST'; } tag = 'CALL_START'; } else if (value === '[' && (ref6 = prev[0], indexOf.call(INDEXABLE, ref6) >= 0)) { tag = 'INDEX_START'; switch (prev[0]) { case '?': prev[0] = 'INDEX_SOAK'; } } } token = this.makeToken(tag, value); switch (value) { case '(': case '{': case '[': this.ends.push({ tag: INVERSES[value], origin: token }); break; case ')': case '}': case ']': this.pair(value); } this.tokens.push(token); return value.length; }; 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.matchWithInterpolations = function(regex, delimiter) { var close, column, firstToken, index, lastToken, line, nested, offsetInChunk, open, ref2, ref3, ref4, str, strPart, tokens; tokens = []; offsetInChunk = delimiter.length; if (this.chunk.slice(0, offsetInChunk) !== delimiter) { return null; } str = this.chunk.slice(offsetInChunk); while (true) { strPart = regex.exec(str)[0]; this.validateEscapes(strPart, { isRegex: delimiter.charAt(0) === '/', offsetInChunk: offsetInChunk }); tokens.push(this.makeToken('NEOSTRING', strPart, offsetInChunk)); str = str.slice(strPart.length); offsetInChunk += strPart.length; if (str.slice(0, 2) !== '#{') { break; } ref2 = this.getLineAndColumnFromChunk(offsetInChunk + 1), line = ref2[0], column = ref2[1]; ref3 = new Lexer().tokenize(str.slice(1), { line: line, column: column, untilBalanced: true }), nested = ref3.tokens, index = ref3.index; index += 1; open = nested[0], close = nested[nested.length - 1]; open[0] = open[1] = '('; close[0] = close[1] = ')'; close.origin = ['', 'end of interpolation', close[2]]; if (((ref4 = nested[1]) != null ? ref4[0] : void 0) === 'TERMINATOR') { nested.splice(1, 1); } tokens.push(['TOKENS', nested]); str = str.slice(index); offsetInChunk += index; } if (str.slice(0, delimiter.length) !== delimiter) { this.error("missing " + delimiter, { length: delimiter.length }); } firstToken = tokens[0], lastToken = tokens[tokens.length - 1]; firstToken[2].first_column -= delimiter.length; if (lastToken[1].substr(-1) === '\n') { lastToken[2].last_line += 1; lastToken[2].last_column = delimiter.length - 1; } else { lastToken[2].last_column += delimiter.length; } if (lastToken[1].length === 0) { lastToken[2].last_column -= 1; } return { tokens: tokens, index: offsetInChunk + delimiter.length }; }; Lexer.prototype.mergeInterpolationTokens = function(tokens, options, fn) { var converted, firstEmptyStringIndex, firstIndex, i, j, lastToken, len, locationToken, lparen, plusToken, ref2, rparen, tag, token, tokensToPush, value; if (tokens.length > 1) { lparen = this.token('STRING_START', '(', 0, 0); } firstIndex = this.tokens.length; for (i = j = 0, len = tokens.length; j < len; i = ++j) { token = tokens[i]; tag = token[0], value = token[1]; switch (tag) { case 'TOKENS': if (value.length === 2) { continue; } locationToken = value[0]; tokensToPush = value; break; case 'NEOSTRING': converted = fn.call(this, token[1], i); if (converted.length === 0) { if (i === 0) { firstEmptyStringIndex = this.tokens.length; } else { continue; } } if (i === 2 && (firstEmptyStringIndex != null)) { this.tokens.splice(firstEmptyStringIndex, 2); } token[0] = 'STRING'; token[1] = this.makeDelimitedLiteral(converted, options); locationToken = token; tokensToPush = [token]; } if (this.tokens.length > firstIndex) { plusToken = this.token('+', '+'); plusToken[2] = { first_line: locationToken[2].first_line, first_column: locationToken[2].first_column, last_line: locationToken[2].first_line, last_column: locationToken[2].first_column }; } (ref2 = this.tokens).push.apply(ref2, tokensToPush); } if (lparen) { lastToken = tokens[tokens.length - 1]; lparen.origin = [ 'STRING', null, { first_line: lparen[2].first_line, first_column: lparen[2].first_column, last_line: lastToken[2].last_line, last_column: lastToken[2].last_column } ]; rparen = this.token('STRING_END', ')'); return rparen[2] = { first_line: lastToken[2].last_line, first_column: lastToken[2].last_column, last_line: lastToken[2].last_line, last_column: lastToken[2].last_column }; } }; Lexer.prototype.pair = function(tag) { var lastIndent, prev, ref2, ref3, wanted; ref2 = this.ends, prev = ref2[ref2.length - 1]; if (tag !== (wanted = prev != null ? prev.tag : void 0)) { if ('OUTDENT' !== wanted) { this.error("unmatched " + tag); } ref3 = this.indents, lastIndent = ref3[ref3.length - 1]; this.outdentToken(lastIndent, true); return this.pair(tag); } return this.ends.pop(); }; Lexer.prototype.getLineAndColumnFromChunk = function(offset) { var column, lastLine, lineCount, ref2, string; if (offset === 0) { return [this.chunkLine, this.chunkColumn]; } if (offset >= this.chunk.length) { string = this.chunk; } else { string = this.chunk.slice(0, +(offset - 1) + 1 || 9e9); } lineCount = count(string, '\n'); column = this.chunkColumn; if (lineCount > 0) { ref2 = string.split('\n'), lastLine = ref2[ref2.length - 1]; column = lastLine.length; } else { column += string.length; } return [this.chunkLine + lineCount, column]; }; Lexer.prototype.makeToken = function(tag, value, offsetInChunk, length) { var lastCharacter, locationData, ref2, ref3, token; if (offsetInChunk == null) { offsetInChunk = 0; } if (length == null) { length = value.length; } locationData = {}; ref2 = this.getLineAndColumnFromChunk(offsetInChunk), locationData.first_line = ref2[0], locationData.first_column = ref2[1]; lastCharacter = length > 0 ? length - 1 : 0; ref3 = this.getLineAndColumnFromChunk(offsetInChunk + lastCharacter), locationData.last_line = ref3[0], locationData.last_column = ref3[1]; token = [tag, value, locationData]; return token; }; Lexer.prototype.token = function(tag, value, offsetInChunk, length, origin) { var token; token = this.makeToken(tag, value, offsetInChunk, length); if (origin) { token.origin = origin; } this.tokens.push(token); return token; }; Lexer.prototype.tag = function() { var ref2, token; ref2 = this.tokens, token = ref2[ref2.length - 1]; return token != null ? token[0] : void 0; }; Lexer.prototype.value = function() { var ref2, token; ref2 = this.tokens, token = ref2[ref2.length - 1]; return token != null ? token[1] : void 0; }; Lexer.prototype.unfinished = function() { var ref2; return LINE_CONTINUER.test(this.chunk) || (ref2 = this.tag(), indexOf.call(UNFINISHED, ref2) >= 0); }; Lexer.prototype.formatString = function(str, options) { return this.replaceUnicodeCodePointEscapes(str.replace(STRING_OMIT, '$1'), options); }; Lexer.prototype.formatHeregex = function(str) { return this.formatRegex(str.replace(HEREGEX_OMIT, '$1$2'), { delimiter: '///' }); }; Lexer.prototype.formatRegex = function(str, options) { return this.replaceUnicodeCodePointEscapes(str, options); }; Lexer.prototype.unicodeCodePointToUnicodeEscapes = function(codePoint) { var high, low, toUnicodeEscape; toUnicodeEscape = function(val) { var str; str = val.toString(16); return "\\u" + (repeat('0', 4 - str.length)) + str; }; if (codePoint < 0x10000) { return toUnicodeEscape(codePoint); } high = Math.floor((codePoint - 0x10000) / 0x400) + 0xD800; low = (codePoint - 0x10000) % 0x400 + 0xDC00; return "" + (toUnicodeEscape(high)) + (toUnicodeEscape(low)); }; Lexer.prototype.replaceUnicodeCodePointEscapes = function(str, options) { return str.replace(UNICODE_CODE_POINT_ESCAPE, (function(_this) { return function(match, escapedBackslash, codePointHex, offset) { var codePointDecimal; if (escapedBackslash) { return escapedBackslash; } codePointDecimal = parseInt(codePointHex, 16); if (codePointDecimal > 0x10ffff) { _this.error("unicode code point escapes greater than \\u{10ffff} are not allowed", { offset: offset + options.delimiter.length, length: codePointHex.length + 4 }); } return _this.unicodeCodePointToUnicodeEscapes(codePointDecimal); }; })(this)); }; Lexer.prototype.validateEscapes = function(str, options) { var before, hex, invalidEscape, invalidEscapeRegex, match, message, octal, ref2, unicode, unicodeCodePoint; if (options == null) { options = {}; } invalidEscapeRegex = options.isRegex ? REGEX_INVALID_ESCAPE : STRING_INVALID_ESCAPE; match = invalidEscapeRegex.exec(str); if (!match) { return; } match[0], before = match[1], octal = match[2], hex = match[3], unicodeCodePoint = match[4], unicode = match[5]; message = octal ? "octal escape sequences are not allowed" : "invalid escape sequence"; invalidEscape = "\\" + (octal || hex || unicodeCodePoint || unicode); return this.error(message + " " + invalidEscape, { offset: ((ref2 = options.offsetInChunk) != null ? ref2 : 0) + match.index + before.length, length: invalidEscape.length }); }; Lexer.prototype.makeDelimitedLiteral = function(body, options) { var regex; if (options == null) { options = {}; } if (body === '' && options.delimiter === '/') { body = '(?:)'; } regex = RegExp("(\\\\\\\\)|(\\\\0(?=[1-7]))|\\\\?(" + options.delimiter + ")|\\\\?(?:(\\n)|(\\r)|(\\u2028)|(\\u2029))|(\\\\.)", "g"); body = body.replace(regex, function(match, backslash, nul, delimiter, lf, cr, ls, ps, other) { switch (false) { case !backslash: if (options.double) { return backslash + backslash; } else { return backslash; } case !nul: return '\\x00'; case !delimiter: return "\\" + delimiter; case !lf: return '\\n'; case !cr: return '\\r'; case !ls: return '\\u2028'; case !ps: return '\\u2029'; case !other: if (options.double) { return "\\" + other; } else { return other; } } }); return "" + options.delimiter + body + options.delimiter; }; Lexer.prototype.error = function(message, options) { var first_column, first_line, location, ref2, ref3, ref4; if (options == null) { options = {}; } location = 'first_line' in options ? options : ((ref3 = this.getLineAndColumnFromChunk((ref2 = options.offset) != null ? ref2 : 0), first_line = ref3[0], first_column = ref3[1], ref3), { first_line: first_line, first_column: first_column, last_column: first_column + ((ref4 = options.length) != null ? ref4 : 1) - 1 }); return throwSyntaxError(message, location); }; return Lexer; })(); isUnassignable = function(name, displayName) { if (displayName == null) { displayName = name; } switch (false) { case indexOf.call(slice.call(JS_KEYWORDS).concat(slice.call(COFFEE_KEYWORDS)), name) < 0: return "keyword '" + displayName + "' can't be assigned"; case indexOf.call(STRICT_PROSCRIBED, name) < 0: return "'" + displayName + "' can't be assigned"; case indexOf.call(RESERVED, name) < 0: return "reserved word '" + displayName + "' can't be assigned"; default: return false; } }; exports.isUnassignable = isUnassignable; isForFrom = function(prev) { var ref2; if (prev[0] === 'IDENTIFIER') { if (prev[1] === 'from') { prev[1][0] = 'IDENTIFIER'; true; } return true; } else if (prev[0] === 'FOR') { return false; } else if ((ref2 = prev[1]) === '{' || ref2 === '[' || ref2 === ',' || ref2 === ':') { return false; } else { return true; } }; JS_KEYWORDS = ['true', 'false', 'null', 'this', 'new', 'delete', 'typeof', 'in', 'instanceof', 'return', 'throw', 'break', 'continue', 'debugger', 'yield', 'if', 'else', 'switch', 'for', 'while', 'do', 'try', 'catch', 'finally', 'class', 'extends', 'super', 'import', 'export', 'default']; COFFEE_KEYWORDS = ['undefined', 'Infinity', 'NaN', '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', 'function', 'var', 'void', 'with', 'const', 'let', 'enum', 'native', 'implements', 'interface', 'package', 'private', 'protected', 'public', 'static']; STRICT_PROSCRIBED = ['arguments', 'eval']; exports.JS_FORBIDDEN = JS_KEYWORDS.concat(RESERVED).concat(STRICT_PROSCRIBED); BOM = 65279; IDENTIFIER = /^(?!\d)((?:(?!\s)[$\w\x7f-\uffff])+)([^\n\S]*:(?!:))?/; NUMBER = /^0b[01]+|^0o[0-7]+|^0x[\da-f]+|^\d*\.?\d+(?:e[+-]?\d+)?/i; OPERATOR = /^(?:[-=]>|[-+*\/%<>&|^!?=]=|>>>=?|([-+:])\1|([&|<>*\/%])\2=?|\?(\.|::)|\.{2,3})/; WHITESPACE = /^[^\n\S]+/; COMMENT = /^###([^#][\s\S]*?)(?:###[^\n\S]*|###$)|^(?:\s*#(?!##[^#]).*)+/; CODE = /^[-=]>/; MULTI_DENT = /^(?:\n[^\n\S]*)+/; JSTOKEN = /^`(?!``)((?:[^`\\]|\\[\s\S])*)`/; HERE_JSTOKEN = /^```((?:[^`\\]|\\[\s\S]|`(?!``))*)```/; STRING_START = /^(?:'''|"""|'|")/; STRING_SINGLE = /^(?:[^\\']|\\[\s\S])*/; STRING_DOUBLE = /^(?:[^\\"#]|\\[\s\S]|\#(?!\{))*/; HEREDOC_SINGLE = /^(?:[^\\']|\\[\s\S]|'(?!''))*/; HEREDOC_DOUBLE = /^(?:[^\\"#]|\\[\s\S]|"(?!"")|\#(?!\{))*/; STRING_OMIT = /((?:\\\\)+)|\\[^\S\n]*\n\s*/g; SIMPLE_STRING_OMIT = /\s*\n\s*/g; HEREDOC_INDENT = /\n+([^\n\S]*)(?=\S)/g; REGEX = /^\/(?!\/)((?:[^[\/\n\\]|\\[^\n]|\[(?:\\[^\n]|[^\]\n\\])*\])*)(\/)?/; REGEX_FLAGS = /^\w*/; VALID_FLAGS = /^(?!.*(.).*\1)[imguy]*$/; HEREGEX = /^(?:[^\\\/#]|\\[\s\S]|\/(?!\/\/)|\#(?!\{))*/; HEREGEX_OMIT = /((?:\\\\)+)|\\(\s)|\s+(?:#.*)?/g; REGEX_ILLEGAL = /^(\/|\/{3}\s*)(\*)/; POSSIBLY_DIVISION = /^\/=?\s/; HERECOMMENT_ILLEGAL = /\*\//; LINE_CONTINUER = /^\s*(?:,|\??\.(?![.\d])|::)/; STRING_INVALID_ESCAPE = /((?:^|[^\\])(?:\\\\)*)\\(?:(0[0-7]|[1-7])|(x(?![\da-fA-F]{2}).{0,2})|(u\{(?![\da-fA-F]{1,}\})[^}]*\}?)|(u(?!\{|[\da-fA-F]{4}).{0,4}))/; REGEX_INVALID_ESCAPE = /((?:^|[^\\])(?:\\\\)*)\\(?:(0[0-7])|(x(?![\da-fA-F]{2}).{0,2})|(u\{(?![\da-fA-F]{1,}\})[^}]*\}?)|(u(?!\{|[\da-fA-F]{4}).{0,4}))/; UNICODE_CODE_POINT_ESCAPE = /(\\\\)|\\u\{([\da-fA-F]+)\}/g; LEADING_BLANK_LINE = /^[^\n\S]*\n/; TRAILING_BLANK_LINE = /\n[^\n\S]*$/; TRAILING_SPACES = /\s+$/; COMPOUND_ASSIGN = ['-=', '+=', '/=', '*=', '%=', '||=', '&&=', '?=', '<<=', '>>=', '>>>=', '&=', '^=', '|=', '**=', '//=', '%%=']; UNARY = ['NEW', 'TYPEOF', 'DELETE', 'DO']; UNARY_MATH = ['!', '~']; SHIFT = ['<<', '>>', '>>>']; COMPARE = ['==', '!=', '<', '>', '<=', '>=']; MATH = ['*', '/', '%', '//', '%%']; RELATION = ['IN', 'OF', 'INSTANCEOF']; BOOL = ['TRUE', 'FALSE']; CALLABLE = ['IDENTIFIER', 'PROPERTY', ')', ']', '?', '@', 'THIS', 'SUPER']; INDEXABLE = CALLABLE.concat(['NUMBER', 'INFINITY', 'NAN', 'STRING', 'STRING_END', 'REGEX', 'REGEX_END', 'BOOL', 'NULL', 'UNDEFINED', '}', '::']); NOT_REGEX = INDEXABLE.concat(['++', '--']); LINE_BREAK = ['INDENT', 'OUTDENT', 'TERMINATOR']; INDENTABLE_CLOSERS = [')', '}', ']']; UNFINISHED = ['\\', '.', '?.', '?::', 'UNARY', 'MATH', 'UNARY_MATH', '+', '-', '**', 'SHIFT', 'RELATION', 'COMPARE', '&', '^', '|', '&&', '||', 'BIN?', 'THROW', 'EXTENDS', 'DEFAULT']; }).call(this); coffeescript-1.12.7/lib/coffee-script/nodes.js000066400000000000000000003752051313305734200212400ustar00rootroot00000000000000// Generated by CoffeeScript 1.12.7 (function() { var Access, Arr, Assign, Base, Block, BooleanLiteral, Call, Class, Code, CodeFragment, Comment, Existence, Expansion, ExportAllDeclaration, ExportDeclaration, ExportDefaultDeclaration, ExportNamedDeclaration, ExportSpecifier, ExportSpecifierList, Extends, For, IdentifierLiteral, If, ImportClause, ImportDeclaration, ImportDefaultSpecifier, ImportNamespaceSpecifier, ImportSpecifier, ImportSpecifierList, In, Index, InfinityLiteral, JS_FORBIDDEN, LEVEL_ACCESS, LEVEL_COND, LEVEL_LIST, LEVEL_OP, LEVEL_PAREN, LEVEL_TOP, Literal, ModuleDeclaration, ModuleSpecifier, ModuleSpecifierList, NEGATE, NO, NaNLiteral, NullLiteral, NumberLiteral, Obj, Op, Param, Parens, PassthroughLiteral, PropertyName, Range, RegexLiteral, RegexWithInterpolations, Return, SIMPLENUM, Scope, Slice, Splat, StatementLiteral, StringLiteral, StringWithInterpolations, SuperCall, Switch, TAB, THIS, TaggedTemplateCall, ThisLiteral, Throw, Try, UTILITIES, UndefinedLiteral, Value, While, YES, YieldReturn, addLocationDataFn, compact, del, ends, extend, flatten, fragmentsToText, isComplexOrAssignable, isLiteralArguments, isLiteralThis, isUnassignable, locationDataToString, merge, multident, ref1, ref2, some, starts, throwSyntaxError, unfoldSoak, utility, extend1 = 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; }, hasProp = {}.hasOwnProperty, 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; Error.stackTraceLimit = 2e308; Scope = require('./scope').Scope; ref1 = require('./lexer'), isUnassignable = ref1.isUnassignable, JS_FORBIDDEN = ref1.JS_FORBIDDEN; ref2 = require('./helpers'), compact = ref2.compact, flatten = ref2.flatten, extend = ref2.extend, merge = ref2.merge, del = ref2.del, starts = ref2.starts, ends = ref2.ends, some = ref2.some, addLocationDataFn = ref2.addLocationDataFn, locationDataToString = ref2.locationDataToString, throwSyntaxError = ref2.throwSyntaxError; exports.extend = extend; exports.addLocationDataFn = addLocationDataFn; YES = function() { return true; }; NO = function() { return false; }; THIS = function() { return this; }; NEGATE = function() { this.negated = !this.negated; return this; }; exports.CodeFragment = CodeFragment = (function() { function CodeFragment(parent, code) { var ref3; this.code = "" + code; this.locationData = parent != null ? parent.locationData : void 0; this.type = (parent != null ? (ref3 = parent.constructor) != null ? ref3.name : void 0 : void 0) || 'unknown'; } CodeFragment.prototype.toString = function() { return "" + this.code + (this.locationData ? ": " + locationDataToString(this.locationData) : ''); }; return CodeFragment; })(); fragmentsToText = function(fragments) { var fragment; return ((function() { var j, len1, results; results = []; for (j = 0, len1 = fragments.length; j < len1; j++) { fragment = fragments[j]; results.push(fragment.code); } return results; })()).join(''); }; exports.Base = Base = (function() { function Base() {} Base.prototype.compile = function(o, lvl) { return fragmentsToText(this.compileToFragments(o, lvl)); }; Base.prototype.compileToFragments = 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) { var args, argumentsNode, func, jumpNode, meth, parts, ref3; if (jumpNode = this.jumps()) { jumpNode.error('cannot use a pure statement in an expression'); } o.sharedScope = true; func = new Code([], Block.wrap([this])); args = []; if ((argumentsNode = this.contains(isLiteralArguments)) || this.contains(isLiteralThis)) { args = [new ThisLiteral]; if (argumentsNode) { meth = 'apply'; args.push(new IdentifierLiteral('arguments')); } else { meth = 'call'; } func = new Value(func, [new Access(new PropertyName(meth))]); } parts = (new Call(func, args)).compileNode(o); if (func.isGenerator || ((ref3 = func.base) != null ? ref3.isGenerator : void 0)) { parts.unshift(this.makeCode("(yield* ")); parts.push(this.makeCode(")")); } return parts; }; Base.prototype.cache = function(o, level, isComplex) { var complex, ref, sub; complex = isComplex != null ? isComplex(this) : this.isComplex(); if (complex) { ref = new IdentifierLiteral(o.scope.freeVariable('ref')); sub = new Assign(ref, this); if (level) { return [sub.compileToFragments(o, level), [this.makeCode(ref.value)]]; } else { return [sub, ref]; } } else { ref = level ? this.compileToFragments(o, level) : this; return [ref, ref]; } }; Base.prototype.cacheToCodeFragments = function(cacheValues) { return [fragmentsToText(cacheValues[0]), fragmentsToText(cacheValues[1])]; }; 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 node; node = void 0; this.traverseChildren(false, function(n) { if (pred(n)) { node = n; return false; } }); return node; }; 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, j, k, len1, len2, ref3, ref4; if (!this.children) { return this; } ref3 = this.children; for (j = 0, len1 = ref3.length; j < len1; j++) { attr = ref3[j]; if (this[attr]) { ref4 = flatten([this[attr]]); for (k = 0, len2 = ref4.length; k < len2; k++) { child = ref4[k]; if (func(child) === false) { return this; } } } } return this; }; Base.prototype.traverseChildren = function(crossScope, func) { return this.eachChild(function(child) { var recur; recur = func(child); if (recur !== 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.isNumber = NO; Base.prototype.unwrap = THIS; Base.prototype.unfoldSoak = NO; Base.prototype.assigns = NO; Base.prototype.updateLocationDataIfMissing = function(locationData) { if (this.locationData) { return this; } this.locationData = locationData; return this.eachChild(function(child) { return child.updateLocationDataIfMissing(locationData); }); }; Base.prototype.error = function(message) { return throwSyntaxError(message, this.locationData); }; Base.prototype.makeCode = function(code) { return new CodeFragment(this, code); }; Base.prototype.wrapInBraces = function(fragments) { return [].concat(this.makeCode('('), fragments, this.makeCode(')')); }; Base.prototype.joinFragmentArrays = function(fragmentsList, joinStr) { var answer, fragments, i, j, len1; answer = []; for (i = j = 0, len1 = fragmentsList.length; j < len1; i = ++j) { fragments = fragmentsList[i]; if (i) { answer.push(this.makeCode(joinStr)); } answer = answer.concat(fragments); } return answer; }; return Base; })(); exports.Block = Block = (function(superClass1) { extend1(Block, superClass1); 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, j, len1, ref3; ref3 = this.expressions; for (j = 0, len1 = ref3.length; j < len1; j++) { exp = ref3[j]; if (exp.isStatement(o)) { return true; } } return false; }; Block.prototype.jumps = function(o) { var exp, j, jumpNode, len1, ref3; ref3 = this.expressions; for (j = 0, len1 = ref3.length; j < len1; j++) { exp = ref3[j]; if (jumpNode = exp.jumps(o)) { return jumpNode; } } }; 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.compileToFragments = function(o, level) { if (o == null) { o = {}; } if (o.scope) { return Block.__super__.compileToFragments.call(this, o, level); } else { return this.compileRoot(o); } }; Block.prototype.compileNode = function(o) { var answer, compiledNodes, fragments, index, j, len1, node, ref3, top; this.tab = o.indent; top = o.level === LEVEL_TOP; compiledNodes = []; ref3 = this.expressions; for (index = j = 0, len1 = ref3.length; j < len1; index = ++j) { node = ref3[index]; node = node.unwrapAll(); node = node.unfoldSoak(o) || node; if (node instanceof Block) { compiledNodes.push(node.compileNode(o)); } else if (top) { node.front = true; fragments = node.compileToFragments(o); if (!node.isStatement(o)) { fragments.unshift(this.makeCode("" + this.tab)); fragments.push(this.makeCode(";")); } compiledNodes.push(fragments); } else { compiledNodes.push(node.compileToFragments(o, LEVEL_LIST)); } } if (top) { if (this.spaced) { return [].concat(this.joinFragmentArrays(compiledNodes, '\n\n'), this.makeCode("\n")); } else { return this.joinFragmentArrays(compiledNodes, '\n'); } } if (compiledNodes.length) { answer = this.joinFragmentArrays(compiledNodes, ', '); } else { answer = [this.makeCode("void 0")]; } if (compiledNodes.length > 1 && o.level >= LEVEL_LIST) { return this.wrapInBraces(answer); } else { return answer; } }; Block.prototype.compileRoot = function(o) { var exp, fragments, i, j, len1, name, prelude, preludeExps, ref3, ref4, rest; o.indent = o.bare ? '' : TAB; o.level = LEVEL_TOP; this.spaced = true; o.scope = new Scope(null, this, null, (ref3 = o.referencedVars) != null ? ref3 : []); ref4 = o.locals || []; for (j = 0, len1 = ref4.length; j < len1; j++) { name = ref4[j]; o.scope.parameter(name); } prelude = []; if (!o.bare) { preludeExps = (function() { var k, len2, ref5, results; ref5 = this.expressions; results = []; for (i = k = 0, len2 = ref5.length; k < len2; i = ++k) { exp = ref5[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: '' })); prelude.push(this.makeCode("\n")); } this.expressions = rest; } fragments = this.compileWithDeclarations(o); if (o.bare) { return fragments; } return [].concat(prelude, this.makeCode("(function() {\n"), fragments, this.makeCode("\n}).call(this);\n")); }; Block.prototype.compileWithDeclarations = function(o) { var assigns, declars, exp, fragments, i, j, len1, post, ref3, ref4, ref5, rest, scope, spaced; fragments = []; post = []; ref3 = this.expressions; for (i = j = 0, len1 = ref3.length; j < len1; i = ++j) { exp = ref3[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); ref4 = [this.spaced, false], spaced = ref4[0], this.spaced = ref4[1]; ref5 = [this.compileNode(o), spaced], fragments = ref5[0], this.spaced = ref5[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) { fragments.push(this.makeCode('\n')); } fragments.push(this.makeCode(this.tab + "var ")); if (declars) { fragments.push(this.makeCode(scope.declaredVariables().join(', '))); } if (assigns) { if (declars) { fragments.push(this.makeCode(",\n" + (this.tab + TAB))); } fragments.push(this.makeCode(scope.assignedVariables().join(",\n" + (this.tab + TAB)))); } fragments.push(this.makeCode(";\n" + (this.spaced ? '\n' : ''))); } else if (fragments.length && post.length) { fragments.push(this.makeCode("\n")); } } return fragments.concat(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(superClass1) { extend1(Literal, superClass1); function Literal(value1) { this.value = value1; } Literal.prototype.isComplex = NO; Literal.prototype.assigns = function(name) { return name === this.value; }; Literal.prototype.compileNode = function(o) { return [this.makeCode(this.value)]; }; Literal.prototype.toString = function() { return " " + (this.isStatement() ? Literal.__super__.toString.apply(this, arguments) : this.constructor.name) + ": " + this.value; }; return Literal; })(Base); exports.NumberLiteral = NumberLiteral = (function(superClass1) { extend1(NumberLiteral, superClass1); function NumberLiteral() { return NumberLiteral.__super__.constructor.apply(this, arguments); } return NumberLiteral; })(Literal); exports.InfinityLiteral = InfinityLiteral = (function(superClass1) { extend1(InfinityLiteral, superClass1); function InfinityLiteral() { return InfinityLiteral.__super__.constructor.apply(this, arguments); } InfinityLiteral.prototype.compileNode = function() { return [this.makeCode('2e308')]; }; return InfinityLiteral; })(NumberLiteral); exports.NaNLiteral = NaNLiteral = (function(superClass1) { extend1(NaNLiteral, superClass1); function NaNLiteral() { NaNLiteral.__super__.constructor.call(this, 'NaN'); } NaNLiteral.prototype.compileNode = function(o) { var code; code = [this.makeCode('0/0')]; if (o.level >= LEVEL_OP) { return this.wrapInBraces(code); } else { return code; } }; return NaNLiteral; })(NumberLiteral); exports.StringLiteral = StringLiteral = (function(superClass1) { extend1(StringLiteral, superClass1); function StringLiteral() { return StringLiteral.__super__.constructor.apply(this, arguments); } return StringLiteral; })(Literal); exports.RegexLiteral = RegexLiteral = (function(superClass1) { extend1(RegexLiteral, superClass1); function RegexLiteral() { return RegexLiteral.__super__.constructor.apply(this, arguments); } return RegexLiteral; })(Literal); exports.PassthroughLiteral = PassthroughLiteral = (function(superClass1) { extend1(PassthroughLiteral, superClass1); function PassthroughLiteral() { return PassthroughLiteral.__super__.constructor.apply(this, arguments); } return PassthroughLiteral; })(Literal); exports.IdentifierLiteral = IdentifierLiteral = (function(superClass1) { extend1(IdentifierLiteral, superClass1); function IdentifierLiteral() { return IdentifierLiteral.__super__.constructor.apply(this, arguments); } IdentifierLiteral.prototype.isAssignable = YES; return IdentifierLiteral; })(Literal); exports.PropertyName = PropertyName = (function(superClass1) { extend1(PropertyName, superClass1); function PropertyName() { return PropertyName.__super__.constructor.apply(this, arguments); } PropertyName.prototype.isAssignable = YES; return PropertyName; })(Literal); exports.StatementLiteral = StatementLiteral = (function(superClass1) { extend1(StatementLiteral, superClass1); function StatementLiteral() { return StatementLiteral.__super__.constructor.apply(this, arguments); } StatementLiteral.prototype.isStatement = YES; StatementLiteral.prototype.makeReturn = THIS; StatementLiteral.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; } }; StatementLiteral.prototype.compileNode = function(o) { return [this.makeCode("" + this.tab + this.value + ";")]; }; return StatementLiteral; })(Literal); exports.ThisLiteral = ThisLiteral = (function(superClass1) { extend1(ThisLiteral, superClass1); function ThisLiteral() { ThisLiteral.__super__.constructor.call(this, 'this'); } ThisLiteral.prototype.compileNode = function(o) { var code, ref3; code = ((ref3 = o.scope.method) != null ? ref3.bound : void 0) ? o.scope.method.context : this.value; return [this.makeCode(code)]; }; return ThisLiteral; })(Literal); exports.UndefinedLiteral = UndefinedLiteral = (function(superClass1) { extend1(UndefinedLiteral, superClass1); function UndefinedLiteral() { UndefinedLiteral.__super__.constructor.call(this, 'undefined'); } UndefinedLiteral.prototype.compileNode = function(o) { return [this.makeCode(o.level >= LEVEL_ACCESS ? '(void 0)' : 'void 0')]; }; return UndefinedLiteral; })(Literal); exports.NullLiteral = NullLiteral = (function(superClass1) { extend1(NullLiteral, superClass1); function NullLiteral() { NullLiteral.__super__.constructor.call(this, 'null'); } return NullLiteral; })(Literal); exports.BooleanLiteral = BooleanLiteral = (function(superClass1) { extend1(BooleanLiteral, superClass1); function BooleanLiteral() { return BooleanLiteral.__super__.constructor.apply(this, arguments); } return BooleanLiteral; })(Literal); exports.Return = Return = (function(superClass1) { extend1(Return, superClass1); function Return(expression) { this.expression = expression; } Return.prototype.children = ['expression']; Return.prototype.isStatement = YES; Return.prototype.makeReturn = THIS; Return.prototype.jumps = THIS; Return.prototype.compileToFragments = function(o, level) { var expr, ref3; expr = (ref3 = this.expression) != null ? ref3.makeReturn() : void 0; if (expr && !(expr instanceof Return)) { return expr.compileToFragments(o, level); } else { return Return.__super__.compileToFragments.call(this, o, level); } }; Return.prototype.compileNode = function(o) { var answer; answer = []; answer.push(this.makeCode(this.tab + ("return" + (this.expression ? " " : "")))); if (this.expression) { answer = answer.concat(this.expression.compileToFragments(o, LEVEL_PAREN)); } answer.push(this.makeCode(";")); return answer; }; return Return; })(Base); exports.YieldReturn = YieldReturn = (function(superClass1) { extend1(YieldReturn, superClass1); function YieldReturn() { return YieldReturn.__super__.constructor.apply(this, arguments); } YieldReturn.prototype.compileNode = function(o) { if (o.scope.parent == null) { this.error('yield can only occur inside functions'); } return YieldReturn.__super__.compileNode.apply(this, arguments); }; return YieldReturn; })(Return); exports.Value = Value = (function(superClass1) { extend1(Value, superClass1); 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.bareLiteral = function(type) { return !this.properties.length && this.base instanceof type; }; Value.prototype.isArray = function() { return this.bareLiteral(Arr); }; Value.prototype.isRange = function() { return this.bareLiteral(Range); }; Value.prototype.isComplex = function() { return this.hasProperties() || this.base.isComplex(); }; Value.prototype.isAssignable = function() { return this.hasProperties() || this.base.isAssignable(); }; Value.prototype.isNumber = function() { return this.bareLiteral(NumberLiteral); }; Value.prototype.isString = function() { return this.bareLiteral(StringLiteral); }; Value.prototype.isRegex = function() { return this.bareLiteral(RegexLiteral); }; Value.prototype.isUndefined = function() { return this.bareLiteral(UndefinedLiteral); }; Value.prototype.isNull = function() { return this.bareLiteral(NullLiteral); }; Value.prototype.isBoolean = function() { return this.bareLiteral(BooleanLiteral); }; Value.prototype.isAtomic = function() { var j, len1, node, ref3; ref3 = this.properties.concat(this.base); for (j = 0, len1 = ref3.length; j < len1; j++) { node = ref3[j]; if (node.soak || node instanceof Call) { return false; } } return true; }; Value.prototype.isNotCallable = function() { return this.isNumber() || this.isString() || this.isRegex() || this.isArray() || this.isRange() || this.isSplice() || this.isObject() || this.isUndefined() || this.isNull() || this.isBoolean(); }; 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() { var lastProp, ref3; ref3 = this.properties, lastProp = ref3[ref3.length - 1]; return lastProp instanceof Slice; }; Value.prototype.looksStatic = function(className) { var ref3; return this.base.value === className && this.properties.length === 1 && ((ref3 = this.properties[0].name) != null ? ref3.value : void 0) !== 'prototype'; }; Value.prototype.unwrap = function() { if (this.properties.length) { return this; } else { return this.base; } }; Value.prototype.cacheReference = function(o) { var base, bref, name, nref, ref3; ref3 = this.properties, name = ref3[ref3.length - 1]; 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 IdentifierLiteral(o.scope.freeVariable('base')); base = new Value(new Parens(new Assign(bref, base))); } if (!name) { return [base, bref]; } if (name.isComplex()) { nref = new IdentifierLiteral(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 fragments, j, len1, prop, props; this.base.front = this.front; props = this.properties; fragments = this.base.compileToFragments(o, (props.length ? LEVEL_ACCESS : null)); if (props.length && SIMPLENUM.test(fragmentsToText(fragments))) { fragments.push(this.makeCode('.')); } for (j = 0, len1 = props.length; j < len1; j++) { prop = props[j]; fragments.push.apply(fragments, prop.compileToFragments(o)); } return fragments; }; Value.prototype.unfoldSoak = function(o) { return this.unfoldedSoak != null ? this.unfoldedSoak : this.unfoldedSoak = (function(_this) { return function() { var fst, i, ifn, j, len1, prop, ref, ref3, ref4, snd; if (ifn = _this.base.unfoldSoak(o)) { (ref3 = ifn.body.properties).push.apply(ref3, _this.properties); return ifn; } ref4 = _this.properties; for (i = j = 0, len1 = ref4.length; j < len1; i = ++j) { prop = ref4[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 IdentifierLiteral(o.scope.freeVariable('ref')); fst = new Parens(new Assign(ref, fst)); snd.base = ref; } return new If(new Existence(fst), snd, { soak: true }); } return false; }; })(this)(); }; return Value; })(Base); exports.Comment = Comment = (function(superClass1) { extend1(Comment, superClass1); function Comment(comment1) { this.comment = comment1; } Comment.prototype.isStatement = YES; Comment.prototype.makeReturn = THIS; Comment.prototype.compileNode = function(o, level) { var code, comment; comment = this.comment.replace(/^(\s*)#(?=\s)/gm, "$1 *"); code = "/*" + (multident(comment, this.tab)) + (indexOf.call(comment, '\n') >= 0 ? "\n" + this.tab : '') + " */"; if ((level || o.level) === LEVEL_TOP) { code = o.indent + code; } return [this.makeCode("\n"), this.makeCode(code)]; }; return Comment; })(Base); exports.Call = Call = (function(superClass1) { extend1(Call, superClass1); function Call(variable1, args1, soak1) { this.variable = variable1; this.args = args1 != null ? args1 : []; this.soak = soak1; this.isNew = false; if (this.variable instanceof Value && this.variable.isNotCallable()) { this.variable.error("literal is not a function"); } } Call.prototype.children = ['variable', 'args']; Call.prototype.updateLocationDataIfMissing = function(locationData) { var base, ref3; if (this.locationData && this.needsUpdatedStartLocation) { this.locationData.first_line = locationData.first_line; this.locationData.first_column = locationData.first_column; base = ((ref3 = this.variable) != null ? ref3.base : void 0) || this.variable; if (base.needsUpdatedStartLocation) { this.variable.locationData.first_line = locationData.first_line; this.variable.locationData.first_column = locationData.first_column; base.updateLocationDataIfMissing(locationData); } delete this.needsUpdatedStartLocation; } return Call.__super__.updateLocationDataIfMissing.apply(this, arguments); }; Call.prototype.newInstance = function() { var base, ref3; base = ((ref3 = this.variable) != null ? ref3.base : void 0) || this.variable; if (base instanceof Call && !base.isNew) { base.newInstance(); } else { this.isNew = true; } this.needsUpdatedStartLocation = true; return this; }; Call.prototype.unfoldSoak = function(o) { var call, ifn, j, left, len1, list, ref3, ref4, rite; if (this.soak) { if (this instanceof SuperCall) { left = new Literal(this.superReference(o)); rite = new Value(left); } else { if (ifn = unfoldSoak(o, this, 'variable')) { return ifn; } ref3 = new Value(this.variable).cacheReference(o), left = ref3[0], rite = ref3[1]; } 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; } } ref4 = list.reverse(); for (j = 0, len1 = ref4.length; j < len1; j++) { call = ref4[j]; if (ifn) { if (call.variable instanceof Call) { call.variable = ifn; } else { call.variable.base = ifn; } } ifn = unfoldSoak(o, call, 'variable'); } return ifn; }; Call.prototype.compileNode = function(o) { var arg, argIndex, compiledArgs, compiledArray, fragments, j, len1, preface, ref3, ref4; if ((ref3 = this.variable) != null) { ref3.front = this.front; } compiledArray = Splat.compileSplattedArray(o, this.args, true); if (compiledArray.length) { return this.compileSplat(o, compiledArray); } compiledArgs = []; ref4 = this.args; for (argIndex = j = 0, len1 = ref4.length; j < len1; argIndex = ++j) { arg = ref4[argIndex]; if (argIndex) { compiledArgs.push(this.makeCode(", ")); } compiledArgs.push.apply(compiledArgs, arg.compileToFragments(o, LEVEL_LIST)); } fragments = []; if (this instanceof SuperCall) { preface = this.superReference(o) + (".call(" + (this.superThis(o))); if (compiledArgs.length) { preface += ", "; } fragments.push(this.makeCode(preface)); } else { if (this.isNew) { fragments.push(this.makeCode('new ')); } fragments.push.apply(fragments, this.variable.compileToFragments(o, LEVEL_ACCESS)); fragments.push(this.makeCode("(")); } fragments.push.apply(fragments, compiledArgs); fragments.push(this.makeCode(")")); return fragments; }; Call.prototype.compileSplat = function(o, splatArgs) { var answer, base, fun, idt, name, ref; if (this instanceof SuperCall) { return [].concat(this.makeCode((this.superReference(o)) + ".apply(" + (this.superThis(o)) + ", "), splatArgs, this.makeCode(")")); } if (this.isNew) { idt = this.tab + TAB; return [].concat(this.makeCode("(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.compileToFragments(o, LEVEL_LIST), this.makeCode(", "), splatArgs, this.makeCode(", function(){})")); } answer = []; base = new Value(this.variable); if ((name = base.properties.pop()) && base.isComplex()) { ref = o.scope.freeVariable('ref'); answer = answer.concat(this.makeCode("(" + ref + " = "), base.compileToFragments(o, LEVEL_LIST), this.makeCode(")"), name.compileToFragments(o)); } else { fun = base.compileToFragments(o, LEVEL_ACCESS); if (SIMPLENUM.test(fragmentsToText(fun))) { fun = this.wrapInBraces(fun); } if (name) { ref = fragmentsToText(fun); fun.push.apply(fun, name.compileToFragments(o)); } else { ref = 'null'; } answer = answer.concat(fun); } return answer = answer.concat(this.makeCode(".apply(" + ref + ", "), splatArgs, this.makeCode(")")); }; return Call; })(Base); exports.SuperCall = SuperCall = (function(superClass1) { extend1(SuperCall, superClass1); function SuperCall(args) { SuperCall.__super__.constructor.call(this, null, args != null ? args : [new Splat(new IdentifierLiteral('arguments'))]); this.isBare = args != null; } SuperCall.prototype.superReference = function(o) { var accesses, base, bref, klass, method, name, nref, variable; method = o.scope.namedMethod(); if (method != null ? method.klass : void 0) { klass = method.klass, name = method.name, variable = method.variable; if (klass.isComplex()) { bref = new IdentifierLiteral(o.scope.parent.freeVariable('base')); base = new Value(new Parens(new Assign(bref, klass))); variable.base = base; variable.properties.splice(0, klass.properties.length); } if (name.isComplex() || (name instanceof Index && name.index.isAssignable())) { nref = new IdentifierLiteral(o.scope.parent.freeVariable('name')); name = new Index(new Assign(nref, name.index)); variable.properties.pop(); variable.properties.push(name); } accesses = [new Access(new PropertyName('__super__'))]; if (method["static"]) { accesses.push(new Access(new PropertyName('constructor'))); } accesses.push(nref != null ? new Index(nref) : name); return (new Value(bref != null ? bref : klass, accesses)).compile(o); } else if (method != null ? method.ctor : void 0) { return method.name + ".__super__.constructor"; } else { return this.error('cannot call super outside of an instance method.'); } }; SuperCall.prototype.superThis = function(o) { var method; method = o.scope.method; return (method && !method.klass && method.context) || "this"; }; return SuperCall; })(Call); exports.RegexWithInterpolations = RegexWithInterpolations = (function(superClass1) { extend1(RegexWithInterpolations, superClass1); function RegexWithInterpolations(args) { if (args == null) { args = []; } RegexWithInterpolations.__super__.constructor.call(this, new Value(new IdentifierLiteral('RegExp')), args, false); } return RegexWithInterpolations; })(Call); exports.TaggedTemplateCall = TaggedTemplateCall = (function(superClass1) { extend1(TaggedTemplateCall, superClass1); function TaggedTemplateCall(variable, arg, soak) { if (arg instanceof StringLiteral) { arg = new StringWithInterpolations(Block.wrap([new Value(arg)])); } TaggedTemplateCall.__super__.constructor.call(this, variable, [arg], soak); } TaggedTemplateCall.prototype.compileNode = function(o) { o.inTaggedTemplateCall = true; return this.variable.compileToFragments(o, LEVEL_ACCESS).concat(this.args[0].compileToFragments(o, LEVEL_LIST)); }; return TaggedTemplateCall; })(Call); exports.Extends = Extends = (function(superClass1) { extend1(Extends, superClass1); function Extends(child1, parent1) { this.child = child1; this.parent = parent1; } Extends.prototype.children = ['child', 'parent']; Extends.prototype.compileToFragments = function(o) { return new Call(new Value(new Literal(utility('extend', o))), [this.child, this.parent]).compileToFragments(o); }; return Extends; })(Base); exports.Access = Access = (function(superClass1) { extend1(Access, superClass1); function Access(name1, tag) { this.name = name1; this.soak = tag === 'soak'; } Access.prototype.children = ['name']; Access.prototype.compileToFragments = function(o) { var name, node, ref3; name = this.name.compileToFragments(o); node = this.name.unwrap(); if (node instanceof PropertyName) { if (ref3 = node.value, indexOf.call(JS_FORBIDDEN, ref3) >= 0) { return [this.makeCode('["')].concat(slice.call(name), [this.makeCode('"]')]); } else { return [this.makeCode('.')].concat(slice.call(name)); } } else { return [this.makeCode('[')].concat(slice.call(name), [this.makeCode(']')]); } }; Access.prototype.isComplex = NO; return Access; })(Base); exports.Index = Index = (function(superClass1) { extend1(Index, superClass1); function Index(index1) { this.index = index1; } Index.prototype.children = ['index']; Index.prototype.compileToFragments = function(o) { return [].concat(this.makeCode("["), this.index.compileToFragments(o, LEVEL_PAREN), this.makeCode("]")); }; Index.prototype.isComplex = function() { return this.index.isComplex(); }; return Index; })(Base); exports.Range = Range = (function(superClass1) { extend1(Range, superClass1); Range.prototype.children = ['from', 'to']; function Range(from1, to1, tag) { this.from = from1; this.to = to1; this.exclusive = tag === 'exclusive'; this.equals = this.exclusive ? '' : '='; } Range.prototype.compileVariables = function(o) { var isComplex, ref3, ref4, ref5, step; o = merge(o, { top: true }); isComplex = del(o, 'isComplex'); ref3 = this.cacheToCodeFragments(this.from.cache(o, LEVEL_LIST, isComplex)), this.fromC = ref3[0], this.fromVar = ref3[1]; ref4 = this.cacheToCodeFragments(this.to.cache(o, LEVEL_LIST, isComplex)), this.toC = ref4[0], this.toVar = ref4[1]; if (step = del(o, 'step')) { ref5 = this.cacheToCodeFragments(step.cache(o, LEVEL_LIST, isComplex)), this.step = ref5[0], this.stepVar = ref5[1]; } this.fromNum = this.from.isNumber() ? Number(this.fromVar) : null; this.toNum = this.to.isNumber() ? Number(this.toVar) : null; return this.stepNum = (step != null ? step.isNumber() : void 0) ? Number(this.stepVar) : null; }; Range.prototype.compileNode = function(o) { var cond, condPart, from, gt, idx, idxName, known, lt, namedIndex, ref3, ref4, stepPart, to, varPart; if (!this.fromVar) { this.compileVariables(o); } if (!o.index) { return this.compileArray(o); } known = (this.fromNum != null) && (this.toNum != null); 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; } ref3 = [idx + " <" + this.equals, idx + " >" + this.equals], lt = ref3[0], gt = ref3[1]; condPart = this.stepNum != null ? this.stepNum > 0 ? lt + " " + this.toVar : gt + " " + this.toVar : known ? ((ref4 = [this.fromNum, this.toNum], from = ref4[0], to = ref4[1], ref4), from <= to ? lt + " " + to : gt + " " + to) : (cond = this.stepVar ? this.stepVar + " > 0" : 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 [this.makeCode(varPart + "; " + condPart + "; " + stepPart)]; }; Range.prototype.compileArray = function(o) { var args, body, cond, hasArgs, i, idt, j, known, post, pre, range, ref3, ref4, result, results, vars; known = (this.fromNum != null) && (this.toNum != null); if (known && Math.abs(this.fromNum - this.toNum) <= 20) { range = (function() { results = []; for (var j = ref3 = this.fromNum, ref4 = this.toNum; ref3 <= ref4 ? j <= ref4 : j >= ref4; ref3 <= ref4 ? j++ : j--){ results.push(j); } return results; }).apply(this); if (this.exclusive) { range.pop(); } return [this.makeCode("[" + (range.join(', ')) + "]")]; } idt = this.tab + TAB; i = o.scope.freeVariable('i', { single: true }); result = o.scope.freeVariable('results'); pre = "\n" + idt + result + " = [];"; if (known) { o.index = i; body = fragmentsToText(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(isLiteralArguments) : void 0; }; if (hasArgs(this.from) || hasArgs(this.to)) { args = ', arguments'; } return [this.makeCode("(function() {" + pre + "\n" + idt + "for (" + body + ")" + post + "}).apply(this" + (args != null ? args : '') + ")")]; }; return Range; })(Base); exports.Slice = Slice = (function(superClass1) { extend1(Slice, superClass1); Slice.prototype.children = ['range']; function Slice(range1) { this.range = range1; Slice.__super__.constructor.call(this); } Slice.prototype.compileNode = function(o) { var compiled, compiledText, from, fromCompiled, ref3, to, toStr; ref3 = this.range, to = ref3.to, from = ref3.from; fromCompiled = from && from.compileToFragments(o, LEVEL_PAREN) || [this.makeCode('0')]; if (to) { compiled = to.compileToFragments(o, LEVEL_PAREN); compiledText = fragmentsToText(compiled); if (!(!this.range.exclusive && +compiledText === -1)) { toStr = ', ' + (this.range.exclusive ? compiledText : to.isNumber() ? "" + (+compiledText + 1) : (compiled = to.compileToFragments(o, LEVEL_ACCESS), "+" + (fragmentsToText(compiled)) + " + 1 || 9e9")); } } return [this.makeCode(".slice(" + (fragmentsToText(fromCompiled)) + (toStr || '') + ")")]; }; return Slice; })(Base); exports.Obj = Obj = (function(superClass1) { extend1(Obj, superClass1); 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 answer, dynamicIndex, hasDynamic, i, idt, indent, j, join, k, key, l, lastNoncom, len1, len2, len3, node, oref, prop, props, ref3, value; props = this.properties; if (this.generated) { for (j = 0, len1 = props.length; j < len1; j++) { node = props[j]; if (node instanceof Value) { node.error('cannot have an implicit value in an implicit object'); } } } for (dynamicIndex = k = 0, len2 = props.length; k < len2; dynamicIndex = ++k) { prop = props[dynamicIndex]; if ((prop.variable || prop).base instanceof Parens) { break; } } hasDynamic = dynamicIndex < props.length; idt = o.indent += TAB; lastNoncom = this.lastNonComment(this.properties); answer = []; if (hasDynamic) { oref = o.scope.freeVariable('obj'); answer.push(this.makeCode("(\n" + idt + oref + " = ")); } answer.push(this.makeCode("{" + (props.length === 0 || dynamicIndex === 0 ? '}' : '\n'))); for (i = l = 0, len3 = props.length; l < len3; i = ++l) { prop = props[i]; if (i === dynamicIndex) { if (i !== 0) { answer.push(this.makeCode("\n" + idt + "}")); } answer.push(this.makeCode(',\n')); } join = i === props.length - 1 || i === dynamicIndex - 1 ? '' : prop === lastNoncom || prop instanceof Comment ? '\n' : ',\n'; indent = prop instanceof Comment ? '' : idt; if (hasDynamic && i < dynamicIndex) { indent += TAB; } if (prop instanceof Assign) { if (prop.context !== 'object') { prop.operatorToken.error("unexpected " + prop.operatorToken.value); } if (prop.variable instanceof Value && prop.variable.hasProperties()) { prop.variable.error('invalid object key'); } } if (prop instanceof Value && prop["this"]) { prop = new Assign(prop.properties[0].name, prop, 'object'); } if (!(prop instanceof Comment)) { if (i < dynamicIndex) { if (!(prop instanceof Assign)) { prop = new Assign(prop, prop, 'object'); } } else { if (prop instanceof Assign) { key = prop.variable; value = prop.value; } else { ref3 = prop.base.cache(o), key = ref3[0], value = ref3[1]; if (key instanceof IdentifierLiteral) { key = new PropertyName(key.value); } } prop = new Assign(new Value(new IdentifierLiteral(oref), [new Access(key)]), value); } } if (indent) { answer.push(this.makeCode(indent)); } answer.push.apply(answer, prop.compileToFragments(o, LEVEL_TOP)); if (join) { answer.push(this.makeCode(join)); } } if (hasDynamic) { answer.push(this.makeCode(",\n" + idt + oref + "\n" + this.tab + ")")); } else { if (props.length !== 0) { answer.push(this.makeCode("\n" + this.tab + "}")); } } if (this.front && !hasDynamic) { return this.wrapInBraces(answer); } else { return answer; } }; Obj.prototype.assigns = function(name) { var j, len1, prop, ref3; ref3 = this.properties; for (j = 0, len1 = ref3.length; j < len1; j++) { prop = ref3[j]; if (prop.assigns(name)) { return true; } } return false; }; return Obj; })(Base); exports.Arr = Arr = (function(superClass1) { extend1(Arr, superClass1); function Arr(objs) { this.objects = objs || []; } Arr.prototype.children = ['objects']; Arr.prototype.compileNode = function(o) { var answer, compiledObjs, fragments, index, j, len1, obj; if (!this.objects.length) { return [this.makeCode('[]')]; } o.indent += TAB; answer = Splat.compileSplattedArray(o, this.objects); if (answer.length) { return answer; } answer = []; compiledObjs = (function() { var j, len1, ref3, results; ref3 = this.objects; results = []; for (j = 0, len1 = ref3.length; j < len1; j++) { obj = ref3[j]; results.push(obj.compileToFragments(o, LEVEL_LIST)); } return results; }).call(this); for (index = j = 0, len1 = compiledObjs.length; j < len1; index = ++j) { fragments = compiledObjs[index]; if (index) { answer.push(this.makeCode(", ")); } answer.push.apply(answer, fragments); } if (fragmentsToText(answer).indexOf('\n') >= 0) { answer.unshift(this.makeCode("[\n" + o.indent)); answer.push(this.makeCode("\n" + this.tab + "]")); } else { answer.unshift(this.makeCode("[")); answer.push(this.makeCode("]")); } return answer; }; Arr.prototype.assigns = function(name) { var j, len1, obj, ref3; ref3 = this.objects; for (j = 0, len1 = ref3.length; j < len1; j++) { obj = ref3[j]; if (obj.assigns(name)) { return true; } } return false; }; return Arr; })(Base); exports.Class = Class = (function(superClass1) { extend1(Class, superClass1); function Class(variable1, parent1, body1) { this.variable = variable1; this.parent = parent1; this.body = body1 != null ? body1 : new Block; this.boundFuncs = []; this.body.classBody = true; } Class.prototype.children = ['variable', 'parent', 'body']; Class.prototype.defaultClassVariableName = '_Class'; Class.prototype.determineName = function() { var message, name, node, ref3, tail; if (!this.variable) { return this.defaultClassVariableName; } ref3 = this.variable.properties, tail = ref3[ref3.length - 1]; node = tail ? tail instanceof Access && tail.name : this.variable.base; if (!(node instanceof IdentifierLiteral || node instanceof PropertyName)) { return this.defaultClassVariableName; } name = node.value; if (!tail) { message = isUnassignable(name); if (message) { this.variable.error(message); } } if (indexOf.call(JS_FORBIDDEN, name) >= 0) { return "_" + name; } else { return name; } }; Class.prototype.setContext = function(name) { return this.body.traverseChildren(false, function(node) { if (node.classBody) { return false; } if (node instanceof ThisLiteral) { return node.value = name; } else if (node instanceof Code) { if (node.bound) { return node.context = name; } } }); }; Class.prototype.addBoundFunctions = function(o) { var bvar, j, len1, lhs, ref3; ref3 = this.boundFuncs; for (j = 0, len1 = ref3.length; j < len1; j++) { bvar = ref3[j]; lhs = (new Value(new ThisLiteral, [new Access(bvar)])).compile(o); this.ctor.body.unshift(new Literal(lhs + " = " + (utility('bind', o)) + "(" + lhs + ", this)")); } }; Class.prototype.addProperties = function(node, name, o) { var acc, 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) { assign.error('cannot define more than one constructor in a class'); } if (func.bound) { assign.error('cannot define a constructor as a bound function'); } if (func instanceof Code) { assign = this.ctor = func; } else { this.externalCtor = o.classScope.freeVariable('ctor'); assign = new Assign(new IdentifierLiteral(this.externalCtor), func); } } else { if (assign.variable["this"]) { func["static"] = true; } else { acc = base.isComplex() ? new Index(base) : new Access(base); assign.variable = new Value(new IdentifierLiteral(name), [new Access(new PropertyName('prototype')), acc]); 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) { return this.traverseChildren(false, (function(_this) { return function(child) { var cont, exps, i, j, len1, node, ref3; cont = true; if (child instanceof Class) { return false; } if (child instanceof Block) { ref3 = exps = child.expressions; for (i = j = 0, len1 = ref3.length; j < len1; i = ++j) { node = ref3[i]; if (node instanceof Assign && node.variable.looksStatic(name)) { node.value["static"] = true; } else if (node instanceof Value && node.isObject(true)) { cont = false; exps[i] = _this.addProperties(node, name, o); } } child.expressions = exps = flatten(exps); } return cont && !(child instanceof Class); }; })(this)); }; 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.externalCtor) { this.ctor.body.push(new Literal(this.externalCtor + ".apply(this, arguments)")); } else if (this.parent) { this.ctor.body.push(new Literal(name + ".__super__.constructor.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 args, argumentsNode, func, jumpNode, klass, lname, name, ref3, superClass; if (jumpNode = this.body.jumps()) { jumpNode.error('Class bodies cannot contain pure statements'); } if (argumentsNode = this.body.contains(isLiteralArguments)) { argumentsNode.error("Class bodies shouldn't reference arguments"); } name = this.determineName(); lname = new IdentifierLiteral(name); func = new Code([], Block.wrap([this.body])); args = []; o.classScope = func.makeScope(o.scope); this.hoistDirectivePrologue(); this.setContext(name); this.walkBody(name, o); this.ensureConstructor(name); this.addBoundFunctions(o); this.body.spaced = true; this.body.expressions.push(lname); if (this.parent) { superClass = new IdentifierLiteral(o.classScope.freeVariable('superClass', { reserve: false })); this.body.expressions.unshift(new Extends(lname, superClass)); func.params.push(new Param(superClass)); args.push(this.parent); } (ref3 = this.body.expressions).unshift.apply(ref3, this.directives); klass = new Parens(new Call(func, args)); if (this.variable) { klass = new Assign(this.variable, klass, null, { moduleDeclaration: this.moduleDeclaration }); } return klass.compileToFragments(o); }; return Class; })(Base); exports.ModuleDeclaration = ModuleDeclaration = (function(superClass1) { extend1(ModuleDeclaration, superClass1); function ModuleDeclaration(clause, source1) { this.clause = clause; this.source = source1; this.checkSource(); } ModuleDeclaration.prototype.children = ['clause', 'source']; ModuleDeclaration.prototype.isStatement = YES; ModuleDeclaration.prototype.jumps = THIS; ModuleDeclaration.prototype.makeReturn = THIS; ModuleDeclaration.prototype.checkSource = function() { if ((this.source != null) && this.source instanceof StringWithInterpolations) { return this.source.error('the name of the module to be imported from must be an uninterpolated string'); } }; ModuleDeclaration.prototype.checkScope = function(o, moduleDeclarationType) { if (o.indent.length !== 0) { return this.error(moduleDeclarationType + " statements must be at top-level scope"); } }; return ModuleDeclaration; })(Base); exports.ImportDeclaration = ImportDeclaration = (function(superClass1) { extend1(ImportDeclaration, superClass1); function ImportDeclaration() { return ImportDeclaration.__super__.constructor.apply(this, arguments); } ImportDeclaration.prototype.compileNode = function(o) { var code, ref3; this.checkScope(o, 'import'); o.importedSymbols = []; code = []; code.push(this.makeCode(this.tab + "import ")); if (this.clause != null) { code.push.apply(code, this.clause.compileNode(o)); } if (((ref3 = this.source) != null ? ref3.value : void 0) != null) { if (this.clause !== null) { code.push(this.makeCode(' from ')); } code.push(this.makeCode(this.source.value)); } code.push(this.makeCode(';')); return code; }; return ImportDeclaration; })(ModuleDeclaration); exports.ImportClause = ImportClause = (function(superClass1) { extend1(ImportClause, superClass1); function ImportClause(defaultBinding, namedImports) { this.defaultBinding = defaultBinding; this.namedImports = namedImports; } ImportClause.prototype.children = ['defaultBinding', 'namedImports']; ImportClause.prototype.compileNode = function(o) { var code; code = []; if (this.defaultBinding != null) { code.push.apply(code, this.defaultBinding.compileNode(o)); if (this.namedImports != null) { code.push(this.makeCode(', ')); } } if (this.namedImports != null) { code.push.apply(code, this.namedImports.compileNode(o)); } return code; }; return ImportClause; })(Base); exports.ExportDeclaration = ExportDeclaration = (function(superClass1) { extend1(ExportDeclaration, superClass1); function ExportDeclaration() { return ExportDeclaration.__super__.constructor.apply(this, arguments); } ExportDeclaration.prototype.compileNode = function(o) { var code, ref3; this.checkScope(o, 'export'); code = []; code.push(this.makeCode(this.tab + "export ")); if (this instanceof ExportDefaultDeclaration) { code.push(this.makeCode('default ')); } if (!(this instanceof ExportDefaultDeclaration) && (this.clause instanceof Assign || this.clause instanceof Class)) { if (this.clause instanceof Class && !this.clause.variable) { this.clause.error('anonymous classes cannot be exported'); } code.push(this.makeCode('var ')); this.clause.moduleDeclaration = 'export'; } if ((this.clause.body != null) && this.clause.body instanceof Block) { code = code.concat(this.clause.compileToFragments(o, LEVEL_TOP)); } else { code = code.concat(this.clause.compileNode(o)); } if (((ref3 = this.source) != null ? ref3.value : void 0) != null) { code.push(this.makeCode(" from " + this.source.value)); } code.push(this.makeCode(';')); return code; }; return ExportDeclaration; })(ModuleDeclaration); exports.ExportNamedDeclaration = ExportNamedDeclaration = (function(superClass1) { extend1(ExportNamedDeclaration, superClass1); function ExportNamedDeclaration() { return ExportNamedDeclaration.__super__.constructor.apply(this, arguments); } return ExportNamedDeclaration; })(ExportDeclaration); exports.ExportDefaultDeclaration = ExportDefaultDeclaration = (function(superClass1) { extend1(ExportDefaultDeclaration, superClass1); function ExportDefaultDeclaration() { return ExportDefaultDeclaration.__super__.constructor.apply(this, arguments); } return ExportDefaultDeclaration; })(ExportDeclaration); exports.ExportAllDeclaration = ExportAllDeclaration = (function(superClass1) { extend1(ExportAllDeclaration, superClass1); function ExportAllDeclaration() { return ExportAllDeclaration.__super__.constructor.apply(this, arguments); } return ExportAllDeclaration; })(ExportDeclaration); exports.ModuleSpecifierList = ModuleSpecifierList = (function(superClass1) { extend1(ModuleSpecifierList, superClass1); function ModuleSpecifierList(specifiers) { this.specifiers = specifiers; } ModuleSpecifierList.prototype.children = ['specifiers']; ModuleSpecifierList.prototype.compileNode = function(o) { var code, compiledList, fragments, index, j, len1, specifier; code = []; o.indent += TAB; compiledList = (function() { var j, len1, ref3, results; ref3 = this.specifiers; results = []; for (j = 0, len1 = ref3.length; j < len1; j++) { specifier = ref3[j]; results.push(specifier.compileToFragments(o, LEVEL_LIST)); } return results; }).call(this); if (this.specifiers.length !== 0) { code.push(this.makeCode("{\n" + o.indent)); for (index = j = 0, len1 = compiledList.length; j < len1; index = ++j) { fragments = compiledList[index]; if (index) { code.push(this.makeCode(",\n" + o.indent)); } code.push.apply(code, fragments); } code.push(this.makeCode("\n}")); } else { code.push(this.makeCode('{}')); } return code; }; return ModuleSpecifierList; })(Base); exports.ImportSpecifierList = ImportSpecifierList = (function(superClass1) { extend1(ImportSpecifierList, superClass1); function ImportSpecifierList() { return ImportSpecifierList.__super__.constructor.apply(this, arguments); } return ImportSpecifierList; })(ModuleSpecifierList); exports.ExportSpecifierList = ExportSpecifierList = (function(superClass1) { extend1(ExportSpecifierList, superClass1); function ExportSpecifierList() { return ExportSpecifierList.__super__.constructor.apply(this, arguments); } return ExportSpecifierList; })(ModuleSpecifierList); exports.ModuleSpecifier = ModuleSpecifier = (function(superClass1) { extend1(ModuleSpecifier, superClass1); function ModuleSpecifier(original, alias, moduleDeclarationType1) { this.original = original; this.alias = alias; this.moduleDeclarationType = moduleDeclarationType1; this.identifier = this.alias != null ? this.alias.value : this.original.value; } ModuleSpecifier.prototype.children = ['original', 'alias']; ModuleSpecifier.prototype.compileNode = function(o) { var code; o.scope.find(this.identifier, this.moduleDeclarationType); code = []; code.push(this.makeCode(this.original.value)); if (this.alias != null) { code.push(this.makeCode(" as " + this.alias.value)); } return code; }; return ModuleSpecifier; })(Base); exports.ImportSpecifier = ImportSpecifier = (function(superClass1) { extend1(ImportSpecifier, superClass1); function ImportSpecifier(imported, local) { ImportSpecifier.__super__.constructor.call(this, imported, local, 'import'); } ImportSpecifier.prototype.compileNode = function(o) { var ref3; if ((ref3 = this.identifier, indexOf.call(o.importedSymbols, ref3) >= 0) || o.scope.check(this.identifier)) { this.error("'" + this.identifier + "' has already been declared"); } else { o.importedSymbols.push(this.identifier); } return ImportSpecifier.__super__.compileNode.call(this, o); }; return ImportSpecifier; })(ModuleSpecifier); exports.ImportDefaultSpecifier = ImportDefaultSpecifier = (function(superClass1) { extend1(ImportDefaultSpecifier, superClass1); function ImportDefaultSpecifier() { return ImportDefaultSpecifier.__super__.constructor.apply(this, arguments); } return ImportDefaultSpecifier; })(ImportSpecifier); exports.ImportNamespaceSpecifier = ImportNamespaceSpecifier = (function(superClass1) { extend1(ImportNamespaceSpecifier, superClass1); function ImportNamespaceSpecifier() { return ImportNamespaceSpecifier.__super__.constructor.apply(this, arguments); } return ImportNamespaceSpecifier; })(ImportSpecifier); exports.ExportSpecifier = ExportSpecifier = (function(superClass1) { extend1(ExportSpecifier, superClass1); function ExportSpecifier(local, exported) { ExportSpecifier.__super__.constructor.call(this, local, exported, 'export'); } return ExportSpecifier; })(ModuleSpecifier); exports.Assign = Assign = (function(superClass1) { extend1(Assign, superClass1); function Assign(variable1, value1, context, options) { this.variable = variable1; this.value = value1; this.context = context; if (options == null) { options = {}; } this.param = options.param, this.subpattern = options.subpattern, this.operatorToken = options.operatorToken, this.moduleDeclaration = options.moduleDeclaration; } Assign.prototype.children = ['variable', 'value']; Assign.prototype.isStatement = function(o) { return (o != null ? o.level : void 0) === LEVEL_TOP && (this.context != null) && (this.moduleDeclaration || indexOf.call(this.context, "?") >= 0); }; Assign.prototype.checkAssignability = function(o, varBase) { if (Object.prototype.hasOwnProperty.call(o.scope.positions, varBase.value) && o.scope.variables[o.scope.positions[varBase.value]].type === 'import') { return varBase.error("'" + varBase.value + "' is read-only"); } }; 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 answer, compiledName, isValue, j, name, properties, prototype, ref3, ref4, ref5, ref6, ref7, ref8, val, varBase; 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 ((ref3 = this.context) === '||=' || ref3 === '&&=' || ref3 === '?=') { return this.compileConditional(o); } if ((ref4 = this.context) === '**=' || ref4 === '//=' || ref4 === '%%=') { return this.compileSpecialMath(o); } } if (this.value instanceof Code) { if (this.value["static"]) { this.value.klass = this.variable.base; this.value.name = this.variable.properties[0]; this.value.variable = this.variable; } else if (((ref5 = this.variable.properties) != null ? ref5.length : void 0) >= 2) { ref6 = this.variable.properties, properties = 3 <= ref6.length ? slice.call(ref6, 0, j = ref6.length - 2) : (j = 0, []), prototype = ref6[j++], name = ref6[j++]; if (((ref7 = prototype.name) != null ? ref7.value : void 0) === 'prototype') { this.value.klass = new Value(this.variable.base, properties); this.value.name = name; this.value.variable = this.variable; } } } if (!this.context) { varBase = this.variable.unwrapAll(); if (!varBase.isAssignable()) { this.variable.error("'" + (this.variable.compile(o)) + "' can't be assigned"); } if (!(typeof varBase.hasProperties === "function" ? varBase.hasProperties() : void 0)) { if (this.moduleDeclaration) { this.checkAssignability(o, varBase); o.scope.add(varBase.value, this.moduleDeclaration); } else if (this.param) { o.scope.add(varBase.value, 'var'); } else { this.checkAssignability(o, varBase); o.scope.find(varBase.value); } } } val = this.value.compileToFragments(o, LEVEL_LIST); if (isValue && this.variable.base instanceof Obj) { this.variable.front = true; } compiledName = this.variable.compileToFragments(o, LEVEL_LIST); if (this.context === 'object') { if (ref8 = fragmentsToText(compiledName), indexOf.call(JS_FORBIDDEN, ref8) >= 0) { compiledName.unshift(this.makeCode('"')); compiledName.push(this.makeCode('"')); } return compiledName.concat(this.makeCode(": "), val); } answer = compiledName.concat(this.makeCode(" " + (this.context || '=') + " "), val); if (o.level <= LEVEL_LIST) { return answer; } else { return this.wrapInBraces(answer); } }; Assign.prototype.compilePatternMatch = function(o) { var acc, assigns, code, defaultValue, expandedIdx, fragments, i, idx, isObject, ivar, j, len1, message, name, obj, objects, olen, ref, ref3, ref4, ref5, ref6, rest, top, val, value, vvar, vvarText; top = o.level === LEVEL_TOP; value = this.value; objects = this.variable.base.objects; if (!(olen = objects.length)) { code = value.compileToFragments(o); if (o.level >= LEVEL_OP) { return this.wrapInBraces(code); } else { return code; } } obj = objects[0]; if (olen === 1 && obj instanceof Expansion) { obj.error('Destructuring assignment has no target'); } isObject = this.variable.isObject(); if (top && olen === 1 && !(obj instanceof Splat)) { defaultValue = null; if (obj instanceof Assign && obj.context === 'object') { ref3 = obj, (ref4 = ref3.variable, idx = ref4.base), obj = ref3.value; if (obj instanceof Assign) { defaultValue = obj.value; obj = obj.variable; } } else { if (obj instanceof Assign) { defaultValue = obj.value; obj = obj.variable; } idx = isObject ? obj["this"] ? obj.properties[0].name : new PropertyName(obj.unwrap().value) : new NumberLiteral(0); } acc = idx.unwrap() instanceof PropertyName; value = new Value(value); value.properties.push(new (acc ? Access : Index)(idx)); message = isUnassignable(obj.unwrap().value); if (message) { obj.error(message); } if (defaultValue) { value = new Op('?', value, defaultValue); } return new Assign(obj, value, null, { param: this.param }).compileToFragments(o, LEVEL_TOP); } vvar = value.compileToFragments(o, LEVEL_LIST); vvarText = fragmentsToText(vvar); assigns = []; expandedIdx = false; if (!(value.unwrap() instanceof IdentifierLiteral) || this.variable.assigns(vvarText)) { assigns.push([this.makeCode((ref = o.scope.freeVariable('ref')) + " = ")].concat(slice.call(vvar))); vvar = [this.makeCode(ref)]; vvarText = ref; } for (i = j = 0, len1 = objects.length; j < len1; i = ++j) { obj = objects[i]; idx = i; if (!expandedIdx && obj instanceof Splat) { name = obj.name.unwrap().value; obj = obj.unwrap(); val = olen + " <= " + vvarText + ".length ? " + (utility('slice', o)) + ".call(" + vvarText + ", " + i; if (rest = olen - i - 1) { ivar = o.scope.freeVariable('i', { single: true }); val += ", " + ivar + " = " + vvarText + ".length - " + rest + ") : (" + ivar + " = " + i + ", [])"; } else { val += ") : []"; } val = new Literal(val); expandedIdx = ivar + "++"; } else if (!expandedIdx && obj instanceof Expansion) { if (rest = olen - i - 1) { if (rest === 1) { expandedIdx = vvarText + ".length - 1"; } else { ivar = o.scope.freeVariable('i', { single: true }); val = new Literal(ivar + " = " + vvarText + ".length - " + rest); expandedIdx = ivar + "++"; assigns.push(val.compileToFragments(o, LEVEL_LIST)); } } continue; } else { if (obj instanceof Splat || obj instanceof Expansion) { obj.error("multiple splats/expansions are disallowed in an assignment"); } defaultValue = null; if (obj instanceof Assign && obj.context === 'object') { ref5 = obj, (ref6 = ref5.variable, idx = ref6.base), obj = ref5.value; if (obj instanceof Assign) { defaultValue = obj.value; obj = obj.variable; } } else { if (obj instanceof Assign) { defaultValue = obj.value; obj = obj.variable; } idx = isObject ? obj["this"] ? obj.properties[0].name : new PropertyName(obj.unwrap().value) : new Literal(expandedIdx || idx); } name = obj.unwrap().value; acc = idx.unwrap() instanceof PropertyName; val = new Value(new Literal(vvarText), [new (acc ? Access : Index)(idx)]); if (defaultValue) { val = new Op('?', val, defaultValue); } } if (name != null) { message = isUnassignable(name); if (message) { obj.error(message); } } assigns.push(new Assign(obj, val, null, { param: this.param, subpattern: true }).compileToFragments(o, LEVEL_LIST)); } if (!(top || this.subpattern)) { assigns.push(vvar); } fragments = this.joinFragmentArrays(assigns, ', '); if (o.level < LEVEL_LIST) { return fragments; } else { return this.wrapInBraces(fragments); } }; Assign.prototype.compileConditional = function(o) { var fragments, left, ref3, right; ref3 = this.variable.cacheReference(o), left = ref3[0], right = ref3[1]; if (!left.properties.length && left.base instanceof Literal && !(left.base instanceof ThisLiteral) && !o.scope.check(left.base.value)) { this.variable.error("the variable \"" + left.base.value + "\" can't be assigned with " + this.context + " because it has not been declared before"); } if (indexOf.call(this.context, "?") >= 0) { o.isExistentialEquals = true; return new If(new Existence(left), right, { type: 'if' }).addElse(new Assign(right, this.value, '=')).compileToFragments(o); } else { fragments = new Op(this.context.slice(0, -1), left, new Assign(right, this.value, '=')).compileToFragments(o); if (o.level <= LEVEL_LIST) { return fragments; } else { return this.wrapInBraces(fragments); } } }; Assign.prototype.compileSpecialMath = function(o) { var left, ref3, right; ref3 = this.variable.cacheReference(o), left = ref3[0], right = ref3[1]; return new Assign(left, new Op(this.context.slice(0, -1), right, this.value)).compileToFragments(o); }; Assign.prototype.compileSplice = function(o) { var answer, exclusive, from, fromDecl, fromRef, name, ref3, ref4, ref5, to, valDef, valRef; ref3 = this.variable.properties.pop().range, from = ref3.from, to = ref3.to, exclusive = ref3.exclusive; name = this.variable.compile(o); if (from) { ref4 = this.cacheToCodeFragments(from.cache(o, LEVEL_OP)), fromDecl = ref4[0], fromRef = ref4[1]; } else { fromDecl = fromRef = '0'; } if (to) { if ((from != null ? from.isNumber() : void 0) && to.isNumber()) { to = to.compile(o) - fromRef; if (!exclusive) { to += 1; } } else { to = to.compile(o, LEVEL_ACCESS) + ' - ' + fromRef; if (!exclusive) { to += ' + 1'; } } } else { to = "9e9"; } ref5 = this.value.cache(o, LEVEL_LIST), valDef = ref5[0], valRef = ref5[1]; answer = [].concat(this.makeCode("[].splice.apply(" + name + ", [" + fromDecl + ", " + to + "].concat("), valDef, this.makeCode(")), "), valRef); if (o.level > LEVEL_TOP) { return this.wrapInBraces(answer); } else { return answer; } }; return Assign; })(Base); exports.Code = Code = (function(superClass1) { extend1(Code, superClass1); function Code(params, body, tag) { this.params = params || []; this.body = body || new Block; this.bound = tag === 'boundfunc'; this.isGenerator = !!this.body.contains(function(node) { return (node instanceof Op && node.isYield()) || node instanceof YieldReturn; }); } Code.prototype.children = ['params', 'body']; Code.prototype.isStatement = function() { return !!this.ctor; }; Code.prototype.jumps = NO; Code.prototype.makeScope = function(parentScope) { return new Scope(parentScope, this.body, this); }; Code.prototype.compileNode = function(o) { var answer, boundfunc, code, exprs, i, j, k, l, len1, len2, len3, len4, len5, len6, lit, m, p, param, params, q, r, ref, ref3, ref4, ref5, ref6, ref7, ref8, splats, uniqs, val, wasEmpty, wrapper; if (this.bound && ((ref3 = o.scope.method) != null ? ref3.bound : void 0)) { this.context = o.scope.method.context; } if (this.bound && !this.context) { this.context = '_this'; wrapper = new Code([new Param(new IdentifierLiteral(this.context))], new Block([this])); boundfunc = new Call(wrapper, [new ThisLiteral]); boundfunc.updateLocationDataIfMissing(this.locationData); return boundfunc.compileNode(o); } o.scope = del(o, 'classScope') || this.makeScope(o.scope); o.scope.shared = del(o, 'sharedScope'); o.indent += TAB; delete o.bare; delete o.isExistentialEquals; params = []; exprs = []; ref4 = this.params; for (j = 0, len1 = ref4.length; j < len1; j++) { param = ref4[j]; if (!(param instanceof Expansion)) { o.scope.parameter(param.asReference(o)); } } ref5 = this.params; for (k = 0, len2 = ref5.length; k < len2; k++) { param = ref5[k]; if (!(param.splat || param instanceof Expansion)) { continue; } ref6 = this.params; for (l = 0, len3 = ref6.length; l < len3; l++) { p = ref6[l]; if (!(p instanceof Expansion) && p.name.value) { o.scope.add(p.name.value, 'var', true); } } splats = new Assign(new Value(new Arr((function() { var len4, m, ref7, results; ref7 = this.params; results = []; for (m = 0, len4 = ref7.length; m < len4; m++) { p = ref7[m]; results.push(p.asReference(o)); } return results; }).call(this))), new Value(new IdentifierLiteral('arguments'))); break; } ref7 = this.params; for (m = 0, len4 = ref7.length; m < len4; m++) { param = ref7[m]; 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) { (ref8 = this.body.expressions).unshift.apply(ref8, exprs); } for (i = q = 0, len5 = params.length; q < len5; i = ++q) { p = params[i]; params[i] = p.compileToFragments(o); o.scope.parameter(fragmentsToText(params[i])); } uniqs = []; this.eachParamName(function(name, node) { if (indexOf.call(uniqs, name) >= 0) { node.error("multiple parameters named " + name); } return uniqs.push(name); }); if (!(wasEmpty || this.noReturn)) { this.body.makeReturn(); } code = 'function'; if (this.isGenerator) { code += '*'; } if (this.ctor) { code += ' ' + this.name; } code += '('; answer = [this.makeCode(code)]; for (i = r = 0, len6 = params.length; r < len6; i = ++r) { p = params[i]; if (i) { answer.push(this.makeCode(", ")); } answer.push.apply(answer, p); } answer.push(this.makeCode(') {')); if (!this.body.isEmpty()) { answer = answer.concat(this.makeCode("\n"), this.body.compileWithDeclarations(o), this.makeCode("\n" + this.tab)); } answer.push(this.makeCode('}')); if (this.ctor) { return [this.makeCode(this.tab)].concat(slice.call(answer)); } if (this.front || (o.level >= LEVEL_ACCESS)) { return this.wrapInBraces(answer); } else { return answer; } }; Code.prototype.eachParamName = function(iterator) { var j, len1, param, ref3, results; ref3 = this.params; results = []; for (j = 0, len1 = ref3.length; j < len1; j++) { param = ref3[j]; results.push(param.eachName(iterator)); } return results; }; Code.prototype.traverseChildren = function(crossScope, func) { if (crossScope) { return Code.__super__.traverseChildren.call(this, crossScope, func); } }; return Code; })(Base); exports.Param = Param = (function(superClass1) { extend1(Param, superClass1); function Param(name1, value1, splat) { var message, token; this.name = name1; this.value = value1; this.splat = splat; message = isUnassignable(this.name.unwrapAll().value); if (message) { this.name.error(message); } if (this.name instanceof Obj && this.name.generated) { token = this.name.objects[0].operatorToken; token.error("unexpected " + token.value); } } Param.prototype.children = ['name', 'value']; Param.prototype.compileToFragments = function(o) { return this.name.compileToFragments(o, LEVEL_LIST); }; Param.prototype.asReference = function(o) { var name, node; if (this.reference) { return this.reference; } node = this.name; if (node["this"]) { name = node.properties[0].name.value; if (indexOf.call(JS_FORBIDDEN, name) >= 0) { name = "_" + name; } node = new IdentifierLiteral(o.scope.freeVariable(name)); } else if (node.isComplex()) { node = new IdentifierLiteral(o.scope.freeVariable('arg')); } node = new Value(node); if (this.splat) { node = new Splat(node); } node.updateLocationDataIfMissing(this.locationData); return this.reference = node; }; Param.prototype.isComplex = function() { return this.name.isComplex(); }; Param.prototype.eachName = function(iterator, name) { var atParam, j, len1, node, obj, ref3, ref4; if (name == null) { name = this.name; } atParam = function(obj) { return iterator("@" + obj.properties[0].name.value, obj); }; if (name instanceof Literal) { return iterator(name.value, name); } if (name instanceof Value) { return atParam(name); } ref4 = (ref3 = name.objects) != null ? ref3 : []; for (j = 0, len1 = ref4.length; j < len1; j++) { obj = ref4[j]; if (obj instanceof Assign && (obj.context == null)) { obj = obj.variable; } if (obj instanceof Assign) { if (obj.value instanceof Assign) { obj = obj.value; } this.eachName(iterator, obj.value.unwrap()); } else if (obj instanceof Splat) { node = obj.name.unwrap(); iterator(node.value, node); } else if (obj instanceof Value) { if (obj.isArray() || obj.isObject()) { this.eachName(iterator, obj.base); } else if (obj["this"]) { atParam(obj); } else { iterator(obj.base.value, obj.base); } } else if (!(obj instanceof Expansion)) { obj.error("illegal parameter " + (obj.compile())); } } }; return Param; })(Base); exports.Splat = Splat = (function(superClass1) { extend1(Splat, superClass1); 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.compileToFragments = function(o) { return this.name.compileToFragments(o); }; Splat.prototype.unwrap = function() { return this.name; }; Splat.compileSplattedArray = function(o, list, apply) { var args, base, compiledNode, concatPart, fragments, i, index, j, last, len1, node; index = -1; while ((node = list[++index]) && !(node instanceof Splat)) { continue; } if (index >= list.length) { return []; } if (list.length === 1) { node = list[0]; fragments = node.compileToFragments(o, LEVEL_LIST); if (apply) { return fragments; } return [].concat(node.makeCode((utility('slice', o)) + ".call("), fragments, node.makeCode(")")); } args = list.slice(index); for (i = j = 0, len1 = args.length; j < len1; i = ++j) { node = args[i]; compiledNode = node.compileToFragments(o, LEVEL_LIST); args[i] = node instanceof Splat ? [].concat(node.makeCode((utility('slice', o)) + ".call("), compiledNode, node.makeCode(")")) : [].concat(node.makeCode("["), compiledNode, node.makeCode("]")); } if (index === 0) { node = list[0]; concatPart = node.joinFragmentArrays(args.slice(1), ', '); return args[0].concat(node.makeCode(".concat("), concatPart, node.makeCode(")")); } base = (function() { var k, len2, ref3, results; ref3 = list.slice(0, index); results = []; for (k = 0, len2 = ref3.length; k < len2; k++) { node = ref3[k]; results.push(node.compileToFragments(o, LEVEL_LIST)); } return results; })(); base = list[0].joinFragmentArrays(base, ', '); concatPart = list[index].joinFragmentArrays(args, ', '); last = list[list.length - 1]; return [].concat(list[0].makeCode("["), base, list[index].makeCode("].concat("), concatPart, last.makeCode(")")); }; return Splat; })(Base); exports.Expansion = Expansion = (function(superClass1) { extend1(Expansion, superClass1); function Expansion() { return Expansion.__super__.constructor.apply(this, arguments); } Expansion.prototype.isComplex = NO; Expansion.prototype.compileNode = function(o) { return this.error('Expansion must be used inside a destructuring assignment or parameter list'); }; Expansion.prototype.asReference = function(o) { return this; }; Expansion.prototype.eachName = function(iterator) {}; return Expansion; })(Base); exports.While = While = (function(superClass1) { extend1(While, superClass1); 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(body1) { this.body = body1; return this; }; While.prototype.jumps = function() { var expressions, j, jumpNode, len1, node; expressions = this.body.expressions; if (!expressions.length) { return false; } for (j = 0, len1 = expressions.length; j < len1; j++) { node = expressions[j]; if (jumpNode = node.jumps({ loop: true })) { return jumpNode; } } return false; }; While.prototype.compileNode = function(o) { var answer, body, rvar, set; o.indent += TAB; set = ''; body = this.body; if (body.isEmpty()) { body = this.makeCode(''); } 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 StatementLiteral("continue"))); } else { if (this.guard) { body = Block.wrap([new If(this.guard, body)]); } } } body = [].concat(this.makeCode("\n"), body.compileToFragments(o, LEVEL_TOP), this.makeCode("\n" + this.tab)); } answer = [].concat(this.makeCode(set + this.tab + "while ("), this.condition.compileToFragments(o, LEVEL_PAREN), this.makeCode(") {"), body, this.makeCode("}")); if (this.returns) { answer.push(this.makeCode("\n" + this.tab + "return " + rvar + ";")); } return answer; }; return While; })(Base); exports.Op = Op = (function(superClass1) { var CONVERSIONS, INVERSIONS; extend1(Op, superClass1); 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', 'yieldfrom': 'yield*' }; INVERSIONS = { '!==': '===', '===': '!==' }; Op.prototype.children = ['first', 'second']; Op.prototype.isNumber = function() { var ref3; return this.isUnary() && ((ref3 = this.operator) === '+' || ref3 === '-') && this.first instanceof Value && this.first.isNumber(); }; Op.prototype.isYield = function() { var ref3; return (ref3 = this.operator) === 'yield' || ref3 === 'yield*'; }; Op.prototype.isUnary = function() { return !this.second; }; Op.prototype.isComplex = function() { return !this.isNumber(); }; Op.prototype.isChainable = function() { var ref3; return (ref3 = this.operator) === '<' || ref3 === '>' || ref3 === '>=' || ref3 === '<=' || ref3 === '===' || ref3 === '!=='; }; Op.prototype.invert = function() { var allInvertable, curr, fst, op, ref3; 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 && ((ref3 = fst.operator) === '!' || ref3 === 'in' || ref3 === 'instanceof')) { return fst; } else { return new Op('!', this); } }; Op.prototype.unfoldSoak = function(o) { var ref3; return ((ref3 = this.operator) === '++' || ref3 === '--' || ref3 === 'delete') && unfoldSoak(o, this, 'first'); }; Op.prototype.generateDo = function(exp) { var call, func, j, len1, param, passedParams, ref, ref3; passedParams = []; func = exp instanceof Assign && (ref = exp.value.unwrap()) instanceof Code ? ref : exp; ref3 = func.params || []; for (j = 0, len1 = ref3.length; j < len1; j++) { param = ref3[j]; 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 answer, isChain, lhs, message, ref3, rhs; isChain = this.isChainable() && this.first.isChainable(); if (!isChain) { this.first.front = this.front; } if (this.operator === 'delete' && o.scope.check(this.first.unwrapAll().value)) { this.error('delete operand may not be argument or var'); } if ((ref3 = this.operator) === '--' || ref3 === '++') { message = isUnassignable(this.first.unwrapAll().value); if (message) { this.first.error(message); } } if (this.isYield()) { return this.compileYield(o); } if (this.isUnary()) { return this.compileUnary(o); } if (isChain) { return this.compileChain(o); } switch (this.operator) { case '?': return this.compileExistence(o); case '**': return this.compilePower(o); case '//': return this.compileFloorDivision(o); case '%%': return this.compileModulo(o); default: lhs = this.first.compileToFragments(o, LEVEL_OP); rhs = this.second.compileToFragments(o, LEVEL_OP); answer = [].concat(lhs, this.makeCode(" " + this.operator + " "), rhs); if (o.level <= LEVEL_OP) { return answer; } else { return this.wrapInBraces(answer); } } }; Op.prototype.compileChain = function(o) { var fragments, fst, ref3, shared; ref3 = this.first.second.cache(o), this.first.second = ref3[0], shared = ref3[1]; fst = this.first.compileToFragments(o, LEVEL_OP); fragments = fst.concat(this.makeCode(" " + (this.invert ? '&&' : '||') + " "), shared.compileToFragments(o), this.makeCode(" " + this.operator + " "), this.second.compileToFragments(o, LEVEL_OP)); return this.wrapInBraces(fragments); }; Op.prototype.compileExistence = function(o) { var fst, ref; if (this.first.isComplex()) { ref = new IdentifierLiteral(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).compileToFragments(o); }; Op.prototype.compileUnary = function(o) { var op, parts, plusMinus; parts = []; op = this.operator; parts.push([this.makeCode(op)]); if (op === '!' && this.first instanceof Existence) { this.first.negated = !this.first.negated; return this.first.compileToFragments(o); } if (o.level >= LEVEL_ACCESS) { return (new Parens(this)).compileToFragments(o); } plusMinus = op === '+' || op === '-'; if ((op === 'new' || op === 'typeof' || op === 'delete') || plusMinus && this.first instanceof Op && this.first.operator === op) { parts.push([this.makeCode(' ')]); } if ((plusMinus && this.first instanceof Op) || (op === 'new' && this.first.isStatement(o))) { this.first = new Parens(this.first); } parts.push(this.first.compileToFragments(o, LEVEL_OP)); if (this.flip) { parts.reverse(); } return this.joinFragmentArrays(parts, ''); }; Op.prototype.compileYield = function(o) { var op, parts, ref3; parts = []; op = this.operator; if (o.scope.parent == null) { this.error('yield can only occur inside functions'); } if (indexOf.call(Object.keys(this.first), 'expression') >= 0 && !(this.first instanceof Throw)) { if (this.first.expression != null) { parts.push(this.first.expression.compileToFragments(o, LEVEL_OP)); } } else { if (o.level >= LEVEL_PAREN) { parts.push([this.makeCode("(")]); } parts.push([this.makeCode(op)]); if (((ref3 = this.first.base) != null ? ref3.value : void 0) !== '') { parts.push([this.makeCode(" ")]); } parts.push(this.first.compileToFragments(o, LEVEL_OP)); if (o.level >= LEVEL_PAREN) { parts.push([this.makeCode(")")]); } } return this.joinFragmentArrays(parts, ''); }; Op.prototype.compilePower = function(o) { var pow; pow = new Value(new IdentifierLiteral('Math'), [new Access(new PropertyName('pow'))]); return new Call(pow, [this.first, this.second]).compileToFragments(o); }; Op.prototype.compileFloorDivision = function(o) { var div, floor, second; floor = new Value(new IdentifierLiteral('Math'), [new Access(new PropertyName('floor'))]); second = this.second.isComplex() ? new Parens(this.second) : this.second; div = new Op('/', this.first, second); return new Call(floor, [div]).compileToFragments(o); }; Op.prototype.compileModulo = function(o) { var mod; mod = new Value(new Literal(utility('modulo', o))); return new Call(mod, [this.first, this.second]).compileToFragments(o); }; Op.prototype.toString = function(idt) { return Op.__super__.toString.call(this, idt, this.constructor.name + ' ' + this.operator); }; return Op; })(Base); exports.In = In = (function(superClass1) { extend1(In, superClass1); 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, j, len1, obj, ref3; if (this.array instanceof Value && this.array.isArray() && this.array.base.objects.length) { ref3 = this.array.base.objects; for (j = 0, len1 = ref3.length; j < len1; j++) { obj = ref3[j]; 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, j, len1, ref, ref3, ref4, ref5, sub, tests; ref3 = this.object.cache(o, LEVEL_OP), sub = ref3[0], ref = ref3[1]; ref4 = this.negated ? [' !== ', ' && '] : [' === ', ' || '], cmp = ref4[0], cnj = ref4[1]; tests = []; ref5 = this.array.base.objects; for (i = j = 0, len1 = ref5.length; j < len1; i = ++j) { item = ref5[i]; if (i) { tests.push(this.makeCode(cnj)); } tests = tests.concat((i ? ref : sub), this.makeCode(cmp), item.compileToFragments(o, LEVEL_ACCESS)); } if (o.level < LEVEL_OP) { return tests; } else { return this.wrapInBraces(tests); } }; In.prototype.compileLoopTest = function(o) { var fragments, ref, ref3, sub; ref3 = this.object.cache(o, LEVEL_LIST), sub = ref3[0], ref = ref3[1]; fragments = [].concat(this.makeCode(utility('indexOf', o) + ".call("), this.array.compileToFragments(o, LEVEL_LIST), this.makeCode(", "), ref, this.makeCode(") " + (this.negated ? '< 0' : '>= 0'))); if (fragmentsToText(sub) === fragmentsToText(ref)) { return fragments; } fragments = sub.concat(this.makeCode(', '), fragments); if (o.level < LEVEL_LIST) { return fragments; } else { return this.wrapInBraces(fragments); } }; In.prototype.toString = function(idt) { return In.__super__.toString.call(this, idt, this.constructor.name + (this.negated ? '!' : '')); }; return In; })(Base); exports.Try = Try = (function(superClass1) { extend1(Try, superClass1); function Try(attempt, errorVariable, recovery, ensure) { this.attempt = attempt; this.errorVariable = errorVariable; this.recovery = recovery; this.ensure = ensure; } Try.prototype.children = ['attempt', 'recovery', 'ensure']; Try.prototype.isStatement = YES; Try.prototype.jumps = function(o) { var ref3; return this.attempt.jumps(o) || ((ref3 = this.recovery) != null ? ref3.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, generatedErrorVariableName, message, placeholder, tryPart; o.indent += TAB; tryPart = this.attempt.compileToFragments(o, LEVEL_TOP); catchPart = this.recovery ? (generatedErrorVariableName = o.scope.freeVariable('error', { reserve: false }), placeholder = new IdentifierLiteral(generatedErrorVariableName), this.errorVariable ? (message = isUnassignable(this.errorVariable.unwrapAll().value), message ? this.errorVariable.error(message) : void 0, this.recovery.unshift(new Assign(this.errorVariable, placeholder))) : void 0, [].concat(this.makeCode(" catch ("), placeholder.compileToFragments(o), this.makeCode(") {\n"), this.recovery.compileToFragments(o, LEVEL_TOP), this.makeCode("\n" + this.tab + "}"))) : !(this.ensure || this.recovery) ? (generatedErrorVariableName = o.scope.freeVariable('error', { reserve: false }), [this.makeCode(" catch (" + generatedErrorVariableName + ") {}")]) : []; ensurePart = this.ensure ? [].concat(this.makeCode(" finally {\n"), this.ensure.compileToFragments(o, LEVEL_TOP), this.makeCode("\n" + this.tab + "}")) : []; return [].concat(this.makeCode(this.tab + "try {\n"), tryPart, this.makeCode("\n" + this.tab + "}"), catchPart, ensurePart); }; return Try; })(Base); exports.Throw = Throw = (function(superClass1) { extend1(Throw, superClass1); 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 [].concat(this.makeCode(this.tab + "throw "), this.expression.compileToFragments(o), this.makeCode(";")); }; return Throw; })(Base); exports.Existence = Existence = (function(superClass1) { extend1(Existence, superClass1); function Existence(expression) { this.expression = expression; } Existence.prototype.children = ['expression']; Existence.prototype.invert = NEGATE; Existence.prototype.compileNode = function(o) { var cmp, cnj, code, ref3; this.expression.front = this.front; code = this.expression.compile(o, LEVEL_OP); if (this.expression.unwrap() instanceof IdentifierLiteral && !o.scope.check(code)) { ref3 = this.negated ? ['===', '||'] : ['!==', '&&'], cmp = ref3[0], cnj = ref3[1]; code = "typeof " + code + " " + cmp + " \"undefined\" " + cnj + " " + code + " " + cmp + " null"; } else { code = code + " " + (this.negated ? '==' : '!=') + " null"; } return [this.makeCode(o.level <= LEVEL_COND ? code : "(" + code + ")")]; }; return Existence; })(Base); exports.Parens = Parens = (function(superClass1) { extend1(Parens, superClass1); function Parens(body1) { this.body = body1; } 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, expr, fragments; expr = this.body.unwrap(); if (expr instanceof Value && expr.isAtomic()) { expr.front = this.front; return expr.compileToFragments(o); } fragments = expr.compileToFragments(o, LEVEL_PAREN); bare = o.level < LEVEL_OP && (expr instanceof Op || expr instanceof Call || (expr instanceof For && expr.returns)) && (o.level < LEVEL_COND || fragments.length <= 3); if (bare) { return fragments; } else { return this.wrapInBraces(fragments); } }; return Parens; })(Base); exports.StringWithInterpolations = StringWithInterpolations = (function(superClass1) { extend1(StringWithInterpolations, superClass1); function StringWithInterpolations() { return StringWithInterpolations.__super__.constructor.apply(this, arguments); } StringWithInterpolations.prototype.compileNode = function(o) { var element, elements, expr, fragments, j, len1, value; if (!o.inTaggedTemplateCall) { return StringWithInterpolations.__super__.compileNode.apply(this, arguments); } expr = this.body.unwrap(); elements = []; expr.traverseChildren(false, function(node) { if (node instanceof StringLiteral) { elements.push(node); return true; } else if (node instanceof Parens) { elements.push(node); return false; } return true; }); fragments = []; fragments.push(this.makeCode('`')); for (j = 0, len1 = elements.length; j < len1; j++) { element = elements[j]; if (element instanceof StringLiteral) { value = element.value.slice(1, -1); value = value.replace(/(\\*)(`|\$\{)/g, function(match, backslashes, toBeEscaped) { if (backslashes.length % 2 === 0) { return backslashes + "\\" + toBeEscaped; } else { return match; } }); fragments.push(this.makeCode(value)); } else { fragments.push(this.makeCode('${')); fragments.push.apply(fragments, element.compileToFragments(o, LEVEL_PAREN)); fragments.push(this.makeCode('}')); } } fragments.push(this.makeCode('`')); return fragments; }; return StringWithInterpolations; })(Parens); exports.For = For = (function(superClass1) { extend1(For, superClass1); function For(body, source) { var ref3; 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; this.from = !!source.from; if (this.from && this.index) { this.index.error('cannot use index with for-from'); } if (this.own && !this.object) { source.ownTag.error("cannot use own with for-" + (this.from ? 'from' : 'in')); } if (this.object) { ref3 = [this.index, this.name], this.name = ref3[0], this.index = ref3[1]; } if (this.index instanceof Value && !this.index.isAssignable()) { this.index.error('index cannot be a pattern matching expression'); } this.range = this.source instanceof Value && this.source.base instanceof Range && !this.source.properties.length && !this.from; this.pattern = this.name instanceof Value; if (this.range && this.index) { this.index.error('indexes do not apply to range loops'); } if (this.range && this.pattern) { this.name.error('cannot pattern match over range loops'); } this.returns = false; } For.prototype.children = ['body', 'source', 'guard', 'step']; For.prototype.compileNode = function(o) { var body, bodyFragments, compare, compareDown, declare, declareDown, defPart, defPartFragments, down, forPartFragments, guardPart, idt1, increment, index, ivar, kvar, kvarAssign, last, lvar, name, namePart, ref, ref3, ref4, resultPart, returnResult, rvar, scope, source, step, stepNum, stepVar, svar, varPart; body = Block.wrap([this.body]); ref3 = body.expressions, last = ref3[ref3.length - 1]; if ((last != null ? last.jumps() : void 0) instanceof Return) { this.returns = false; } source = this.range ? this.source.base : this.source; scope = o.scope; if (!this.pattern) { 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 && !(this.index instanceof Value)) { scope.find(index); } if (this.returns) { rvar = scope.freeVariable('results'); } if (this.from) { if (this.pattern) { ivar = scope.freeVariable('x', { single: true }); } } else { ivar = (this.object && index) || scope.freeVariable('i', { single: true }); } kvar = ((this.range || this.from) && name) || index || ivar; kvarAssign = kvar !== ivar ? kvar + " = " : ""; if (this.step && !this.range) { ref4 = this.cacheToCodeFragments(this.step.cache(o, LEVEL_LIST, isComplexOrAssignable)), step = ref4[0], stepVar = ref4[1]; if (this.step.isNumber()) { stepNum = Number(stepVar); } } if (this.pattern) { name = ivar; } varPart = ''; guardPart = ''; defPart = ''; idt1 = this.tab + TAB; if (this.range) { forPartFragments = source.compileToFragments(merge(o, { index: ivar, name: name, step: this.step, isComplex: isComplexOrAssignable })); } else { svar = this.source.compile(o, LEVEL_LIST); if ((name || this.own) && !(this.source.unwrap() instanceof IdentifierLiteral)) { defPart += "" + this.tab + (ref = scope.freeVariable('ref')) + " = " + svar + ";\n"; svar = ref; } if (name && !this.pattern && !this.from) { namePart = name + " = " + svar + "[" + kvar + "]"; } if (!this.object && !this.from) { if (step !== stepVar) { defPart += "" + this.tab + step + ";\n"; } down = stepNum < 0; if (!(this.step && (stepNum != null) && down)) { lvar = scope.freeVariable('len'); } declare = "" + kvarAssign + ivar + " = 0, " + lvar + " = " + svar + ".length"; declareDown = "" + kvarAssign + ivar + " = " + svar + ".length - 1"; compare = ivar + " < " + lvar; compareDown = ivar + " >= 0"; if (this.step) { if (stepNum != null) { if (down) { compare = compareDown; declare = declareDown; } } else { compare = stepVar + " > 0 ? " + compare + " : " + compareDown; declare = "(" + stepVar + " > 0 ? (" + declare + ") : " + declareDown + ")"; } increment = ivar + " += " + stepVar; } else { increment = "" + (kvar !== ivar ? "++" + ivar : ivar + "++"); } forPartFragments = [this.makeCode(declare + "; " + compare + "; " + kvarAssign + increment)]; } } 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 StatementLiteral("continue"))); } else { if (this.guard) { body = Block.wrap([new If(this.guard, body)]); } } } if (this.pattern) { body.expressions.unshift(new Assign(this.name, this.from ? new IdentifierLiteral(kvar) : new Literal(svar + "[" + kvar + "]"))); } defPartFragments = [].concat(this.makeCode(defPart), this.pluckDirectCall(o, body)); if (namePart) { varPart = "\n" + idt1 + namePart + ";"; } if (this.object) { forPartFragments = [this.makeCode(kvar + " in " + svar)]; if (this.own) { guardPart = "\n" + idt1 + "if (!" + (utility('hasProp', o)) + ".call(" + svar + ", " + kvar + ")) continue;"; } } else if (this.from) { forPartFragments = [this.makeCode(kvar + " of " + svar)]; } bodyFragments = body.compileToFragments(merge(o, { indent: idt1 }), LEVEL_TOP); if (bodyFragments && bodyFragments.length > 0) { bodyFragments = [].concat(this.makeCode("\n"), bodyFragments, this.makeCode("\n")); } return [].concat(defPartFragments, this.makeCode("" + (resultPart || '') + this.tab + "for ("), forPartFragments, this.makeCode(") {" + guardPart + varPart), bodyFragments, this.makeCode(this.tab + "}" + (returnResult || ''))); }; For.prototype.pluckDirectCall = function(o, body) { var base, defs, expr, fn, idx, j, len1, ref, ref3, ref4, ref5, ref6, ref7, ref8, ref9, val; defs = []; ref3 = body.expressions; for (idx = j = 0, len1 = ref3.length; j < len1; idx = ++j) { expr = ref3[idx]; expr = expr.unwrapAll(); if (!(expr instanceof Call)) { continue; } val = (ref4 = expr.variable) != null ? ref4.unwrapAll() : void 0; if (!((val instanceof Code) || (val instanceof Value && ((ref5 = val.base) != null ? ref5.unwrapAll() : void 0) instanceof Code && val.properties.length === 1 && ((ref6 = (ref7 = val.properties[0].name) != null ? ref7.value : void 0) === 'call' || ref6 === 'apply')))) { continue; } fn = ((ref8 = val.base) != null ? ref8.unwrapAll() : void 0) || val; ref = new IdentifierLiteral(o.scope.freeVariable('fn')); base = new Value(ref); if (val.base) { ref9 = [base, val], val.base = ref9[0], base = ref9[1]; } body.expressions[idx] = new Call(base, expr.args); defs = defs.concat(this.makeCode(this.tab), new Assign(ref, fn).compileToFragments(o, LEVEL_TOP), this.makeCode(';\n')); } return defs; }; return For; })(While); exports.Switch = Switch = (function(superClass1) { extend1(Switch, superClass1); 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, j, jumpNode, len1, ref3, ref4, ref5; if (o == null) { o = { block: true }; } ref3 = this.cases; for (j = 0, len1 = ref3.length; j < len1; j++) { ref4 = ref3[j], conds = ref4[0], block = ref4[1]; if (jumpNode = block.jumps(o)) { return jumpNode; } } return (ref5 = this.otherwise) != null ? ref5.jumps(o) : void 0; }; Switch.prototype.makeReturn = function(res) { var j, len1, pair, ref3, ref4; ref3 = this.cases; for (j = 0, len1 = ref3.length; j < len1; j++) { pair = ref3[j]; pair[1].makeReturn(res); } if (res) { this.otherwise || (this.otherwise = new Block([new Literal('void 0')])); } if ((ref4 = this.otherwise) != null) { ref4.makeReturn(res); } return this; }; Switch.prototype.compileNode = function(o) { var block, body, cond, conditions, expr, fragments, i, idt1, idt2, j, k, len1, len2, ref3, ref4, ref5; idt1 = o.indent + TAB; idt2 = o.indent = idt1 + TAB; fragments = [].concat(this.makeCode(this.tab + "switch ("), (this.subject ? this.subject.compileToFragments(o, LEVEL_PAREN) : this.makeCode("false")), this.makeCode(") {\n")); ref3 = this.cases; for (i = j = 0, len1 = ref3.length; j < len1; i = ++j) { ref4 = ref3[i], conditions = ref4[0], block = ref4[1]; ref5 = flatten([conditions]); for (k = 0, len2 = ref5.length; k < len2; k++) { cond = ref5[k]; if (!this.subject) { cond = cond.invert(); } fragments = fragments.concat(this.makeCode(idt1 + "case "), cond.compileToFragments(o, LEVEL_PAREN), this.makeCode(":\n")); } if ((body = block.compileToFragments(o, LEVEL_TOP)).length > 0) { fragments = fragments.concat(body, this.makeCode('\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; } fragments.push(cond.makeCode(idt2 + 'break;\n')); } if (this.otherwise && this.otherwise.expressions.length) { fragments.push.apply(fragments, [this.makeCode(idt1 + "default:\n")].concat(slice.call(this.otherwise.compileToFragments(o, LEVEL_TOP)), [this.makeCode("\n")])); } fragments.push(this.makeCode(this.tab + '}')); return fragments; }; return Switch; })(Base); exports.If = If = (function(superClass1) { extend1(If, superClass1); function If(condition, body1, options) { this.body = body1; 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 ref3; return (ref3 = this.body) != null ? ref3.unwrap() : void 0; }; If.prototype.elseBodyNode = function() { var ref3; return (ref3 = this.elseBody) != null ? ref3.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); this.elseBody.updateLocationDataIfMissing(elseBody.locationData); } return this; }; If.prototype.isStatement = function(o) { var ref3; return (o != null ? o.level : void 0) === LEVEL_TOP || this.bodyNode().isStatement(o) || ((ref3 = this.elseBodyNode()) != null ? ref3.isStatement(o) : void 0); }; If.prototype.jumps = function(o) { var ref3; return this.body.jumps(o) || ((ref3 = this.elseBody) != null ? ref3.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 answer, body, child, cond, exeq, ifPart, indent; child = del(o, 'chainChild'); exeq = del(o, 'isExistentialEquals'); if (exeq) { return new If(this.condition.invert(), this.elseBodyNode(), { type: 'if' }).compileToFragments(o); } indent = o.indent + TAB; cond = this.condition.compileToFragments(o, LEVEL_PAREN); body = this.ensureBlock(this.body).compileToFragments(merge(o, { indent: indent })); ifPart = [].concat(this.makeCode("if ("), cond, this.makeCode(") {\n"), body, this.makeCode("\n" + this.tab + "}")); if (!child) { ifPart.unshift(this.makeCode(this.tab)); } if (!this.elseBody) { return ifPart; } answer = ifPart.concat(this.makeCode(' else ')); if (this.isChain) { o.chainChild = true; answer = answer.concat(this.elseBody.unwrap().compileToFragments(o, LEVEL_TOP)); } else { answer = answer.concat(this.makeCode("{\n"), this.elseBody.compileToFragments(merge(o, { indent: indent }), LEVEL_TOP), this.makeCode("\n" + this.tab + "}")); } return answer; }; If.prototype.compileExpression = function(o) { var alt, body, cond, fragments; cond = this.condition.compileToFragments(o, LEVEL_COND); body = this.bodyNode().compileToFragments(o, LEVEL_LIST); alt = this.elseBodyNode() ? this.elseBodyNode().compileToFragments(o, LEVEL_LIST) : [this.makeCode('void 0')]; fragments = cond.concat(this.makeCode(" ? "), body, this.makeCode(" : "), alt); if (o.level >= LEVEL_COND) { return this.wrapInBraces(fragments); } else { return fragments; } }; If.prototype.unfoldSoak = function() { return this.soak && this; }; return If; })(Base); UTILITIES = { extend: function(o) { return "function(child, parent) { for (var key in parent) { if (" + (utility('hasProp', o)) + ".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; }"; }, modulo: function() { return "function(a, b) { return (+a % (b = +b) + b) % b; }"; }, 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 = ' '; SIMPLENUM = /^[+-]?\d+$/; utility = function(name, o) { var ref, root; root = o.scope.root; if (name in root.utilities) { return root.utilities[name]; } else { ref = root.freeVariable(name); root.assign(ref, UTILITIES[name](o)); return root.utilities[name] = ref; } }; multident = function(code, tab) { code = code.replace(/\n/g, '$&' + tab); return code.replace(/\s+$/, ''); }; isLiteralArguments = function(node) { return node instanceof IdentifierLiteral && node.value === 'arguments'; }; isLiteralThis = function(node) { return node instanceof ThisLiteral || (node instanceof Code && node.bound) || node instanceof SuperCall; }; isComplexOrAssignable = function(node) { return node.isComplex() || (typeof node.isAssignable === "function" ? node.isAssignable() : void 0); }; 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; }; }).call(this); coffeescript-1.12.7/lib/coffee-script/optparse.js000066400000000000000000000077511313305734200217630ustar00rootroot00000000000000// Generated by CoffeeScript 1.12.7 (function() { var LONG_FLAG, MULTI_FLAG, OPTIONAL, OptionParser, SHORT_FLAG, buildRule, buildRules, normalizeArguments, repeat; repeat = require('./helpers').repeat; exports.OptionParser = OptionParser = (function() { function OptionParser(rules, banner) { this.banner = banner; this.rules = buildRules(rules); } OptionParser.prototype.parse = function(args) { var arg, i, isOption, j, k, len, len1, matchedRule, options, originalArgs, pos, ref, rule, seenNonOptionArg, skippingArgument, value; options = { "arguments": [] }; skippingArgument = false; originalArgs = args; args = normalizeArguments(args); for (i = j = 0, len = args.length; j < len; i = ++j) { 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 (k = 0, len1 = ref.length; k < len1; k++) { rule = ref[k]; 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 j, len, letPart, lines, ref, rule, spaces; lines = []; if (this.banner) { lines.unshift(this.banner + "\n"); } ref = this.rules; for (j = 0, len = ref.length; j < len; j++) { rule = ref[j]; spaces = 15 - rule.longFlag.length; spaces = spaces > 0 ? repeat(' ', spaces) : ''; 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 j, len, results, tuple; results = []; for (j = 0, len = rules.length; j < len; j++) { tuple = rules[j]; 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, j, k, l, len, len1, match, ref, result; args = args.slice(0); result = []; for (j = 0, len = args.length; j < len; j++) { arg = args[j]; if (match = arg.match(MULTI_FLAG)) { ref = match[1].split(''); for (k = 0, len1 = ref.length; k < len1; k++) { l = ref[k]; result.push('-' + l); } } else { result.push(arg); } } return result; }; }).call(this); coffeescript-1.12.7/lib/coffee-script/parser.js000077500000000000000000003214711313305734200214230ustar00rootroot00000000000000/* parser generated by jison 0.4.17 */ /* Returns a Parser object of the following structure: Parser: { yy: {} } Parser.prototype: { yy: {}, trace: function(), symbols_: {associative list: name ==> number}, terminals_: {associative list: number ==> name}, productions_: [...], performAction: function anonymous(yytext, yyleng, yylineno, yy, yystate, $$, _$), table: [...], defaultActions: {...}, parseError: function(str, hash), parse: function(input), lexer: { EOF: 1, parseError: function(str, hash), setInput: function(input), input: function(), unput: function(str), more: function(), less: function(n), pastInput: function(), upcomingInput: function(), showPosition: function(), test_match: function(regex_match_array, rule_index), next: function(), lex: function(), begin: function(condition), popState: function(), _currentRules: function(), topState: function(), pushState: function(condition), options: { ranges: boolean (optional: true ==> token location info will include a .range[] member) flex: boolean (optional: true ==> flex-like lexing behaviour where the rules are tested exhaustively to find the longest match) backtrack_lexer: boolean (optional: true ==> lexer regexes are tested in order and for each matching regex the action code is invoked; the lexer terminates the scan when a token is returned by the action code) }, performAction: function(yy, yy_, $avoiding_name_collisions, YY_START), rules: [...], conditions: {associative list: name ==> set}, } } token location info (@$, _$, etc.): { first_line: n, last_line: n, first_column: n, last_column: n, range: [start_number, end_number] (where the numbers are indexes into the input string, regular zero-based) } the parseError function receives a 'hash' object with these members for lexer and parser errors: { text: (matched text) token: (the produced terminal token, if any) line: (yylineno) } while parser (grammar) errors will also provide these members, i.e. parser errors deliver a superset of attributes: { loc: (yylloc) expected: (string describing the set of expected tokens) recoverable: (boolean: TRUE when the parser has a error recovery rule available for this particular error) } */ var parser = (function(){ var o=function(k,v,o,l){for(o=o||{},l=k.length;l--;o[k[l]]=v);return o},$V0=[1,22],$V1=[1,25],$V2=[1,83],$V3=[1,79],$V4=[1,84],$V5=[1,85],$V6=[1,81],$V7=[1,82],$V8=[1,56],$V9=[1,58],$Va=[1,59],$Vb=[1,60],$Vc=[1,61],$Vd=[1,62],$Ve=[1,49],$Vf=[1,50],$Vg=[1,32],$Vh=[1,68],$Vi=[1,69],$Vj=[1,78],$Vk=[1,47],$Vl=[1,51],$Vm=[1,52],$Vn=[1,67],$Vo=[1,65],$Vp=[1,66],$Vq=[1,64],$Vr=[1,42],$Vs=[1,48],$Vt=[1,63],$Vu=[1,73],$Vv=[1,74],$Vw=[1,75],$Vx=[1,76],$Vy=[1,46],$Vz=[1,72],$VA=[1,34],$VB=[1,35],$VC=[1,36],$VD=[1,37],$VE=[1,38],$VF=[1,39],$VG=[1,86],$VH=[1,6,32,42,131],$VI=[1,101],$VJ=[1,89],$VK=[1,88],$VL=[1,87],$VM=[1,90],$VN=[1,91],$VO=[1,92],$VP=[1,93],$VQ=[1,94],$VR=[1,95],$VS=[1,96],$VT=[1,97],$VU=[1,98],$VV=[1,99],$VW=[1,100],$VX=[1,104],$VY=[1,6,31,32,42,66,71,74,89,94,115,120,122,131,133,134,135,139,140,156,159,160,163,164,165,166,167,168,169,170,171,172,173,174],$VZ=[2,167],$V_=[1,110],$V$=[1,111],$V01=[1,112],$V11=[1,113],$V21=[1,115],$V31=[1,116],$V41=[1,109],$V51=[1,6,32,42,131,133,135,139,156],$V61=[2,27],$V71=[1,123],$V81=[1,121],$V91=[1,6,31,32,40,41,42,66,71,74,82,83,84,85,87,89,90,94,113,114,115,120,122,131,133,134,135,139,140,156,159,160,163,164,165,166,167,168,169,170,171,172,173,174],$Va1=[2,95],$Vb1=[1,6,31,32,42,46,66,71,74,82,83,84,85,87,89,90,94,113,114,115,120,122,131,133,134,135,139,140,156,159,160,163,164,165,166,167,168,169,170,171,172,173,174],$Vc1=[2,74],$Vd1=[1,128],$Ve1=[1,133],$Vf1=[1,134],$Vg1=[1,136],$Vh1=[1,6,31,32,40,41,42,55,66,71,74,82,83,84,85,87,89,90,94,113,114,115,120,122,131,133,134,135,139,140,156,159,160,163,164,165,166,167,168,169,170,171,172,173,174],$Vi1=[2,92],$Vj1=[1,6,32,42,66,71,74,89,94,115,120,122,131,133,134,135,139,140,156,159,160,163,164,165,166,167,168,169,170,171,172,173,174],$Vk1=[2,64],$Vl1=[1,161],$Vm1=[1,167],$Vn1=[1,179],$Vo1=[1,181],$Vp1=[1,176],$Vq1=[1,183],$Vr1=[1,185],$Vs1=[1,6,31,32,40,41,42,55,66,71,74,82,83,84,85,87,89,90,94,96,113,114,115,120,122,131,133,134,135,139,140,156,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175],$Vt1=[2,111],$Vu1=[1,6,31,32,40,41,42,58,66,71,74,82,83,84,85,87,89,90,94,113,114,115,120,122,131,133,134,135,139,140,156,159,160,163,164,165,166,167,168,169,170,171,172,173,174],$Vv1=[1,6,31,32,40,41,42,46,58,66,71,74,82,83,84,85,87,89,90,94,113,114,115,120,122,131,133,134,135,139,140,156,159,160,163,164,165,166,167,168,169,170,171,172,173,174],$Vw1=[40,41,114],$Vx1=[1,242],$Vy1=[1,241],$Vz1=[1,6,31,32,42,66,71,74,89,94,115,120,122,131,133,134,135,139,140,156],$VA1=[2,72],$VB1=[1,251],$VC1=[6,31,32,66,71],$VD1=[6,31,32,55,66,71,74],$VE1=[1,6,31,32,42,66,71,74,89,94,115,120,122,131,133,134,135,139,140,156,159,160,164,166,167,168,169,170,171,172,173,174],$VF1=[40,41,82,83,84,85,87,90,113,114],$VG1=[1,270],$VH1=[2,62],$VI1=[1,281],$VJ1=[1,283],$VK1=[1,288],$VL1=[1,290],$VM1=[2,188],$VN1=[1,6,31,32,40,41,42,55,66,71,74,82,83,84,85,87,89,90,94,113,114,115,120,122,131,133,134,135,139,140,146,147,148,156,159,160,163,164,165,166,167,168,169,170,171,172,173,174],$VO1=[1,299],$VP1=[6,31,32,71,115,120],$VQ1=[1,6,31,32,40,41,42,55,58,66,71,74,82,83,84,85,87,89,90,94,96,113,114,115,120,122,131,133,134,135,139,140,146,147,148,156,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175],$VR1=[1,6,31,32,42,66,71,74,89,94,115,120,122,131,140,156],$VS1=[1,6,31,32,42,66,71,74,89,94,115,120,122,131,134,140,156],$VT1=[146,147,148],$VU1=[71,146,147,148],$VV1=[6,31,94],$VW1=[1,313],$VX1=[6,31,32,71,94],$VY1=[6,31,32,58,71,94],$VZ1=[6,31,32,55,58,71,94],$V_1=[1,6,31,32,42,66,71,74,89,94,115,120,122,131,133,134,135,139,140,156,159,160,166,167,168,169,170,171,172,173,174],$V$1=[12,28,34,38,40,41,44,45,48,49,50,51,52,53,61,63,64,68,69,89,92,95,97,105,112,117,118,119,125,129,130,133,135,137,139,149,155,157,158,159,160,161,162],$V02=[2,177],$V12=[6,31,32],$V22=[2,73],$V32=[1,325],$V42=[1,326],$V52=[1,6,31,32,42,66,71,74,89,94,115,120,122,127,128,131,133,134,135,139,140,151,153,156,159,160,163,164,165,166,167,168,169,170,171,172,173,174],$V62=[32,151,153],$V72=[1,6,32,42,66,71,74,89,94,115,120,122,131,134,140,156],$V82=[1,353],$V92=[1,359],$Va2=[1,6,32,42,131,156],$Vb2=[2,87],$Vc2=[1,370],$Vd2=[1,371],$Ve2=[1,6,31,32,42,66,71,74,89,94,115,120,122,131,133,134,135,139,140,151,156,159,160,163,164,165,166,167,168,169,170,171,172,173,174],$Vf2=[1,6,31,32,42,66,71,74,89,94,115,120,122,131,133,135,139,140,156],$Vg2=[1,384],$Vh2=[1,385],$Vi2=[6,31,32,94],$Vj2=[6,31,32,71],$Vk2=[1,6,31,32,42,66,71,74,89,94,115,120,122,127,131,133,134,135,139,140,156,159,160,163,164,165,166,167,168,169,170,171,172,173,174],$Vl2=[31,71],$Vm2=[1,411],$Vn2=[1,412],$Vo2=[1,418],$Vp2=[1,419]; var parser = {trace: function trace() { }, yy: {}, symbols_: {"error":2,"Root":3,"Body":4,"Line":5,"TERMINATOR":6,"Expression":7,"Statement":8,"YieldReturn":9,"Return":10,"Comment":11,"STATEMENT":12,"Import":13,"Export":14,"Value":15,"Invocation":16,"Code":17,"Operation":18,"Assign":19,"If":20,"Try":21,"While":22,"For":23,"Switch":24,"Class":25,"Throw":26,"Yield":27,"YIELD":28,"FROM":29,"Block":30,"INDENT":31,"OUTDENT":32,"Identifier":33,"IDENTIFIER":34,"Property":35,"PROPERTY":36,"AlphaNumeric":37,"NUMBER":38,"String":39,"STRING":40,"STRING_START":41,"STRING_END":42,"Regex":43,"REGEX":44,"REGEX_START":45,"REGEX_END":46,"Literal":47,"JS":48,"UNDEFINED":49,"NULL":50,"BOOL":51,"INFINITY":52,"NAN":53,"Assignable":54,"=":55,"AssignObj":56,"ObjAssignable":57,":":58,"SimpleObjAssignable":59,"ThisProperty":60,"RETURN":61,"Object":62,"HERECOMMENT":63,"PARAM_START":64,"ParamList":65,"PARAM_END":66,"FuncGlyph":67,"->":68,"=>":69,"OptComma":70,",":71,"Param":72,"ParamVar":73,"...":74,"Array":75,"Splat":76,"SimpleAssignable":77,"Accessor":78,"Parenthetical":79,"Range":80,"This":81,".":82,"?.":83,"::":84,"?::":85,"Index":86,"INDEX_START":87,"IndexValue":88,"INDEX_END":89,"INDEX_SOAK":90,"Slice":91,"{":92,"AssignList":93,"}":94,"CLASS":95,"EXTENDS":96,"IMPORT":97,"ImportDefaultSpecifier":98,"ImportNamespaceSpecifier":99,"ImportSpecifierList":100,"ImportSpecifier":101,"AS":102,"DEFAULT":103,"IMPORT_ALL":104,"EXPORT":105,"ExportSpecifierList":106,"EXPORT_ALL":107,"ExportSpecifier":108,"OptFuncExist":109,"Arguments":110,"Super":111,"SUPER":112,"FUNC_EXIST":113,"CALL_START":114,"CALL_END":115,"ArgList":116,"THIS":117,"@":118,"[":119,"]":120,"RangeDots":121,"..":122,"Arg":123,"SimpleArgs":124,"TRY":125,"Catch":126,"FINALLY":127,"CATCH":128,"THROW":129,"(":130,")":131,"WhileSource":132,"WHILE":133,"WHEN":134,"UNTIL":135,"Loop":136,"LOOP":137,"ForBody":138,"FOR":139,"BY":140,"ForStart":141,"ForSource":142,"ForVariables":143,"OWN":144,"ForValue":145,"FORIN":146,"FOROF":147,"FORFROM":148,"SWITCH":149,"Whens":150,"ELSE":151,"When":152,"LEADING_WHEN":153,"IfBlock":154,"IF":155,"POST_IF":156,"UNARY":157,"UNARY_MATH":158,"-":159,"+":160,"--":161,"++":162,"?":163,"MATH":164,"**":165,"SHIFT":166,"COMPARE":167,"&":168,"^":169,"|":170,"&&":171,"||":172,"BIN?":173,"RELATION":174,"COMPOUND_ASSIGN":175,"$accept":0,"$end":1}, terminals_: {2:"error",6:"TERMINATOR",12:"STATEMENT",28:"YIELD",29:"FROM",31:"INDENT",32:"OUTDENT",34:"IDENTIFIER",36:"PROPERTY",38:"NUMBER",40:"STRING",41:"STRING_START",42:"STRING_END",44:"REGEX",45:"REGEX_START",46:"REGEX_END",48:"JS",49:"UNDEFINED",50:"NULL",51:"BOOL",52:"INFINITY",53:"NAN",55:"=",58:":",61:"RETURN",63:"HERECOMMENT",64:"PARAM_START",66:"PARAM_END",68:"->",69:"=>",71:",",74:"...",82:".",83:"?.",84:"::",85:"?::",87:"INDEX_START",89:"INDEX_END",90:"INDEX_SOAK",92:"{",94:"}",95:"CLASS",96:"EXTENDS",97:"IMPORT",102:"AS",103:"DEFAULT",104:"IMPORT_ALL",105:"EXPORT",107:"EXPORT_ALL",112:"SUPER",113:"FUNC_EXIST",114:"CALL_START",115:"CALL_END",117:"THIS",118:"@",119:"[",120:"]",122:"..",125:"TRY",127:"FINALLY",128:"CATCH",129:"THROW",130:"(",131:")",133:"WHILE",134:"WHEN",135:"UNTIL",137:"LOOP",139:"FOR",140:"BY",144:"OWN",146:"FORIN",147:"FOROF",148:"FORFROM",149:"SWITCH",151:"ELSE",153:"LEADING_WHEN",155:"IF",156:"POST_IF",157:"UNARY",158:"UNARY_MATH",159:"-",160:"+",161:"--",162:"++",163:"?",164:"MATH",165:"**",166:"SHIFT",167:"COMPARE",168:"&",169:"^",170:"|",171:"&&",172:"||",173:"BIN?",174:"RELATION",175:"COMPOUND_ASSIGN"}, productions_: [0,[3,0],[3,1],[4,1],[4,3],[4,2],[5,1],[5,1],[5,1],[8,1],[8,1],[8,1],[8,1],[8,1],[7,1],[7,1],[7,1],[7,1],[7,1],[7,1],[7,1],[7,1],[7,1],[7,1],[7,1],[7,1],[7,1],[27,1],[27,2],[27,3],[30,2],[30,3],[33,1],[35,1],[37,1],[37,1],[39,1],[39,3],[43,1],[43,3],[47,1],[47,1],[47,1],[47,1],[47,1],[47,1],[47,1],[47,1],[19,3],[19,4],[19,5],[56,1],[56,3],[56,5],[56,3],[56,5],[56,1],[59,1],[59,1],[59,1],[57,1],[57,1],[10,2],[10,4],[10,1],[9,3],[9,2],[11,1],[17,5],[17,2],[67,1],[67,1],[70,0],[70,1],[65,0],[65,1],[65,3],[65,4],[65,6],[72,1],[72,2],[72,3],[72,1],[73,1],[73,1],[73,1],[73,1],[76,2],[77,1],[77,2],[77,2],[77,1],[54,1],[54,1],[54,1],[15,1],[15,1],[15,1],[15,1],[15,1],[78,2],[78,2],[78,2],[78,2],[78,1],[78,1],[86,3],[86,2],[88,1],[88,1],[62,4],[93,0],[93,1],[93,3],[93,4],[93,6],[25,1],[25,2],[25,3],[25,4],[25,2],[25,3],[25,4],[25,5],[13,2],[13,4],[13,4],[13,5],[13,7],[13,6],[13,9],[100,1],[100,3],[100,4],[100,4],[100,6],[101,1],[101,3],[101,1],[101,3],[98,1],[99,3],[14,3],[14,5],[14,2],[14,4],[14,5],[14,6],[14,3],[14,4],[14,7],[106,1],[106,3],[106,4],[106,4],[106,6],[108,1],[108,3],[108,3],[108,1],[108,3],[16,3],[16,3],[16,3],[16,1],[111,1],[111,2],[109,0],[109,1],[110,2],[110,4],[81,1],[81,1],[60,2],[75,2],[75,4],[121,1],[121,1],[80,5],[91,3],[91,2],[91,2],[91,1],[116,1],[116,3],[116,4],[116,4],[116,6],[123,1],[123,1],[123,1],[124,1],[124,3],[21,2],[21,3],[21,4],[21,5],[126,3],[126,3],[126,2],[26,2],[79,3],[79,5],[132,2],[132,4],[132,2],[132,4],[22,2],[22,2],[22,2],[22,1],[136,2],[136,2],[23,2],[23,2],[23,2],[138,2],[138,4],[138,2],[141,2],[141,3],[145,1],[145,1],[145,1],[145,1],[143,1],[143,3],[142,2],[142,2],[142,4],[142,4],[142,4],[142,6],[142,6],[142,2],[142,4],[24,5],[24,7],[24,4],[24,6],[150,1],[150,2],[152,3],[152,4],[154,3],[154,5],[20,1],[20,3],[20,3],[20,3],[18,2],[18,2],[18,2],[18,2],[18,2],[18,2],[18,2],[18,2],[18,2],[18,3],[18,3],[18,3],[18,3],[18,3],[18,3],[18,3],[18,3],[18,3],[18,3],[18,3],[18,3],[18,3],[18,3],[18,5],[18,4],[18,3]], performAction: function anonymous(yytext, yyleng, yylineno, yy, yystate /* action[1] */, $$ /* vstack */, _$ /* lstack */) { /* this == yyval */ var $0 = $$.length - 1; switch (yystate) { case 1: return this.$ = yy.addLocationDataFn(_$[$0], _$[$0])(new yy.Block); break; case 2: return this.$ = $$[$0]; break; case 3: this.$ = yy.addLocationDataFn(_$[$0], _$[$0])(yy.Block.wrap([$$[$0]])); break; case 4: this.$ = yy.addLocationDataFn(_$[$0-2], _$[$0])($$[$0-2].push($$[$0])); break; case 5: this.$ = $$[$0-1]; break; case 6: case 7: case 8: case 9: case 10: case 12: case 13: case 14: case 15: case 16: case 17: case 18: case 19: case 20: case 21: case 22: case 23: case 24: case 25: case 26: case 35: case 40: case 42: case 56: case 57: case 58: case 59: case 60: case 61: case 72: case 73: case 83: case 84: case 85: case 86: case 91: case 92: case 95: case 99: case 105: case 164: case 188: case 189: case 191: case 221: case 222: case 240: case 246: this.$ = $$[$0]; break; case 11: this.$ = yy.addLocationDataFn(_$[$0], _$[$0])(new yy.StatementLiteral($$[$0])); break; case 27: this.$ = yy.addLocationDataFn(_$[$0], _$[$0])(new yy.Op($$[$0], new yy.Value(new yy.Literal('')))); break; case 28: case 250: case 251: this.$ = yy.addLocationDataFn(_$[$0-1], _$[$0])(new yy.Op($$[$0-1], $$[$0])); break; case 29: this.$ = yy.addLocationDataFn(_$[$0-2], _$[$0])(new yy.Op($$[$0-2].concat($$[$0-1]), $$[$0])); break; case 30: this.$ = yy.addLocationDataFn(_$[$0-1], _$[$0])(new yy.Block); break; case 31: case 106: this.$ = yy.addLocationDataFn(_$[$0-2], _$[$0])($$[$0-1]); break; case 32: this.$ = yy.addLocationDataFn(_$[$0], _$[$0])(new yy.IdentifierLiteral($$[$0])); break; case 33: this.$ = yy.addLocationDataFn(_$[$0], _$[$0])(new yy.PropertyName($$[$0])); break; case 34: this.$ = yy.addLocationDataFn(_$[$0], _$[$0])(new yy.NumberLiteral($$[$0])); break; case 36: this.$ = yy.addLocationDataFn(_$[$0], _$[$0])(new yy.StringLiteral($$[$0])); break; case 37: this.$ = yy.addLocationDataFn(_$[$0-2], _$[$0])(new yy.StringWithInterpolations($$[$0-1])); break; case 38: this.$ = yy.addLocationDataFn(_$[$0], _$[$0])(new yy.RegexLiteral($$[$0])); break; case 39: this.$ = yy.addLocationDataFn(_$[$0-2], _$[$0])(new yy.RegexWithInterpolations($$[$0-1].args)); break; case 41: this.$ = yy.addLocationDataFn(_$[$0], _$[$0])(new yy.PassthroughLiteral($$[$0])); break; case 43: this.$ = yy.addLocationDataFn(_$[$0], _$[$0])(new yy.UndefinedLiteral); break; case 44: this.$ = yy.addLocationDataFn(_$[$0], _$[$0])(new yy.NullLiteral); break; case 45: this.$ = yy.addLocationDataFn(_$[$0], _$[$0])(new yy.BooleanLiteral($$[$0])); break; case 46: this.$ = yy.addLocationDataFn(_$[$0], _$[$0])(new yy.InfinityLiteral($$[$0])); break; case 47: this.$ = yy.addLocationDataFn(_$[$0], _$[$0])(new yy.NaNLiteral); break; case 48: this.$ = yy.addLocationDataFn(_$[$0-2], _$[$0])(new yy.Assign($$[$0-2], $$[$0])); break; case 49: this.$ = yy.addLocationDataFn(_$[$0-3], _$[$0])(new yy.Assign($$[$0-3], $$[$0])); break; case 50: this.$ = yy.addLocationDataFn(_$[$0-4], _$[$0])(new yy.Assign($$[$0-4], $$[$0-1])); break; case 51: case 88: case 93: case 94: case 96: case 97: case 98: case 223: case 224: this.$ = yy.addLocationDataFn(_$[$0], _$[$0])(new yy.Value($$[$0])); break; case 52: this.$ = yy.addLocationDataFn(_$[$0-2], _$[$0])(new yy.Assign(yy.addLocationDataFn(_$[$0-2])(new yy.Value($$[$0-2])), $$[$0], 'object', { operatorToken: yy.addLocationDataFn(_$[$0-1])(new yy.Literal($$[$0-1])) })); break; case 53: this.$ = yy.addLocationDataFn(_$[$0-4], _$[$0])(new yy.Assign(yy.addLocationDataFn(_$[$0-4])(new yy.Value($$[$0-4])), $$[$0-1], 'object', { operatorToken: yy.addLocationDataFn(_$[$0-3])(new yy.Literal($$[$0-3])) })); break; case 54: this.$ = yy.addLocationDataFn(_$[$0-2], _$[$0])(new yy.Assign(yy.addLocationDataFn(_$[$0-2])(new yy.Value($$[$0-2])), $$[$0], null, { operatorToken: yy.addLocationDataFn(_$[$0-1])(new yy.Literal($$[$0-1])) })); break; case 55: this.$ = yy.addLocationDataFn(_$[$0-4], _$[$0])(new yy.Assign(yy.addLocationDataFn(_$[$0-4])(new yy.Value($$[$0-4])), $$[$0-1], null, { operatorToken: yy.addLocationDataFn(_$[$0-3])(new yy.Literal($$[$0-3])) })); break; case 62: this.$ = yy.addLocationDataFn(_$[$0-1], _$[$0])(new yy.Return($$[$0])); break; case 63: this.$ = yy.addLocationDataFn(_$[$0-3], _$[$0])(new yy.Return(new yy.Value($$[$0-1]))); break; case 64: this.$ = yy.addLocationDataFn(_$[$0], _$[$0])(new yy.Return); break; case 65: this.$ = yy.addLocationDataFn(_$[$0-2], _$[$0])(new yy.YieldReturn($$[$0])); break; case 66: this.$ = yy.addLocationDataFn(_$[$0-1], _$[$0])(new yy.YieldReturn); break; case 67: this.$ = yy.addLocationDataFn(_$[$0], _$[$0])(new yy.Comment($$[$0])); break; case 68: this.$ = yy.addLocationDataFn(_$[$0-4], _$[$0])(new yy.Code($$[$0-3], $$[$0], $$[$0-1])); break; case 69: this.$ = yy.addLocationDataFn(_$[$0-1], _$[$0])(new yy.Code([], $$[$0], $$[$0-1])); break; case 70: this.$ = yy.addLocationDataFn(_$[$0], _$[$0])('func'); break; case 71: this.$ = yy.addLocationDataFn(_$[$0], _$[$0])('boundfunc'); break; case 74: case 111: this.$ = yy.addLocationDataFn(_$[$0], _$[$0])([]); break; case 75: case 112: case 131: case 151: case 183: case 225: this.$ = yy.addLocationDataFn(_$[$0], _$[$0])([$$[$0]]); break; case 76: case 113: case 132: case 152: case 184: this.$ = yy.addLocationDataFn(_$[$0-2], _$[$0])($$[$0-2].concat($$[$0])); break; case 77: case 114: case 133: case 153: case 185: this.$ = yy.addLocationDataFn(_$[$0-3], _$[$0])($$[$0-3].concat($$[$0])); break; case 78: case 115: case 135: case 155: case 187: this.$ = yy.addLocationDataFn(_$[$0-5], _$[$0])($$[$0-5].concat($$[$0-2])); break; case 79: this.$ = yy.addLocationDataFn(_$[$0], _$[$0])(new yy.Param($$[$0])); break; case 80: this.$ = yy.addLocationDataFn(_$[$0-1], _$[$0])(new yy.Param($$[$0-1], null, true)); break; case 81: this.$ = yy.addLocationDataFn(_$[$0-2], _$[$0])(new yy.Param($$[$0-2], $$[$0])); break; case 82: case 190: this.$ = yy.addLocationDataFn(_$[$0], _$[$0])(new yy.Expansion); break; case 87: this.$ = yy.addLocationDataFn(_$[$0-1], _$[$0])(new yy.Splat($$[$0-1])); break; case 89: this.$ = yy.addLocationDataFn(_$[$0-1], _$[$0])($$[$0-1].add($$[$0])); break; case 90: this.$ = yy.addLocationDataFn(_$[$0-1], _$[$0])(new yy.Value($$[$0-1], [].concat($$[$0]))); break; case 100: this.$ = yy.addLocationDataFn(_$[$0-1], _$[$0])(new yy.Access($$[$0])); break; case 101: this.$ = yy.addLocationDataFn(_$[$0-1], _$[$0])(new yy.Access($$[$0], 'soak')); break; case 102: this.$ = yy.addLocationDataFn(_$[$0-1], _$[$0])([yy.addLocationDataFn(_$[$0-1])(new yy.Access(new yy.PropertyName('prototype'))), yy.addLocationDataFn(_$[$0])(new yy.Access($$[$0]))]); break; case 103: this.$ = yy.addLocationDataFn(_$[$0-1], _$[$0])([yy.addLocationDataFn(_$[$0-1])(new yy.Access(new yy.PropertyName('prototype'), 'soak')), yy.addLocationDataFn(_$[$0])(new yy.Access($$[$0]))]); break; case 104: this.$ = yy.addLocationDataFn(_$[$0], _$[$0])(new yy.Access(new yy.PropertyName('prototype'))); break; case 107: this.$ = yy.addLocationDataFn(_$[$0-1], _$[$0])(yy.extend($$[$0], { soak: true })); break; case 108: this.$ = yy.addLocationDataFn(_$[$0], _$[$0])(new yy.Index($$[$0])); break; case 109: this.$ = yy.addLocationDataFn(_$[$0], _$[$0])(new yy.Slice($$[$0])); break; case 110: this.$ = yy.addLocationDataFn(_$[$0-3], _$[$0])(new yy.Obj($$[$0-2], $$[$0-3].generated)); break; case 116: this.$ = yy.addLocationDataFn(_$[$0], _$[$0])(new yy.Class); break; case 117: this.$ = yy.addLocationDataFn(_$[$0-1], _$[$0])(new yy.Class(null, null, $$[$0])); break; case 118: this.$ = yy.addLocationDataFn(_$[$0-2], _$[$0])(new yy.Class(null, $$[$0])); break; case 119: this.$ = yy.addLocationDataFn(_$[$0-3], _$[$0])(new yy.Class(null, $$[$0-1], $$[$0])); break; case 120: this.$ = yy.addLocationDataFn(_$[$0-1], _$[$0])(new yy.Class($$[$0])); break; case 121: this.$ = yy.addLocationDataFn(_$[$0-2], _$[$0])(new yy.Class($$[$0-1], null, $$[$0])); break; case 122: this.$ = yy.addLocationDataFn(_$[$0-3], _$[$0])(new yy.Class($$[$0-2], $$[$0])); break; case 123: this.$ = yy.addLocationDataFn(_$[$0-4], _$[$0])(new yy.Class($$[$0-3], $$[$0-1], $$[$0])); break; case 124: this.$ = yy.addLocationDataFn(_$[$0-1], _$[$0])(new yy.ImportDeclaration(null, $$[$0])); break; case 125: this.$ = yy.addLocationDataFn(_$[$0-3], _$[$0])(new yy.ImportDeclaration(new yy.ImportClause($$[$0-2], null), $$[$0])); break; case 126: this.$ = yy.addLocationDataFn(_$[$0-3], _$[$0])(new yy.ImportDeclaration(new yy.ImportClause(null, $$[$0-2]), $$[$0])); break; case 127: this.$ = yy.addLocationDataFn(_$[$0-4], _$[$0])(new yy.ImportDeclaration(new yy.ImportClause(null, new yy.ImportSpecifierList([])), $$[$0])); break; case 128: this.$ = yy.addLocationDataFn(_$[$0-6], _$[$0])(new yy.ImportDeclaration(new yy.ImportClause(null, new yy.ImportSpecifierList($$[$0-4])), $$[$0])); break; case 129: this.$ = yy.addLocationDataFn(_$[$0-5], _$[$0])(new yy.ImportDeclaration(new yy.ImportClause($$[$0-4], $$[$0-2]), $$[$0])); break; case 130: this.$ = yy.addLocationDataFn(_$[$0-8], _$[$0])(new yy.ImportDeclaration(new yy.ImportClause($$[$0-7], new yy.ImportSpecifierList($$[$0-4])), $$[$0])); break; case 134: case 154: case 170: case 186: this.$ = yy.addLocationDataFn(_$[$0-3], _$[$0])($$[$0-2]); break; case 136: this.$ = yy.addLocationDataFn(_$[$0], _$[$0])(new yy.ImportSpecifier($$[$0])); break; case 137: this.$ = yy.addLocationDataFn(_$[$0-2], _$[$0])(new yy.ImportSpecifier($$[$0-2], $$[$0])); break; case 138: this.$ = yy.addLocationDataFn(_$[$0], _$[$0])(new yy.ImportSpecifier(new yy.Literal($$[$0]))); break; case 139: this.$ = yy.addLocationDataFn(_$[$0-2], _$[$0])(new yy.ImportSpecifier(new yy.Literal($$[$0-2]), $$[$0])); break; case 140: this.$ = yy.addLocationDataFn(_$[$0], _$[$0])(new yy.ImportDefaultSpecifier($$[$0])); break; case 141: this.$ = yy.addLocationDataFn(_$[$0-2], _$[$0])(new yy.ImportNamespaceSpecifier(new yy.Literal($$[$0-2]), $$[$0])); break; case 142: this.$ = yy.addLocationDataFn(_$[$0-2], _$[$0])(new yy.ExportNamedDeclaration(new yy.ExportSpecifierList([]))); break; case 143: this.$ = yy.addLocationDataFn(_$[$0-4], _$[$0])(new yy.ExportNamedDeclaration(new yy.ExportSpecifierList($$[$0-2]))); break; case 144: this.$ = yy.addLocationDataFn(_$[$0-1], _$[$0])(new yy.ExportNamedDeclaration($$[$0])); break; case 145: this.$ = yy.addLocationDataFn(_$[$0-3], _$[$0])(new yy.ExportNamedDeclaration(new yy.Assign($$[$0-2], $$[$0], null, { moduleDeclaration: 'export' }))); break; case 146: this.$ = yy.addLocationDataFn(_$[$0-4], _$[$0])(new yy.ExportNamedDeclaration(new yy.Assign($$[$0-3], $$[$0], null, { moduleDeclaration: 'export' }))); break; case 147: this.$ = yy.addLocationDataFn(_$[$0-5], _$[$0])(new yy.ExportNamedDeclaration(new yy.Assign($$[$0-4], $$[$0-1], null, { moduleDeclaration: 'export' }))); break; case 148: this.$ = yy.addLocationDataFn(_$[$0-2], _$[$0])(new yy.ExportDefaultDeclaration($$[$0])); break; case 149: this.$ = yy.addLocationDataFn(_$[$0-3], _$[$0])(new yy.ExportAllDeclaration(new yy.Literal($$[$0-2]), $$[$0])); break; case 150: this.$ = yy.addLocationDataFn(_$[$0-6], _$[$0])(new yy.ExportNamedDeclaration(new yy.ExportSpecifierList($$[$0-4]), $$[$0])); break; case 156: this.$ = yy.addLocationDataFn(_$[$0], _$[$0])(new yy.ExportSpecifier($$[$0])); break; case 157: this.$ = yy.addLocationDataFn(_$[$0-2], _$[$0])(new yy.ExportSpecifier($$[$0-2], $$[$0])); break; case 158: this.$ = yy.addLocationDataFn(_$[$0-2], _$[$0])(new yy.ExportSpecifier($$[$0-2], new yy.Literal($$[$0]))); break; case 159: this.$ = yy.addLocationDataFn(_$[$0], _$[$0])(new yy.ExportSpecifier(new yy.Literal($$[$0]))); break; case 160: this.$ = yy.addLocationDataFn(_$[$0-2], _$[$0])(new yy.ExportSpecifier(new yy.Literal($$[$0-2]), $$[$0])); break; case 161: this.$ = yy.addLocationDataFn(_$[$0-2], _$[$0])(new yy.TaggedTemplateCall($$[$0-2], $$[$0], $$[$0-1])); break; case 162: case 163: this.$ = yy.addLocationDataFn(_$[$0-2], _$[$0])(new yy.Call($$[$0-2], $$[$0], $$[$0-1])); break; case 165: this.$ = yy.addLocationDataFn(_$[$0], _$[$0])(new yy.SuperCall); break; case 166: this.$ = yy.addLocationDataFn(_$[$0-1], _$[$0])(new yy.SuperCall($$[$0])); break; case 167: this.$ = yy.addLocationDataFn(_$[$0], _$[$0])(false); break; case 168: this.$ = yy.addLocationDataFn(_$[$0], _$[$0])(true); break; case 169: this.$ = yy.addLocationDataFn(_$[$0-1], _$[$0])([]); break; case 171: case 172: this.$ = yy.addLocationDataFn(_$[$0], _$[$0])(new yy.Value(new yy.ThisLiteral)); break; case 173: this.$ = yy.addLocationDataFn(_$[$0-1], _$[$0])(new yy.Value(yy.addLocationDataFn(_$[$0-1])(new yy.ThisLiteral), [yy.addLocationDataFn(_$[$0])(new yy.Access($$[$0]))], 'this')); break; case 174: this.$ = yy.addLocationDataFn(_$[$0-1], _$[$0])(new yy.Arr([])); break; case 175: this.$ = yy.addLocationDataFn(_$[$0-3], _$[$0])(new yy.Arr($$[$0-2])); break; case 176: this.$ = yy.addLocationDataFn(_$[$0], _$[$0])('inclusive'); break; case 177: this.$ = yy.addLocationDataFn(_$[$0], _$[$0])('exclusive'); break; case 178: this.$ = yy.addLocationDataFn(_$[$0-4], _$[$0])(new yy.Range($$[$0-3], $$[$0-1], $$[$0-2])); break; case 179: this.$ = yy.addLocationDataFn(_$[$0-2], _$[$0])(new yy.Range($$[$0-2], $$[$0], $$[$0-1])); break; case 180: this.$ = yy.addLocationDataFn(_$[$0-1], _$[$0])(new yy.Range($$[$0-1], null, $$[$0])); break; case 181: this.$ = yy.addLocationDataFn(_$[$0-1], _$[$0])(new yy.Range(null, $$[$0], $$[$0-1])); break; case 182: this.$ = yy.addLocationDataFn(_$[$0], _$[$0])(new yy.Range(null, null, $$[$0])); break; case 192: this.$ = yy.addLocationDataFn(_$[$0-2], _$[$0])([].concat($$[$0-2], $$[$0])); break; case 193: this.$ = yy.addLocationDataFn(_$[$0-1], _$[$0])(new yy.Try($$[$0])); break; case 194: this.$ = yy.addLocationDataFn(_$[$0-2], _$[$0])(new yy.Try($$[$0-1], $$[$0][0], $$[$0][1])); break; case 195: this.$ = yy.addLocationDataFn(_$[$0-3], _$[$0])(new yy.Try($$[$0-2], null, null, $$[$0])); break; case 196: this.$ = yy.addLocationDataFn(_$[$0-4], _$[$0])(new yy.Try($$[$0-3], $$[$0-2][0], $$[$0-2][1], $$[$0])); break; case 197: this.$ = yy.addLocationDataFn(_$[$0-2], _$[$0])([$$[$0-1], $$[$0]]); break; case 198: this.$ = yy.addLocationDataFn(_$[$0-2], _$[$0])([yy.addLocationDataFn(_$[$0-1])(new yy.Value($$[$0-1])), $$[$0]]); break; case 199: this.$ = yy.addLocationDataFn(_$[$0-1], _$[$0])([null, $$[$0]]); break; case 200: this.$ = yy.addLocationDataFn(_$[$0-1], _$[$0])(new yy.Throw($$[$0])); break; case 201: this.$ = yy.addLocationDataFn(_$[$0-2], _$[$0])(new yy.Parens($$[$0-1])); break; case 202: this.$ = yy.addLocationDataFn(_$[$0-4], _$[$0])(new yy.Parens($$[$0-2])); break; case 203: this.$ = yy.addLocationDataFn(_$[$0-1], _$[$0])(new yy.While($$[$0])); break; case 204: this.$ = yy.addLocationDataFn(_$[$0-3], _$[$0])(new yy.While($$[$0-2], { guard: $$[$0] })); break; case 205: this.$ = yy.addLocationDataFn(_$[$0-1], _$[$0])(new yy.While($$[$0], { invert: true })); break; case 206: this.$ = yy.addLocationDataFn(_$[$0-3], _$[$0])(new yy.While($$[$0-2], { invert: true, guard: $$[$0] })); break; case 207: this.$ = yy.addLocationDataFn(_$[$0-1], _$[$0])($$[$0-1].addBody($$[$0])); break; case 208: case 209: this.$ = yy.addLocationDataFn(_$[$0-1], _$[$0])($$[$0].addBody(yy.addLocationDataFn(_$[$0-1])(yy.Block.wrap([$$[$0-1]])))); break; case 210: this.$ = yy.addLocationDataFn(_$[$0], _$[$0])($$[$0]); break; case 211: this.$ = yy.addLocationDataFn(_$[$0-1], _$[$0])(new yy.While(yy.addLocationDataFn(_$[$0-1])(new yy.BooleanLiteral('true'))).addBody($$[$0])); break; case 212: this.$ = yy.addLocationDataFn(_$[$0-1], _$[$0])(new yy.While(yy.addLocationDataFn(_$[$0-1])(new yy.BooleanLiteral('true'))).addBody(yy.addLocationDataFn(_$[$0])(yy.Block.wrap([$$[$0]])))); break; case 213: case 214: this.$ = yy.addLocationDataFn(_$[$0-1], _$[$0])(new yy.For($$[$0-1], $$[$0])); break; case 215: this.$ = yy.addLocationDataFn(_$[$0-1], _$[$0])(new yy.For($$[$0], $$[$0-1])); break; case 216: this.$ = yy.addLocationDataFn(_$[$0-1], _$[$0])({ source: yy.addLocationDataFn(_$[$0])(new yy.Value($$[$0])) }); break; case 217: this.$ = yy.addLocationDataFn(_$[$0-3], _$[$0])({ source: yy.addLocationDataFn(_$[$0-2])(new yy.Value($$[$0-2])), step: $$[$0] }); break; case 218: this.$ = yy.addLocationDataFn(_$[$0-1], _$[$0])((function () { $$[$0].own = $$[$0-1].own; $$[$0].ownTag = $$[$0-1].ownTag; $$[$0].name = $$[$0-1][0]; $$[$0].index = $$[$0-1][1]; return $$[$0]; }())); break; case 219: this.$ = yy.addLocationDataFn(_$[$0-1], _$[$0])($$[$0]); break; case 220: this.$ = yy.addLocationDataFn(_$[$0-2], _$[$0])((function () { $$[$0].own = true; $$[$0].ownTag = yy.addLocationDataFn(_$[$0-1])(new yy.Literal($$[$0-1])); return $$[$0]; }())); break; case 226: this.$ = yy.addLocationDataFn(_$[$0-2], _$[$0])([$$[$0-2], $$[$0]]); break; case 227: this.$ = yy.addLocationDataFn(_$[$0-1], _$[$0])({ source: $$[$0] }); break; case 228: this.$ = yy.addLocationDataFn(_$[$0-1], _$[$0])({ source: $$[$0], object: true }); break; case 229: this.$ = yy.addLocationDataFn(_$[$0-3], _$[$0])({ source: $$[$0-2], guard: $$[$0] }); break; case 230: this.$ = yy.addLocationDataFn(_$[$0-3], _$[$0])({ source: $$[$0-2], guard: $$[$0], object: true }); break; case 231: this.$ = yy.addLocationDataFn(_$[$0-3], _$[$0])({ source: $$[$0-2], step: $$[$0] }); break; case 232: this.$ = yy.addLocationDataFn(_$[$0-5], _$[$0])({ source: $$[$0-4], guard: $$[$0-2], step: $$[$0] }); break; case 233: this.$ = yy.addLocationDataFn(_$[$0-5], _$[$0])({ source: $$[$0-4], step: $$[$0-2], guard: $$[$0] }); break; case 234: this.$ = yy.addLocationDataFn(_$[$0-1], _$[$0])({ source: $$[$0], from: true }); break; case 235: this.$ = yy.addLocationDataFn(_$[$0-3], _$[$0])({ source: $$[$0-2], guard: $$[$0], from: true }); break; case 236: this.$ = yy.addLocationDataFn(_$[$0-4], _$[$0])(new yy.Switch($$[$0-3], $$[$0-1])); break; case 237: this.$ = yy.addLocationDataFn(_$[$0-6], _$[$0])(new yy.Switch($$[$0-5], $$[$0-3], $$[$0-1])); break; case 238: this.$ = yy.addLocationDataFn(_$[$0-3], _$[$0])(new yy.Switch(null, $$[$0-1])); break; case 239: this.$ = yy.addLocationDataFn(_$[$0-5], _$[$0])(new yy.Switch(null, $$[$0-3], $$[$0-1])); break; case 241: this.$ = yy.addLocationDataFn(_$[$0-1], _$[$0])($$[$0-1].concat($$[$0])); break; case 242: this.$ = yy.addLocationDataFn(_$[$0-2], _$[$0])([[$$[$0-1], $$[$0]]]); break; case 243: this.$ = yy.addLocationDataFn(_$[$0-3], _$[$0])([[$$[$0-2], $$[$0-1]]]); break; case 244: this.$ = yy.addLocationDataFn(_$[$0-2], _$[$0])(new yy.If($$[$0-1], $$[$0], { type: $$[$0-2] })); break; case 245: this.$ = yy.addLocationDataFn(_$[$0-4], _$[$0])($$[$0-4].addElse(yy.addLocationDataFn(_$[$0-2], _$[$0])(new yy.If($$[$0-1], $$[$0], { type: $$[$0-2] })))); break; case 247: this.$ = yy.addLocationDataFn(_$[$0-2], _$[$0])($$[$0-2].addElse($$[$0])); break; case 248: case 249: this.$ = yy.addLocationDataFn(_$[$0-2], _$[$0])(new yy.If($$[$0], yy.addLocationDataFn(_$[$0-2])(yy.Block.wrap([$$[$0-2]])), { type: $$[$0-1], statement: true })); break; case 252: this.$ = yy.addLocationDataFn(_$[$0-1], _$[$0])(new yy.Op('-', $$[$0])); break; case 253: this.$ = yy.addLocationDataFn(_$[$0-1], _$[$0])(new yy.Op('+', $$[$0])); break; case 254: this.$ = yy.addLocationDataFn(_$[$0-1], _$[$0])(new yy.Op('--', $$[$0])); break; case 255: this.$ = yy.addLocationDataFn(_$[$0-1], _$[$0])(new yy.Op('++', $$[$0])); break; case 256: this.$ = yy.addLocationDataFn(_$[$0-1], _$[$0])(new yy.Op('--', $$[$0-1], null, true)); break; case 257: this.$ = yy.addLocationDataFn(_$[$0-1], _$[$0])(new yy.Op('++', $$[$0-1], null, true)); break; case 258: this.$ = yy.addLocationDataFn(_$[$0-1], _$[$0])(new yy.Existence($$[$0-1])); break; case 259: this.$ = yy.addLocationDataFn(_$[$0-2], _$[$0])(new yy.Op('+', $$[$0-2], $$[$0])); break; case 260: this.$ = yy.addLocationDataFn(_$[$0-2], _$[$0])(new yy.Op('-', $$[$0-2], $$[$0])); break; case 261: case 262: case 263: case 264: case 265: case 266: case 267: case 268: case 269: case 270: this.$ = yy.addLocationDataFn(_$[$0-2], _$[$0])(new yy.Op($$[$0-1], $$[$0-2], $$[$0])); break; case 271: this.$ = yy.addLocationDataFn(_$[$0-2], _$[$0])((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 272: this.$ = yy.addLocationDataFn(_$[$0-2], _$[$0])(new yy.Assign($$[$0-2], $$[$0], $$[$0-1])); break; case 273: this.$ = yy.addLocationDataFn(_$[$0-4], _$[$0])(new yy.Assign($$[$0-4], $$[$0-1], $$[$0-3])); break; case 274: this.$ = yy.addLocationDataFn(_$[$0-3], _$[$0])(new yy.Assign($$[$0-3], $$[$0], $$[$0-2])); break; case 275: this.$ = yy.addLocationDataFn(_$[$0-2], _$[$0])(new yy.Extends($$[$0-2], $$[$0])); break; } }, table: [{1:[2,1],3:1,4:2,5:3,7:4,8:5,9:6,10:20,11:21,12:$V0,13:23,14:24,15:7,16:8,17:9,18:10,19:11,20:12,21:13,22:14,23:15,24:16,25:17,26:18,27:19,28:$V1,33:70,34:$V2,37:55,38:$V3,39:80,40:$V4,41:$V5,43:57,44:$V6,45:$V7,47:27,48:$V8,49:$V9,50:$Va,51:$Vb,52:$Vc,53:$Vd,54:26,60:71,61:$Ve,62:54,63:$Vf,64:$Vg,67:33,68:$Vh,69:$Vi,75:53,77:40,79:28,80:29,81:30,92:$Vj,95:$Vk,97:$Vl,105:$Vm,111:31,112:$Vn,117:$Vo,118:$Vp,119:$Vq,125:$Vr,129:$Vs,130:$Vt,132:43,133:$Vu,135:$Vv,136:44,137:$Vw,138:45,139:$Vx,141:77,149:$Vy,154:41,155:$Vz,157:$VA,158:$VB,159:$VC,160:$VD,161:$VE,162:$VF},{1:[3]},{1:[2,2],6:$VG},o($VH,[2,3]),o($VH,[2,6],{141:77,132:102,138:103,133:$Vu,135:$Vv,139:$Vx,156:$VI,159:$VJ,160:$VK,163:$VL,164:$VM,165:$VN,166:$VO,167:$VP,168:$VQ,169:$VR,170:$VS,171:$VT,172:$VU,173:$VV,174:$VW}),o($VH,[2,7],{141:77,132:105,138:106,133:$Vu,135:$Vv,139:$Vx,156:$VX}),o($VH,[2,8]),o($VY,[2,14],{109:107,78:108,86:114,40:$VZ,41:$VZ,114:$VZ,82:$V_,83:$V$,84:$V01,85:$V11,87:$V21,90:$V31,113:$V41}),o($VY,[2,15],{86:114,109:117,78:118,82:$V_,83:$V$,84:$V01,85:$V11,87:$V21,90:$V31,113:$V41,114:$VZ}),o($VY,[2,16]),o($VY,[2,17]),o($VY,[2,18]),o($VY,[2,19]),o($VY,[2,20]),o($VY,[2,21]),o($VY,[2,22]),o($VY,[2,23]),o($VY,[2,24]),o($VY,[2,25]),o($VY,[2,26]),o($V51,[2,9]),o($V51,[2,10]),o($V51,[2,11]),o($V51,[2,12]),o($V51,[2,13]),o([1,6,32,42,131,133,135,139,156,163,164,165,166,167,168,169,170,171,172,173,174],$V61,{15:7,16:8,17:9,18:10,19:11,20:12,21:13,22:14,23:15,24:16,25:17,26:18,27:19,10:20,11:21,13:23,14:24,54:26,47:27,79:28,80:29,81:30,111:31,67:33,77:40,154:41,132:43,136:44,138:45,75:53,62:54,37:55,43:57,33:70,60:71,141:77,39:80,7:120,8:122,12:$V0,28:$V71,29:$V81,34:$V2,38:$V3,40:$V4,41:$V5,44:$V6,45:$V7,48:$V8,49:$V9,50:$Va,51:$Vb,52:$Vc,53:$Vd,61:[1,119],63:$Vf,64:$Vg,68:$Vh,69:$Vi,92:$Vj,95:$Vk,97:$Vl,105:$Vm,112:$Vn,117:$Vo,118:$Vp,119:$Vq,125:$Vr,129:$Vs,130:$Vt,137:$Vw,149:$Vy,155:$Vz,157:$VA,158:$VB,159:$VC,160:$VD,161:$VE,162:$VF}),o($V91,$Va1,{55:[1,124]}),o($V91,[2,96]),o($V91,[2,97]),o($V91,[2,98]),o($V91,[2,99]),o($Vb1,[2,164]),o([6,31,66,71],$Vc1,{65:125,72:126,73:127,33:129,60:130,75:131,62:132,34:$V2,74:$Vd1,92:$Vj,118:$Ve1,119:$Vf1}),{30:135,31:$Vg1},{7:137,8:122,10:20,11:21,12:$V0,13:23,14:24,15:7,16:8,17:9,18:10,19:11,20:12,21:13,22:14,23:15,24:16,25:17,26:18,27:19,28:$V71,33:70,34:$V2,37:55,38:$V3,39:80,40:$V4,41:$V5,43:57,44:$V6,45:$V7,47:27,48:$V8,49:$V9,50:$Va,51:$Vb,52:$Vc,53:$Vd,54:26,60:71,61:$Ve,62:54,63:$Vf,64:$Vg,67:33,68:$Vh,69:$Vi,75:53,77:40,79:28,80:29,81:30,92:$Vj,95:$Vk,97:$Vl,105:$Vm,111:31,112:$Vn,117:$Vo,118:$Vp,119:$Vq,125:$Vr,129:$Vs,130:$Vt,132:43,133:$Vu,135:$Vv,136:44,137:$Vw,138:45,139:$Vx,141:77,149:$Vy,154:41,155:$Vz,157:$VA,158:$VB,159:$VC,160:$VD,161:$VE,162:$VF},{7:138,8:122,10:20,11:21,12:$V0,13:23,14:24,15:7,16:8,17:9,18:10,19:11,20:12,21:13,22:14,23:15,24:16,25:17,26:18,27:19,28:$V71,33:70,34:$V2,37:55,38:$V3,39:80,40:$V4,41:$V5,43:57,44:$V6,45:$V7,47:27,48:$V8,49:$V9,50:$Va,51:$Vb,52:$Vc,53:$Vd,54:26,60:71,61:$Ve,62:54,63:$Vf,64:$Vg,67:33,68:$Vh,69:$Vi,75:53,77:40,79:28,80:29,81:30,92:$Vj,95:$Vk,97:$Vl,105:$Vm,111:31,112:$Vn,117:$Vo,118:$Vp,119:$Vq,125:$Vr,129:$Vs,130:$Vt,132:43,133:$Vu,135:$Vv,136:44,137:$Vw,138:45,139:$Vx,141:77,149:$Vy,154:41,155:$Vz,157:$VA,158:$VB,159:$VC,160:$VD,161:$VE,162:$VF},{7:139,8:122,10:20,11:21,12:$V0,13:23,14:24,15:7,16:8,17:9,18:10,19:11,20:12,21:13,22:14,23:15,24:16,25:17,26:18,27:19,28:$V71,33:70,34:$V2,37:55,38:$V3,39:80,40:$V4,41:$V5,43:57,44:$V6,45:$V7,47:27,48:$V8,49:$V9,50:$Va,51:$Vb,52:$Vc,53:$Vd,54:26,60:71,61:$Ve,62:54,63:$Vf,64:$Vg,67:33,68:$Vh,69:$Vi,75:53,77:40,79:28,80:29,81:30,92:$Vj,95:$Vk,97:$Vl,105:$Vm,111:31,112:$Vn,117:$Vo,118:$Vp,119:$Vq,125:$Vr,129:$Vs,130:$Vt,132:43,133:$Vu,135:$Vv,136:44,137:$Vw,138:45,139:$Vx,141:77,149:$Vy,154:41,155:$Vz,157:$VA,158:$VB,159:$VC,160:$VD,161:$VE,162:$VF},{7:140,8:122,10:20,11:21,12:$V0,13:23,14:24,15:7,16:8,17:9,18:10,19:11,20:12,21:13,22:14,23:15,24:16,25:17,26:18,27:19,28:$V71,33:70,34:$V2,37:55,38:$V3,39:80,40:$V4,41:$V5,43:57,44:$V6,45:$V7,47:27,48:$V8,49:$V9,50:$Va,51:$Vb,52:$Vc,53:$Vd,54:26,60:71,61:$Ve,62:54,63:$Vf,64:$Vg,67:33,68:$Vh,69:$Vi,75:53,77:40,79:28,80:29,81:30,92:$Vj,95:$Vk,97:$Vl,105:$Vm,111:31,112:$Vn,117:$Vo,118:$Vp,119:$Vq,125:$Vr,129:$Vs,130:$Vt,132:43,133:$Vu,135:$Vv,136:44,137:$Vw,138:45,139:$Vx,141:77,149:$Vy,154:41,155:$Vz,157:$VA,158:$VB,159:$VC,160:$VD,161:$VE,162:$VF},{15:142,16:143,33:70,34:$V2,37:55,38:$V3,39:80,40:$V4,41:$V5,43:57,44:$V6,45:$V7,47:27,48:$V8,49:$V9,50:$Va,51:$Vb,52:$Vc,53:$Vd,54:144,60:71,62:54,75:53,77:141,79:28,80:29,81:30,92:$Vj,111:31,112:$Vn,117:$Vo,118:$Vp,119:$Vq,130:$Vt},{15:142,16:143,33:70,34:$V2,37:55,38:$V3,39:80,40:$V4,41:$V5,43:57,44:$V6,45:$V7,47:27,48:$V8,49:$V9,50:$Va,51:$Vb,52:$Vc,53:$Vd,54:144,60:71,62:54,75:53,77:145,79:28,80:29,81:30,92:$Vj,111:31,112:$Vn,117:$Vo,118:$Vp,119:$Vq,130:$Vt},o($Vh1,$Vi1,{96:[1,149],161:[1,146],162:[1,147],175:[1,148]}),o($VY,[2,246],{151:[1,150]}),{30:151,31:$Vg1},{30:152,31:$Vg1},o($VY,[2,210]),{30:153,31:$Vg1},{7:154,8:122,10:20,11:21,12:$V0,13:23,14:24,15:7,16:8,17:9,18:10,19:11,20:12,21:13,22:14,23:15,24:16,25:17,26:18,27:19,28:$V71,31:[1,155],33:70,34:$V2,37:55,38:$V3,39:80,40:$V4,41:$V5,43:57,44:$V6,45:$V7,47:27,48:$V8,49:$V9,50:$Va,51:$Vb,52:$Vc,53:$Vd,54:26,60:71,61:$Ve,62:54,63:$Vf,64:$Vg,67:33,68:$Vh,69:$Vi,75:53,77:40,79:28,80:29,81:30,92:$Vj,95:$Vk,97:$Vl,105:$Vm,111:31,112:$Vn,117:$Vo,118:$Vp,119:$Vq,125:$Vr,129:$Vs,130:$Vt,132:43,133:$Vu,135:$Vv,136:44,137:$Vw,138:45,139:$Vx,141:77,149:$Vy,154:41,155:$Vz,157:$VA,158:$VB,159:$VC,160:$VD,161:$VE,162:$VF},o($Vj1,[2,116],{47:27,79:28,80:29,81:30,111:31,75:53,62:54,37:55,43:57,33:70,60:71,39:80,15:142,16:143,54:144,30:156,77:158,31:$Vg1,34:$V2,38:$V3,40:$V4,41:$V5,44:$V6,45:$V7,48:$V8,49:$V9,50:$Va,51:$Vb,52:$Vc,53:$Vd,92:$Vj,96:[1,157],112:$Vn,117:$Vo,118:$Vp,119:$Vq,130:$Vt}),{7:159,8:122,10:20,11:21,12:$V0,13:23,14:24,15:7,16:8,17:9,18:10,19:11,20:12,21:13,22:14,23:15,24:16,25:17,26:18,27:19,28:$V71,33:70,34:$V2,37:55,38:$V3,39:80,40:$V4,41:$V5,43:57,44:$V6,45:$V7,47:27,48:$V8,49:$V9,50:$Va,51:$Vb,52:$Vc,53:$Vd,54:26,60:71,61:$Ve,62:54,63:$Vf,64:$Vg,67:33,68:$Vh,69:$Vi,75:53,77:40,79:28,80:29,81:30,92:$Vj,95:$Vk,97:$Vl,105:$Vm,111:31,112:$Vn,117:$Vo,118:$Vp,119:$Vq,125:$Vr,129:$Vs,130:$Vt,132:43,133:$Vu,135:$Vv,136:44,137:$Vw,138:45,139:$Vx,141:77,149:$Vy,154:41,155:$Vz,157:$VA,158:$VB,159:$VC,160:$VD,161:$VE,162:$VF},o($V51,$Vk1,{15:7,16:8,17:9,18:10,19:11,20:12,21:13,22:14,23:15,24:16,25:17,26:18,27:19,10:20,11:21,13:23,14:24,54:26,47:27,79:28,80:29,81:30,111:31,67:33,77:40,154:41,132:43,136:44,138:45,75:53,62:54,37:55,43:57,33:70,60:71,141:77,39:80,8:122,7:160,12:$V0,28:$V71,31:$Vl1,34:$V2,38:$V3,40:$V4,41:$V5,44:$V6,45:$V7,48:$V8,49:$V9,50:$Va,51:$Vb,52:$Vc,53:$Vd,61:$Ve,63:$Vf,64:$Vg,68:$Vh,69:$Vi,92:$Vj,95:$Vk,97:$Vl,105:$Vm,112:$Vn,117:$Vo,118:$Vp,119:$Vq,125:$Vr,129:$Vs,130:$Vt,137:$Vw,149:$Vy,155:$Vz,157:$VA,158:$VB,159:$VC,160:$VD,161:$VE,162:$VF}),o([1,6,31,32,42,71,94,131,133,135,139,156],[2,67]),{33:166,34:$V2,39:162,40:$V4,41:$V5,92:[1,165],98:163,99:164,104:$Vm1},{25:169,33:170,34:$V2,92:[1,168],95:$Vk,103:[1,171],107:[1,172]},o($Vh1,[2,93]),o($Vh1,[2,94]),o($V91,[2,40]),o($V91,[2,41]),o($V91,[2,42]),o($V91,[2,43]),o($V91,[2,44]),o($V91,[2,45]),o($V91,[2,46]),o($V91,[2,47]),{4:173,5:3,7:4,8:5,9:6,10:20,11:21,12:$V0,13:23,14:24,15:7,16:8,17:9,18:10,19:11,20:12,21:13,22:14,23:15,24:16,25:17,26:18,27:19,28:$V1,31:[1,174],33:70,34:$V2,37:55,38:$V3,39:80,40:$V4,41:$V5,43:57,44:$V6,45:$V7,47:27,48:$V8,49:$V9,50:$Va,51:$Vb,52:$Vc,53:$Vd,54:26,60:71,61:$Ve,62:54,63:$Vf,64:$Vg,67:33,68:$Vh,69:$Vi,75:53,77:40,79:28,80:29,81:30,92:$Vj,95:$Vk,97:$Vl,105:$Vm,111:31,112:$Vn,117:$Vo,118:$Vp,119:$Vq,125:$Vr,129:$Vs,130:$Vt,132:43,133:$Vu,135:$Vv,136:44,137:$Vw,138:45,139:$Vx,141:77,149:$Vy,154:41,155:$Vz,157:$VA,158:$VB,159:$VC,160:$VD,161:$VE,162:$VF},{7:175,8:122,10:20,11:21,12:$V0,13:23,14:24,15:7,16:8,17:9,18:10,19:11,20:12,21:13,22:14,23:15,24:16,25:17,26:18,27:19,28:$V71,31:$Vn1,33:70,34:$V2,37:55,38:$V3,39:80,40:$V4,41:$V5,43:57,44:$V6,45:$V7,47:27,48:$V8,49:$V9,50:$Va,51:$Vb,52:$Vc,53:$Vd,54:26,60:71,61:$Ve,62:54,63:$Vf,64:$Vg,67:33,68:$Vh,69:$Vi,74:$Vo1,75:53,76:180,77:40,79:28,80:29,81:30,92:$Vj,95:$Vk,97:$Vl,105:$Vm,111:31,112:$Vn,116:177,117:$Vo,118:$Vp,119:$Vq,120:$Vp1,123:178,125:$Vr,129:$Vs,130:$Vt,132:43,133:$Vu,135:$Vv,136:44,137:$Vw,138:45,139:$Vx,141:77,149:$Vy,154:41,155:$Vz,157:$VA,158:$VB,159:$VC,160:$VD,161:$VE,162:$VF},o($V91,[2,171]),o($V91,[2,172],{35:182,36:$Vq1}),o([1,6,31,32,42,46,66,71,74,82,83,84,85,87,89,90,94,113,115,120,122,131,133,134,135,139,140,156,159,160,163,164,165,166,167,168,169,170,171,172,173,174],[2,165],{110:184,114:$Vr1}),{31:[2,70]},{31:[2,71]},o($Vs1,[2,88]),o($Vs1,[2,91]),{7:186,8:122,10:20,11:21,12:$V0,13:23,14:24,15:7,16:8,17:9,18:10,19:11,20:12,21:13,22:14,23:15,24:16,25:17,26:18,27:19,28:$V71,33:70,34:$V2,37:55,38:$V3,39:80,40:$V4,41:$V5,43:57,44:$V6,45:$V7,47:27,48:$V8,49:$V9,50:$Va,51:$Vb,52:$Vc,53:$Vd,54:26,60:71,61:$Ve,62:54,63:$Vf,64:$Vg,67:33,68:$Vh,69:$Vi,75:53,77:40,79:28,80:29,81:30,92:$Vj,95:$Vk,97:$Vl,105:$Vm,111:31,112:$Vn,117:$Vo,118:$Vp,119:$Vq,125:$Vr,129:$Vs,130:$Vt,132:43,133:$Vu,135:$Vv,136:44,137:$Vw,138:45,139:$Vx,141:77,149:$Vy,154:41,155:$Vz,157:$VA,158:$VB,159:$VC,160:$VD,161:$VE,162:$VF},{7:187,8:122,10:20,11:21,12:$V0,13:23,14:24,15:7,16:8,17:9,18:10,19:11,20:12,21:13,22:14,23:15,24:16,25:17,26:18,27:19,28:$V71,33:70,34:$V2,37:55,38:$V3,39:80,40:$V4,41:$V5,43:57,44:$V6,45:$V7,47:27,48:$V8,49:$V9,50:$Va,51:$Vb,52:$Vc,53:$Vd,54:26,60:71,61:$Ve,62:54,63:$Vf,64:$Vg,67:33,68:$Vh,69:$Vi,75:53,77:40,79:28,80:29,81:30,92:$Vj,95:$Vk,97:$Vl,105:$Vm,111:31,112:$Vn,117:$Vo,118:$Vp,119:$Vq,125:$Vr,129:$Vs,130:$Vt,132:43,133:$Vu,135:$Vv,136:44,137:$Vw,138:45,139:$Vx,141:77,149:$Vy,154:41,155:$Vz,157:$VA,158:$VB,159:$VC,160:$VD,161:$VE,162:$VF},{7:188,8:122,10:20,11:21,12:$V0,13:23,14:24,15:7,16:8,17:9,18:10,19:11,20:12,21:13,22:14,23:15,24:16,25:17,26:18,27:19,28:$V71,33:70,34:$V2,37:55,38:$V3,39:80,40:$V4,41:$V5,43:57,44:$V6,45:$V7,47:27,48:$V8,49:$V9,50:$Va,51:$Vb,52:$Vc,53:$Vd,54:26,60:71,61:$Ve,62:54,63:$Vf,64:$Vg,67:33,68:$Vh,69:$Vi,75:53,77:40,79:28,80:29,81:30,92:$Vj,95:$Vk,97:$Vl,105:$Vm,111:31,112:$Vn,117:$Vo,118:$Vp,119:$Vq,125:$Vr,129:$Vs,130:$Vt,132:43,133:$Vu,135:$Vv,136:44,137:$Vw,138:45,139:$Vx,141:77,149:$Vy,154:41,155:$Vz,157:$VA,158:$VB,159:$VC,160:$VD,161:$VE,162:$VF},{7:190,8:122,10:20,11:21,12:$V0,13:23,14:24,15:7,16:8,17:9,18:10,19:11,20:12,21:13,22:14,23:15,24:16,25:17,26:18,27:19,28:$V71,30:189,31:$Vg1,33:70,34:$V2,37:55,38:$V3,39:80,40:$V4,41:$V5,43:57,44:$V6,45:$V7,47:27,48:$V8,49:$V9,50:$Va,51:$Vb,52:$Vc,53:$Vd,54:26,60:71,61:$Ve,62:54,63:$Vf,64:$Vg,67:33,68:$Vh,69:$Vi,75:53,77:40,79:28,80:29,81:30,92:$Vj,95:$Vk,97:$Vl,105:$Vm,111:31,112:$Vn,117:$Vo,118:$Vp,119:$Vq,125:$Vr,129:$Vs,130:$Vt,132:43,133:$Vu,135:$Vv,136:44,137:$Vw,138:45,139:$Vx,141:77,149:$Vy,154:41,155:$Vz,157:$VA,158:$VB,159:$VC,160:$VD,161:$VE,162:$VF},{33:195,34:$V2,60:196,62:198,75:197,80:191,92:$Vj,118:$Ve1,119:$Vq,143:192,144:[1,193],145:194},{142:199,146:[1,200],147:[1,201],148:[1,202]},o([6,31,71,94],$Vt1,{39:80,93:203,56:204,57:205,59:206,11:207,37:208,33:209,35:210,60:211,34:$V2,36:$Vq1,38:$V3,40:$V4,41:$V5,63:$Vf,118:$Ve1}),o($Vu1,[2,34]),o($Vu1,[2,35]),o($V91,[2,38]),{15:142,16:212,33:70,34:$V2,37:55,38:$V3,39:80,40:$V4,41:$V5,43:57,44:$V6,45:$V7,47:27,48:$V8,49:$V9,50:$Va,51:$Vb,52:$Vc,53:$Vd,54:144,60:71,62:54,75:53,77:213,79:28,80:29,81:30,92:$Vj,111:31,112:$Vn,117:$Vo,118:$Vp,119:$Vq,130:$Vt},o([1,6,29,31,32,40,41,42,55,58,66,71,74,82,83,84,85,87,89,90,94,96,102,113,114,115,120,122,131,133,134,135,139,140,146,147,148,156,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175],[2,32]),o($Vv1,[2,36]),{4:214,5:3,7:4,8:5,9:6,10:20,11:21,12:$V0,13:23,14:24,15:7,16:8,17:9,18:10,19:11,20:12,21:13,22:14,23:15,24:16,25:17,26:18,27:19,28:$V1,33:70,34:$V2,37:55,38:$V3,39:80,40:$V4,41:$V5,43:57,44:$V6,45:$V7,47:27,48:$V8,49:$V9,50:$Va,51:$Vb,52:$Vc,53:$Vd,54:26,60:71,61:$Ve,62:54,63:$Vf,64:$Vg,67:33,68:$Vh,69:$Vi,75:53,77:40,79:28,80:29,81:30,92:$Vj,95:$Vk,97:$Vl,105:$Vm,111:31,112:$Vn,117:$Vo,118:$Vp,119:$Vq,125:$Vr,129:$Vs,130:$Vt,132:43,133:$Vu,135:$Vv,136:44,137:$Vw,138:45,139:$Vx,141:77,149:$Vy,154:41,155:$Vz,157:$VA,158:$VB,159:$VC,160:$VD,161:$VE,162:$VF},o($VH,[2,5],{7:4,8:5,9:6,15:7,16:8,17:9,18:10,19:11,20:12,21:13,22:14,23:15,24:16,25:17,26:18,27:19,10:20,11:21,13:23,14:24,54:26,47:27,79:28,80:29,81:30,111:31,67:33,77:40,154:41,132:43,136:44,138:45,75:53,62:54,37:55,43:57,33:70,60:71,141:77,39:80,5:215,12:$V0,28:$V1,34:$V2,38:$V3,40:$V4,41:$V5,44:$V6,45:$V7,48:$V8,49:$V9,50:$Va,51:$Vb,52:$Vc,53:$Vd,61:$Ve,63:$Vf,64:$Vg,68:$Vh,69:$Vi,92:$Vj,95:$Vk,97:$Vl,105:$Vm,112:$Vn,117:$Vo,118:$Vp,119:$Vq,125:$Vr,129:$Vs,130:$Vt,133:$Vu,135:$Vv,137:$Vw,139:$Vx,149:$Vy,155:$Vz,157:$VA,158:$VB,159:$VC,160:$VD,161:$VE,162:$VF}),o($VY,[2,258]),{7:216,8:122,10:20,11:21,12:$V0,13:23,14:24,15:7,16:8,17:9,18:10,19:11,20:12,21:13,22:14,23:15,24:16,25:17,26:18,27:19,28:$V71,33:70,34:$V2,37:55,38:$V3,39:80,40:$V4,41:$V5,43:57,44:$V6,45:$V7,47:27,48:$V8,49:$V9,50:$Va,51:$Vb,52:$Vc,53:$Vd,54:26,60:71,61:$Ve,62:54,63:$Vf,64:$Vg,67:33,68:$Vh,69:$Vi,75:53,77:40,79:28,80:29,81:30,92:$Vj,95:$Vk,97:$Vl,105:$Vm,111:31,112:$Vn,117:$Vo,118:$Vp,119:$Vq,125:$Vr,129:$Vs,130:$Vt,132:43,133:$Vu,135:$Vv,136:44,137:$Vw,138:45,139:$Vx,141:77,149:$Vy,154:41,155:$Vz,157:$VA,158:$VB,159:$VC,160:$VD,161:$VE,162:$VF},{7:217,8:122,10:20,11:21,12:$V0,13:23,14:24,15:7,16:8,17:9,18:10,19:11,20:12,21:13,22:14,23:15,24:16,25:17,26:18,27:19,28:$V71,33:70,34:$V2,37:55,38:$V3,39:80,40:$V4,41:$V5,43:57,44:$V6,45:$V7,47:27,48:$V8,49:$V9,50:$Va,51:$Vb,52:$Vc,53:$Vd,54:26,60:71,61:$Ve,62:54,63:$Vf,64:$Vg,67:33,68:$Vh,69:$Vi,75:53,77:40,79:28,80:29,81:30,92:$Vj,95:$Vk,97:$Vl,105:$Vm,111:31,112:$Vn,117:$Vo,118:$Vp,119:$Vq,125:$Vr,129:$Vs,130:$Vt,132:43,133:$Vu,135:$Vv,136:44,137:$Vw,138:45,139:$Vx,141:77,149:$Vy,154:41,155:$Vz,157:$VA,158:$VB,159:$VC,160:$VD,161:$VE,162:$VF},{7:218,8:122,10:20,11:21,12:$V0,13:23,14:24,15:7,16:8,17:9,18:10,19:11,20:12,21:13,22:14,23:15,24:16,25:17,26:18,27:19,28:$V71,33:70,34:$V2,37:55,38:$V3,39:80,40:$V4,41:$V5,43:57,44:$V6,45:$V7,47:27,48:$V8,49:$V9,50:$Va,51:$Vb,52:$Vc,53:$Vd,54:26,60:71,61:$Ve,62:54,63:$Vf,64:$Vg,67:33,68:$Vh,69:$Vi,75:53,77:40,79:28,80:29,81:30,92:$Vj,95:$Vk,97:$Vl,105:$Vm,111:31,112:$Vn,117:$Vo,118:$Vp,119:$Vq,125:$Vr,129:$Vs,130:$Vt,132:43,133:$Vu,135:$Vv,136:44,137:$Vw,138:45,139:$Vx,141:77,149:$Vy,154:41,155:$Vz,157:$VA,158:$VB,159:$VC,160:$VD,161:$VE,162:$VF},{7:219,8:122,10:20,11:21,12:$V0,13:23,14:24,15:7,16:8,17:9,18:10,19:11,20:12,21:13,22:14,23:15,24:16,25:17,26:18,27:19,28:$V71,33:70,34:$V2,37:55,38:$V3,39:80,40:$V4,41:$V5,43:57,44:$V6,45:$V7,47:27,48:$V8,49:$V9,50:$Va,51:$Vb,52:$Vc,53:$Vd,54:26,60:71,61:$Ve,62:54,63:$Vf,64:$Vg,67:33,68:$Vh,69:$Vi,75:53,77:40,79:28,80:29,81:30,92:$Vj,95:$Vk,97:$Vl,105:$Vm,111:31,112:$Vn,117:$Vo,118:$Vp,119:$Vq,125:$Vr,129:$Vs,130:$Vt,132:43,133:$Vu,135:$Vv,136:44,137:$Vw,138:45,139:$Vx,141:77,149:$Vy,154:41,155:$Vz,157:$VA,158:$VB,159:$VC,160:$VD,161:$VE,162:$VF},{7:220,8:122,10:20,11:21,12:$V0,13:23,14:24,15:7,16:8,17:9,18:10,19:11,20:12,21:13,22:14,23:15,24:16,25:17,26:18,27:19,28:$V71,33:70,34:$V2,37:55,38:$V3,39:80,40:$V4,41:$V5,43:57,44:$V6,45:$V7,47:27,48:$V8,49:$V9,50:$Va,51:$Vb,52:$Vc,53:$Vd,54:26,60:71,61:$Ve,62:54,63:$Vf,64:$Vg,67:33,68:$Vh,69:$Vi,75:53,77:40,79:28,80:29,81:30,92:$Vj,95:$Vk,97:$Vl,105:$Vm,111:31,112:$Vn,117:$Vo,118:$Vp,119:$Vq,125:$Vr,129:$Vs,130:$Vt,132:43,133:$Vu,135:$Vv,136:44,137:$Vw,138:45,139:$Vx,141:77,149:$Vy,154:41,155:$Vz,157:$VA,158:$VB,159:$VC,160:$VD,161:$VE,162:$VF},{7:221,8:122,10:20,11:21,12:$V0,13:23,14:24,15:7,16:8,17:9,18:10,19:11,20:12,21:13,22:14,23:15,24:16,25:17,26:18,27:19,28:$V71,33:70,34:$V2,37:55,38:$V3,39:80,40:$V4,41:$V5,43:57,44:$V6,45:$V7,47:27,48:$V8,49:$V9,50:$Va,51:$Vb,52:$Vc,53:$Vd,54:26,60:71,61:$Ve,62:54,63:$Vf,64:$Vg,67:33,68:$Vh,69:$Vi,75:53,77:40,79:28,80:29,81:30,92:$Vj,95:$Vk,97:$Vl,105:$Vm,111:31,112:$Vn,117:$Vo,118:$Vp,119:$Vq,125:$Vr,129:$Vs,130:$Vt,132:43,133:$Vu,135:$Vv,136:44,137:$Vw,138:45,139:$Vx,141:77,149:$Vy,154:41,155:$Vz,157:$VA,158:$VB,159:$VC,160:$VD,161:$VE,162:$VF},{7:222,8:122,10:20,11:21,12:$V0,13:23,14:24,15:7,16:8,17:9,18:10,19:11,20:12,21:13,22:14,23:15,24:16,25:17,26:18,27:19,28:$V71,33:70,34:$V2,37:55,38:$V3,39:80,40:$V4,41:$V5,43:57,44:$V6,45:$V7,47:27,48:$V8,49:$V9,50:$Va,51:$Vb,52:$Vc,53:$Vd,54:26,60:71,61:$Ve,62:54,63:$Vf,64:$Vg,67:33,68:$Vh,69:$Vi,75:53,77:40,79:28,80:29,81:30,92:$Vj,95:$Vk,97:$Vl,105:$Vm,111:31,112:$Vn,117:$Vo,118:$Vp,119:$Vq,125:$Vr,129:$Vs,130:$Vt,132:43,133:$Vu,135:$Vv,136:44,137:$Vw,138:45,139:$Vx,141:77,149:$Vy,154:41,155:$Vz,157:$VA,158:$VB,159:$VC,160:$VD,161:$VE,162:$VF},{7:223,8:122,10:20,11:21,12:$V0,13:23,14:24,15:7,16:8,17:9,18:10,19:11,20:12,21:13,22:14,23:15,24:16,25:17,26:18,27:19,28:$V71,33:70,34:$V2,37:55,38:$V3,39:80,40:$V4,41:$V5,43:57,44:$V6,45:$V7,47:27,48:$V8,49:$V9,50:$Va,51:$Vb,52:$Vc,53:$Vd,54:26,60:71,61:$Ve,62:54,63:$Vf,64:$Vg,67:33,68:$Vh,69:$Vi,75:53,77:40,79:28,80:29,81:30,92:$Vj,95:$Vk,97:$Vl,105:$Vm,111:31,112:$Vn,117:$Vo,118:$Vp,119:$Vq,125:$Vr,129:$Vs,130:$Vt,132:43,133:$Vu,135:$Vv,136:44,137:$Vw,138:45,139:$Vx,141:77,149:$Vy,154:41,155:$Vz,157:$VA,158:$VB,159:$VC,160:$VD,161:$VE,162:$VF},{7:224,8:122,10:20,11:21,12:$V0,13:23,14:24,15:7,16:8,17:9,18:10,19:11,20:12,21:13,22:14,23:15,24:16,25:17,26:18,27:19,28:$V71,33:70,34:$V2,37:55,38:$V3,39:80,40:$V4,41:$V5,43:57,44:$V6,45:$V7,47:27,48:$V8,49:$V9,50:$Va,51:$Vb,52:$Vc,53:$Vd,54:26,60:71,61:$Ve,62:54,63:$Vf,64:$Vg,67:33,68:$Vh,69:$Vi,75:53,77:40,79:28,80:29,81:30,92:$Vj,95:$Vk,97:$Vl,105:$Vm,111:31,112:$Vn,117:$Vo,118:$Vp,119:$Vq,125:$Vr,129:$Vs,130:$Vt,132:43,133:$Vu,135:$Vv,136:44,137:$Vw,138:45,139:$Vx,141:77,149:$Vy,154:41,155:$Vz,157:$VA,158:$VB,159:$VC,160:$VD,161:$VE,162:$VF},{7:225,8:122,10:20,11:21,12:$V0,13:23,14:24,15:7,16:8,17:9,18:10,19:11,20:12,21:13,22:14,23:15,24:16,25:17,26:18,27:19,28:$V71,33:70,34:$V2,37:55,38:$V3,39:80,40:$V4,41:$V5,43:57,44:$V6,45:$V7,47:27,48:$V8,49:$V9,50:$Va,51:$Vb,52:$Vc,53:$Vd,54:26,60:71,61:$Ve,62:54,63:$Vf,64:$Vg,67:33,68:$Vh,69:$Vi,75:53,77:40,79:28,80:29,81:30,92:$Vj,95:$Vk,97:$Vl,105:$Vm,111:31,112:$Vn,117:$Vo,118:$Vp,119:$Vq,125:$Vr,129:$Vs,130:$Vt,132:43,133:$Vu,135:$Vv,136:44,137:$Vw,138:45,139:$Vx,141:77,149:$Vy,154:41,155:$Vz,157:$VA,158:$VB,159:$VC,160:$VD,161:$VE,162:$VF},{7:226,8:122,10:20,11:21,12:$V0,13:23,14:24,15:7,16:8,17:9,18:10,19:11,20:12,21:13,22:14,23:15,24:16,25:17,26:18,27:19,28:$V71,33:70,34:$V2,37:55,38:$V3,39:80,40:$V4,41:$V5,43:57,44:$V6,45:$V7,47:27,48:$V8,49:$V9,50:$Va,51:$Vb,52:$Vc,53:$Vd,54:26,60:71,61:$Ve,62:54,63:$Vf,64:$Vg,67:33,68:$Vh,69:$Vi,75:53,77:40,79:28,80:29,81:30,92:$Vj,95:$Vk,97:$Vl,105:$Vm,111:31,112:$Vn,117:$Vo,118:$Vp,119:$Vq,125:$Vr,129:$Vs,130:$Vt,132:43,133:$Vu,135:$Vv,136:44,137:$Vw,138:45,139:$Vx,141:77,149:$Vy,154:41,155:$Vz,157:$VA,158:$VB,159:$VC,160:$VD,161:$VE,162:$VF},{7:227,8:122,10:20,11:21,12:$V0,13:23,14:24,15:7,16:8,17:9,18:10,19:11,20:12,21:13,22:14,23:15,24:16,25:17,26:18,27:19,28:$V71,33:70,34:$V2,37:55,38:$V3,39:80,40:$V4,41:$V5,43:57,44:$V6,45:$V7,47:27,48:$V8,49:$V9,50:$Va,51:$Vb,52:$Vc,53:$Vd,54:26,60:71,61:$Ve,62:54,63:$Vf,64:$Vg,67:33,68:$Vh,69:$Vi,75:53,77:40,79:28,80:29,81:30,92:$Vj,95:$Vk,97:$Vl,105:$Vm,111:31,112:$Vn,117:$Vo,118:$Vp,119:$Vq,125:$Vr,129:$Vs,130:$Vt,132:43,133:$Vu,135:$Vv,136:44,137:$Vw,138:45,139:$Vx,141:77,149:$Vy,154:41,155:$Vz,157:$VA,158:$VB,159:$VC,160:$VD,161:$VE,162:$VF},{7:228,8:122,10:20,11:21,12:$V0,13:23,14:24,15:7,16:8,17:9,18:10,19:11,20:12,21:13,22:14,23:15,24:16,25:17,26:18,27:19,28:$V71,33:70,34:$V2,37:55,38:$V3,39:80,40:$V4,41:$V5,43:57,44:$V6,45:$V7,47:27,48:$V8,49:$V9,50:$Va,51:$Vb,52:$Vc,53:$Vd,54:26,60:71,61:$Ve,62:54,63:$Vf,64:$Vg,67:33,68:$Vh,69:$Vi,75:53,77:40,79:28,80:29,81:30,92:$Vj,95:$Vk,97:$Vl,105:$Vm,111:31,112:$Vn,117:$Vo,118:$Vp,119:$Vq,125:$Vr,129:$Vs,130:$Vt,132:43,133:$Vu,135:$Vv,136:44,137:$Vw,138:45,139:$Vx,141:77,149:$Vy,154:41,155:$Vz,157:$VA,158:$VB,159:$VC,160:$VD,161:$VE,162:$VF},{7:229,8:122,10:20,11:21,12:$V0,13:23,14:24,15:7,16:8,17:9,18:10,19:11,20:12,21:13,22:14,23:15,24:16,25:17,26:18,27:19,28:$V71,33:70,34:$V2,37:55,38:$V3,39:80,40:$V4,41:$V5,43:57,44:$V6,45:$V7,47:27,48:$V8,49:$V9,50:$Va,51:$Vb,52:$Vc,53:$Vd,54:26,60:71,61:$Ve,62:54,63:$Vf,64:$Vg,67:33,68:$Vh,69:$Vi,75:53,77:40,79:28,80:29,81:30,92:$Vj,95:$Vk,97:$Vl,105:$Vm,111:31,112:$Vn,117:$Vo,118:$Vp,119:$Vq,125:$Vr,129:$Vs,130:$Vt,132:43,133:$Vu,135:$Vv,136:44,137:$Vw,138:45,139:$Vx,141:77,149:$Vy,154:41,155:$Vz,157:$VA,158:$VB,159:$VC,160:$VD,161:$VE,162:$VF},o($VY,[2,209]),o($VY,[2,214]),{7:230,8:122,10:20,11:21,12:$V0,13:23,14:24,15:7,16:8,17:9,18:10,19:11,20:12,21:13,22:14,23:15,24:16,25:17,26:18,27:19,28:$V71,33:70,34:$V2,37:55,38:$V3,39:80,40:$V4,41:$V5,43:57,44:$V6,45:$V7,47:27,48:$V8,49:$V9,50:$Va,51:$Vb,52:$Vc,53:$Vd,54:26,60:71,61:$Ve,62:54,63:$Vf,64:$Vg,67:33,68:$Vh,69:$Vi,75:53,77:40,79:28,80:29,81:30,92:$Vj,95:$Vk,97:$Vl,105:$Vm,111:31,112:$Vn,117:$Vo,118:$Vp,119:$Vq,125:$Vr,129:$Vs,130:$Vt,132:43,133:$Vu,135:$Vv,136:44,137:$Vw,138:45,139:$Vx,141:77,149:$Vy,154:41,155:$Vz,157:$VA,158:$VB,159:$VC,160:$VD,161:$VE,162:$VF},o($VY,[2,208]),o($VY,[2,213]),{39:231,40:$V4,41:$V5,110:232,114:$Vr1},o($Vs1,[2,89]),o($Vw1,[2,168]),{35:233,36:$Vq1},{35:234,36:$Vq1},o($Vs1,[2,104],{35:235,36:$Vq1}),{35:236,36:$Vq1},o($Vs1,[2,105]),{7:238,8:122,10:20,11:21,12:$V0,13:23,14:24,15:7,16:8,17:9,18:10,19:11,20:12,21:13,22:14,23:15,24:16,25:17,26:18,27:19,28:$V71,33:70,34:$V2,37:55,38:$V3,39:80,40:$V4,41:$V5,43:57,44:$V6,45:$V7,47:27,48:$V8,49:$V9,50:$Va,51:$Vb,52:$Vc,53:$Vd,54:26,60:71,61:$Ve,62:54,63:$Vf,64:$Vg,67:33,68:$Vh,69:$Vi,74:$Vx1,75:53,77:40,79:28,80:29,81:30,88:237,91:239,92:$Vj,95:$Vk,97:$Vl,105:$Vm,111:31,112:$Vn,117:$Vo,118:$Vp,119:$Vq,121:240,122:$Vy1,125:$Vr,129:$Vs,130:$Vt,132:43,133:$Vu,135:$Vv,136:44,137:$Vw,138:45,139:$Vx,141:77,149:$Vy,154:41,155:$Vz,157:$VA,158:$VB,159:$VC,160:$VD,161:$VE,162:$VF},{86:243,87:$V21,90:$V31},{110:244,114:$Vr1},o($Vs1,[2,90]),o($VH,[2,66],{15:7,16:8,17:9,18:10,19:11,20:12,21:13,22:14,23:15,24:16,25:17,26:18,27:19,10:20,11:21,13:23,14:24,54:26,47:27,79:28,80:29,81:30,111:31,67:33,77:40,154:41,132:43,136:44,138:45,75:53,62:54,37:55,43:57,33:70,60:71,141:77,39:80,8:122,7:245,12:$V0,28:$V71,31:$Vl1,34:$V2,38:$V3,40:$V4,41:$V5,44:$V6,45:$V7,48:$V8,49:$V9,50:$Va,51:$Vb,52:$Vc,53:$Vd,61:$Ve,63:$Vf,64:$Vg,68:$Vh,69:$Vi,92:$Vj,95:$Vk,97:$Vl,105:$Vm,112:$Vn,117:$Vo,118:$Vp,119:$Vq,125:$Vr,129:$Vs,130:$Vt,133:$Vk1,135:$Vk1,139:$Vk1,156:$Vk1,137:$Vw,149:$Vy,155:$Vz,157:$VA,158:$VB,159:$VC,160:$VD,161:$VE,162:$VF}),o($Vz1,[2,28],{141:77,132:102,138:103,159:$VJ,160:$VK,163:$VL,164:$VM,165:$VN,166:$VO,167:$VP,168:$VQ,169:$VR,170:$VS,171:$VT,172:$VU,173:$VV,174:$VW}),{7:246,8:122,10:20,11:21,12:$V0,13:23,14:24,15:7,16:8,17:9,18:10,19:11,20:12,21:13,22:14,23:15,24:16,25:17,26:18,27:19,28:$V71,33:70,34:$V2,37:55,38:$V3,39:80,40:$V4,41:$V5,43:57,44:$V6,45:$V7,47:27,48:$V8,49:$V9,50:$Va,51:$Vb,52:$Vc,53:$Vd,54:26,60:71,61:$Ve,62:54,63:$Vf,64:$Vg,67:33,68:$Vh,69:$Vi,75:53,77:40,79:28,80:29,81:30,92:$Vj,95:$Vk,97:$Vl,105:$Vm,111:31,112:$Vn,117:$Vo,118:$Vp,119:$Vq,125:$Vr,129:$Vs,130:$Vt,132:43,133:$Vu,135:$Vv,136:44,137:$Vw,138:45,139:$Vx,141:77,149:$Vy,154:41,155:$Vz,157:$VA,158:$VB,159:$VC,160:$VD,161:$VE,162:$VF},{132:105,133:$Vu,135:$Vv,138:106,139:$Vx,141:77,156:$VX},o([1,6,31,32,42,66,71,74,89,94,115,120,122,131,133,134,135,139,140,156,163,164,165,166,167,168,169,170,171,172,173,174],$V61,{15:7,16:8,17:9,18:10,19:11,20:12,21:13,22:14,23:15,24:16,25:17,26:18,27:19,10:20,11:21,13:23,14:24,54:26,47:27,79:28,80:29,81:30,111:31,67:33,77:40,154:41,132:43,136:44,138:45,75:53,62:54,37:55,43:57,33:70,60:71,141:77,39:80,7:120,8:122,12:$V0,28:$V71,29:$V81,34:$V2,38:$V3,40:$V4,41:$V5,44:$V6,45:$V7,48:$V8,49:$V9,50:$Va,51:$Vb,52:$Vc,53:$Vd,61:$Ve,63:$Vf,64:$Vg,68:$Vh,69:$Vi,92:$Vj,95:$Vk,97:$Vl,105:$Vm,112:$Vn,117:$Vo,118:$Vp,119:$Vq,125:$Vr,129:$Vs,130:$Vt,137:$Vw,149:$Vy,155:$Vz,157:$VA,158:$VB,159:$VC,160:$VD,161:$VE,162:$VF}),{6:[1,248],7:247,8:122,10:20,11:21,12:$V0,13:23,14:24,15:7,16:8,17:9,18:10,19:11,20:12,21:13,22:14,23:15,24:16,25:17,26:18,27:19,28:$V71,31:[1,249],33:70,34:$V2,37:55,38:$V3,39:80,40:$V4,41:$V5,43:57,44:$V6,45:$V7,47:27,48:$V8,49:$V9,50:$Va,51:$Vb,52:$Vc,53:$Vd,54:26,60:71,61:$Ve,62:54,63:$Vf,64:$Vg,67:33,68:$Vh,69:$Vi,75:53,77:40,79:28,80:29,81:30,92:$Vj,95:$Vk,97:$Vl,105:$Vm,111:31,112:$Vn,117:$Vo,118:$Vp,119:$Vq,125:$Vr,129:$Vs,130:$Vt,132:43,133:$Vu,135:$Vv,136:44,137:$Vw,138:45,139:$Vx,141:77,149:$Vy,154:41,155:$Vz,157:$VA,158:$VB,159:$VC,160:$VD,161:$VE,162:$VF},o([6,31],$VA1,{70:252,66:[1,250],71:$VB1}),o($VC1,[2,75]),o($VC1,[2,79],{55:[1,254],74:[1,253]}),o($VC1,[2,82]),o($VD1,[2,83]),o($VD1,[2,84]),o($VD1,[2,85]),o($VD1,[2,86]),{35:182,36:$Vq1},{7:255,8:122,10:20,11:21,12:$V0,13:23,14:24,15:7,16:8,17:9,18:10,19:11,20:12,21:13,22:14,23:15,24:16,25:17,26:18,27:19,28:$V71,31:$Vn1,33:70,34:$V2,37:55,38:$V3,39:80,40:$V4,41:$V5,43:57,44:$V6,45:$V7,47:27,48:$V8,49:$V9,50:$Va,51:$Vb,52:$Vc,53:$Vd,54:26,60:71,61:$Ve,62:54,63:$Vf,64:$Vg,67:33,68:$Vh,69:$Vi,74:$Vo1,75:53,76:180,77:40,79:28,80:29,81:30,92:$Vj,95:$Vk,97:$Vl,105:$Vm,111:31,112:$Vn,116:177,117:$Vo,118:$Vp,119:$Vq,120:$Vp1,123:178,125:$Vr,129:$Vs,130:$Vt,132:43,133:$Vu,135:$Vv,136:44,137:$Vw,138:45,139:$Vx,141:77,149:$Vy,154:41,155:$Vz,157:$VA,158:$VB,159:$VC,160:$VD,161:$VE,162:$VF},o($VY,[2,69]),{4:257,5:3,7:4,8:5,9:6,10:20,11:21,12:$V0,13:23,14:24,15:7,16:8,17:9,18:10,19:11,20:12,21:13,22:14,23:15,24:16,25:17,26:18,27:19,28:$V1,32:[1,256],33:70,34:$V2,37:55,38:$V3,39:80,40:$V4,41:$V5,43:57,44:$V6,45:$V7,47:27,48:$V8,49:$V9,50:$Va,51:$Vb,52:$Vc,53:$Vd,54:26,60:71,61:$Ve,62:54,63:$Vf,64:$Vg,67:33,68:$Vh,69:$Vi,75:53,77:40,79:28,80:29,81:30,92:$Vj,95:$Vk,97:$Vl,105:$Vm,111:31,112:$Vn,117:$Vo,118:$Vp,119:$Vq,125:$Vr,129:$Vs,130:$Vt,132:43,133:$Vu,135:$Vv,136:44,137:$Vw,138:45,139:$Vx,141:77,149:$Vy,154:41,155:$Vz,157:$VA,158:$VB,159:$VC,160:$VD,161:$VE,162:$VF},o([1,6,31,32,42,66,71,74,89,94,115,120,122,131,133,134,135,139,140,156,159,160,164,165,166,167,168,169,170,171,172,173,174],[2,250],{141:77,132:102,138:103,163:$VL}),o($VE1,[2,251],{141:77,132:102,138:103,163:$VL,165:$VN}),o($VE1,[2,252],{141:77,132:102,138:103,163:$VL,165:$VN}),o($VE1,[2,253],{141:77,132:102,138:103,163:$VL,165:$VN}),o($VY,[2,254],{40:$Vi1,41:$Vi1,82:$Vi1,83:$Vi1,84:$Vi1,85:$Vi1,87:$Vi1,90:$Vi1,113:$Vi1,114:$Vi1}),o($Vw1,$VZ,{109:107,78:108,86:114,82:$V_,83:$V$,84:$V01,85:$V11,87:$V21,90:$V31,113:$V41}),{78:118,82:$V_,83:$V$,84:$V01,85:$V11,86:114,87:$V21,90:$V31,109:117,113:$V41,114:$VZ},o($VF1,$Va1),o($VY,[2,255],{40:$Vi1,41:$Vi1,82:$Vi1,83:$Vi1,84:$Vi1,85:$Vi1,87:$Vi1,90:$Vi1,113:$Vi1,114:$Vi1}),o($VY,[2,256]),o($VY,[2,257]),{6:[1,260],7:258,8:122,10:20,11:21,12:$V0,13:23,14:24,15:7,16:8,17:9,18:10,19:11,20:12,21:13,22:14,23:15,24:16,25:17,26:18,27:19,28:$V71,31:[1,259],33:70,34:$V2,37:55,38:$V3,39:80,40:$V4,41:$V5,43:57,44:$V6,45:$V7,47:27,48:$V8,49:$V9,50:$Va,51:$Vb,52:$Vc,53:$Vd,54:26,60:71,61:$Ve,62:54,63:$Vf,64:$Vg,67:33,68:$Vh,69:$Vi,75:53,77:40,79:28,80:29,81:30,92:$Vj,95:$Vk,97:$Vl,105:$Vm,111:31,112:$Vn,117:$Vo,118:$Vp,119:$Vq,125:$Vr,129:$Vs,130:$Vt,132:43,133:$Vu,135:$Vv,136:44,137:$Vw,138:45,139:$Vx,141:77,149:$Vy,154:41,155:$Vz,157:$VA,158:$VB,159:$VC,160:$VD,161:$VE,162:$VF},{7:261,8:122,10:20,11:21,12:$V0,13:23,14:24,15:7,16:8,17:9,18:10,19:11,20:12,21:13,22:14,23:15,24:16,25:17,26:18,27:19,28:$V71,33:70,34:$V2,37:55,38:$V3,39:80,40:$V4,41:$V5,43:57,44:$V6,45:$V7,47:27,48:$V8,49:$V9,50:$Va,51:$Vb,52:$Vc,53:$Vd,54:26,60:71,61:$Ve,62:54,63:$Vf,64:$Vg,67:33,68:$Vh,69:$Vi,75:53,77:40,79:28,80:29,81:30,92:$Vj,95:$Vk,97:$Vl,105:$Vm,111:31,112:$Vn,117:$Vo,118:$Vp,119:$Vq,125:$Vr,129:$Vs,130:$Vt,132:43,133:$Vu,135:$Vv,136:44,137:$Vw,138:45,139:$Vx,141:77,149:$Vy,154:41,155:$Vz,157:$VA,158:$VB,159:$VC,160:$VD,161:$VE,162:$VF},{30:262,31:$Vg1,155:[1,263]},o($VY,[2,193],{126:264,127:[1,265],128:[1,266]}),o($VY,[2,207]),o($VY,[2,215]),{31:[1,267],132:102,133:$Vu,135:$Vv,138:103,139:$Vx,141:77,156:$VI,159:$VJ,160:$VK,163:$VL,164:$VM,165:$VN,166:$VO,167:$VP,168:$VQ,169:$VR,170:$VS,171:$VT,172:$VU,173:$VV,174:$VW},{150:268,152:269,153:$VG1},o($VY,[2,117]),{7:271,8:122,10:20,11:21,12:$V0,13:23,14:24,15:7,16:8,17:9,18:10,19:11,20:12,21:13,22:14,23:15,24:16,25:17,26:18,27:19,28:$V71,33:70,34:$V2,37:55,38:$V3,39:80,40:$V4,41:$V5,43:57,44:$V6,45:$V7,47:27,48:$V8,49:$V9,50:$Va,51:$Vb,52:$Vc,53:$Vd,54:26,60:71,61:$Ve,62:54,63:$Vf,64:$Vg,67:33,68:$Vh,69:$Vi,75:53,77:40,79:28,80:29,81:30,92:$Vj,95:$Vk,97:$Vl,105:$Vm,111:31,112:$Vn,117:$Vo,118:$Vp,119:$Vq,125:$Vr,129:$Vs,130:$Vt,132:43,133:$Vu,135:$Vv,136:44,137:$Vw,138:45,139:$Vx,141:77,149:$Vy,154:41,155:$Vz,157:$VA,158:$VB,159:$VC,160:$VD,161:$VE,162:$VF},o($Vj1,[2,120],{30:272,31:$Vg1,40:$Vi1,41:$Vi1,82:$Vi1,83:$Vi1,84:$Vi1,85:$Vi1,87:$Vi1,90:$Vi1,113:$Vi1,114:$Vi1,96:[1,273]}),o($Vz1,[2,200],{141:77,132:102,138:103,159:$VJ,160:$VK,163:$VL,164:$VM,165:$VN,166:$VO,167:$VP,168:$VQ,169:$VR,170:$VS,171:$VT,172:$VU,173:$VV,174:$VW}),o($V51,$VH1,{141:77,132:102,138:103,159:$VJ,160:$VK,163:$VL,164:$VM,165:$VN,166:$VO,167:$VP,168:$VQ,169:$VR,170:$VS,171:$VT,172:$VU,173:$VV,174:$VW}),{62:274,92:$Vj},o($V51,[2,124]),{29:[1,275],71:[1,276]},{29:[1,277]},{31:$VI1,33:282,34:$V2,94:[1,278],100:279,101:280,103:$VJ1},o([29,71],[2,140]),{102:[1,284]},{31:$VK1,33:289,34:$V2,94:[1,285],103:$VL1,106:286,108:287},o($V51,[2,144]),{55:[1,291]},{7:292,8:122,10:20,11:21,12:$V0,13:23,14:24,15:7,16:8,17:9,18:10,19:11,20:12,21:13,22:14,23:15,24:16,25:17,26:18,27:19,28:$V71,33:70,34:$V2,37:55,38:$V3,39:80,40:$V4,41:$V5,43:57,44:$V6,45:$V7,47:27,48:$V8,49:$V9,50:$Va,51:$Vb,52:$Vc,53:$Vd,54:26,60:71,61:$Ve,62:54,63:$Vf,64:$Vg,67:33,68:$Vh,69:$Vi,75:53,77:40,79:28,80:29,81:30,92:$Vj,95:$Vk,97:$Vl,105:$Vm,111:31,112:$Vn,117:$Vo,118:$Vp,119:$Vq,125:$Vr,129:$Vs,130:$Vt,132:43,133:$Vu,135:$Vv,136:44,137:$Vw,138:45,139:$Vx,141:77,149:$Vy,154:41,155:$Vz,157:$VA,158:$VB,159:$VC,160:$VD,161:$VE,162:$VF},{29:[1,293]},{6:$VG,131:[1,294]},{4:295,5:3,7:4,8:5,9:6,10:20,11:21,12:$V0,13:23,14:24,15:7,16:8,17:9,18:10,19:11,20:12,21:13,22:14,23:15,24:16,25:17,26:18,27:19,28:$V1,33:70,34:$V2,37:55,38:$V3,39:80,40:$V4,41:$V5,43:57,44:$V6,45:$V7,47:27,48:$V8,49:$V9,50:$Va,51:$Vb,52:$Vc,53:$Vd,54:26,60:71,61:$Ve,62:54,63:$Vf,64:$Vg,67:33,68:$Vh,69:$Vi,75:53,77:40,79:28,80:29,81:30,92:$Vj,95:$Vk,97:$Vl,105:$Vm,111:31,112:$Vn,117:$Vo,118:$Vp,119:$Vq,125:$Vr,129:$Vs,130:$Vt,132:43,133:$Vu,135:$Vv,136:44,137:$Vw,138:45,139:$Vx,141:77,149:$Vy,154:41,155:$Vz,157:$VA,158:$VB,159:$VC,160:$VD,161:$VE,162:$VF},o([6,31,71,120],$VM1,{141:77,132:102,138:103,121:296,74:[1,297],122:$Vy1,133:$Vu,135:$Vv,139:$Vx,156:$VI,159:$VJ,160:$VK,163:$VL,164:$VM,165:$VN,166:$VO,167:$VP,168:$VQ,169:$VR,170:$VS,171:$VT,172:$VU,173:$VV,174:$VW}),o($VN1,[2,174]),o([6,31,120],$VA1,{70:298,71:$VO1}),o($VP1,[2,183]),{7:255,8:122,10:20,11:21,12:$V0,13:23,14:24,15:7,16:8,17:9,18:10,19:11,20:12,21:13,22:14,23:15,24:16,25:17,26:18,27:19,28:$V71,31:$Vn1,33:70,34:$V2,37:55,38:$V3,39:80,40:$V4,41:$V5,43:57,44:$V6,45:$V7,47:27,48:$V8,49:$V9,50:$Va,51:$Vb,52:$Vc,53:$Vd,54:26,60:71,61:$Ve,62:54,63:$Vf,64:$Vg,67:33,68:$Vh,69:$Vi,74:$Vo1,75:53,76:180,77:40,79:28,80:29,81:30,92:$Vj,95:$Vk,97:$Vl,105:$Vm,111:31,112:$Vn,116:300,117:$Vo,118:$Vp,119:$Vq,123:178,125:$Vr,129:$Vs,130:$Vt,132:43,133:$Vu,135:$Vv,136:44,137:$Vw,138:45,139:$Vx,141:77,149:$Vy,154:41,155:$Vz,157:$VA,158:$VB,159:$VC,160:$VD,161:$VE,162:$VF},o($VP1,[2,189]),o($VP1,[2,190]),o($VQ1,[2,173]),o($VQ1,[2,33]),o($Vb1,[2,166]),{7:255,8:122,10:20,11:21,12:$V0,13:23,14:24,15:7,16:8,17:9,18:10,19:11,20:12,21:13,22:14,23:15,24:16,25:17,26:18,27:19,28:$V71,31:$Vn1,33:70,34:$V2,37:55,38:$V3,39:80,40:$V4,41:$V5,43:57,44:$V6,45:$V7,47:27,48:$V8,49:$V9,50:$Va,51:$Vb,52:$Vc,53:$Vd,54:26,60:71,61:$Ve,62:54,63:$Vf,64:$Vg,67:33,68:$Vh,69:$Vi,74:$Vo1,75:53,76:180,77:40,79:28,80:29,81:30,92:$Vj,95:$Vk,97:$Vl,105:$Vm,111:31,112:$Vn,115:[1,301],116:302,117:$Vo,118:$Vp,119:$Vq,123:178,125:$Vr,129:$Vs,130:$Vt,132:43,133:$Vu,135:$Vv,136:44,137:$Vw,138:45,139:$Vx,141:77,149:$Vy,154:41,155:$Vz,157:$VA,158:$VB,159:$VC,160:$VD,161:$VE,162:$VF},{30:303,31:$Vg1,132:102,133:$Vu,135:$Vv,138:103,139:$Vx,141:77,156:$VI,159:$VJ,160:$VK,163:$VL,164:$VM,165:$VN,166:$VO,167:$VP,168:$VQ,169:$VR,170:$VS,171:$VT,172:$VU,173:$VV,174:$VW},o($VR1,[2,203],{141:77,132:102,138:103,133:$Vu,134:[1,304],135:$Vv,139:$Vx,159:$VJ,160:$VK,163:$VL,164:$VM,165:$VN,166:$VO,167:$VP,168:$VQ,169:$VR,170:$VS,171:$VT,172:$VU,173:$VV,174:$VW}),o($VR1,[2,205],{141:77,132:102,138:103,133:$Vu,134:[1,305],135:$Vv,139:$Vx,159:$VJ,160:$VK,163:$VL,164:$VM,165:$VN,166:$VO,167:$VP,168:$VQ,169:$VR,170:$VS,171:$VT,172:$VU,173:$VV,174:$VW}),o($VY,[2,211]),o($VS1,[2,212],{141:77,132:102,138:103,133:$Vu,135:$Vv,139:$Vx,159:$VJ,160:$VK,163:$VL,164:$VM,165:$VN,166:$VO,167:$VP,168:$VQ,169:$VR,170:$VS,171:$VT,172:$VU,173:$VV,174:$VW}),o([1,6,31,32,42,66,71,74,89,94,115,120,122,131,133,134,135,139,156,159,160,163,164,165,166,167,168,169,170,171,172,173,174],[2,216],{140:[1,306]}),o($VT1,[2,219]),{33:195,34:$V2,60:196,62:198,75:197,92:$Vj,118:$Ve1,119:$Vf1,143:307,145:194},o($VT1,[2,225],{71:[1,308]}),o($VU1,[2,221]),o($VU1,[2,222]),o($VU1,[2,223]),o($VU1,[2,224]),o($VY,[2,218]),{7:309,8:122,10:20,11:21,12:$V0,13:23,14:24,15:7,16:8,17:9,18:10,19:11,20:12,21:13,22:14,23:15,24:16,25:17,26:18,27:19,28:$V71,33:70,34:$V2,37:55,38:$V3,39:80,40:$V4,41:$V5,43:57,44:$V6,45:$V7,47:27,48:$V8,49:$V9,50:$Va,51:$Vb,52:$Vc,53:$Vd,54:26,60:71,61:$Ve,62:54,63:$Vf,64:$Vg,67:33,68:$Vh,69:$Vi,75:53,77:40,79:28,80:29,81:30,92:$Vj,95:$Vk,97:$Vl,105:$Vm,111:31,112:$Vn,117:$Vo,118:$Vp,119:$Vq,125:$Vr,129:$Vs,130:$Vt,132:43,133:$Vu,135:$Vv,136:44,137:$Vw,138:45,139:$Vx,141:77,149:$Vy,154:41,155:$Vz,157:$VA,158:$VB,159:$VC,160:$VD,161:$VE,162:$VF},{7:310,8:122,10:20,11:21,12:$V0,13:23,14:24,15:7,16:8,17:9,18:10,19:11,20:12,21:13,22:14,23:15,24:16,25:17,26:18,27:19,28:$V71,33:70,34:$V2,37:55,38:$V3,39:80,40:$V4,41:$V5,43:57,44:$V6,45:$V7,47:27,48:$V8,49:$V9,50:$Va,51:$Vb,52:$Vc,53:$Vd,54:26,60:71,61:$Ve,62:54,63:$Vf,64:$Vg,67:33,68:$Vh,69:$Vi,75:53,77:40,79:28,80:29,81:30,92:$Vj,95:$Vk,97:$Vl,105:$Vm,111:31,112:$Vn,117:$Vo,118:$Vp,119:$Vq,125:$Vr,129:$Vs,130:$Vt,132:43,133:$Vu,135:$Vv,136:44,137:$Vw,138:45,139:$Vx,141:77,149:$Vy,154:41,155:$Vz,157:$VA,158:$VB,159:$VC,160:$VD,161:$VE,162:$VF},{7:311,8:122,10:20,11:21,12:$V0,13:23,14:24,15:7,16:8,17:9,18:10,19:11,20:12,21:13,22:14,23:15,24:16,25:17,26:18,27:19,28:$V71,33:70,34:$V2,37:55,38:$V3,39:80,40:$V4,41:$V5,43:57,44:$V6,45:$V7,47:27,48:$V8,49:$V9,50:$Va,51:$Vb,52:$Vc,53:$Vd,54:26,60:71,61:$Ve,62:54,63:$Vf,64:$Vg,67:33,68:$Vh,69:$Vi,75:53,77:40,79:28,80:29,81:30,92:$Vj,95:$Vk,97:$Vl,105:$Vm,111:31,112:$Vn,117:$Vo,118:$Vp,119:$Vq,125:$Vr,129:$Vs,130:$Vt,132:43,133:$Vu,135:$Vv,136:44,137:$Vw,138:45,139:$Vx,141:77,149:$Vy,154:41,155:$Vz,157:$VA,158:$VB,159:$VC,160:$VD,161:$VE,162:$VF},o($VV1,$VA1,{70:312,71:$VW1}),o($VX1,[2,112]),o($VX1,[2,51],{58:[1,314]}),o($VY1,[2,60],{55:[1,315]}),o($VX1,[2,56]),o($VY1,[2,61]),o($VZ1,[2,57]),o($VZ1,[2,58]),o($VZ1,[2,59]),{46:[1,316],78:118,82:$V_,83:$V$,84:$V01,85:$V11,86:114,87:$V21,90:$V31,109:117,113:$V41,114:$VZ},o($VF1,$Vi1),{6:$VG,42:[1,317]},o($VH,[2,4]),o($V_1,[2,259],{141:77,132:102,138:103,163:$VL,164:$VM,165:$VN}),o($V_1,[2,260],{141:77,132:102,138:103,163:$VL,164:$VM,165:$VN}),o($VE1,[2,261],{141:77,132:102,138:103,163:$VL,165:$VN}),o($VE1,[2,262],{141:77,132:102,138:103,163:$VL,165:$VN}),o([1,6,31,32,42,66,71,74,89,94,115,120,122,131,133,134,135,139,140,156,166,167,168,169,170,171,172,173,174],[2,263],{141:77,132:102,138:103,159:$VJ,160:$VK,163:$VL,164:$VM,165:$VN}),o([1,6,31,32,42,66,71,74,89,94,115,120,122,131,133,134,135,139,140,156,167,168,169,170,171,172,173],[2,264],{141:77,132:102,138:103,159:$VJ,160:$VK,163:$VL,164:$VM,165:$VN,166:$VO,174:$VW}),o([1,6,31,32,42,66,71,74,89,94,115,120,122,131,133,134,135,139,140,156,168,169,170,171,172,173],[2,265],{141:77,132:102,138:103,159:$VJ,160:$VK,163:$VL,164:$VM,165:$VN,166:$VO,167:$VP,174:$VW}),o([1,6,31,32,42,66,71,74,89,94,115,120,122,131,133,134,135,139,140,156,169,170,171,172,173],[2,266],{141:77,132:102,138:103,159:$VJ,160:$VK,163:$VL,164:$VM,165:$VN,166:$VO,167:$VP,168:$VQ,174:$VW}),o([1,6,31,32,42,66,71,74,89,94,115,120,122,131,133,134,135,139,140,156,170,171,172,173],[2,267],{141:77,132:102,138:103,159:$VJ,160:$VK,163:$VL,164:$VM,165:$VN,166:$VO,167:$VP,168:$VQ,169:$VR,174:$VW}),o([1,6,31,32,42,66,71,74,89,94,115,120,122,131,133,134,135,139,140,156,171,172,173],[2,268],{141:77,132:102,138:103,159:$VJ,160:$VK,163:$VL,164:$VM,165:$VN,166:$VO,167:$VP,168:$VQ,169:$VR,170:$VS,174:$VW}),o([1,6,31,32,42,66,71,74,89,94,115,120,122,131,133,134,135,139,140,156,172,173],[2,269],{141:77,132:102,138:103,159:$VJ,160:$VK,163:$VL,164:$VM,165:$VN,166:$VO,167:$VP,168:$VQ,169:$VR,170:$VS,171:$VT,174:$VW}),o([1,6,31,32,42,66,71,74,89,94,115,120,122,131,133,134,135,139,140,156,173],[2,270],{141:77,132:102,138:103,159:$VJ,160:$VK,163:$VL,164:$VM,165:$VN,166:$VO,167:$VP,168:$VQ,169:$VR,170:$VS,171:$VT,172:$VU,174:$VW}),o([1,6,31,32,42,66,71,74,89,94,115,120,122,131,133,134,135,139,140,156,167,168,169,170,171,172,173,174],[2,271],{141:77,132:102,138:103,159:$VJ,160:$VK,163:$VL,164:$VM,165:$VN,166:$VO}),o($VS1,[2,249],{141:77,132:102,138:103,133:$Vu,135:$Vv,139:$Vx,159:$VJ,160:$VK,163:$VL,164:$VM,165:$VN,166:$VO,167:$VP,168:$VQ,169:$VR,170:$VS,171:$VT,172:$VU,173:$VV,174:$VW}),o($VS1,[2,248],{141:77,132:102,138:103,133:$Vu,135:$Vv,139:$Vx,159:$VJ,160:$VK,163:$VL,164:$VM,165:$VN,166:$VO,167:$VP,168:$VQ,169:$VR,170:$VS,171:$VT,172:$VU,173:$VV,174:$VW}),o($Vb1,[2,161]),o($Vb1,[2,162]),o($Vs1,[2,100]),o($Vs1,[2,101]),o($Vs1,[2,102]),o($Vs1,[2,103]),{89:[1,318]},{74:$Vx1,89:[2,108],121:319,122:$Vy1,132:102,133:$Vu,135:$Vv,138:103,139:$Vx,141:77,156:$VI,159:$VJ,160:$VK,163:$VL,164:$VM,165:$VN,166:$VO,167:$VP,168:$VQ,169:$VR,170:$VS,171:$VT,172:$VU,173:$VV,174:$VW},{89:[2,109]},{7:320,8:122,10:20,11:21,12:$V0,13:23,14:24,15:7,16:8,17:9,18:10,19:11,20:12,21:13,22:14,23:15,24:16,25:17,26:18,27:19,28:$V71,33:70,34:$V2,37:55,38:$V3,39:80,40:$V4,41:$V5,43:57,44:$V6,45:$V7,47:27,48:$V8,49:$V9,50:$Va,51:$Vb,52:$Vc,53:$Vd,54:26,60:71,61:$Ve,62:54,63:$Vf,64:$Vg,67:33,68:$Vh,69:$Vi,75:53,77:40,79:28,80:29,81:30,89:[2,182],92:$Vj,95:$Vk,97:$Vl,105:$Vm,111:31,112:$Vn,117:$Vo,118:$Vp,119:$Vq,125:$Vr,129:$Vs,130:$Vt,132:43,133:$Vu,135:$Vv,136:44,137:$Vw,138:45,139:$Vx,141:77,149:$Vy,154:41,155:$Vz,157:$VA,158:$VB,159:$VC,160:$VD,161:$VE,162:$VF},o($V$1,[2,176]),o($V$1,$V02),o($Vs1,[2,107]),o($Vb1,[2,163]),o($VH,[2,65],{141:77,132:102,138:103,133:$VH1,135:$VH1,139:$VH1,156:$VH1,159:$VJ,160:$VK,163:$VL,164:$VM,165:$VN,166:$VO,167:$VP,168:$VQ,169:$VR,170:$VS,171:$VT,172:$VU,173:$VV,174:$VW}),o($Vz1,[2,29],{141:77,132:102,138:103,159:$VJ,160:$VK,163:$VL,164:$VM,165:$VN,166:$VO,167:$VP,168:$VQ,169:$VR,170:$VS,171:$VT,172:$VU,173:$VV,174:$VW}),o($Vz1,[2,48],{141:77,132:102,138:103,159:$VJ,160:$VK,163:$VL,164:$VM,165:$VN,166:$VO,167:$VP,168:$VQ,169:$VR,170:$VS,171:$VT,172:$VU,173:$VV,174:$VW}),{7:321,8:122,10:20,11:21,12:$V0,13:23,14:24,15:7,16:8,17:9,18:10,19:11,20:12,21:13,22:14,23:15,24:16,25:17,26:18,27:19,28:$V71,33:70,34:$V2,37:55,38:$V3,39:80,40:$V4,41:$V5,43:57,44:$V6,45:$V7,47:27,48:$V8,49:$V9,50:$Va,51:$Vb,52:$Vc,53:$Vd,54:26,60:71,61:$Ve,62:54,63:$Vf,64:$Vg,67:33,68:$Vh,69:$Vi,75:53,77:40,79:28,80:29,81:30,92:$Vj,95:$Vk,97:$Vl,105:$Vm,111:31,112:$Vn,117:$Vo,118:$Vp,119:$Vq,125:$Vr,129:$Vs,130:$Vt,132:43,133:$Vu,135:$Vv,136:44,137:$Vw,138:45,139:$Vx,141:77,149:$Vy,154:41,155:$Vz,157:$VA,158:$VB,159:$VC,160:$VD,161:$VE,162:$VF},{7:322,8:122,10:20,11:21,12:$V0,13:23,14:24,15:7,16:8,17:9,18:10,19:11,20:12,21:13,22:14,23:15,24:16,25:17,26:18,27:19,28:$V71,33:70,34:$V2,37:55,38:$V3,39:80,40:$V4,41:$V5,43:57,44:$V6,45:$V7,47:27,48:$V8,49:$V9,50:$Va,51:$Vb,52:$Vc,53:$Vd,54:26,60:71,61:$Ve,62:54,63:$Vf,64:$Vg,67:33,68:$Vh,69:$Vi,75:53,77:40,79:28,80:29,81:30,92:$Vj,95:$Vk,97:$Vl,105:$Vm,111:31,112:$Vn,117:$Vo,118:$Vp,119:$Vq,125:$Vr,129:$Vs,130:$Vt,132:43,133:$Vu,135:$Vv,136:44,137:$Vw,138:45,139:$Vx,141:77,149:$Vy,154:41,155:$Vz,157:$VA,158:$VB,159:$VC,160:$VD,161:$VE,162:$VF},{67:323,68:$Vh,69:$Vi},o($V12,$V22,{73:127,33:129,60:130,75:131,62:132,72:324,34:$V2,74:$Vd1,92:$Vj,118:$Ve1,119:$Vf1}),{6:$V32,31:$V42},o($VC1,[2,80]),{7:327,8:122,10:20,11:21,12:$V0,13:23,14:24,15:7,16:8,17:9,18:10,19:11,20:12,21:13,22:14,23:15,24:16,25:17,26:18,27:19,28:$V71,33:70,34:$V2,37:55,38:$V3,39:80,40:$V4,41:$V5,43:57,44:$V6,45:$V7,47:27,48:$V8,49:$V9,50:$Va,51:$Vb,52:$Vc,53:$Vd,54:26,60:71,61:$Ve,62:54,63:$Vf,64:$Vg,67:33,68:$Vh,69:$Vi,75:53,77:40,79:28,80:29,81:30,92:$Vj,95:$Vk,97:$Vl,105:$Vm,111:31,112:$Vn,117:$Vo,118:$Vp,119:$Vq,125:$Vr,129:$Vs,130:$Vt,132:43,133:$Vu,135:$Vv,136:44,137:$Vw,138:45,139:$Vx,141:77,149:$Vy,154:41,155:$Vz,157:$VA,158:$VB,159:$VC,160:$VD,161:$VE,162:$VF},o($VP1,$VM1,{141:77,132:102,138:103,74:[1,328],133:$Vu,135:$Vv,139:$Vx,156:$VI,159:$VJ,160:$VK,163:$VL,164:$VM,165:$VN,166:$VO,167:$VP,168:$VQ,169:$VR,170:$VS,171:$VT,172:$VU,173:$VV,174:$VW}),o($V52,[2,30]),{6:$VG,32:[1,329]},o($Vz1,[2,272],{141:77,132:102,138:103,159:$VJ,160:$VK,163:$VL,164:$VM,165:$VN,166:$VO,167:$VP,168:$VQ,169:$VR,170:$VS,171:$VT,172:$VU,173:$VV,174:$VW}),{7:330,8:122,10:20,11:21,12:$V0,13:23,14:24,15:7,16:8,17:9,18:10,19:11,20:12,21:13,22:14,23:15,24:16,25:17,26:18,27:19,28:$V71,33:70,34:$V2,37:55,38:$V3,39:80,40:$V4,41:$V5,43:57,44:$V6,45:$V7,47:27,48:$V8,49:$V9,50:$Va,51:$Vb,52:$Vc,53:$Vd,54:26,60:71,61:$Ve,62:54,63:$Vf,64:$Vg,67:33,68:$Vh,69:$Vi,75:53,77:40,79:28,80:29,81:30,92:$Vj,95:$Vk,97:$Vl,105:$Vm,111:31,112:$Vn,117:$Vo,118:$Vp,119:$Vq,125:$Vr,129:$Vs,130:$Vt,132:43,133:$Vu,135:$Vv,136:44,137:$Vw,138:45,139:$Vx,141:77,149:$Vy,154:41,155:$Vz,157:$VA,158:$VB,159:$VC,160:$VD,161:$VE,162:$VF},{7:331,8:122,10:20,11:21,12:$V0,13:23,14:24,15:7,16:8,17:9,18:10,19:11,20:12,21:13,22:14,23:15,24:16,25:17,26:18,27:19,28:$V71,33:70,34:$V2,37:55,38:$V3,39:80,40:$V4,41:$V5,43:57,44:$V6,45:$V7,47:27,48:$V8,49:$V9,50:$Va,51:$Vb,52:$Vc,53:$Vd,54:26,60:71,61:$Ve,62:54,63:$Vf,64:$Vg,67:33,68:$Vh,69:$Vi,75:53,77:40,79:28,80:29,81:30,92:$Vj,95:$Vk,97:$Vl,105:$Vm,111:31,112:$Vn,117:$Vo,118:$Vp,119:$Vq,125:$Vr,129:$Vs,130:$Vt,132:43,133:$Vu,135:$Vv,136:44,137:$Vw,138:45,139:$Vx,141:77,149:$Vy,154:41,155:$Vz,157:$VA,158:$VB,159:$VC,160:$VD,161:$VE,162:$VF},o($Vz1,[2,275],{141:77,132:102,138:103,159:$VJ,160:$VK,163:$VL,164:$VM,165:$VN,166:$VO,167:$VP,168:$VQ,169:$VR,170:$VS,171:$VT,172:$VU,173:$VV,174:$VW}),o($VY,[2,247]),{7:332,8:122,10:20,11:21,12:$V0,13:23,14:24,15:7,16:8,17:9,18:10,19:11,20:12,21:13,22:14,23:15,24:16,25:17,26:18,27:19,28:$V71,33:70,34:$V2,37:55,38:$V3,39:80,40:$V4,41:$V5,43:57,44:$V6,45:$V7,47:27,48:$V8,49:$V9,50:$Va,51:$Vb,52:$Vc,53:$Vd,54:26,60:71,61:$Ve,62:54,63:$Vf,64:$Vg,67:33,68:$Vh,69:$Vi,75:53,77:40,79:28,80:29,81:30,92:$Vj,95:$Vk,97:$Vl,105:$Vm,111:31,112:$Vn,117:$Vo,118:$Vp,119:$Vq,125:$Vr,129:$Vs,130:$Vt,132:43,133:$Vu,135:$Vv,136:44,137:$Vw,138:45,139:$Vx,141:77,149:$Vy,154:41,155:$Vz,157:$VA,158:$VB,159:$VC,160:$VD,161:$VE,162:$VF},o($VY,[2,194],{127:[1,333]}),{30:334,31:$Vg1},{30:337,31:$Vg1,33:335,34:$V2,62:336,92:$Vj},{150:338,152:269,153:$VG1},{32:[1,339],151:[1,340],152:341,153:$VG1},o($V62,[2,240]),{7:343,8:122,10:20,11:21,12:$V0,13:23,14:24,15:7,16:8,17:9,18:10,19:11,20:12,21:13,22:14,23:15,24:16,25:17,26:18,27:19,28:$V71,33:70,34:$V2,37:55,38:$V3,39:80,40:$V4,41:$V5,43:57,44:$V6,45:$V7,47:27,48:$V8,49:$V9,50:$Va,51:$Vb,52:$Vc,53:$Vd,54:26,60:71,61:$Ve,62:54,63:$Vf,64:$Vg,67:33,68:$Vh,69:$Vi,75:53,77:40,79:28,80:29,81:30,92:$Vj,95:$Vk,97:$Vl,105:$Vm,111:31,112:$Vn,117:$Vo,118:$Vp,119:$Vq,124:342,125:$Vr,129:$Vs,130:$Vt,132:43,133:$Vu,135:$Vv,136:44,137:$Vw,138:45,139:$Vx,141:77,149:$Vy,154:41,155:$Vz,157:$VA,158:$VB,159:$VC,160:$VD,161:$VE,162:$VF},o($V72,[2,118],{141:77,132:102,138:103,30:344,31:$Vg1,133:$Vu,135:$Vv,139:$Vx,159:$VJ,160:$VK,163:$VL,164:$VM,165:$VN,166:$VO,167:$VP,168:$VQ,169:$VR,170:$VS,171:$VT,172:$VU,173:$VV,174:$VW}),o($VY,[2,121]),{7:345,8:122,10:20,11:21,12:$V0,13:23,14:24,15:7,16:8,17:9,18:10,19:11,20:12,21:13,22:14,23:15,24:16,25:17,26:18,27:19,28:$V71,33:70,34:$V2,37:55,38:$V3,39:80,40:$V4,41:$V5,43:57,44:$V6,45:$V7,47:27,48:$V8,49:$V9,50:$Va,51:$Vb,52:$Vc,53:$Vd,54:26,60:71,61:$Ve,62:54,63:$Vf,64:$Vg,67:33,68:$Vh,69:$Vi,75:53,77:40,79:28,80:29,81:30,92:$Vj,95:$Vk,97:$Vl,105:$Vm,111:31,112:$Vn,117:$Vo,118:$Vp,119:$Vq,125:$Vr,129:$Vs,130:$Vt,132:43,133:$Vu,135:$Vv,136:44,137:$Vw,138:45,139:$Vx,141:77,149:$Vy,154:41,155:$Vz,157:$VA,158:$VB,159:$VC,160:$VD,161:$VE,162:$VF},{32:[1,346]},{39:347,40:$V4,41:$V5},{92:[1,349],99:348,104:$Vm1},{39:350,40:$V4,41:$V5},{29:[1,351]},o($VV1,$VA1,{70:352,71:$V82}),o($VX1,[2,131]),{31:$VI1,33:282,34:$V2,100:354,101:280,103:$VJ1},o($VX1,[2,136],{102:[1,355]}),o($VX1,[2,138],{102:[1,356]}),{33:357,34:$V2},o($V51,[2,142]),o($VV1,$VA1,{70:358,71:$V92}),o($VX1,[2,151]),{31:$VK1,33:289,34:$V2,103:$VL1,106:360,108:287},o($VX1,[2,156],{102:[1,361]}),o($VX1,[2,159],{102:[1,362]}),{6:[1,364],7:363,8:122,10:20,11:21,12:$V0,13:23,14:24,15:7,16:8,17:9,18:10,19:11,20:12,21:13,22:14,23:15,24:16,25:17,26:18,27:19,28:$V71,31:[1,365],33:70,34:$V2,37:55,38:$V3,39:80,40:$V4,41:$V5,43:57,44:$V6,45:$V7,47:27,48:$V8,49:$V9,50:$Va,51:$Vb,52:$Vc,53:$Vd,54:26,60:71,61:$Ve,62:54,63:$Vf,64:$Vg,67:33,68:$Vh,69:$Vi,75:53,77:40,79:28,80:29,81:30,92:$Vj,95:$Vk,97:$Vl,105:$Vm,111:31,112:$Vn,117:$Vo,118:$Vp,119:$Vq,125:$Vr,129:$Vs,130:$Vt,132:43,133:$Vu,135:$Vv,136:44,137:$Vw,138:45,139:$Vx,141:77,149:$Vy,154:41,155:$Vz,157:$VA,158:$VB,159:$VC,160:$VD,161:$VE,162:$VF},o($Va2,[2,148],{141:77,132:102,138:103,133:$Vu,135:$Vv,139:$Vx,159:$VJ,160:$VK,163:$VL,164:$VM,165:$VN,166:$VO,167:$VP,168:$VQ,169:$VR,170:$VS,171:$VT,172:$VU,173:$VV,174:$VW}),{39:366,40:$V4,41:$V5},o($V91,[2,201]),{6:$VG,32:[1,367]},{7:368,8:122,10:20,11:21,12:$V0,13:23,14:24,15:7,16:8,17:9,18:10,19:11,20:12,21:13,22:14,23:15,24:16,25:17,26:18,27:19,28:$V71,33:70,34:$V2,37:55,38:$V3,39:80,40:$V4,41:$V5,43:57,44:$V6,45:$V7,47:27,48:$V8,49:$V9,50:$Va,51:$Vb,52:$Vc,53:$Vd,54:26,60:71,61:$Ve,62:54,63:$Vf,64:$Vg,67:33,68:$Vh,69:$Vi,75:53,77:40,79:28,80:29,81:30,92:$Vj,95:$Vk,97:$Vl,105:$Vm,111:31,112:$Vn,117:$Vo,118:$Vp,119:$Vq,125:$Vr,129:$Vs,130:$Vt,132:43,133:$Vu,135:$Vv,136:44,137:$Vw,138:45,139:$Vx,141:77,149:$Vy,154:41,155:$Vz,157:$VA,158:$VB,159:$VC,160:$VD,161:$VE,162:$VF},o([12,28,34,38,40,41,44,45,48,49,50,51,52,53,61,63,64,68,69,92,95,97,105,112,117,118,119,125,129,130,133,135,137,139,149,155,157,158,159,160,161,162],$V02,{6:$Vb2,31:$Vb2,71:$Vb2,120:$Vb2}),{6:$Vc2,31:$Vd2,120:[1,369]},o([6,31,32,115,120],$V22,{15:7,16:8,17:9,18:10,19:11,20:12,21:13,22:14,23:15,24:16,25:17,26:18,27:19,10:20,11:21,13:23,14:24,54:26,47:27,79:28,80:29,81:30,111:31,67:33,77:40,154:41,132:43,136:44,138:45,75:53,62:54,37:55,43:57,33:70,60:71,141:77,39:80,8:122,76:180,7:255,123:372,12:$V0,28:$V71,34:$V2,38:$V3,40:$V4,41:$V5,44:$V6,45:$V7,48:$V8,49:$V9,50:$Va,51:$Vb,52:$Vc,53:$Vd,61:$Ve,63:$Vf,64:$Vg,68:$Vh,69:$Vi,74:$Vo1,92:$Vj,95:$Vk,97:$Vl,105:$Vm,112:$Vn,117:$Vo,118:$Vp,119:$Vq,125:$Vr,129:$Vs,130:$Vt,133:$Vu,135:$Vv,137:$Vw,139:$Vx,149:$Vy,155:$Vz,157:$VA,158:$VB,159:$VC,160:$VD,161:$VE,162:$VF}),o($V12,$VA1,{70:373,71:$VO1}),o($Vb1,[2,169]),o([6,31,115],$VA1,{70:374,71:$VO1}),o($Ve2,[2,244]),{7:375,8:122,10:20,11:21,12:$V0,13:23,14:24,15:7,16:8,17:9,18:10,19:11,20:12,21:13,22:14,23:15,24:16,25:17,26:18,27:19,28:$V71,33:70,34:$V2,37:55,38:$V3,39:80,40:$V4,41:$V5,43:57,44:$V6,45:$V7,47:27,48:$V8,49:$V9,50:$Va,51:$Vb,52:$Vc,53:$Vd,54:26,60:71,61:$Ve,62:54,63:$Vf,64:$Vg,67:33,68:$Vh,69:$Vi,75:53,77:40,79:28,80:29,81:30,92:$Vj,95:$Vk,97:$Vl,105:$Vm,111:31,112:$Vn,117:$Vo,118:$Vp,119:$Vq,125:$Vr,129:$Vs,130:$Vt,132:43,133:$Vu,135:$Vv,136:44,137:$Vw,138:45,139:$Vx,141:77,149:$Vy,154:41,155:$Vz,157:$VA,158:$VB,159:$VC,160:$VD,161:$VE,162:$VF},{7:376,8:122,10:20,11:21,12:$V0,13:23,14:24,15:7,16:8,17:9,18:10,19:11,20:12,21:13,22:14,23:15,24:16,25:17,26:18,27:19,28:$V71,33:70,34:$V2,37:55,38:$V3,39:80,40:$V4,41:$V5,43:57,44:$V6,45:$V7,47:27,48:$V8,49:$V9,50:$Va,51:$Vb,52:$Vc,53:$Vd,54:26,60:71,61:$Ve,62:54,63:$Vf,64:$Vg,67:33,68:$Vh,69:$Vi,75:53,77:40,79:28,80:29,81:30,92:$Vj,95:$Vk,97:$Vl,105:$Vm,111:31,112:$Vn,117:$Vo,118:$Vp,119:$Vq,125:$Vr,129:$Vs,130:$Vt,132:43,133:$Vu,135:$Vv,136:44,137:$Vw,138:45,139:$Vx,141:77,149:$Vy,154:41,155:$Vz,157:$VA,158:$VB,159:$VC,160:$VD,161:$VE,162:$VF},{7:377,8:122,10:20,11:21,12:$V0,13:23,14:24,15:7,16:8,17:9,18:10,19:11,20:12,21:13,22:14,23:15,24:16,25:17,26:18,27:19,28:$V71,33:70,34:$V2,37:55,38:$V3,39:80,40:$V4,41:$V5,43:57,44:$V6,45:$V7,47:27,48:$V8,49:$V9,50:$Va,51:$Vb,52:$Vc,53:$Vd,54:26,60:71,61:$Ve,62:54,63:$Vf,64:$Vg,67:33,68:$Vh,69:$Vi,75:53,77:40,79:28,80:29,81:30,92:$Vj,95:$Vk,97:$Vl,105:$Vm,111:31,112:$Vn,117:$Vo,118:$Vp,119:$Vq,125:$Vr,129:$Vs,130:$Vt,132:43,133:$Vu,135:$Vv,136:44,137:$Vw,138:45,139:$Vx,141:77,149:$Vy,154:41,155:$Vz,157:$VA,158:$VB,159:$VC,160:$VD,161:$VE,162:$VF},o($VT1,[2,220]),{33:195,34:$V2,60:196,62:198,75:197,92:$Vj,118:$Ve1,119:$Vf1,145:378},o([1,6,31,32,42,66,71,74,89,94,115,120,122,131,133,135,139,156],[2,227],{141:77,132:102,138:103,134:[1,379],140:[1,380],159:$VJ,160:$VK,163:$VL,164:$VM,165:$VN,166:$VO,167:$VP,168:$VQ,169:$VR,170:$VS,171:$VT,172:$VU,173:$VV,174:$VW}),o($Vf2,[2,228],{141:77,132:102,138:103,134:[1,381],159:$VJ,160:$VK,163:$VL,164:$VM,165:$VN,166:$VO,167:$VP,168:$VQ,169:$VR,170:$VS,171:$VT,172:$VU,173:$VV,174:$VW}),o($Vf2,[2,234],{141:77,132:102,138:103,134:[1,382],159:$VJ,160:$VK,163:$VL,164:$VM,165:$VN,166:$VO,167:$VP,168:$VQ,169:$VR,170:$VS,171:$VT,172:$VU,173:$VV,174:$VW}),{6:$Vg2,31:$Vh2,94:[1,383]},o($Vi2,$V22,{39:80,57:205,59:206,11:207,37:208,33:209,35:210,60:211,56:386,34:$V2,36:$Vq1,38:$V3,40:$V4,41:$V5,63:$Vf,118:$Ve1}),{7:387,8:122,10:20,11:21,12:$V0,13:23,14:24,15:7,16:8,17:9,18:10,19:11,20:12,21:13,22:14,23:15,24:16,25:17,26:18,27:19,28:$V71,31:[1,388],33:70,34:$V2,37:55,38:$V3,39:80,40:$V4,41:$V5,43:57,44:$V6,45:$V7,47:27,48:$V8,49:$V9,50:$Va,51:$Vb,52:$Vc,53:$Vd,54:26,60:71,61:$Ve,62:54,63:$Vf,64:$Vg,67:33,68:$Vh,69:$Vi,75:53,77:40,79:28,80:29,81:30,92:$Vj,95:$Vk,97:$Vl,105:$Vm,111:31,112:$Vn,117:$Vo,118:$Vp,119:$Vq,125:$Vr,129:$Vs,130:$Vt,132:43,133:$Vu,135:$Vv,136:44,137:$Vw,138:45,139:$Vx,141:77,149:$Vy,154:41,155:$Vz,157:$VA,158:$VB,159:$VC,160:$VD,161:$VE,162:$VF},{7:389,8:122,10:20,11:21,12:$V0,13:23,14:24,15:7,16:8,17:9,18:10,19:11,20:12,21:13,22:14,23:15,24:16,25:17,26:18,27:19,28:$V71,31:[1,390],33:70,34:$V2,37:55,38:$V3,39:80,40:$V4,41:$V5,43:57,44:$V6,45:$V7,47:27,48:$V8,49:$V9,50:$Va,51:$Vb,52:$Vc,53:$Vd,54:26,60:71,61:$Ve,62:54,63:$Vf,64:$Vg,67:33,68:$Vh,69:$Vi,75:53,77:40,79:28,80:29,81:30,92:$Vj,95:$Vk,97:$Vl,105:$Vm,111:31,112:$Vn,117:$Vo,118:$Vp,119:$Vq,125:$Vr,129:$Vs,130:$Vt,132:43,133:$Vu,135:$Vv,136:44,137:$Vw,138:45,139:$Vx,141:77,149:$Vy,154:41,155:$Vz,157:$VA,158:$VB,159:$VC,160:$VD,161:$VE,162:$VF},o($V91,[2,39]),o($Vv1,[2,37]),o($Vs1,[2,106]),{7:391,8:122,10:20,11:21,12:$V0,13:23,14:24,15:7,16:8,17:9,18:10,19:11,20:12,21:13,22:14,23:15,24:16,25:17,26:18,27:19,28:$V71,33:70,34:$V2,37:55,38:$V3,39:80,40:$V4,41:$V5,43:57,44:$V6,45:$V7,47:27,48:$V8,49:$V9,50:$Va,51:$Vb,52:$Vc,53:$Vd,54:26,60:71,61:$Ve,62:54,63:$Vf,64:$Vg,67:33,68:$Vh,69:$Vi,75:53,77:40,79:28,80:29,81:30,89:[2,180],92:$Vj,95:$Vk,97:$Vl,105:$Vm,111:31,112:$Vn,117:$Vo,118:$Vp,119:$Vq,125:$Vr,129:$Vs,130:$Vt,132:43,133:$Vu,135:$Vv,136:44,137:$Vw,138:45,139:$Vx,141:77,149:$Vy,154:41,155:$Vz,157:$VA,158:$VB,159:$VC,160:$VD,161:$VE,162:$VF},{89:[2,181],132:102,133:$Vu,135:$Vv,138:103,139:$Vx,141:77,156:$VI,159:$VJ,160:$VK,163:$VL,164:$VM,165:$VN,166:$VO,167:$VP,168:$VQ,169:$VR,170:$VS,171:$VT,172:$VU,173:$VV,174:$VW},o($Vz1,[2,49],{141:77,132:102,138:103,159:$VJ,160:$VK,163:$VL,164:$VM,165:$VN,166:$VO,167:$VP,168:$VQ,169:$VR,170:$VS,171:$VT,172:$VU,173:$VV,174:$VW}),{32:[1,392],132:102,133:$Vu,135:$Vv,138:103,139:$Vx,141:77,156:$VI,159:$VJ,160:$VK,163:$VL,164:$VM,165:$VN,166:$VO,167:$VP,168:$VQ,169:$VR,170:$VS,171:$VT,172:$VU,173:$VV,174:$VW},{30:393,31:$Vg1},o($VC1,[2,76]),{33:129,34:$V2,60:130,62:132,72:394,73:127,74:$Vd1,75:131,92:$Vj,118:$Ve1,119:$Vf1},o($Vj2,$Vc1,{72:126,73:127,33:129,60:130,75:131,62:132,65:395,34:$V2,74:$Vd1,92:$Vj,118:$Ve1,119:$Vf1}),o($VC1,[2,81],{141:77,132:102,138:103,133:$Vu,135:$Vv,139:$Vx,156:$VI,159:$VJ,160:$VK,163:$VL,164:$VM,165:$VN,166:$VO,167:$VP,168:$VQ,169:$VR,170:$VS,171:$VT,172:$VU,173:$VV,174:$VW}),o($VP1,$Vb2),o($V52,[2,31]),{32:[1,396],132:102,133:$Vu,135:$Vv,138:103,139:$Vx,141:77,156:$VI,159:$VJ,160:$VK,163:$VL,164:$VM,165:$VN,166:$VO,167:$VP,168:$VQ,169:$VR,170:$VS,171:$VT,172:$VU,173:$VV,174:$VW},o($Vz1,[2,274],{141:77,132:102,138:103,159:$VJ,160:$VK,163:$VL,164:$VM,165:$VN,166:$VO,167:$VP,168:$VQ,169:$VR,170:$VS,171:$VT,172:$VU,173:$VV,174:$VW}),{30:397,31:$Vg1,132:102,133:$Vu,135:$Vv,138:103,139:$Vx,141:77,156:$VI,159:$VJ,160:$VK,163:$VL,164:$VM,165:$VN,166:$VO,167:$VP,168:$VQ,169:$VR,170:$VS,171:$VT,172:$VU,173:$VV,174:$VW},{30:398,31:$Vg1},o($VY,[2,195]),{30:399,31:$Vg1},{30:400,31:$Vg1},o($Vk2,[2,199]),{32:[1,401],151:[1,402],152:341,153:$VG1},o($VY,[2,238]),{30:403,31:$Vg1},o($V62,[2,241]),{30:404,31:$Vg1,71:[1,405]},o($Vl2,[2,191],{141:77,132:102,138:103,133:$Vu,135:$Vv,139:$Vx,156:$VI,159:$VJ,160:$VK,163:$VL,164:$VM,165:$VN,166:$VO,167:$VP,168:$VQ,169:$VR,170:$VS,171:$VT,172:$VU,173:$VV,174:$VW}),o($VY,[2,119]),o($V72,[2,122],{141:77,132:102,138:103,30:406,31:$Vg1,133:$Vu,135:$Vv,139:$Vx,159:$VJ,160:$VK,163:$VL,164:$VM,165:$VN,166:$VO,167:$VP,168:$VQ,169:$VR,170:$VS,171:$VT,172:$VU,173:$VV,174:$VW}),o($V51,[2,63]),o($V51,[2,125]),{29:[1,407]},{31:$VI1,33:282,34:$V2,100:408,101:280,103:$VJ1},o($V51,[2,126]),{39:409,40:$V4,41:$V5},{6:$Vm2,31:$Vn2,94:[1,410]},o($Vi2,$V22,{33:282,101:413,34:$V2,103:$VJ1}),o($V12,$VA1,{70:414,71:$V82}),{33:415,34:$V2},{33:416,34:$V2},{29:[2,141]},{6:$Vo2,31:$Vp2,94:[1,417]},o($Vi2,$V22,{33:289,108:420,34:$V2,103:$VL1}),o($V12,$VA1,{70:421,71:$V92}),{33:422,34:$V2,103:[1,423]},{33:424,34:$V2},o($Va2,[2,145],{141:77,132:102,138:103,133:$Vu,135:$Vv,139:$Vx,159:$VJ,160:$VK,163:$VL,164:$VM,165:$VN,166:$VO,167:$VP,168:$VQ,169:$VR,170:$VS,171:$VT,172:$VU,173:$VV,174:$VW}),{7:425,8:122,10:20,11:21,12:$V0,13:23,14:24,15:7,16:8,17:9,18:10,19:11,20:12,21:13,22:14,23:15,24:16,25:17,26:18,27:19,28:$V71,33:70,34:$V2,37:55,38:$V3,39:80,40:$V4,41:$V5,43:57,44:$V6,45:$V7,47:27,48:$V8,49:$V9,50:$Va,51:$Vb,52:$Vc,53:$Vd,54:26,60:71,61:$Ve,62:54,63:$Vf,64:$Vg,67:33,68:$Vh,69:$Vi,75:53,77:40,79:28,80:29,81:30,92:$Vj,95:$Vk,97:$Vl,105:$Vm,111:31,112:$Vn,117:$Vo,118:$Vp,119:$Vq,125:$Vr,129:$Vs,130:$Vt,132:43,133:$Vu,135:$Vv,136:44,137:$Vw,138:45,139:$Vx,141:77,149:$Vy,154:41,155:$Vz,157:$VA,158:$VB,159:$VC,160:$VD,161:$VE,162:$VF},{7:426,8:122,10:20,11:21,12:$V0,13:23,14:24,15:7,16:8,17:9,18:10,19:11,20:12,21:13,22:14,23:15,24:16,25:17,26:18,27:19,28:$V71,33:70,34:$V2,37:55,38:$V3,39:80,40:$V4,41:$V5,43:57,44:$V6,45:$V7,47:27,48:$V8,49:$V9,50:$Va,51:$Vb,52:$Vc,53:$Vd,54:26,60:71,61:$Ve,62:54,63:$Vf,64:$Vg,67:33,68:$Vh,69:$Vi,75:53,77:40,79:28,80:29,81:30,92:$Vj,95:$Vk,97:$Vl,105:$Vm,111:31,112:$Vn,117:$Vo,118:$Vp,119:$Vq,125:$Vr,129:$Vs,130:$Vt,132:43,133:$Vu,135:$Vv,136:44,137:$Vw,138:45,139:$Vx,141:77,149:$Vy,154:41,155:$Vz,157:$VA,158:$VB,159:$VC,160:$VD,161:$VE,162:$VF},o($V51,[2,149]),{131:[1,427]},{120:[1,428],132:102,133:$Vu,135:$Vv,138:103,139:$Vx,141:77,156:$VI,159:$VJ,160:$VK,163:$VL,164:$VM,165:$VN,166:$VO,167:$VP,168:$VQ,169:$VR,170:$VS,171:$VT,172:$VU,173:$VV,174:$VW},o($VN1,[2,175]),{7:255,8:122,10:20,11:21,12:$V0,13:23,14:24,15:7,16:8,17:9,18:10,19:11,20:12,21:13,22:14,23:15,24:16,25:17,26:18,27:19,28:$V71,33:70,34:$V2,37:55,38:$V3,39:80,40:$V4,41:$V5,43:57,44:$V6,45:$V7,47:27,48:$V8,49:$V9,50:$Va,51:$Vb,52:$Vc,53:$Vd,54:26,60:71,61:$Ve,62:54,63:$Vf,64:$Vg,67:33,68:$Vh,69:$Vi,74:$Vo1,75:53,76:180,77:40,79:28,80:29,81:30,92:$Vj,95:$Vk,97:$Vl,105:$Vm,111:31,112:$Vn,117:$Vo,118:$Vp,119:$Vq,123:429,125:$Vr,129:$Vs,130:$Vt,132:43,133:$Vu,135:$Vv,136:44,137:$Vw,138:45,139:$Vx,141:77,149:$Vy,154:41,155:$Vz,157:$VA,158:$VB,159:$VC,160:$VD,161:$VE,162:$VF},{7:255,8:122,10:20,11:21,12:$V0,13:23,14:24,15:7,16:8,17:9,18:10,19:11,20:12,21:13,22:14,23:15,24:16,25:17,26:18,27:19,28:$V71,31:$Vn1,33:70,34:$V2,37:55,38:$V3,39:80,40:$V4,41:$V5,43:57,44:$V6,45:$V7,47:27,48:$V8,49:$V9,50:$Va,51:$Vb,52:$Vc,53:$Vd,54:26,60:71,61:$Ve,62:54,63:$Vf,64:$Vg,67:33,68:$Vh,69:$Vi,74:$Vo1,75:53,76:180,77:40,79:28,80:29,81:30,92:$Vj,95:$Vk,97:$Vl,105:$Vm,111:31,112:$Vn,116:430,117:$Vo,118:$Vp,119:$Vq,123:178,125:$Vr,129:$Vs,130:$Vt,132:43,133:$Vu,135:$Vv,136:44,137:$Vw,138:45,139:$Vx,141:77,149:$Vy,154:41,155:$Vz,157:$VA,158:$VB,159:$VC,160:$VD,161:$VE,162:$VF},o($VP1,[2,184]),{6:$Vc2,31:$Vd2,32:[1,431]},{6:$Vc2,31:$Vd2,115:[1,432]},o($VS1,[2,204],{141:77,132:102,138:103,133:$Vu,135:$Vv,139:$Vx,159:$VJ,160:$VK,163:$VL,164:$VM,165:$VN,166:$VO,167:$VP,168:$VQ,169:$VR,170:$VS,171:$VT,172:$VU,173:$VV,174:$VW}),o($VS1,[2,206],{141:77,132:102,138:103,133:$Vu,135:$Vv,139:$Vx,159:$VJ,160:$VK,163:$VL,164:$VM,165:$VN,166:$VO,167:$VP,168:$VQ,169:$VR,170:$VS,171:$VT,172:$VU,173:$VV,174:$VW}),o($VS1,[2,217],{141:77,132:102,138:103,133:$Vu,135:$Vv,139:$Vx,159:$VJ,160:$VK,163:$VL,164:$VM,165:$VN,166:$VO,167:$VP,168:$VQ,169:$VR,170:$VS,171:$VT,172:$VU,173:$VV,174:$VW}),o($VT1,[2,226]),{7:433,8:122,10:20,11:21,12:$V0,13:23,14:24,15:7,16:8,17:9,18:10,19:11,20:12,21:13,22:14,23:15,24:16,25:17,26:18,27:19,28:$V71,33:70,34:$V2,37:55,38:$V3,39:80,40:$V4,41:$V5,43:57,44:$V6,45:$V7,47:27,48:$V8,49:$V9,50:$Va,51:$Vb,52:$Vc,53:$Vd,54:26,60:71,61:$Ve,62:54,63:$Vf,64:$Vg,67:33,68:$Vh,69:$Vi,75:53,77:40,79:28,80:29,81:30,92:$Vj,95:$Vk,97:$Vl,105:$Vm,111:31,112:$Vn,117:$Vo,118:$Vp,119:$Vq,125:$Vr,129:$Vs,130:$Vt,132:43,133:$Vu,135:$Vv,136:44,137:$Vw,138:45,139:$Vx,141:77,149:$Vy,154:41,155:$Vz,157:$VA,158:$VB,159:$VC,160:$VD,161:$VE,162:$VF},{7:434,8:122,10:20,11:21,12:$V0,13:23,14:24,15:7,16:8,17:9,18:10,19:11,20:12,21:13,22:14,23:15,24:16,25:17,26:18,27:19,28:$V71,33:70,34:$V2,37:55,38:$V3,39:80,40:$V4,41:$V5,43:57,44:$V6,45:$V7,47:27,48:$V8,49:$V9,50:$Va,51:$Vb,52:$Vc,53:$Vd,54:26,60:71,61:$Ve,62:54,63:$Vf,64:$Vg,67:33,68:$Vh,69:$Vi,75:53,77:40,79:28,80:29,81:30,92:$Vj,95:$Vk,97:$Vl,105:$Vm,111:31,112:$Vn,117:$Vo,118:$Vp,119:$Vq,125:$Vr,129:$Vs,130:$Vt,132:43,133:$Vu,135:$Vv,136:44,137:$Vw,138:45,139:$Vx,141:77,149:$Vy,154:41,155:$Vz,157:$VA,158:$VB,159:$VC,160:$VD,161:$VE,162:$VF},{7:435,8:122,10:20,11:21,12:$V0,13:23,14:24,15:7,16:8,17:9,18:10,19:11,20:12,21:13,22:14,23:15,24:16,25:17,26:18,27:19,28:$V71,33:70,34:$V2,37:55,38:$V3,39:80,40:$V4,41:$V5,43:57,44:$V6,45:$V7,47:27,48:$V8,49:$V9,50:$Va,51:$Vb,52:$Vc,53:$Vd,54:26,60:71,61:$Ve,62:54,63:$Vf,64:$Vg,67:33,68:$Vh,69:$Vi,75:53,77:40,79:28,80:29,81:30,92:$Vj,95:$Vk,97:$Vl,105:$Vm,111:31,112:$Vn,117:$Vo,118:$Vp,119:$Vq,125:$Vr,129:$Vs,130:$Vt,132:43,133:$Vu,135:$Vv,136:44,137:$Vw,138:45,139:$Vx,141:77,149:$Vy,154:41,155:$Vz,157:$VA,158:$VB,159:$VC,160:$VD,161:$VE,162:$VF},{7:436,8:122,10:20,11:21,12:$V0,13:23,14:24,15:7,16:8,17:9,18:10,19:11,20:12,21:13,22:14,23:15,24:16,25:17,26:18,27:19,28:$V71,33:70,34:$V2,37:55,38:$V3,39:80,40:$V4,41:$V5,43:57,44:$V6,45:$V7,47:27,48:$V8,49:$V9,50:$Va,51:$Vb,52:$Vc,53:$Vd,54:26,60:71,61:$Ve,62:54,63:$Vf,64:$Vg,67:33,68:$Vh,69:$Vi,75:53,77:40,79:28,80:29,81:30,92:$Vj,95:$Vk,97:$Vl,105:$Vm,111:31,112:$Vn,117:$Vo,118:$Vp,119:$Vq,125:$Vr,129:$Vs,130:$Vt,132:43,133:$Vu,135:$Vv,136:44,137:$Vw,138:45,139:$Vx,141:77,149:$Vy,154:41,155:$Vz,157:$VA,158:$VB,159:$VC,160:$VD,161:$VE,162:$VF},o($VN1,[2,110]),{11:207,33:209,34:$V2,35:210,36:$Vq1,37:208,38:$V3,39:80,40:$V4,41:$V5,56:437,57:205,59:206,60:211,63:$Vf,118:$Ve1},o($Vj2,$Vt1,{39:80,56:204,57:205,59:206,11:207,37:208,33:209,35:210,60:211,93:438,34:$V2,36:$Vq1,38:$V3,40:$V4,41:$V5,63:$Vf,118:$Ve1}),o($VX1,[2,113]),o($VX1,[2,52],{141:77,132:102,138:103,133:$Vu,135:$Vv,139:$Vx,156:$VI,159:$VJ,160:$VK,163:$VL,164:$VM,165:$VN,166:$VO,167:$VP,168:$VQ,169:$VR,170:$VS,171:$VT,172:$VU,173:$VV,174:$VW}),{7:439,8:122,10:20,11:21,12:$V0,13:23,14:24,15:7,16:8,17:9,18:10,19:11,20:12,21:13,22:14,23:15,24:16,25:17,26:18,27:19,28:$V71,33:70,34:$V2,37:55,38:$V3,39:80,40:$V4,41:$V5,43:57,44:$V6,45:$V7,47:27,48:$V8,49:$V9,50:$Va,51:$Vb,52:$Vc,53:$Vd,54:26,60:71,61:$Ve,62:54,63:$Vf,64:$Vg,67:33,68:$Vh,69:$Vi,75:53,77:40,79:28,80:29,81:30,92:$Vj,95:$Vk,97:$Vl,105:$Vm,111:31,112:$Vn,117:$Vo,118:$Vp,119:$Vq,125:$Vr,129:$Vs,130:$Vt,132:43,133:$Vu,135:$Vv,136:44,137:$Vw,138:45,139:$Vx,141:77,149:$Vy,154:41,155:$Vz,157:$VA,158:$VB,159:$VC,160:$VD,161:$VE,162:$VF},o($VX1,[2,54],{141:77,132:102,138:103,133:$Vu,135:$Vv,139:$Vx,156:$VI,159:$VJ,160:$VK,163:$VL,164:$VM,165:$VN,166:$VO,167:$VP,168:$VQ,169:$VR,170:$VS,171:$VT,172:$VU,173:$VV,174:$VW}),{7:440,8:122,10:20,11:21,12:$V0,13:23,14:24,15:7,16:8,17:9,18:10,19:11,20:12,21:13,22:14,23:15,24:16,25:17,26:18,27:19,28:$V71,33:70,34:$V2,37:55,38:$V3,39:80,40:$V4,41:$V5,43:57,44:$V6,45:$V7,47:27,48:$V8,49:$V9,50:$Va,51:$Vb,52:$Vc,53:$Vd,54:26,60:71,61:$Ve,62:54,63:$Vf,64:$Vg,67:33,68:$Vh,69:$Vi,75:53,77:40,79:28,80:29,81:30,92:$Vj,95:$Vk,97:$Vl,105:$Vm,111:31,112:$Vn,117:$Vo,118:$Vp,119:$Vq,125:$Vr,129:$Vs,130:$Vt,132:43,133:$Vu,135:$Vv,136:44,137:$Vw,138:45,139:$Vx,141:77,149:$Vy,154:41,155:$Vz,157:$VA,158:$VB,159:$VC,160:$VD,161:$VE,162:$VF},{89:[2,179],132:102,133:$Vu,135:$Vv,138:103,139:$Vx,141:77,156:$VI,159:$VJ,160:$VK,163:$VL,164:$VM,165:$VN,166:$VO,167:$VP,168:$VQ,169:$VR,170:$VS,171:$VT,172:$VU,173:$VV,174:$VW},o($VY,[2,50]),o($VY,[2,68]),o($VC1,[2,77]),o($V12,$VA1,{70:441,71:$VB1}),o($VY,[2,273]),o($Ve2,[2,245]),o($VY,[2,196]),o($Vk2,[2,197]),o($Vk2,[2,198]),o($VY,[2,236]),{30:442,31:$Vg1},{32:[1,443]},o($V62,[2,242],{6:[1,444]}),{7:445,8:122,10:20,11:21,12:$V0,13:23,14:24,15:7,16:8,17:9,18:10,19:11,20:12,21:13,22:14,23:15,24:16,25:17,26:18,27:19,28:$V71,33:70,34:$V2,37:55,38:$V3,39:80,40:$V4,41:$V5,43:57,44:$V6,45:$V7,47:27,48:$V8,49:$V9,50:$Va,51:$Vb,52:$Vc,53:$Vd,54:26,60:71,61:$Ve,62:54,63:$Vf,64:$Vg,67:33,68:$Vh,69:$Vi,75:53,77:40,79:28,80:29,81:30,92:$Vj,95:$Vk,97:$Vl,105:$Vm,111:31,112:$Vn,117:$Vo,118:$Vp,119:$Vq,125:$Vr,129:$Vs,130:$Vt,132:43,133:$Vu,135:$Vv,136:44,137:$Vw,138:45,139:$Vx,141:77,149:$Vy,154:41,155:$Vz,157:$VA,158:$VB,159:$VC,160:$VD,161:$VE,162:$VF},o($VY,[2,123]),{39:446,40:$V4,41:$V5},o($VV1,$VA1,{70:447,71:$V82}),o($V51,[2,127]),{29:[1,448]},{33:282,34:$V2,101:449,103:$VJ1},{31:$VI1,33:282,34:$V2,100:450,101:280,103:$VJ1},o($VX1,[2,132]),{6:$Vm2,31:$Vn2,32:[1,451]},o($VX1,[2,137]),o($VX1,[2,139]),o($V51,[2,143],{29:[1,452]}),{33:289,34:$V2,103:$VL1,108:453},{31:$VK1,33:289,34:$V2,103:$VL1,106:454,108:287},o($VX1,[2,152]),{6:$Vo2,31:$Vp2,32:[1,455]},o($VX1,[2,157]),o($VX1,[2,158]),o($VX1,[2,160]),o($Va2,[2,146],{141:77,132:102,138:103,133:$Vu,135:$Vv,139:$Vx,159:$VJ,160:$VK,163:$VL,164:$VM,165:$VN,166:$VO,167:$VP,168:$VQ,169:$VR,170:$VS,171:$VT,172:$VU,173:$VV,174:$VW}),{32:[1,456],132:102,133:$Vu,135:$Vv,138:103,139:$Vx,141:77,156:$VI,159:$VJ,160:$VK,163:$VL,164:$VM,165:$VN,166:$VO,167:$VP,168:$VQ,169:$VR,170:$VS,171:$VT,172:$VU,173:$VV,174:$VW},o($V91,[2,202]),o($V91,[2,178]),o($VP1,[2,185]),o($V12,$VA1,{70:457,71:$VO1}),o($VP1,[2,186]),o($Vb1,[2,170]),o([1,6,31,32,42,66,71,74,89,94,115,120,122,131,133,134,135,139,156],[2,229],{141:77,132:102,138:103,140:[1,458],159:$VJ,160:$VK,163:$VL,164:$VM,165:$VN,166:$VO,167:$VP,168:$VQ,169:$VR,170:$VS,171:$VT,172:$VU,173:$VV,174:$VW}),o($Vf2,[2,231],{141:77,132:102,138:103,134:[1,459],159:$VJ,160:$VK,163:$VL,164:$VM,165:$VN,166:$VO,167:$VP,168:$VQ,169:$VR,170:$VS,171:$VT,172:$VU,173:$VV,174:$VW}),o($Vz1,[2,230],{141:77,132:102,138:103,159:$VJ,160:$VK,163:$VL,164:$VM,165:$VN,166:$VO,167:$VP,168:$VQ,169:$VR,170:$VS,171:$VT,172:$VU,173:$VV,174:$VW}),o($Vz1,[2,235],{141:77,132:102,138:103,159:$VJ,160:$VK,163:$VL,164:$VM,165:$VN,166:$VO,167:$VP,168:$VQ,169:$VR,170:$VS,171:$VT,172:$VU,173:$VV,174:$VW}),o($VX1,[2,114]),o($V12,$VA1,{70:460,71:$VW1}),{32:[1,461],132:102,133:$Vu,135:$Vv,138:103,139:$Vx,141:77,156:$VI,159:$VJ,160:$VK,163:$VL,164:$VM,165:$VN,166:$VO,167:$VP,168:$VQ,169:$VR,170:$VS,171:$VT,172:$VU,173:$VV,174:$VW},{32:[1,462],132:102,133:$Vu,135:$Vv,138:103,139:$Vx,141:77,156:$VI,159:$VJ,160:$VK,163:$VL,164:$VM,165:$VN,166:$VO,167:$VP,168:$VQ,169:$VR,170:$VS,171:$VT,172:$VU,173:$VV,174:$VW},{6:$V32,31:$V42,32:[1,463]},{32:[1,464]},o($VY,[2,239]),o($V62,[2,243]),o($Vl2,[2,192],{141:77,132:102,138:103,133:$Vu,135:$Vv,139:$Vx,156:$VI,159:$VJ,160:$VK,163:$VL,164:$VM,165:$VN,166:$VO,167:$VP,168:$VQ,169:$VR,170:$VS,171:$VT,172:$VU,173:$VV,174:$VW}),o($V51,[2,129]),{6:$Vm2,31:$Vn2,94:[1,465]},{39:466,40:$V4,41:$V5},o($VX1,[2,133]),o($V12,$VA1,{70:467,71:$V82}),o($VX1,[2,134]),{39:468,40:$V4,41:$V5},o($VX1,[2,153]),o($V12,$VA1,{70:469,71:$V92}),o($VX1,[2,154]),o($V51,[2,147]),{6:$Vc2,31:$Vd2,32:[1,470]},{7:471,8:122,10:20,11:21,12:$V0,13:23,14:24,15:7,16:8,17:9,18:10,19:11,20:12,21:13,22:14,23:15,24:16,25:17,26:18,27:19,28:$V71,33:70,34:$V2,37:55,38:$V3,39:80,40:$V4,41:$V5,43:57,44:$V6,45:$V7,47:27,48:$V8,49:$V9,50:$Va,51:$Vb,52:$Vc,53:$Vd,54:26,60:71,61:$Ve,62:54,63:$Vf,64:$Vg,67:33,68:$Vh,69:$Vi,75:53,77:40,79:28,80:29,81:30,92:$Vj,95:$Vk,97:$Vl,105:$Vm,111:31,112:$Vn,117:$Vo,118:$Vp,119:$Vq,125:$Vr,129:$Vs,130:$Vt,132:43,133:$Vu,135:$Vv,136:44,137:$Vw,138:45,139:$Vx,141:77,149:$Vy,154:41,155:$Vz,157:$VA,158:$VB,159:$VC,160:$VD,161:$VE,162:$VF},{7:472,8:122,10:20,11:21,12:$V0,13:23,14:24,15:7,16:8,17:9,18:10,19:11,20:12,21:13,22:14,23:15,24:16,25:17,26:18,27:19,28:$V71,33:70,34:$V2,37:55,38:$V3,39:80,40:$V4,41:$V5,43:57,44:$V6,45:$V7,47:27,48:$V8,49:$V9,50:$Va,51:$Vb,52:$Vc,53:$Vd,54:26,60:71,61:$Ve,62:54,63:$Vf,64:$Vg,67:33,68:$Vh,69:$Vi,75:53,77:40,79:28,80:29,81:30,92:$Vj,95:$Vk,97:$Vl,105:$Vm,111:31,112:$Vn,117:$Vo,118:$Vp,119:$Vq,125:$Vr,129:$Vs,130:$Vt,132:43,133:$Vu,135:$Vv,136:44,137:$Vw,138:45,139:$Vx,141:77,149:$Vy,154:41,155:$Vz,157:$VA,158:$VB,159:$VC,160:$VD,161:$VE,162:$VF},{6:$Vg2,31:$Vh2,32:[1,473]},o($VX1,[2,53]),o($VX1,[2,55]),o($VC1,[2,78]),o($VY,[2,237]),{29:[1,474]},o($V51,[2,128]),{6:$Vm2,31:$Vn2,32:[1,475]},o($V51,[2,150]),{6:$Vo2,31:$Vp2,32:[1,476]},o($VP1,[2,187]),o($Vz1,[2,232],{141:77,132:102,138:103,159:$VJ,160:$VK,163:$VL,164:$VM,165:$VN,166:$VO,167:$VP,168:$VQ,169:$VR,170:$VS,171:$VT,172:$VU,173:$VV,174:$VW}),o($Vz1,[2,233],{141:77,132:102,138:103,159:$VJ,160:$VK,163:$VL,164:$VM,165:$VN,166:$VO,167:$VP,168:$VQ,169:$VR,170:$VS,171:$VT,172:$VU,173:$VV,174:$VW}),o($VX1,[2,115]),{39:477,40:$V4,41:$V5},o($VX1,[2,135]),o($VX1,[2,155]),o($V51,[2,130])], defaultActions: {68:[2,70],69:[2,71],239:[2,109],357:[2,141]}, parseError: function parseError(str, hash) { if (hash.recoverable) { this.trace(str); } else { function _parseError (msg, hash) { this.message = msg; this.hash = hash; } _parseError.prototype = Error; throw new _parseError(str, hash); } }, parse: function parse(input) { var self = this, stack = [0], tstack = [], vstack = [null], lstack = [], table = this.table, yytext = '', yylineno = 0, yyleng = 0, recovering = 0, TERROR = 2, EOF = 1; var args = lstack.slice.call(arguments, 1); var lexer = Object.create(this.lexer); var sharedState = { yy: {} }; for (var k in this.yy) { if (Object.prototype.hasOwnProperty.call(this.yy, k)) { sharedState.yy[k] = this.yy[k]; } } lexer.setInput(input, sharedState.yy); sharedState.yy.lexer = lexer; sharedState.yy.parser = this; if (typeof lexer.yylloc == 'undefined') { lexer.yylloc = {}; } var yyloc = lexer.yylloc; lstack.push(yyloc); var ranges = lexer.options && lexer.options.ranges; if (typeof sharedState.yy.parseError === 'function') { this.parseError = sharedState.yy.parseError; } else { this.parseError = Object.getPrototypeOf(this).parseError; } function popStack(n) { stack.length = stack.length - 2 * n; vstack.length = vstack.length - n; lstack.length = lstack.length - n; } _token_stack: var lex = function () { var token; token = lexer.lex() || EOF; 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) { state = stack[stack.length - 1]; if (this.defaultActions[state]) { action = this.defaultActions[state]; } else { if (symbol === null || typeof symbol == 'undefined') { symbol = lex(); } action = table[state] && table[state][symbol]; } if (typeof action === 'undefined' || !action.length || !action[0]) { var errStr = ''; expected = []; for (p in table[state]) { if (this.terminals_[p] && p > TERROR) { expected.push('\'' + this.terminals_[p] + '\''); } } if (lexer.showPosition) { errStr = 'Parse error on line ' + (yylineno + 1) + ':\n' + lexer.showPosition() + '\nExpecting ' + expected.join(', ') + ', got \'' + (this.terminals_[symbol] || symbol) + '\''; } else { errStr = 'Parse error on line ' + (yylineno + 1) + ': Unexpected ' + (symbol == EOF ? 'end of input' : '\'' + (this.terminals_[symbol] || symbol) + '\''); } this.parseError(errStr, { text: lexer.match, token: this.terminals_[symbol] || symbol, line: lexer.yylineno, loc: yyloc, expected: expected }); } 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: stack.push(symbol); vstack.push(lexer.yytext); lstack.push(lexer.yylloc); stack.push(action[1]); symbol = null; if (!preErrorSymbol) { yyleng = lexer.yyleng; yytext = lexer.yytext; yylineno = lexer.yylineno; yyloc = lexer.yylloc; if (recovering > 0) { recovering--; } } else { symbol = preErrorSymbol; preErrorSymbol = null; } break; case 2: len = this.productions_[action[1]][1]; yyval.$ = vstack[vstack.length - len]; 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 }; if (ranges) { yyval._$.range = [ lstack[lstack.length - (len || 1)].range[0], lstack[lstack.length - 1].range[1] ]; } r = this.performAction.apply(yyval, [ yytext, yyleng, yylineno, sharedState.yy, action[1], vstack, lstack ].concat(args)); if (typeof r !== 'undefined') { return r; } 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]); vstack.push(yyval.$); lstack.push(yyval._$); newState = table[stack[stack.length - 2]][stack[stack.length - 1]]; stack.push(newState); break; case 3: return true; } } return true; }}; function Parser () { this.yy = {}; } Parser.prototype = parser;parser.Parser = Parser; return new Parser; })(); if (typeof require !== 'undefined' && typeof exports !== 'undefined') { exports.parser = parser; exports.Parser = parser.Parser; exports.parse = function () { return parser.parse.apply(parser, arguments); }; exports.main = function commonjsMain(args) { if (!args[1]) { console.log('Usage: '+args[0]+' FILE'); process.exit(1); } var source = ''; var fs = require('fs'); if (typeof fs !== 'undefined' && fs !== null) source = fs.readFileSync(require('path').normalize(args[1]), "utf8"); return exports.parser.parse(source); }; if (typeof module !== 'undefined' && require.main === module) { exports.main(process.argv.slice(1)); } }coffeescript-1.12.7/lib/coffee-script/register.js000066400000000000000000000035071313305734200217450ustar00rootroot00000000000000// Generated by CoffeeScript 1.12.7 (function() { var CoffeeScript, Module, binary, child_process, ext, findExtension, fork, helpers, i, len, loadFile, path, ref; CoffeeScript = require('./coffee-script'); child_process = require('child_process'); helpers = require('./helpers'); path = require('path'); loadFile = function(module, filename) { var answer; answer = CoffeeScript._compileFile(filename, false, true); return module._compile(answer, filename); }; if (require.extensions) { ref = CoffeeScript.FILE_EXTENSIONS; for (i = 0, len = ref.length; i < len; i++) { ext = ref[i]; require.extensions[ext] = loadFile; } Module = require('module'); findExtension = function(filename) { var curExtension, extensions; extensions = path.basename(filename).split('.'); if (extensions[0] === '') { extensions.shift(); } while (extensions.shift()) { curExtension = '.' + extensions.join('.'); if (Module._extensions[curExtension]) { return curExtension; } } return '.js'; }; Module.prototype.load = function(filename) { var extension; this.filename = filename; this.paths = Module._nodeModulePaths(path.dirname(filename)); extension = findExtension(filename); Module._extensions[extension](this, filename); return this.loaded = true; }; } if (child_process) { fork = child_process.fork; binary = require.resolve('../../bin/coffee'); child_process.fork = function(path, args, options) { if (helpers.isCoffee(path)) { if (!Array.isArray(args)) { options = args || {}; args = []; } args = [path].concat(args); path = binary; } return fork(path, args, options); }; } }).call(this); coffeescript-1.12.7/lib/coffee-script/repl.js000066400000000000000000000150121313305734200210550ustar00rootroot00000000000000// Generated by CoffeeScript 1.12.7 (function() { var CoffeeScript, addHistory, addMultilineHandler, fs, getCommandId, merge, nodeREPL, path, ref, replDefaults, runInContext, updateSyntaxError, vm; fs = require('fs'); path = require('path'); vm = require('vm'); nodeREPL = require('repl'); CoffeeScript = require('./coffee-script'); ref = require('./helpers'), merge = ref.merge, updateSyntaxError = ref.updateSyntaxError; replDefaults = { prompt: 'coffee> ', historyFile: process.env.HOME ? path.join(process.env.HOME, '.coffee_history') : void 0, historyMaxInputSize: 10240, "eval": function(input, context, filename, cb) { var Assign, Block, Literal, Value, ast, err, js, ref1, referencedVars, token, tokens; input = input.replace(/\uFF00/g, '\n'); input = input.replace(/^\(([\s\S]*)\n\)$/m, '$1'); input = input.replace(/^\s*try\s*{([\s\S]*)}\s*catch.*$/m, '$1'); ref1 = require('./nodes'), Block = ref1.Block, Assign = ref1.Assign, Value = ref1.Value, Literal = ref1.Literal; try { tokens = CoffeeScript.tokens(input); referencedVars = (function() { var i, len, results; results = []; for (i = 0, len = tokens.length; i < len; i++) { token = tokens[i]; if (token[0] === 'IDENTIFIER') { results.push(token[1]); } } return results; })(); ast = CoffeeScript.nodes(tokens); ast = new Block([new Assign(new Value(new Literal('__')), ast, '=')]); js = ast.compile({ bare: true, locals: Object.keys(context), referencedVars: referencedVars }); return cb(null, runInContext(js, context, filename)); } catch (error) { err = error; updateSyntaxError(err, input); return cb(err); } } }; runInContext = function(js, context, filename) { if (context === global) { return vm.runInThisContext(js, filename); } else { return vm.runInContext(js, context, filename); } }; addMultilineHandler = function(repl) { var inputStream, multiline, nodeLineListener, origPrompt, outputStream, ref1, rli; rli = repl.rli, inputStream = repl.inputStream, outputStream = repl.outputStream; origPrompt = (ref1 = repl._prompt) != null ? ref1 : repl.prompt; multiline = { enabled: false, initialPrompt: origPrompt.replace(/^[^> ]*/, function(x) { return x.replace(/./g, '-'); }), prompt: origPrompt.replace(/^[^> ]*>?/, function(x) { return x.replace(/./g, '.'); }), buffer: '' }; nodeLineListener = rli.listeners('line')[0]; rli.removeListener('line', nodeLineListener); rli.on('line', function(cmd) { if (multiline.enabled) { multiline.buffer += cmd + "\n"; rli.setPrompt(multiline.prompt); rli.prompt(true); } else { rli.setPrompt(origPrompt); nodeLineListener(cmd); } }); return inputStream.on('keypress', function(char, key) { if (!(key && key.ctrl && !key.meta && !key.shift && key.name === 'v')) { return; } if (multiline.enabled) { if (!multiline.buffer.match(/\n/)) { multiline.enabled = !multiline.enabled; rli.setPrompt(origPrompt); rli.prompt(true); return; } if ((rli.line != null) && !rli.line.match(/^\s*$/)) { return; } multiline.enabled = !multiline.enabled; rli.line = ''; rli.cursor = 0; rli.output.cursorTo(0); rli.output.clearLine(1); multiline.buffer = multiline.buffer.replace(/\n/g, '\uFF00'); rli.emit('line', multiline.buffer); multiline.buffer = ''; } else { multiline.enabled = !multiline.enabled; rli.setPrompt(multiline.initialPrompt); rli.prompt(true); } }); }; addHistory = function(repl, filename, maxSize) { var buffer, fd, lastLine, readFd, size, stat; lastLine = null; try { stat = fs.statSync(filename); size = Math.min(maxSize, stat.size); readFd = fs.openSync(filename, 'r'); buffer = new Buffer(size); fs.readSync(readFd, buffer, 0, size, stat.size - size); fs.closeSync(readFd); repl.rli.history = buffer.toString().split('\n').reverse(); if (stat.size > maxSize) { repl.rli.history.pop(); } if (repl.rli.history[0] === '') { repl.rli.history.shift(); } repl.rli.historyIndex = -1; lastLine = repl.rli.history[0]; } catch (error) {} fd = fs.openSync(filename, 'a'); repl.rli.addListener('line', function(code) { if (code && code.length && code !== '.history' && code !== '.exit' && lastLine !== code) { fs.writeSync(fd, code + "\n"); return lastLine = code; } }); repl.on('exit', function() { return fs.closeSync(fd); }); return repl.commands[getCommandId(repl, 'history')] = { help: 'Show command history', action: function() { repl.outputStream.write((repl.rli.history.slice(0).reverse().join('\n')) + "\n"); return repl.displayPrompt(); } }; }; getCommandId = function(repl, commandName) { var commandsHaveLeadingDot; commandsHaveLeadingDot = repl.commands['.help'] != null; if (commandsHaveLeadingDot) { return "." + commandName; } else { return commandName; } }; module.exports = { start: function(opts) { var build, major, minor, ref1, repl; if (opts == null) { opts = {}; } ref1 = process.versions.node.split('.').map(function(n) { return parseInt(n, 10); }), major = ref1[0], minor = ref1[1], build = ref1[2]; if (major === 0 && minor < 8) { console.warn("Node 0.8.0+ required for CoffeeScript REPL"); process.exit(1); } CoffeeScript.register(); process.argv = ['coffee'].concat(process.argv.slice(2)); opts = merge(replDefaults, opts); repl = nodeREPL.start(opts); if (opts.prelude) { runInContext(opts.prelude, repl.context, 'prelude'); } repl.on('exit', function() { if (!repl.rli.closed) { return repl.outputStream.write('\n'); } }); addMultilineHandler(repl); if (opts.historyFile) { addHistory(repl, opts.historyFile, opts.historyMaxInputSize); } repl.commands[getCommandId(repl, 'load')].help = 'Load code from a file into this REPL session'; return repl; } }; }).call(this); coffeescript-1.12.7/lib/coffee-script/rewriter.js000066400000000000000000000472331313305734200217700ustar00rootroot00000000000000// Generated by CoffeeScript 1.12.7 (function() { var BALANCED_PAIRS, CALL_CLOSERS, EXPRESSION_CLOSE, EXPRESSION_END, EXPRESSION_START, IMPLICIT_CALL, IMPLICIT_END, IMPLICIT_FUNC, IMPLICIT_UNSPACED_CALL, INVERSES, LINEBREAKS, Rewriter, SINGLE_CLOSERS, SINGLE_LINERS, generate, k, left, len, ref, rite, 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; generate = function(tag, value, origin) { var tok; tok = [tag, value]; tok.generated = true; if (origin) { tok.origin = origin; } return tok; }; exports.Rewriter = Rewriter = (function() { function Rewriter() {} Rewriter.prototype.rewrite = function(tokens1) { this.tokens = tokens1; this.removeLeadingNewlines(); this.closeOpenCalls(); this.closeOpenIndexes(); this.normalizeLines(); this.tagPostfixConditionals(); this.addImplicitBracesAndParens(); this.addLocationDataToGeneratedTokens(); this.fixOutdentLocationData(); 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, ref, ref1, token, tokens; 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, k, len, ref, tag; ref = this.tokens; for (i = k = 0, len = ref.length; k < len; i = ++k) { tag = ref[i][0]; if (tag !== 'TERMINATOR') { break; } } if (i) { return this.tokens.splice(0, i); } }; 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.indexOfTag = function() { var fuzz, i, j, k, pattern, ref, ref1; i = arguments[0], pattern = 2 <= arguments.length ? slice.call(arguments, 1) : []; fuzz = 0; for (j = k = 0, ref = pattern.length; 0 <= ref ? k < ref : k > ref; j = 0 <= ref ? ++k : --k) { while (this.tag(i + j + fuzz) === 'HERECOMMENT') { fuzz += 2; } if (pattern[j] == null) { continue; } if (typeof pattern[j] === 'string') { pattern[j] = [pattern[j]]; } if (ref1 = this.tag(i + j + fuzz), indexOf.call(pattern[j], ref1) < 0) { return -1; } } return i + j + fuzz - 1; }; Rewriter.prototype.looksObjectish = function(j) { var end, index; if (this.indexOfTag(j, '@', null, ':') > -1 || this.indexOfTag(j, null, ':') > -1) { return true; } index = this.indexOfTag(j, EXPRESSION_START); if (index > -1) { end = null; this.detectEnd(index + 1, (function(token) { var ref; return ref = token[0], indexOf.call(EXPRESSION_END, ref) >= 0; }), (function(token, i) { return end = i; })); if (this.tag(end + 1) === ':') { return true; } } return false; }; Rewriter.prototype.findTagsBackwards = function(i, tags) { var backStack, ref, ref1, ref2, ref3, ref4, ref5; backStack = []; while (i >= 0 && (backStack.length || (ref2 = this.tag(i), indexOf.call(tags, ref2) < 0) && ((ref3 = this.tag(i), indexOf.call(EXPRESSION_START, ref3) < 0) || this.tokens[i].generated) && (ref4 = this.tag(i), indexOf.call(LINEBREAKS, ref4) < 0))) { if (ref = this.tag(i), indexOf.call(EXPRESSION_END, ref) >= 0) { backStack.push(this.tag(i)); } if ((ref1 = this.tag(i), indexOf.call(EXPRESSION_START, ref1) >= 0) && backStack.length) { backStack.pop(); } i -= 1; } return ref5 = this.tag(i), indexOf.call(tags, ref5) >= 0; }; Rewriter.prototype.addImplicitBracesAndParens = function() { var stack, start; stack = []; start = null; return this.scanTokens(function(token, i, tokens) { var endImplicitCall, endImplicitObject, forward, inImplicit, inImplicitCall, inImplicitControl, inImplicitObject, isImplicit, isImplicitCall, isImplicitObject, k, newLine, nextTag, offset, prevTag, prevToken, ref, ref1, ref2, ref3, ref4, ref5, s, sameLine, stackIdx, stackItem, stackTag, stackTop, startIdx, startImplicitCall, startImplicitObject, startsLine, tag; tag = token[0]; prevTag = (prevToken = i > 0 ? tokens[i - 1] : [])[0]; nextTag = (i < tokens.length - 1 ? tokens[i + 1] : [])[0]; stackTop = function() { return stack[stack.length - 1]; }; startIdx = i; forward = function(n) { return i - startIdx + n; }; isImplicit = function(stackItem) { var ref; return stackItem != null ? (ref = stackItem[2]) != null ? ref.ours : void 0 : void 0; }; isImplicitObject = function(stackItem) { return isImplicit(stackItem) && (stackItem != null ? stackItem[0] : void 0) === '{'; }; isImplicitCall = function(stackItem) { return isImplicit(stackItem) && (stackItem != null ? stackItem[0] : void 0) === '('; }; inImplicit = function() { return isImplicit(stackTop()); }; inImplicitCall = function() { return isImplicitCall(stackTop()); }; inImplicitObject = function() { return isImplicitObject(stackTop()); }; inImplicitControl = function() { var ref; return inImplicit && ((ref = stackTop()) != null ? ref[0] : void 0) === 'CONTROL'; }; startImplicitCall = function(j) { var idx; idx = j != null ? j : i; stack.push([ '(', idx, { ours: true } ]); tokens.splice(idx, 0, generate('CALL_START', '(', ['', 'implicit function call', token[2]])); if (j == null) { return i += 1; } }; endImplicitCall = function() { stack.pop(); tokens.splice(i, 0, generate('CALL_END', ')', ['', 'end of input', token[2]])); return i += 1; }; startImplicitObject = function(j, startsLine) { var idx, val; if (startsLine == null) { startsLine = true; } idx = j != null ? j : i; stack.push([ '{', idx, { sameLine: true, startsLine: startsLine, ours: true } ]); val = new String('{'); val.generated = true; tokens.splice(idx, 0, generate('{', val, token)); if (j == null) { return i += 1; } }; endImplicitObject = function(j) { j = j != null ? j : i; stack.pop(); tokens.splice(j, 0, generate('}', '}', token)); return i += 1; }; if (inImplicitCall() && (tag === 'IF' || tag === 'TRY' || tag === 'FINALLY' || tag === 'CATCH' || tag === 'CLASS' || tag === 'SWITCH')) { stack.push([ 'CONTROL', i, { ours: true } ]); return forward(1); } if (tag === 'INDENT' && inImplicit()) { if (prevTag !== '=>' && prevTag !== '->' && prevTag !== '[' && prevTag !== '(' && prevTag !== ',' && prevTag !== '{' && prevTag !== 'TRY' && prevTag !== 'ELSE' && prevTag !== '=') { while (inImplicitCall()) { endImplicitCall(); } } if (inImplicitControl()) { stack.pop(); } stack.push([tag, i]); return forward(1); } if (indexOf.call(EXPRESSION_START, tag) >= 0) { stack.push([tag, i]); return forward(1); } if (indexOf.call(EXPRESSION_END, tag) >= 0) { while (inImplicit()) { if (inImplicitCall()) { endImplicitCall(); } else if (inImplicitObject()) { endImplicitObject(); } else { stack.pop(); } } start = stack.pop(); } if ((indexOf.call(IMPLICIT_FUNC, tag) >= 0 && token.spaced || tag === '?' && i > 0 && !tokens[i - 1].spaced) && (indexOf.call(IMPLICIT_CALL, nextTag) >= 0 || indexOf.call(IMPLICIT_UNSPACED_CALL, nextTag) >= 0 && !((ref = tokens[i + 1]) != null ? ref.spaced : void 0) && !((ref1 = tokens[i + 1]) != null ? ref1.newLine : void 0))) { if (tag === '?') { tag = token[0] = 'FUNC_EXIST'; } startImplicitCall(i + 1); return forward(2); } if (indexOf.call(IMPLICIT_FUNC, tag) >= 0 && this.indexOfTag(i + 1, 'INDENT') > -1 && this.looksObjectish(i + 2) && !this.findTagsBackwards(i, ['CLASS', 'EXTENDS', 'IF', 'CATCH', 'SWITCH', 'LEADING_WHEN', 'FOR', 'WHILE', 'UNTIL'])) { startImplicitCall(i + 1); stack.push(['INDENT', i + 2]); return forward(3); } if (tag === ':') { s = (function() { var ref2; switch (false) { case ref2 = this.tag(i - 1), indexOf.call(EXPRESSION_END, ref2) < 0: return start[1]; case this.tag(i - 2) !== '@': return i - 2; default: return i - 1; } }).call(this); while (this.tag(s - 2) === 'HERECOMMENT') { s -= 2; } this.insideForDeclaration = nextTag === 'FOR'; startsLine = s === 0 || (ref2 = this.tag(s - 1), indexOf.call(LINEBREAKS, ref2) >= 0) || tokens[s - 1].newLine; if (stackTop()) { ref3 = stackTop(), stackTag = ref3[0], stackIdx = ref3[1]; if ((stackTag === '{' || stackTag === 'INDENT' && this.tag(stackIdx - 1) === '{') && (startsLine || this.tag(s - 1) === ',' || this.tag(s - 1) === '{')) { return forward(1); } } startImplicitObject(s, !!startsLine); return forward(2); } if (indexOf.call(LINEBREAKS, tag) >= 0) { for (k = stack.length - 1; k >= 0; k += -1) { stackItem = stack[k]; if (!isImplicit(stackItem)) { break; } if (isImplicitObject(stackItem)) { stackItem[2].sameLine = false; } } } newLine = prevTag === 'OUTDENT' || prevToken.newLine; if (indexOf.call(IMPLICIT_END, tag) >= 0 || indexOf.call(CALL_CLOSERS, tag) >= 0 && newLine) { while (inImplicit()) { ref4 = stackTop(), stackTag = ref4[0], stackIdx = ref4[1], (ref5 = ref4[2], sameLine = ref5.sameLine, startsLine = ref5.startsLine); if (inImplicitCall() && prevTag !== ',') { endImplicitCall(); } else if (inImplicitObject() && !this.insideForDeclaration && sameLine && tag !== 'TERMINATOR' && prevTag !== ':') { endImplicitObject(); } else if (inImplicitObject() && tag === 'TERMINATOR' && prevTag !== ',' && !(startsLine && this.looksObjectish(i + 1))) { if (nextTag === 'HERECOMMENT') { return forward(1); } endImplicitObject(); } else { break; } } } if (tag === ',' && !this.looksObjectish(i + 1) && inImplicitObject() && !this.insideForDeclaration && (nextTag !== 'TERMINATOR' || !this.looksObjectish(i + 2))) { offset = nextTag === 'OUTDENT' ? 1 : 0; while (inImplicitObject()) { endImplicitObject(i + offset); } } return forward(1); }); }; Rewriter.prototype.addLocationDataToGeneratedTokens = function() { return this.scanTokens(function(token, i, tokens) { var column, line, nextLocation, prevLocation, ref, ref1; if (token[2]) { return 1; } if (!(token.generated || token.explicit)) { return 1; } if (token[0] === '{' && (nextLocation = (ref = tokens[i + 1]) != null ? ref[2] : void 0)) { line = nextLocation.first_line, column = nextLocation.first_column; } else if (prevLocation = (ref1 = tokens[i - 1]) != null ? ref1[2] : void 0) { line = prevLocation.last_line, column = prevLocation.last_column; } else { line = column = 0; } token[2] = { first_line: line, first_column: column, last_line: line, last_column: column }; return 1; }); }; Rewriter.prototype.fixOutdentLocationData = function() { return this.scanTokens(function(token, i, tokens) { var prevLocationData; if (!(token[0] === 'OUTDENT' || (token.generated && token[0] === 'CALL_END') || (token.generated && token[0] === '}'))) { return 1; } prevLocationData = tokens[i - 1][2]; token[2] = { first_line: prevLocationData.last_line, first_column: prevLocationData.last_column, last_line: prevLocationData.last_line, last_column: prevLocationData.last_column }; return 1; }); }; Rewriter.prototype.normalizeLines = function() { var action, condition, indent, outdent, starter; starter = indent = outdent = null; condition = function(token, i) { var ref, ref1, ref2, ref3; return token[1] !== ';' && (ref = token[0], indexOf.call(SINGLE_CLOSERS, ref) >= 0) && !(token[0] === 'TERMINATOR' && (ref1 = this.tag(i + 1), indexOf.call(EXPRESSION_CLOSE, ref1) >= 0)) && !(token[0] === 'ELSE' && starter !== 'THEN') && !(((ref2 = token[0]) === 'CATCH' || ref2 === 'FINALLY') && (starter === '->' || starter === '=>')) || (ref3 = token[0], indexOf.call(CALL_CLOSERS, ref3) >= 0) && (this.tokens[i - 1].newLine || this.tokens[i - 1][0] === 'OUTDENT'); }; 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 j, k, ref, ref1, ref2, tag; tag = token[0]; if (tag === 'TERMINATOR') { if (this.tag(i + 1) === 'ELSE' && this.tag(i - 1) !== 'OUTDENT') { tokens.splice.apply(tokens, [i, 1].concat(slice.call(this.indentation()))); return 1; } if (ref = this.tag(i + 1), indexOf.call(EXPRESSION_CLOSE, ref) >= 0) { tokens.splice(i, 1); return 0; } } if (tag === 'CATCH') { for (j = k = 1; k <= 2; j = ++k) { if (!((ref1 = this.tag(i + j)) === 'OUTDENT' || ref1 === 'TERMINATOR' || ref1 === 'FINALLY')) { continue; } tokens.splice.apply(tokens, [i + j, 0].concat(slice.call(this.indentation()))); return 2 + j; } } if (indexOf.call(SINGLE_LINERS, tag) >= 0 && this.tag(i + 1) !== 'INDENT' && !(tag === 'ELSE' && this.tag(i + 1) === 'IF')) { starter = tag; ref2 = this.indentation(tokens[i]), indent = ref2[0], outdent = ref2[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 prevTag, tag; tag = token[0]; prevTag = this.tokens[i - 1][0]; return tag === 'TERMINATOR' || (tag === 'INDENT' && indexOf.call(SINGLE_LINERS, prevTag) < 0); }; 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(origin) { var indent, outdent; indent = ['INDENT', 2]; outdent = ['OUTDENT', 2]; if (origin) { indent.generated = outdent.generated = true; indent.origin = outdent.origin = origin; } else { indent.explicit = outdent.explicit = true; } return [indent, outdent]; }; Rewriter.prototype.generate = generate; 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'], ['STRING_START', 'STRING_END'], ['REGEX_START', 'REGEX_END']]; exports.INVERSES = INVERSES = {}; EXPRESSION_START = []; EXPRESSION_END = []; for (k = 0, len = BALANCED_PAIRS.length; k < len; k++) { ref = BALANCED_PAIRS[k], left = ref[0], rite = ref[1]; EXPRESSION_START.push(INVERSES[rite] = left); EXPRESSION_END.push(INVERSES[left] = rite); } EXPRESSION_CLOSE = ['CATCH', 'THEN', 'ELSE', 'FINALLY'].concat(EXPRESSION_END); IMPLICIT_FUNC = ['IDENTIFIER', 'PROPERTY', 'SUPER', ')', 'CALL_END', ']', 'INDEX_END', '@', 'THIS']; IMPLICIT_CALL = ['IDENTIFIER', 'PROPERTY', 'NUMBER', 'INFINITY', 'NAN', 'STRING', 'STRING_START', 'REGEX', 'REGEX_START', 'JS', 'NEW', 'PARAM_START', 'CLASS', 'IF', 'TRY', 'SWITCH', 'THIS', 'UNDEFINED', 'NULL', 'BOOL', 'UNARY', 'YIELD', 'UNARY_MATH', 'SUPER', 'THROW', '@', '->', '=>', '[', '(', '{', '--', '++']; IMPLICIT_UNSPACED_CALL = ['+', '-']; 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_CLOSERS = ['.', '?.', '::', '?::']; }).call(this); coffeescript-1.12.7/lib/coffee-script/scope.js000066400000000000000000000105631313305734200212320ustar00rootroot00000000000000// Generated by CoffeeScript 1.12.7 (function() { var Scope, 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; }; exports.Scope = Scope = (function() { function Scope(parent, expressions, method, referencedVars) { var ref, ref1; this.parent = parent; this.expressions = expressions; this.method = method; this.referencedVars = referencedVars; this.variables = [ { name: 'arguments', type: 'arguments' } ]; this.positions = {}; if (!this.parent) { this.utilities = {}; } this.root = (ref = (ref1 = this.parent) != null ? ref1.root : void 0) != null ? ref : 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() { var ref; if (((ref = this.method) != null ? ref.name : void 0) || !this.parent) { return this.method; } return this.parent.namedMethod(); }; Scope.prototype.find = function(name, type) { if (type == null) { type = 'var'; } if (this.check(name)) { return true; } this.add(name, type); 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 ref; return !!(this.type(name) || ((ref = this.parent) != null ? ref.check(name) : void 0)); }; Scope.prototype.temporary = function(name, index, single) { var diff, endCode, letter, newCode, num, startCode; if (single == null) { single = false; } if (single) { startCode = name.charCodeAt(0); endCode = 'z'.charCodeAt(0); diff = endCode - startCode; newCode = startCode + index % (diff + 1); letter = String.fromCharCode(newCode); num = Math.floor(index / (diff + 1)); return "" + letter + (num || ''); } else { return "" + name + (index || ''); } }; Scope.prototype.type = function(name) { var i, len, ref, v; ref = this.variables; for (i = 0, len = ref.length; i < len; i++) { v = ref[i]; if (v.name === name) { return v.type; } } return null; }; Scope.prototype.freeVariable = function(name, options) { var index, ref, temp; if (options == null) { options = {}; } index = 0; while (true) { temp = this.temporary(name, index, options.single); if (!(this.check(temp) || indexOf.call(this.root.referencedVars, temp) >= 0)) { break; } index++; } if ((ref = options.reserve) != null ? ref : true) { 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 v; return ((function() { var i, len, ref, results; ref = this.variables; results = []; for (i = 0, len = ref.length; i < len; i++) { v = ref[i]; if (v.type === 'var') { results.push(v.name); } } return results; }).call(this)).sort(); }; Scope.prototype.assignedVariables = function() { var i, len, ref, results, v; ref = this.variables; results = []; for (i = 0, len = ref.length; i < len; i++) { v = ref[i]; if (v.type.assigned) { results.push(v.name + " = " + v.type.value); } } return results; }; return Scope; })(); }).call(this); coffeescript-1.12.7/lib/coffee-script/sourcemap.js000066400000000000000000000110551313305734200221140ustar00rootroot00000000000000// Generated by CoffeeScript 1.12.7 (function() { var LineMap, SourceMap; LineMap = (function() { function LineMap(line1) { this.line = line1; this.columns = []; } LineMap.prototype.add = function(column, arg, options) { var sourceColumn, sourceLine; sourceLine = arg[0], sourceColumn = arg[1]; if (options == null) { options = {}; } if (this.columns[column] && options.noReplace) { return; } return this.columns[column] = { line: this.line, column: column, sourceLine: sourceLine, sourceColumn: sourceColumn }; }; LineMap.prototype.sourceLocation = function(column) { var mapping; while (!((mapping = this.columns[column]) || (column <= 0))) { column--; } return mapping && [mapping.sourceLine, mapping.sourceColumn]; }; return LineMap; })(); SourceMap = (function() { var BASE64_CHARS, VLQ_CONTINUATION_BIT, VLQ_SHIFT, VLQ_VALUE_MASK; function SourceMap() { this.lines = []; } SourceMap.prototype.add = function(sourceLocation, generatedLocation, options) { var base, column, line, lineMap; if (options == null) { options = {}; } line = generatedLocation[0], column = generatedLocation[1]; lineMap = ((base = this.lines)[line] || (base[line] = new LineMap(line))); return lineMap.add(column, sourceLocation, options); }; SourceMap.prototype.sourceLocation = function(arg) { var column, line, lineMap; line = arg[0], column = arg[1]; while (!((lineMap = this.lines[line]) || (line <= 0))) { line--; } return lineMap && lineMap.sourceLocation(column); }; SourceMap.prototype.generate = function(options, code) { var buffer, i, j, lastColumn, lastSourceColumn, lastSourceLine, len, len1, lineMap, lineNumber, mapping, needComma, ref, ref1, v3, writingline; if (options == null) { options = {}; } if (code == null) { code = null; } writingline = 0; lastColumn = 0; lastSourceLine = 0; lastSourceColumn = 0; needComma = false; buffer = ""; ref = this.lines; for (lineNumber = i = 0, len = ref.length; i < len; lineNumber = ++i) { lineMap = ref[lineNumber]; if (lineMap) { ref1 = lineMap.columns; for (j = 0, len1 = ref1.length; j < len1; j++) { mapping = ref1[j]; if (!(mapping)) { continue; } while (writingline < mapping.line) { lastColumn = 0; needComma = false; buffer += ";"; writingline++; } if (needComma) { buffer += ","; needComma = false; } buffer += this.encodeVlq(mapping.column - lastColumn); lastColumn = mapping.column; buffer += this.encodeVlq(0); buffer += this.encodeVlq(mapping.sourceLine - lastSourceLine); lastSourceLine = mapping.sourceLine; buffer += this.encodeVlq(mapping.sourceColumn - lastSourceColumn); lastSourceColumn = mapping.sourceColumn; needComma = true; } } } v3 = { version: 3, file: options.generatedFile || '', sourceRoot: options.sourceRoot || '', sources: options.sourceFiles || [''], names: [], mappings: buffer }; if (options.inlineMap) { v3.sourcesContent = [code]; } return v3; }; VLQ_SHIFT = 5; VLQ_CONTINUATION_BIT = 1 << VLQ_SHIFT; VLQ_VALUE_MASK = VLQ_CONTINUATION_BIT - 1; SourceMap.prototype.encodeVlq = function(value) { var answer, nextChunk, signBit, valueToEncode; answer = ''; signBit = value < 0 ? 1 : 0; valueToEncode = (Math.abs(value) << 1) + signBit; while (valueToEncode || !answer) { nextChunk = valueToEncode & VLQ_VALUE_MASK; valueToEncode = valueToEncode >> VLQ_SHIFT; if (valueToEncode) { nextChunk |= VLQ_CONTINUATION_BIT; } answer += this.encodeBase64(nextChunk); } return answer; }; BASE64_CHARS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; SourceMap.prototype.encodeBase64 = function(value) { return BASE64_CHARS[value] || (function() { throw new Error("Cannot Base64 encode value: " + value); })(); }; return SourceMap; })(); module.exports = SourceMap; }).call(this); coffeescript-1.12.7/package.json000066400000000000000000000020301313305734200165400ustar00rootroot00000000000000{ "name": "coffee-script", "description": "Unfancy JavaScript", "keywords": [ "javascript", "language", "coffeescript", "compiler" ], "author": "Jeremy Ashkenas", "version": "1.12.7", "license": "MIT", "engines": { "node": ">=0.8.0" }, "directories": { "lib": "./lib/coffee-script" }, "main": "./lib/coffee-script/coffee-script", "bin": { "coffee": "./bin/coffee", "cake": "./bin/cake" }, "files": [ "bin", "lib", "register.js", "repl.js" ], "scripts": { "test": "node ./bin/cake test", "test-harmony": "node --harmony ./bin/cake test" }, "homepage": "http://coffeescript.org", "bugs": "https://github.com/jashkenas/coffeescript/issues", "repository": { "type": "git", "url": "git://github.com/jashkenas/coffeescript.git" }, "devDependencies": { "docco": "~0.7.0", "google-closure-compiler-js": "^20170626.0.0", "highlight.js": "~9.12.0", "jison": ">=0.4.17", "markdown-it": "^8.3.1", "underscore": "~1.8.3" } } coffeescript-1.12.7/register.js000066400000000000000000000000511313305734200164350ustar00rootroot00000000000000require('./lib/coffee-script/register'); coffeescript-1.12.7/repl.js000066400000000000000000000000661313305734200155610ustar00rootroot00000000000000module.exports = require('./lib/coffee-script/repl'); coffeescript-1.12.7/src/000077500000000000000000000000001313305734200150465ustar00rootroot00000000000000coffeescript-1.12.7/src/browser.coffee000066400000000000000000000056361313305734200177140ustar00rootroot00000000000000# This **Browser** compatibility layer extends core CoffeeScript functions # to make things work smoothly when compiling code directly in the browser. # We add support for loading remote Coffee scripts via **XHR**, and # `text/coffeescript` script tags, source maps via data-URLs, and so on. CoffeeScript = require './coffee-script' CoffeeScript.require = require compile = CoffeeScript.compile # Use standard JavaScript `eval` to eval code. CoffeeScript.eval = (code, options = {}) -> options.bare ?= on eval compile code, options # Running code does not provide access to this scope. CoffeeScript.run = (code, options = {}) -> options.bare = on options.shiftLine = on Function(compile code, options)() # If we're not in a browser environment, we're finished with the public API. return unless window? # Include source maps where possible. If we've got a base64 encoder, a # JSON serializer, and tools for escaping unicode characters, we're good to go. # Ported from https://developer.mozilla.org/en-US/docs/DOM/window.btoa if btoa? and JSON? compile = (code, options = {}) -> options.inlineMap = true CoffeeScript.compile code, options # Load a remote script from the current domain via XHR. CoffeeScript.load = (url, callback, options = {}, hold = false) -> options.sourceFiles = [url] xhr = if window.ActiveXObject new window.ActiveXObject('Microsoft.XMLHTTP') else new window.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] param = [xhr.responseText, options] CoffeeScript.run param... unless hold else throw new Error "Could not load #{url}" callback param 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 = window.document.getElementsByTagName 'script' coffeetypes = ['text/coffeescript', 'text/literate-coffeescript'] coffees = (s for s in scripts when s.type in coffeetypes) index = 0 execute = -> param = coffees[index] if param instanceof Array CoffeeScript.run param... index++ execute() for script, i in coffees do (script, i) -> options = literate: script.type is coffeetypes[1] source = script.src or script.getAttribute('data-src') if source CoffeeScript.load source, (param) -> coffees[i] = param execute() options true else options.sourceFiles = ['embedded'] coffees[i] = [script.innerHTML, options] execute() # Listen for window load, both in decent browsers and in IE. if window.addEventListener window.addEventListener 'DOMContentLoaded', runScripts, no else window.attachEvent 'onload', runScripts coffeescript-1.12.7/src/cake.coffee000066400000000000000000000067101313305734200171260ustar00rootroot00000000000000# `cake` is a simplified version of [Make](http://www.gnu.org/software/make/) # ([Rake](http://rake.rubyforge.org/), [Jake](https://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' # Register .coffee extension CoffeeScript.register() # 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 fs.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()}" coffeescript-1.12.7/src/coffee-script.coffee000066400000000000000000000340121313305734200207500ustar00rootroot00000000000000# CoffeeScript can be used both on the server, as a command-line compiler based # on Node.js/V8, or to run CoffeeScript directly in the browser. This module # contains the main entry functions for tokenizing, parsing, and compiling # source CoffeeScript into JavaScript. fs = require 'fs' vm = require 'vm' path = require 'path' {Lexer} = require './lexer' {parser} = require './parser' helpers = require './helpers' SourceMap = require './sourcemap' # Require `package.json`, which is two levels above this file, as this file is # evaluated from `lib/coffee-script`. packageJson = require '../../package.json' # The current CoffeeScript version number. exports.VERSION = packageJson.version exports.FILE_EXTENSIONS = ['.coffee', '.litcoffee', '.coffee.md'] # Expose helpers for testing. exports.helpers = helpers # Function that allows for btoa in both nodejs and the browser. base64encode = (src) -> switch when typeof Buffer is 'function' new Buffer(src).toString('base64') when typeof btoa is 'function' # The contents of a `