Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

The Great Purge. Removing the Ruby compiler, and all of its accoutrem…

…ents. bin/coffee is now CoffeeScript-in-CoffeeScript
  • Loading branch information...
commit 6446e0004c6e53cf909b300ebb12a934ccb33eb6 1 parent edf5f49
Jeremy Ashkenas authored
2  Cakefile
View
@@ -3,7 +3,7 @@ coffee: require 'coffee-script'
# Run a CoffeeScript through our node/coffee interpreter.
run: (args) ->
- proc: process.createChildProcess 'bin/node_coffee', args
+ proc: process.createChildProcess 'bin/coffee', args
proc.addListener 'error', (err) -> if err then puts err
14 README
View
@@ -23,7 +23,7 @@
CoffeeScript is a little language that compiles into JavaScript.
Install the compiler:
- gem install coffee-script
+ ... to be determined ...
Compile a script:
coffee /path/to/script.coffee
@@ -38,14 +38,4 @@
The source repository:
git://github.com/jashkenas/coffee-script.git
-
- Warning: A new version of the compiler, written entirely in CoffeeScript,
- is in the works. Check out /src for the details. To try it out, use
- bin/node_coffee. To have CoffeeScript recompile itself, run:
-
- build compiler
-
- To rebuild the Jison parser (takes about 30 seconds), run:
-
- build grammar
-
+
8 bin/coffee
View
@@ -1,5 +1,7 @@
-#!/usr/bin/env ruby
+#!/usr/bin/env node --
-require "#{File.dirname(__FILE__)}/../lib/coffee_script/command_line.rb"
+process.mixin(require('sys'));
-CoffeeScript::CommandLine.new
+require.paths.unshift('./lib/coffee_script');
+
+require('command_line').run();
7 bin/node_coffee
View
@@ -1,7 +0,0 @@
-#!/usr/bin/env node --
-
-process.mixin(require('sys'));
-
-require.paths.unshift('./lib/coffee_script');
-
-require('command_line').run();
27 coffee-script.gemspec
View
@@ -1,27 +0,0 @@
-Gem::Specification.new do |s|
- s.name = 'coffee-script'
- s.version = '0.3.2' # Keep version in sync with coffee-script.rb
- s.date = '2010-2-8'
-
- s.homepage = "http://jashkenas.github.com/coffee-script/"
- s.summary = "The CoffeeScript Compiler"
- s.description = <<-EOS
- CoffeeScript is a little language that compiles into JavaScript. Think
- of it as JavaScript's less ostentatious kid brother -- the same genes,
- roughly the same height, but a different sense of style. Apart from a
- handful of bonus goodies, statements in CoffeeScript correspond
- one-to-one with their equivalent in JavaScript, it's just another
- way of saying it.
- EOS
-
- s.authors = ['Jeremy Ashkenas']
- s.email = 'jashkenas@gmail.com'
- s.rubyforge_project = 'coffee-script'
- s.has_rdoc = false
-
- s.require_paths = ['lib']
- s.executables = ['coffee']
-
- s.files = Dir['bin/*', 'examples/*', 'extras/**/*', 'lib/**/*',
- 'coffee-script.gemspec', 'LICENSE', 'README', 'package.json']
-end
4 extras/EXTRAS
View
@@ -1,8 +1,8 @@
This folder includes rough cuts of CoffeeScript syntax highlighters for
TextMate and Vim. Improvements to their lexing ability are always welcome.
-To install the TextMate bundle, run `bin/coffee --install-bundle`, or drop it
-into "~/Library/Application Support/TextMate/Bundles".
+To install the TextMate bundle, drop it into:
+ ~/Library/Application Support/TextMate/Bundles
To install the Vim highlighter, copy "coffee.vim" into the "syntax" directory of
your vim72, and enable it in either of the following two ways:
21 lib/coffee-script.rb
View
@@ -1,21 +0,0 @@
-$LOAD_PATH.unshift(File.dirname(__FILE__))
-require "coffee_script/lexer"
-require "coffee_script/parser"
-require "coffee_script/nodes"
-require "coffee_script/value"
-require "coffee_script/scope"
-require "coffee_script/rewriter"
-require "coffee_script/parse_error"
-
-# Namespace for all CoffeeScript internal classes.
-module CoffeeScript
-
- VERSION = '0.3.2' # Keep in sync with the gemspec.
-
- # Compile a script (String or IO) to JavaScript.
- def self.compile(script, options={})
- script = script.read if script.respond_to?(:read)
- Parser.new.parse(script).compile(options)
- end
-
-end
235 lib/coffee_script/command_line.rb
View
@@ -1,235 +0,0 @@
-require 'optparse'
-require 'fileutils'
-require 'open3'
-begin
- require File.expand_path(File.dirname(__FILE__) + '/../coffee-script')
-rescue LoadError => e
- puts(e.message)
- puts("use \"rake build:parser\" to regenerate parser.rb")
- exit(1)
-end
-
-module CoffeeScript
-
- # The CommandLine handles all of the functionality of the `coffee`
- # utility.
- class CommandLine
-
- BANNER = <<-EOS
-coffee compiles CoffeeScript source files into JavaScript.
-
-Usage:
- coffee path/to/script.coffee
- EOS
-
- # Seconds to pause between checks for changed source files.
- WATCH_INTERVAL = 0.5
-
- # Path to the root of the CoffeeScript install.
- ROOT = File.expand_path(File.dirname(__FILE__) + '/../..')
-
- # Commands to execute CoffeeScripts.
- RUNNERS = {
- :node => "node #{ROOT}/lib/coffee_script/runner.js",
- :narwhal => "narwhal -p #{ROOT} -e 'require(\"coffee-script\").run(system.args);'"
- }
-
- # Run the CommandLine off the contents of ARGV.
- def initialize
- @mtimes = {}
- parse_options
- return launch_repl if @options[:interactive]
- return eval_scriptlet if @options[:eval]
- check_sources
- return run_scripts if @options[:run]
- @sources.each {|source| compile_javascript(source) }
- watch_coffee_scripts if @options[:watch]
- end
-
- # The "--help" usage message.
- def usage
- puts "\n#{@option_parser}\n"
- exit
- end
-
-
- private
-
- # Compiles (or partially compiles) the source CoffeeScript file, returning
- # the desired JS, tokens, or lint results.
- def compile_javascript(source)
- script = File.read(source)
- return tokens(script) if @options[:tokens]
- js = compile(script, source)
- return unless js
- return puts(js) if @options[:print]
- return lint(js) if @options[:lint]
- File.open(path_for(source), 'w+') {|f| f.write(js) }
- end
-
- # Spins up a watcher thread to keep track of the modification times of the
- # source files, recompiling them whenever they're saved.
- def watch_coffee_scripts
- watch_thread = Thread.start do
- loop do
- @sources.each do |source|
- mtime = File.stat(source).mtime
- @mtimes[source] ||= mtime
- if mtime > @mtimes[source]
- @mtimes[source] = mtime
- compile_javascript(source)
- end
- end
- sleep WATCH_INTERVAL
- end
- end
- Signal.trap("INT") { watch_thread.kill }
- watch_thread.join
- end
-
- # Ensure that all of the source files exist.
- def check_sources
- usage if @sources.empty?
- missing = @sources.detect {|s| !File.exists?(s) }
- if missing
- STDERR.puts("File not found: '#{missing}'")
- exit(1)
- end
- end
-
- # Pipe compiled JS through JSLint (requires a working 'jsl' command).
- def lint(js)
- stdin, stdout, stderr = Open3.popen3('jsl -nologo -stdin')
- stdin.write(js)
- stdin.close
- puts stdout.read.tr("\n", '')
- errs = stderr.read.chomp
- puts errs unless errs.empty?
- stdout.close and stderr.close
- end
-
- # Eval a little piece of CoffeeScript directly from the command line.
- def eval_scriptlet
- script = STDIN.tty? ? @sources.join(' ') : STDIN.read
- return tokens(script) if @options[:tokens]
- js = compile(script)
- return lint(js) if @options[:lint]
- puts js
- end
-
- # Use Node.js or Narwhal to run an interactive CoffeeScript session.
- def launch_repl
- exec "#{RUNNERS[@options[:runner]]}"
- rescue Errno::ENOENT
- puts "Error: #{@options[:runner]} must be installed to use the interactive REPL."
- exit(1)
- end
-
- # Use Node.js or Narwhal to compile and execute CoffeeScripts.
- def run_scripts
- sources = @sources.join(' ')
- exec "#{RUNNERS[@options[:runner]]} #{sources}"
- rescue Errno::ENOENT
- puts "Error: #{@options[:runner]} must be installed in order to execute scripts."
- exit(1)
- end
-
- # Print the tokens that the lexer generates from a source script.
- def tokens(script)
- puts Lexer.new.tokenize(script).inspect
- end
-
- # Compile a single source file to JavaScript.
- def compile(script, source='error')
- begin
- options = {}
- options[:no_wrap] = true if @options[:no_wrap]
- options[:globals] = true if @options[:globals]
- CoffeeScript.compile(script, options)
- rescue CoffeeScript::ParseError => e
- STDERR.puts "#{source}: #{e.message}"
- exit(1) unless @options[:watch]
- nil
- end
- end
-
- # Write out JavaScript alongside CoffeeScript unless an output directory
- # is specified.
- def path_for(source)
- filename = File.basename(source, File.extname(source)) + '.js'
- dir = @options[:output] || File.dirname(source)
- File.join(dir, filename)
- end
-
- # Install the CoffeeScript TextMate bundle to ~/Library.
- def install_bundle
- bundle_dir = File.expand_path('~/Library/Application Support/TextMate/Bundles/')
- FileUtils.cp_r("#{ROOT}/extras/CoffeeScript.tmbundle", bundle_dir)
- end
-
- # Use OptionParser for all the options.
- def parse_options
- @options = {:runner => :node}
- @option_parser = OptionParser.new do |opts|
- opts.on('-i', '--interactive', 'run an interactive CoffeeScript REPL') do |i|
- @options[:interactive] = true
- end
- opts.on('-r', '--run', 'compile and run a CoffeeScript') do |r|
- @options[:run] = true
- end
- opts.on('-o', '--output [DIR]', 'set the directory for compiled JavaScript') do |d|
- @options[:output] = d
- FileUtils.mkdir_p(d) unless File.exists?(d)
- end
- opts.on('-w', '--watch', 'watch scripts for changes, and recompile') do |w|
- @options[:watch] = true
- end
- opts.on('-p', '--print', 'print the compiled JavaScript to stdout') do |d|
- @options[:print] = true
- end
- opts.on('-l', '--lint', 'pipe the compiled JavaScript through JSLint') do |l|
- @options[:lint] = true
- end
- opts.on('-e', '--eval', 'compile a cli scriptlet or read from stdin') do |e|
- @options[:eval] = true
- end
- opts.on('-t', '--tokens', 'print the tokens that the lexer produces') do |t|
- @options[:tokens] = true
- end
- opts.on('-v', '--verbose', 'print at every step of code generation') do |v|
- ENV['VERBOSE'] = 'true'
- end
- opts.on('-n', '--no-wrap', 'raw output, no function safety wrapper') do |n|
- @options[:no_wrap] = true
- end
- opts.on('-g', '--globals', 'attach all top-level variables as globals') do |n|
- @options[:globals] = true
- end
- opts.on_tail('--narwhal', 'use Narwhal instead of Node.js') do |n|
- @options[:runner] = :narwhal
- end
- opts.on_tail('--install-bundle', 'install the CoffeeScript TextMate bundle') do |i|
- install_bundle
- exit
- end
- opts.on_tail('--version', 'display CoffeeScript version') do
- puts "CoffeeScript version #{CoffeeScript::VERSION}"
- exit
- end
- opts.on_tail('-h', '--help', 'display this help message') do
- usage
- end
- end
- @option_parser.banner = BANNER
- begin
- @option_parser.parse!(ARGV)
- rescue OptionParser::InvalidOption => e
- puts e.message
- exit(1)
- end
- @sources = ARGV
- end
-
- end
-
-end
483 lib/coffee_script/grammar.y
View
@@ -1,483 +0,0 @@
-class Parser
-
-# Declare terminal tokens produced by the lexer.
-token IF ELSE UNLESS
-token NUMBER STRING REGEX
-token TRUE FALSE YES NO ON OFF
-token IDENTIFIER PROPERTY_ACCESS PROTOTYPE_ACCESS SOAK_ACCESS
-token CODE PARAM_START PARAM PARAM_END NEW RETURN
-token CALL_START CALL_END INDEX_START INDEX_END
-token TRY CATCH FINALLY THROW
-token BREAK CONTINUE
-token FOR IN OF BY WHEN WHILE
-token SWITCH LEADING_WHEN
-token DELETE INSTANCEOF TYPEOF
-token SUPER EXTENDS
-token ASSIGN RETURN
-token NEWLINE
-token COMMENT
-token JS
-token INDENT OUTDENT
-
-# Declare order of operations.
-prechigh
- left '?'
- nonassoc UMINUS UPLUS NOT '!' '!!' '~' '++' '--'
- left '*' '/' '%' '.'
- left '+' '-'
- left '<<' '>>' '>>>' '&' '|' '^'
- left '<=' '<' '>' '>='
- right DELETE INSTANCEOF TYPEOF
- right '==' '!=' IS ISNT
- left '&&' '||' AND OR
- right '-=' '+=' '/=' '*=' '%=' '||=' '&&=' '?='
- right INDENT
- left OUTDENT
- right WHEN LEADING_WHEN IN OF BY
- right THROW FOR NEW SUPER
- left EXTENDS
- right ASSIGN RETURN
- right '->' '=>' UNLESS IF ELSE WHILE
-preclow
-
-rule
-
- # All parsing will end in this rule, being the trunk of the AST.
- Root:
- /* nothing */ { result = Expressions.new }
- | Terminator { result = Expressions.new }
- | Expressions { result = val[0] }
- | Block Terminator { result = val[0] }
- ;
-
- # Any list of expressions or method body, seperated by line breaks or semis.
- Expressions:
- Expression { result = Expressions.wrap(val) }
- | Expressions Terminator Expression { result = val[0] << val[2] }
- | Expressions Terminator { result = val[0] }
- ;
-
- # All types of expressions in our language. The basic unit of CoffeeScript
- # is the expression.
- Expression:
- Value
- | Call
- | Code
- | Operation
- | Assign
- | If
- | Try
- | Throw
- | Return
- | While
- | For
- | Switch
- | Extends
- | Splat
- | Existence
- | Comment
- ;
-
- # A block of expressions. Note that the Rewriter will convert some postfix
- # forms into blocks for us, by altering the token stream.
- Block:
- INDENT Expressions OUTDENT { result = val[1] }
- | INDENT OUTDENT { result = Expressions.new }
- ;
-
- # Tokens that can terminate an expression.
- Terminator:
- "\n"
- | ";"
- ;
-
- # All hard-coded values. These can be printed straight to JavaScript.
- Literal:
- NUMBER { result = LiteralNode.new(val[0]) }
- | STRING { result = LiteralNode.new(val[0]) }
- | JS { result = LiteralNode.new(val[0]) }
- | REGEX { result = LiteralNode.new(val[0]) }
- | BREAK { result = LiteralNode.new(val[0]) }
- | CONTINUE { result = LiteralNode.new(val[0]) }
- | TRUE { result = LiteralNode.new(Value.new(true)) }
- | FALSE { result = LiteralNode.new(Value.new(false)) }
- | YES { result = LiteralNode.new(Value.new(true)) }
- | NO { result = LiteralNode.new(Value.new(false)) }
- | ON { result = LiteralNode.new(Value.new(true)) }
- | OFF { result = LiteralNode.new(Value.new(false)) }
- ;
-
- # Assignment to a variable (or index).
- Assign:
- Value ASSIGN Expression { result = AssignNode.new(val[0], val[2]) }
- ;
-
- # Assignment within an object literal (can be quoted).
- AssignObj:
- IDENTIFIER ASSIGN Expression { result = AssignNode.new(ValueNode.new(val[0]), val[2], :object) }
- | STRING ASSIGN Expression { result = AssignNode.new(ValueNode.new(LiteralNode.new(val[0])), val[2], :object) }
- | NUMBER ASSIGN Expression { result = AssignNode.new(ValueNode.new(LiteralNode.new(val[0])), val[2], :object) }
- | Comment { result = val[0] }
- ;
-
- # A return statement.
- Return:
- RETURN Expression { result = ReturnNode.new(val[1]) }
- | RETURN { result = ReturnNode.new(ValueNode.new(Value.new('null'))) }
- ;
-
- # A comment.
- Comment:
- COMMENT { result = CommentNode.new(val[0]) }
- ;
-
- # Arithmetic and logical operators
- # For Ruby's Operator precedence, see:
- # https://www.cs.auckland.ac.nz/references/ruby/ProgrammingRuby/language.html
- Operation:
- '!' Expression { result = OpNode.new(val[0], val[1]) }
- | '!!' Expression { result = OpNode.new(val[0], val[1]) }
- | '-' Expression = UMINUS { result = OpNode.new(val[0], val[1]) }
- | '+' Expression = UPLUS { result = OpNode.new(val[0], val[1]) }
- | NOT Expression { result = OpNode.new(val[0], val[1]) }
- | '~' Expression { result = OpNode.new(val[0], val[1]) }
- | '--' Expression { result = OpNode.new(val[0], val[1]) }
- | '++' Expression { result = OpNode.new(val[0], val[1]) }
- | DELETE Expression { result = OpNode.new(val[0], val[1]) }
- | TYPEOF Expression { result = OpNode.new(val[0], val[1]) }
- | Expression '--' { result = OpNode.new(val[1], val[0], nil, true) }
- | Expression '++' { result = OpNode.new(val[1], val[0], nil, true) }
-
- | Expression '*' Expression { result = OpNode.new(val[1], val[0], val[2]) }
- | Expression '/' Expression { result = OpNode.new(val[1], val[0], val[2]) }
- | Expression '%' Expression { result = OpNode.new(val[1], val[0], val[2]) }
-
- | Expression '+' Expression { result = OpNode.new(val[1], val[0], val[2]) }
- | Expression '-' Expression { result = OpNode.new(val[1], val[0], val[2]) }
-
- | Expression '<<' Expression { result = OpNode.new(val[1], val[0], val[2]) }
- | Expression '>>' Expression { result = OpNode.new(val[1], val[0], val[2]) }
- | Expression '>>>' Expression { result = OpNode.new(val[1], val[0], val[2]) }
-
- | Expression '&' Expression { result = OpNode.new(val[1], val[0], val[2]) }
- | Expression '|' Expression { result = OpNode.new(val[1], val[0], val[2]) }
- | Expression '^' Expression { result = OpNode.new(val[1], val[0], val[2]) }
-
- | Expression '<=' Expression { result = OpNode.new(val[1], val[0], val[2]) }
- | Expression '<' Expression { result = OpNode.new(val[1], val[0], val[2]) }
- | Expression '>' Expression { result = OpNode.new(val[1], val[0], val[2]) }
- | Expression '>=' Expression { result = OpNode.new(val[1], val[0], val[2]) }
-
- | Expression '==' Expression { result = OpNode.new(val[1], val[0], val[2]) }
- | Expression '!=' Expression { result = OpNode.new(val[1], val[0], val[2]) }
- | Expression IS Expression { result = OpNode.new(val[1], val[0], val[2]) }
- | Expression ISNT Expression { result = OpNode.new(val[1], val[0], val[2]) }
-
- | Expression '&&' Expression { result = OpNode.new(val[1], val[0], val[2]) }
- | Expression '||' Expression { result = OpNode.new(val[1], val[0], val[2]) }
- | Expression AND Expression { result = OpNode.new(val[1], val[0], val[2]) }
- | Expression OR Expression { result = OpNode.new(val[1], val[0], val[2]) }
- | Expression '?' Expression { result = OpNode.new(val[1], val[0], val[2]) }
-
- | Expression '-=' Expression { result = OpNode.new(val[1], val[0], val[2]) }
- | Expression '+=' Expression { result = OpNode.new(val[1], val[0], val[2]) }
- | Expression '/=' Expression { result = OpNode.new(val[1], val[0], val[2]) }
- | Expression '*=' Expression { result = OpNode.new(val[1], val[0], val[2]) }
- | Expression '%=' Expression { result = OpNode.new(val[1], val[0], val[2]) }
- | Expression '||=' Expression { result = OpNode.new(val[1], val[0], val[2]) }
- | Expression '&&=' Expression { result = OpNode.new(val[1], val[0], val[2]) }
- | Expression '?=' Expression { result = OpNode.new(val[1], val[0], val[2]) }
-
- | Expression INSTANCEOF Expression { result = OpNode.new(val[1], val[0], val[2]) }
- | Expression IN Expression { result = OpNode.new(val[1], val[0], val[2]) }
- ;
-
- # The existence operator.
- Existence:
- Expression '?' { result = ExistenceNode.new(val[0]) }
- ;
-
- # Function definition.
- Code:
- PARAM_START ParamList PARAM_END
- FuncGlyph Block { result = CodeNode.new(val[1], val[4], val[3]) }
- | FuncGlyph Block { result = CodeNode.new([], val[1], val[0]) }
- ;
-
- # The symbols to signify functions, and bound functions.
- FuncGlyph:
- '->' { result = :func }
- | '=>' { result = :boundfunc }
- ;
-
- # The parameters to a function definition.
- ParamList:
- Param { result = val }
- | ParamList "," Param { result = val[0] << val[2] }
- ;
-
- # A Parameter (or ParamSplat) in a function definition.
- Param:
- PARAM
- | PARAM "." "." "." { result = SplatNode.new(val[0]) }
- ;
-
- # A regular splat.
- Splat:
- Expression "." "." "." { result = SplatNode.new(val[0]) }
- ;
-
- # Expressions that can be treated as values.
- Value:
- IDENTIFIER { result = ValueNode.new(val[0]) }
- | Literal { result = ValueNode.new(val[0]) }
- | Array { result = ValueNode.new(val[0]) }
- | Object { result = ValueNode.new(val[0]) }
- | Parenthetical { result = ValueNode.new(val[0]) }
- | Range { result = ValueNode.new(val[0]) }
- | This { result = ValueNode.new(val[0]) }
- | Value Accessor { result = val[0] << val[1] }
- | Invocation Accessor { result = ValueNode.new(val[0], [val[1]]) }
- ;
-
- # Accessing into an object or array, through dot or index notation.
- Accessor:
- PROPERTY_ACCESS IDENTIFIER { result = AccessorNode.new(val[1]) }
- | PROTOTYPE_ACCESS IDENTIFIER { result = AccessorNode.new(val[1], :prototype) }
- | SOAK_ACCESS IDENTIFIER { result = AccessorNode.new(val[1], :soak) }
- | Index { result = val[0] }
- | Slice { result = SliceNode.new(val[0]) }
- ;
-
- # Indexing into an object or array.
- Index:
- INDEX_START Expression INDEX_END { result = IndexNode.new(val[1]) }
- ;
-
- # An object literal.
- Object:
- "{" AssignList "}" { result = ObjectNode.new(val[1]) }
- ;
-
- # Assignment within an object literal (comma or newline separated).
- AssignList:
- /* nothing */ { result = [] }
- | AssignObj { result = val }
- | AssignList "," AssignObj { result = val[0] << val[2] }
- | AssignList Terminator AssignObj { result = val[0] << val[2] }
- | AssignList ","
- Terminator AssignObj { result = val[0] << val[3] }
- | INDENT AssignList OUTDENT { result = val[1] }
- ;
-
- # All flavors of function call (instantiation, super, and regular).
- Call:
- Invocation { result = val[0] }
- | NEW Invocation { result = val[1].new_instance }
- | Super { result = val[0] }
- ;
-
- # Extending an object's prototype.
- Extends:
- Value EXTENDS Value { result = ExtendsNode.new(val[0], val[2]) }
- ;
-
- # A generic function invocation.
- Invocation:
- Value Arguments { result = CallNode.new(val[0], val[1]) }
- | Invocation Arguments { result = CallNode.new(val[0], val[1]) }
- ;
-
- # The list of arguments to a function invocation.
- Arguments:
- CALL_START ArgList CALL_END { result = val[1] }
- ;
-
- # Calling super.
- Super:
- SUPER CALL_START ArgList CALL_END { result = CallNode.new(Value.new('super'), val[2]) }
- ;
-
- # This references, either naked or to a property.
- This:
- '@' { result = ThisNode.new }
- | '@' IDENTIFIER { result = ThisNode.new(val[1]) }
- ;
-
- # The range literal.
- Range:
- "[" Expression
- "." "." Expression "]" { result = RangeNode.new(val[1], val[4]) }
- | "[" Expression
- "." "." "." Expression "]" { result = RangeNode.new(val[1], val[5], true) }
- ;
-
- # The slice literal.
- Slice:
- INDEX_START Expression "." "."
- Expression INDEX_END { result = RangeNode.new(val[1], val[4]) }
- | INDEX_START Expression "." "." "."
- Expression INDEX_END { result = RangeNode.new(val[1], val[5], true) }
- ;
-
- # The array literal.
- Array:
- "[" ArgList "]" { result = ArrayNode.new(val[1]) }
- ;
-
- # A list of arguments to a method call, or as the contents of an array.
- ArgList:
- /* nothing */ { result = [] }
- | Expression { result = val }
- | INDENT Expression { result = [val[1]] }
- | ArgList "," Expression { result = val[0] << val[2] }
- | ArgList Terminator Expression { result = val[0] << val[2] }
- | ArgList "," Terminator Expression { result = val[0] << val[3] }
- | ArgList "," INDENT Expression { result = val[0] << val[3] }
- | ArgList OUTDENT { result = val[0] }
- ;
-
- # Just simple, comma-separated, required arguments (no fancy syntax).
- SimpleArgs:
- Expression { result = val[0] }
- | SimpleArgs "," Expression { result = ([val[0]] << val[2]).flatten }
- ;
-
- # Try/catch/finally exception handling blocks.
- Try:
- TRY Block Catch { result = TryNode.new(val[1], val[2][0], val[2][1]) }
- | TRY Block FINALLY Block { result = TryNode.new(val[1], nil, nil, val[3]) }
- | TRY Block Catch
- FINALLY Block { result = TryNode.new(val[1], val[2][0], val[2][1], val[4]) }
- ;
-
- # A catch clause.
- Catch:
- CATCH IDENTIFIER Block { result = [val[1], val[2]] }
- ;
-
- # Throw an exception.
- Throw:
- THROW Expression { result = ThrowNode.new(val[1]) }
- ;
-
- # Parenthetical expressions.
- Parenthetical:
- "(" Expression ")" { result = ParentheticalNode.new(val[1], val[0].line) }
- ;
-
- # The while loop. (there is no do..while).
- While:
- WHILE Expression Block { result = WhileNode.new(val[1], val[2]) }
- | WHILE Expression { result = WhileNode.new(val[1], nil) }
- | Expression WHILE Expression { result = WhileNode.new(val[2], Expressions.wrap(val[0])) }
- ;
-
- # Array comprehensions, including guard and current index.
- # Looks a little confusing, check nodes.rb for the arguments to ForNode.
- For:
- Expression FOR
- ForVariables ForSource { result = ForNode.new(val[0], val[3], val[2][0], val[2][1]) }
- | FOR ForVariables ForSource Block { result = ForNode.new(val[3], val[2], val[1][0], val[1][1]) }
- ;
-
- # An array comprehension has variables for the current element and index.
- ForVariables:
- IDENTIFIER { result = val }
- | IDENTIFIER "," IDENTIFIER { result = [val[0], val[2]] }
- ;
-
- # The source of the array comprehension can optionally be filtered.
- ForSource:
- IN Expression { result = {:source => val[1]} }
- | OF Expression { result = {:source => val[1], :object => true} }
- | ForSource
- WHEN Expression { result = val[0].merge(:filter => val[2]) }
- | ForSource
- BY Expression { result = val[0].merge(:step => val[2]) }
- ;
-
- # Switch/When blocks.
- Switch:
- SWITCH Expression INDENT
- Whens OUTDENT { result = val[3].rewrite_condition(val[1]) }
- | SWITCH Expression INDENT
- Whens ELSE Block OUTDENT { result = val[3].rewrite_condition(val[1]).add_else(val[5]) }
- ;
-
- # The inner list of whens.
- Whens:
- When { result = val[0] }
- | Whens When { result = val[0] << val[1] }
- ;
-
- # An individual when.
- When:
- LEADING_WHEN SimpleArgs Block { result = IfNode.new(val[1], val[2], nil, {:statement => true}) }
- | LEADING_WHEN SimpleArgs Block
- Terminator { result = IfNode.new(val[1], val[2], nil, {:statement => true}) }
- | Comment Terminator When { result = val[2].add_comment(val[0]) }
- ;
-
- # The most basic form of "if".
- IfBlock:
- IF Expression Block { result = IfNode.new(val[1], val[2]) }
- ;
-
- # An elsif portion of an if-else block.
- ElsIf:
- ELSE IfBlock { result = val[1].force_statement }
- ;
-
- # Multiple elsifs can be chained together.
- ElsIfs:
- ElsIf { result = val[0] }
- | ElsIfs ElsIf { result = val[0].add_else(val[1]) }
- ;
-
- # Terminating else bodies are strictly optional.
- ElseBody
- /* nothing */ { result = nil }
- | ELSE Block { result = val[1] }
- ;
-
- # All the alternatives for ending an if-else block.
- IfEnd:
- ElseBody { result = val[0] }
- | ElsIfs ElseBody { result = val[0].add_else(val[1]) }
- ;
-
- # The full complement of if blocks, including postfix one-liner ifs and unlesses.
- If:
- IfBlock IfEnd { result = val[0].add_else(val[1]) }
- | Expression IF Expression { result = IfNode.new(val[2], Expressions.wrap(val[0]), nil, {:statement => true}) }
- | Expression UNLESS Expression { result = IfNode.new(val[2], Expressions.wrap(val[0]), nil, {:statement => true, :invert => true}) }
- ;
-
-end
-
----- header
-module CoffeeScript
-
----- inner
- # Lex and parse a CoffeeScript.
- def parse(code)
- # Uncomment the following line to enable grammar debugging, in combination
- # with the -g flag in the Rake build task.
- # @yydebug = true
- @tokens = Lexer.new.tokenize(code)
- do_parse
- end
-
- # Retrieve the next token from the list.
- def next_token
- @tokens.shift
- end
-
- # Raise a custom error class that knows about line numbers.
- def on_error(error_token_id, error_value, value_stack)
- raise ParseError.new(token_to_str(error_token_id), error_value, value_stack)
- end
-
----- footer
-end
273 lib/coffee_script/lexer.rb
View
@@ -1,273 +0,0 @@
-module CoffeeScript
-
- # The lexer reads a stream of CoffeeScript and divvys it up into tagged
- # tokens. A minor bit of the ambiguity in the grammar has been avoided by
- # pushing some extra smarts into the Lexer.
- class Lexer
-
- # The list of keywords passed verbatim to the parser.
- KEYWORDS = ["if", "else", "then", "unless",
- "true", "false", "yes", "no", "on", "off",
- "and", "or", "is", "isnt", "not",
- "new", "return",
- "try", "catch", "finally", "throw",
- "break", "continue",
- "for", "in", "of", "by", "where", "while",
- "delete", "instanceof", "typeof",
- "switch", "when",
- "super", "extends"]
-
- # Token matching regexes.
- IDENTIFIER = /\A([a-zA-Z$_](\w|\$)*)/
- NUMBER = /\A(\b((0(x|X)[0-9a-fA-F]+)|([0-9]+(\.[0-9]+)?(e[+\-]?[0-9]+)?)))\b/i
- STRING = /\A(""|''|"(.*?)([^\\]|\\\\)"|'(.*?)([^\\]|\\\\)')/m
- HEREDOC = /\A("{6}|'{6}|"{3}\n?(.*?)\n?([ \t]*)"{3}|'{3}\n?(.*?)\n?([ \t]*)'{3})/m
- JS = /\A(``|`(.*?)([^\\]|\\\\)`)/m
- OPERATOR = /\A([+\*&|\/\-%=<>:!?]+)/
- WHITESPACE = /\A([ \t]+)/
- COMMENT = /\A(((\n?[ \t]*)?#.*$)+)/
- CODE = /\A((-|=)>)/
- REGEX = /\A(\/(.*?)([^\\]|\\\\)\/[imgy]{0,4})/
- MULTI_DENT = /\A((\n([ \t]*))+)(\.)?/
- LAST_DENT = /\n([ \t]*)/
- ASSIGNMENT = /\A(:|=)\Z/
-
- # Token cleaning regexes.
- JS_CLEANER = /(\A`|`\Z)/
- MULTILINER = /\n/
- STRING_NEWLINES = /\n[ \t]*/
- COMMENT_CLEANER = /(^[ \t]*#|\n[ \t]*$)/
- NO_NEWLINE = /\A([+\*&|\/\-%=<>:!.\\][<>=&|]*|and|or|is|isnt|not|delete|typeof|instanceof)\Z/
- HEREDOC_INDENT = /^[ \t]+/
-
- # Tokens which a regular expression will never immediately follow, but which
- # a division operator might.
- # See: http://www.mozilla.org/js/language/js20-2002-04/rationale/syntax.html#regular-expressions
- NOT_REGEX = [
- :IDENTIFIER, :NUMBER, :REGEX, :STRING,
- ')', '++', '--', ']', '}',
- :FALSE, :NULL, :TRUE
- ]
-
- # Tokens which could legitimately be invoked or indexed.
- CALLABLE = [:IDENTIFIER, :SUPER, ')', ']', '}', :STRING]
-
- # Scan by attempting to match tokens one character at a time. Slow and steady.
- def tokenize(code)
- @code = code.chomp # Cleanup code by remove extra line breaks
- @i = 0 # Current character position we're parsing
- @line = 1 # The current line.
- @indent = 0 # The current indent level.
- @indents = [] # The stack of all indent levels we are currently within.
- @tokens = [] # Collection of all parsed tokens in the form [:TOKEN_TYPE, value]
- @spaced = nil # The last value that has a space following it.
- while @i < @code.length
- @chunk = @code[@i..-1]
- extract_next_token
- end
- puts "original stream: #{@tokens.inspect}" if ENV['VERBOSE']
- close_indentation
- Rewriter.new.rewrite(@tokens)
- end
-
- # At every position, run through this list of attempted matches,
- # short-circuiting if any of them succeed.
- def extract_next_token
- return if identifier_token
- return if number_token
- return if heredoc_token
- return if string_token
- return if js_token
- return if regex_token
- return if indent_token
- return if comment_token
- return if whitespace_token
- return literal_token
- end
-
- # Tokenizers ==========================================================
-
- # Matches identifying literals: variables, keywords, method names, etc.
- def identifier_token
- return false unless identifier = @chunk[IDENTIFIER, 1]
- # Keywords are special identifiers tagged with their own name,
- # 'if' will result in an [:IF, "if"] token.
- tag = KEYWORDS.include?(identifier) ? identifier.upcase.to_sym : :IDENTIFIER
- tag = :LEADING_WHEN if tag == :WHEN && [:OUTDENT, :INDENT, "\n"].include?(last_tag)
- @tokens[-1][0] = :PROTOTYPE_ACCESS if tag == :IDENTIFIER && last_value == '::'
- if tag == :IDENTIFIER && last_value == '.' && !(@tokens[-2] && @tokens[-2][1] == '.')
- if @tokens[-2][0] == "?"
- @tokens[-1][0] = :SOAK_ACCESS
- @tokens.delete_at(-2)
- else
- @tokens[-1][0] = :PROPERTY_ACCESS
- end
- end
- token(tag, identifier)
- @i += identifier.length
- end
-
- # Matches numbers, including decimals, hex, and exponential notation.
- def number_token
- return false unless number = @chunk[NUMBER, 1]
- token(:NUMBER, number)
- @i += number.length
- end
-
- # Matches strings, including multi-line strings.
- def string_token
- return false unless string = @chunk[STRING, 1]
- escaped = string.gsub(STRING_NEWLINES, " \\\n")
- token(:STRING, escaped)
- @line += string.count("\n")
- @i += string.length
- end
-
- # Matches heredocs, adjusting indentation to the correct level.
- def heredoc_token
- return false unless match = @chunk.match(HEREDOC)
- doc = match[2] || match[4]
- indent = doc.scan(HEREDOC_INDENT).min
- doc.gsub!(/^#{indent}/, "")
- doc.gsub!("\n", "\\n")
- doc.gsub!('"', '\\"')
- token(:STRING, "\"#{doc}\"")
- @line += match[1].count("\n")
- @i += match[1].length
- end
-
- # Matches interpolated JavaScript.
- def js_token
- return false unless script = @chunk[JS, 1]
- token(:JS, script.gsub(JS_CLEANER, ''))
- @i += script.length
- end
-
- # Matches regular expression literals.
- def regex_token
- return false unless regex = @chunk[REGEX, 1]
- return false if NOT_REGEX.include?(last_tag)
- token(:REGEX, regex)
- @i += regex.length
- end
-
- # Matches and consumes comments.
- def comment_token
- return false unless comment = @chunk[COMMENT, 1]
- @line += comment.scan(MULTILINER).length
- token(:COMMENT, comment.gsub(COMMENT_CLEANER, '').split(MULTILINER))
- token("\n", "\n")
- @i += comment.length
- end
-
- # Record tokens for indentation differing from the previous line.
- def indent_token
- return false unless indent = @chunk[MULTI_DENT, 1]
- @line += indent.scan(MULTILINER).size
- @i += indent.size
- next_character = @chunk[MULTI_DENT, 4]
- prev = @tokens[-2]
- no_newlines = next_character == '.' || (last_value.to_s.match(NO_NEWLINE) && prev && prev[0] != '.' && !last_value.match(CODE))
- return suppress_newlines(indent) if no_newlines
- size = indent.scan(LAST_DENT).last.last.length
- return newline_token(indent) if size == @indent
- if size > @indent
- token(:INDENT, size - @indent)
- @indents << (size - @indent)
- else
- outdent_token(@indent - size)
- end
- @indent = size
- end
-
- # Record an oudent token or tokens, if we're moving back inwards past
- # multiple recorded indents.
- def outdent_token(move_out)
- while move_out > 0 && !@indents.empty?
- last_indent = @indents.pop
- token(:OUTDENT, last_indent)
- move_out -= last_indent
- end
- token("\n", "\n")
- end
-
- # Matches and consumes non-meaningful whitespace.
- def whitespace_token
- return false unless whitespace = @chunk[WHITESPACE, 1]
- @spaced = last_value
- @i += whitespace.length
- end
-
- # Multiple newlines get merged together.
- # Use a trailing \ to escape newlines.
- def newline_token(newlines)
- token("\n", "\n") unless last_value == "\n"
- true
- end
-
- # Tokens to explicitly escape newlines are removed once their job is done.
- def suppress_newlines(newlines)
- @tokens.pop if last_value == "\\"
- true
- end
-
- # We treat all other single characters as a token. Eg.: ( ) , . !
- # Multi-character operators are also literal tokens, so that Racc can assign
- # the proper order of operations.
- def literal_token
- value = @chunk[OPERATOR, 1]
- tag_parameters if value && value.match(CODE)
- value ||= @chunk[0,1]
- tag = value.match(ASSIGNMENT) ? :ASSIGN : value
- if !@spaced.equal?(last_value) && CALLABLE.include?(last_tag)
- tag = :CALL_START if value == '('
- tag = :INDEX_START if value == '['
- end
- token(tag, value)
- @i += value.length
- end
-
- # Helpers ==========================================================
-
- # Add a token to the results, taking note of the line number.
- def token(tag, value)
- @tokens << [tag, Value.new(value, @line)]
- end
-
- # Peek at the previous token's value.
- def last_value
- @tokens.last && @tokens.last[1]
- end
-
- # Peek at the previous token's tag.
- def last_tag
- @tokens.last && @tokens.last[0]
- end
-
- # A source of ambiguity in our grammar was parameter lists in function
- # definitions (as opposed to argument lists in function calls). Tag
- # parameter identifiers in order to avoid this. Also, parameter lists can
- # make use of splats.
- def tag_parameters
- return if last_tag != ')'
- i = 0
- loop do
- i -= 1
- tok = @tokens[i]
- return if !tok
- case tok[0]
- when :IDENTIFIER then tok[0] = :PARAM
- when ')' then tok[0] = :PARAM_END
- when '(' then return tok[0] = :PARAM_START
- end
- end
- end
-
- # Close up all remaining open blocks. IF the first token is an indent,
- # axe it.
- def close_indentation
- outdent_token(@indent)
- end
-
- end
-end
1,037 lib/coffee_script/nodes.rb
View
@@ -1,1037 +0,0 @@
-module CoffeeScript
-
- # The abstract base class for all CoffeeScript nodes.
- # All nodes are implement a "compile_node" method, which performs the
- # code generation for that node. To compile a node, call the "compile"
- # method, which wraps "compile_node" in some extra smarts, to know when the
- # generated code should be wrapped up in a closure. An options hash is passed
- # and cloned throughout, containing messages from higher in the AST,
- # information about the current scope, and indentation level.
- class Node
- # Tabs are two spaces for pretty-printing.
- TAB = ' '
-
- # Tag this node as a statement, meaning that it can't be used directly as
- # the result of an expression.
- def self.statement
- class_eval "def statement?; true; end"
- end
-
- # Tag this node as a statement that cannot be transformed into an expression.
- # (break, continue, etc.) It doesn't make sense to try to transform it.
- def self.statement_only
- statement
- class_eval "def statement_only?; true; end"
- end
-
- # This node needs to know if it's being compiled as a top-level statement,
- # in order to compile without special expression conversion.
- def self.top_sensitive
- class_eval "def top_sensitive?; true; end"
- end
-
- # Provide a quick implementation of a children method.
- def self.children(*attributes)
- attr_reader(*attributes)
- attrs = attributes.map {|a| "[@#{a}]" }.join(', ')
- class_eval "def children; [#{attrs}].flatten.compact; end"
- end
-
- def write(code)
- puts "#{self.class.to_s}:\n#{@options.inspect}\n#{code}\n\n" if ENV['VERBOSE']
- code
- end
-
- # This is extremely important -- we convert JS statements into expressions
- # by wrapping them in a closure, only if it's possible, 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.
- def compile(o={})
- @options = o.dup
- @indent = o[:indent]
- top = self.top_sensitive? ? @options[:top] : @options.delete(:top)
- closure = statement? && !statement_only? && !top && !@options[:return] && !self.is_a?(CommentNode)
- closure &&= !contains? {|n| n.statement_only? }
- closure ? compile_closure(@options) : compile_node(@options)
- end
-
- # Statements converted into expressions share scope with their parent
- # closure, to preserve JavaScript-style lexical scope.
- def compile_closure(o={})
- @indent = o[:indent]
- ClosureNode.wrap(self).compile(o.merge(:shared_scope => o[:scope]))
- end
-
- # Quick short method for the current indentation level, plus tabbing in.
- def idt(tabs=0)
- @indent + (TAB * tabs)
- end
-
- # Does this node, or any of its children, contain a node of a certain kind?
- def contains?(&block)
- children.each do |node|
- return true if yield(node)
- return true if node.is_a?(Node) && node.contains?(&block)
- end
- false
- end
-
- # Default implementations of the common node methods.
- def unwrap; self; end
- def children; []; end
- def statement?; false; end
- def statement_only?; false; end
- def top_sensitive?; false; end
- end
-
- # A collection of nodes, each one representing an expression.
- class Expressions < Node
- statement
- children :expressions
- attr_accessor :function
-
- TRAILING_WHITESPACE = /\s+$/
-
- # Wrap up a node as an Expressions, unless it already is.
- def self.wrap(*nodes)
- return nodes[0] if nodes.length == 1 && nodes[0].is_a?(Expressions)
- Expressions.new(*nodes)
- end
-
- def initialize(*nodes)
- @expressions = nodes.flatten
- end
-
- # Tack an expression on to the end of this expression list.
- def <<(node)
- @expressions << node
- self
- end
-
- # Tack an expression on to the beginning of this expression list.
- def unshift(node)
- @expressions.unshift(node)
- self
- end
-
- # If this Expressions consists of a single node, pull it back out.
- def unwrap
- @expressions.length == 1 ? @expressions.first : self
- end
-
- # Is this an empty block of code?
- def empty?
- @expressions.empty?
- end
-
- # Is the node last in this block of expressions?
- def last?(node)
- @last_index ||= @expressions.last.is_a?(CommentNode) ? -2 : -1
- node == @expressions[@last_index]
- end
-
- def compile(o={})
- o[:scope] ? super(o) : compile_root(o)
- end
-
- # Compile each expression in the Expressions body.
- def compile_node(o={})
- write(@expressions.map {|n| compile_expression(n, o.dup) }.join("\n"))
- end
-
- # If this is the top-level Expressions, wrap everything in a safety closure.
- def compile_root(o={})
- indent = o[:no_wrap] ? '' : TAB
- @indent = indent
- o.merge!(:indent => indent, :scope => Scope.new(nil, self, nil))
- code = o[:globals] ? compile_node(o) : compile_with_declarations(o)
- code.gsub!(TRAILING_WHITESPACE, '')
- write(o[:no_wrap] ? code : "(function(){\n#{code}\n})();")
- end
-
- # Compile the expressions body, with declarations of all inner variables
- # pushed up to the top.
- def compile_with_declarations(o={})
- code = compile_node(o)
- args = self.contains? {|n| n.is_a?(ValueNode) && n.arguments? }
- argv = args && o[:scope].check('arguments') ? '' : 'var '
- code = "#{idt}#{argv}arguments = Array.prototype.slice.call(arguments, 0);\n#{code}" if args
- code = "#{idt}var #{o[:scope].compiled_assignments};\n#{code}" if o[:scope].assignments?(self)
- code = "#{idt}var #{o[:scope].compiled_declarations};\n#{code}" if o[:scope].declarations?(self)
- write(code)
- end
-
- # Compiles a single expression within the expressions body.
- def compile_expression(node, o)
- @indent = o[:indent]
- stmt = node.statement?
- # We need to return the result if this is the last node in the expressions body.
- returns = o.delete(:return) && last?(node) && !node.statement_only?
- # Return the regular compile of the node, unless we need to return the result.
- return "#{stmt ? '' : idt}#{node.compile(o.merge(:top => true))}#{stmt ? '' : ';'}" unless returns
- # If it's a statement, the node knows how to return itself.
- return node.compile(o.merge(:return => true)) if node.statement?
- # Otherwise, we can just return the value of the expression.
- return "#{idt}return #{node.compile(o)};"
- end
-
- end
-
- # Literals are static values that can be passed through directly into
- # JavaScript without translation, eg.: strings, numbers, true, false, null...
- class LiteralNode < Node
- children :value
-
- # Values of a literal node that much be treated as a statement -- no
- # sense returning or assigning them.
- STATEMENTS = ['break', 'continue']
-
- # Wrap up a compiler-generated string as a LiteralNode.
- def self.wrap(string)
- self.new(Value.new(string))
- end
-
- def initialize(value)
- @value = value
- end
-
- def statement?
- STATEMENTS.include?(@value.to_s)
- end
- alias_method :statement_only?, :statement?
-
- def compile_node(o)
- indent = statement? ? idt : ''
- ending = statement? ? ';' : ''
- "#{indent}#{@value}#{ending}"
- end
- end
-
- # Return an expression, or wrap it in a closure and return it.
- class ReturnNode < Node
- statement_only
- children :expression
-
- def initialize(expression)
- @expression = expression
- end
-
- def compile_node(o)
- return write(@expression.compile(o.merge(:return => true))) if @expression.statement?
- compiled = @expression.compile(o)
- write("#{idt}return #{compiled};")
- end
- end
-
- # A value, indexed or dotted into, or vanilla.
- class ValueNode < Node
- children :base, :properties
- attr_reader :last, :source
-
- # Soak up undefined properties and call attempts.
- SOAK = " == undefined ? undefined : "
-
- def initialize(base, properties=[])
- @base, @properties = base, [properties].flatten
- end
-
- def <<(other)
- @properties << other
- self
- end
-
- def properties?
- return !@properties.empty? || @base.is_a?(ThisNode)
- end
-
- def array?
- @base.is_a?(ArrayNode) && !properties?
- end
-
- def object?
- @base.is_a?(ObjectNode) && !properties?
- end
-
- def splice?
- properties? && @properties.last.is_a?(SliceNode)
- end
-
- def arguments?
- @base.to_s == 'arguments'
- end
-
- def unwrap
- @properties.empty? ? @base : self
- end
-
- # Values are statements if their base is a statement.
- def statement?
- @base.is_a?(Node) && @base.statement? && !properties?
- end
-
- def compile_node(o)
- soaked = false
- only = o.delete(:only_first)
- props = only ? @properties[0...-1] : @properties
- baseline = @base.compile(o)
- parts = [baseline.dup]
- props.each do |prop|
- if prop.is_a?(AccessorNode) && prop.soak
- soaked = true
- if @base.is_a?(CallNode) && prop == props.first
- temp = o[:scope].free_variable
- parts[-1] = "(#{temp} = #{baseline})#{SOAK}#{baseline = temp.to_s + prop.compile(o)}"
- else
- parts[-1] << "#{SOAK}#{baseline += prop.compile(o)}"
- end
- else
- part = prop.compile(o)
- baseline += part
- parts << part
- end
- end
- @last = parts.last
- @source = parts.length > 1 ? parts[0...-1].join('') : nil
- code = parts.join('').gsub(')())', '()))')
- write(soaked ? "(#{code})" : code)
- end
- end
-
- # Pass through CoffeeScript comments into JavaScript comments at the
- # same position.
- class CommentNode < Node
- statement
-
- def initialize(lines)
- @lines = lines.value
- end
-
- def compile_node(o={})
- delimiter = "\n#{idt}//"
- write("#{delimiter}#{@lines.join(delimiter)}")
- end
-
- end
-
- # Node for a function invocation. Takes care of converting super() calls into
- # calls against the prototype's function of the same name.
- class CallNode < Node
- children :variable, :arguments
-
- def initialize(variable, arguments=[])
- @variable, @arguments = variable, arguments
- @prefix = ''
- end
-
- def new_instance
- @prefix = "new "
- self
- end
-
- def <<(argument)
- @arguments << argument
- self
- end
-
- # Compile a vanilla function call.
- def compile_node(o)
- return write(compile_splat(o)) if @arguments.any? {|a| a.is_a?(SplatNode) }
- args = @arguments.map{|a| a.compile(o) }.join(', ')
- return write(compile_super(args, o)) if @variable == 'super'
- write("#{@prefix}#{@variable.compile(o)}(#{args})")
- end
-
- # Compile a call against the superclass's implementation of the current function.
- def compile_super(args, o)
- methname = o[:scope].function.name
- arg_part = args.empty? ? '' : ", #{args}"
- meth = o[:scope].function.proto ?
- "#{o[:scope].function.proto}.__superClass__.#{methname}" :
- "#{methname}.__superClass__.constructor"
- "#{meth}.call(this#{arg_part})"
- end
-
- # Compile a function call being passed variable arguments.
- def compile_splat(o)
- meth = @variable.compile(o)
- obj = @variable.source || 'this'
- args = @arguments.map do |arg|
- code = arg.compile(o)
- code = arg.is_a?(SplatNode) ? code : "[#{code}]"
- arg.equal?(@arguments.first) ? code : ".concat(#{code})"
- end
- "#{@prefix}#{meth}.apply(#{obj}, #{args.join('')})"
- end
-
- # If the code generation wished to use the result of a function call
- # in multiple places, ensure that the function is only ever called once.
- def compile_reference(o)
- reference = o[:scope].free_variable
- call = ParentheticalNode.new(AssignNode.new(reference, self))
- return call, reference
- end
- end
-
- # Node to extend an object's prototype with an ancestor object.
- # After goog.inherits from the Closure Library.
- class ExtendsNode < Node
- children :sub_object, :super_object
- statement
-
- def initialize(sub_object, super_object)
- @sub_object, @super_object = sub_object, super_object
- end
-
- # Hooking one constructor into another's prototype chain.
- def compile_node(o={})
- constructor = o[:scope].free_variable
- sub, sup = @sub_object.compile(o), @super_object.compile(o)
- "#{idt}#{constructor} = function(){};\n#{idt}" +
- "#{constructor}.prototype = #{sup}.prototype;\n#{idt}" +
- "#{sub}.__superClass__ = #{sup}.prototype;\n#{idt}" +
- "#{sub}.prototype = new #{constructor}();\n#{idt}" +
- "#{sub}.prototype.constructor = #{sub};"
- end
-
- end
-
- # A dotted accessor into a part of a value, or the :: shorthand for
- # an accessor into the object's prototype.
- class AccessorNode < Node
- children :name
- attr_reader :soak
-
- def initialize(name, tag=nil)
- @name = name
- @prototype = tag == :prototype
- @soak = tag == :soak
- end
-
- def compile_node(o)
- proto = @prototype ? "prototype." : ''
- write(".#{proto}#{@name}")
- end
- end
-
- # An indexed accessor into a part of an array or object.
- class IndexNode < Node
- children :index
-
- def initialize(index)
- @index = index
- end
-
- def compile_node(o)
- write("[#{@index.compile(o)}]")
- end
- end
-
- # A this-reference, using '@'.
- class ThisNode < Node
- def initialize(property=nil)
- @property = property
- end
-
- def compile_node(o)
- prop = @property ? ".#{@property}" : ''
- write("this#{prop}")
- end
- end
-
- # A range literal. Ranges can be used to extract portions (slices) of arrays,
- # or to specify a range for list comprehensions.
- class RangeNode < Node
- children :from, :to
-
- def initialize(from, to, exclusive=false)
- @from, @to, @exclusive = from, to, exclusive
- end
-
- def exclusive?
- @exclusive
- end
-
- def compile_variables(o)
- @indent = o[:indent]
- @from_var, @to_var = o[:scope].free_variable, o[:scope].free_variable
- from_val, to_val = @from.compile(o), @to.compile(o)
- write("#{@from_var} = #{from_val}; #{@to_var} = #{to_val};\n#{idt}")
- end
-
- def compile_node(o)
- return compile_array(o) unless o[:index]
- idx, step = o.delete(:index), o.delete(:step)
- vars = "#{idx}=#{@from_var}"
- step = step ? step.compile(o) : '1'
- equals = @exclusive ? '' : '='
- intro = "(#{@from_var} <= #{@to_var} ? #{idx}"
- compare = "#{intro} <#{equals} #{@to_var} : #{idx} >#{equals} #{@to_var})"
- incr = "#{intro} += #{step} : #{idx} -= #{step})"
- write("#{vars}; #{compare}; #{incr}")
- end
-
- # Expand the range into the equivalent array, if it's not being used as
- # part of a comprehension, slice, or splice.
- # TODO: This generates pretty ugly code ... shrink it.
- def compile_array(o)
- body = Expressions.wrap(LiteralNode.wrap('i'))
- arr = Expressions.wrap(ForNode.new(body, {:source => ValueNode.new(self)}, Value.new('i')))
- ParentheticalNode.new(CallNode.new(CodeNode.new([], arr))).compile(o)
- end
-
- end
-
- # An array slice literal. Unlike JavaScript's Array#slice, the second parameter
- # specifies the index of the end of the slice (just like the first parameter)
- # is the index of the beginning.
- class SliceNode < Node
- children :range
-
- def initialize(range)
- @range = range
- end
-
- def compile_node(o)
- from = @range.from.compile(o)
- to = @range.to.compile(o)
- plus_part = @range.exclusive? ? '' : ' + 1'
- write(".slice(#{from}, #{to}#{plus_part})")
- end
- end
-
- # An object literal.
- class ObjectNode < Node
- children :properties
- alias_method :objects, :properties
-
- def initialize(properties = [])
- @properties = properties
- end
-
- # All the mucking about with commas is to make sure that CommentNodes and
- # AssignNodes get interleaved correctly, with no trailing commas or
- # commas affixed to comments. TODO: Extract this and add it to ArrayNode.
- def compile_node(o)
- o[:indent] = idt(1)
- joins = Hash.new("\n")
- non_comments = @properties.select {|p| !p.is_a?(CommentNode) }
- non_comments.each {|p| joins[p] = p == non_comments.last ? "\n" : ",\n" }
- props = @properties.map { |prop|
- join = joins[prop]
- join = '' if prop == @properties.last
- indent = prop.is_a?(CommentNode) ? '' : idt(1)
- "#{indent}#{prop.compile(o)}#{join}"
- }.join('')
- write("{\n#{props}\n#{idt}}")
- end
- end
-
- # An array literal.
- class ArrayNode < Node
- children :objects
-
- def initialize(objects=[])
- @objects = objects
- end
-
- def compile_node(o)
- o[:indent] = idt(1)
- objects = @objects.map { |obj|
- code = obj.compile(o)
- obj.is_a?(CommentNode) ? "\n#{code}\n#{o[:indent]}" :
- obj == @objects.last ? code : "#{code}, "
- }.join('')
- ending = objects.include?("\n") ? "\n#{idt}]" : ']'
- write("[#{objects}#{ending}")
- end
- end
-
- # A faux-node that is never created by the grammar, but is used during
- # code generation to generate a quick "array.push(value)" tree of nodes.
- class PushNode
- def self.wrap(array, expressions)
- expr = expressions.unwrap
- return expressions if expr.statement_only? || expr.contains? {|n| n.statement_only? }
- Expressions.wrap(CallNode.new(
- ValueNode.new(LiteralNode.new(array), [AccessorNode.new(Value.new('push'))]),
- [expr]
- ))
- end
- end
-
- # A faux-node used to wrap an expressions body in a closure.
- class ClosureNode
- def self.wrap(expressions, statement=false)
- func = ParentheticalNode.new(CodeNode.new([], Expressions.wrap(expressions)))
- call = CallNode.new(ValueNode.new(func, AccessorNode.new(Value.new('call'))), [Value.new('this')])
- statement ? Expressions.wrap(call) : call
- end
- end
-
- # Setting the value of a local variable, or the value of an object property.
- class AssignNode < Node
- top_sensitive
- children :variable, :value
-
- PROTO_ASSIGN = /\A(\S+)\.prototype/
- LEADING_DOT = /\A\.(prototype\.)?/
-
- def initialize(variable, value, context=nil)
- @variable, @value, @context = variable, value, context
- end
-
- def value?
- @variable.is_a?(ValueNode)
- end
-
- def statement?
- value? && (@variable.array? || @variable.object?)
- end
-
- def compile_node(o)
- top = o.delete(:top)
- return compile_pattern_match(o) if statement?
- return compile_splice(o) if value? && @variable.splice?
- stmt = o.delete(:as_statement)
- name = @variable.compile(o)
- last = value? ? @variable.last.to_s.sub(LEADING_DOT, '') : name
- proto = name[PROTO_ASSIGN, 1]
- if @value.is_a?(CodeNode)
- @value.name = last if last.match(Lexer::IDENTIFIER)
- @value.proto = proto if proto
- end
- return write("#{name}: #{@value.compile(o)}") if @context == :object
- o[:scope].find(name) unless value? && @variable.properties?
- val = "#{name} = #{@value.compile(o)}"
- return write("#{idt}#{val};") if stmt
- val = "(#{val})" if !top || o[:return]
- val = "#{idt}return #{val}" if o[:return]
- write(val)
- end
-
- # Implementation of recursive pattern matching, when assigning array or
- # object literals to a value. Peeks at their properties to assign inner names.
- # See: http://wiki.ecmascript.org/doku.php?id=harmony:destructuring
- def compile_pattern_match(o)
- val_var = o[:scope].free_variable
- assigns = ["#{idt}#{val_var} = #{@value.compile(o)};"]
- o.merge!(:top => true, :as_statement => true)
- @variable.base.objects.each_with_index do |obj, i|
- obj, i = obj.value, obj.variable.base if @variable.object?
- access_class = @variable.array? ? IndexNode : AccessorNode
- if obj.is_a?(SplatNode)
- val = LiteralNode.wrap(obj.compile_value(o, val_var, @variable.base.objects.index(obj)))
- else
- val = ValueNode.new(val_var, [access_class.new(Value.new(i.to_s))])
- end
- assigns << AssignNode.new(obj, val).compile(o)
- end
- write(assigns.join("\n"))
- end
-
- def compile_splice(o)
- var = @variable.compile(o.merge(:only_first => true))
- range = @variable.properties.last.range
- plus = range.exclusive? ? '' : ' + 1'
- from = range.from.compile(o)
- to = "#{range.to.compile(o)} - #{from}#{plus}"
- write("#{var}.splice.apply(#{var}, [#{from}, #{to}].concat(#{@value.compile(o)}))")
- end
- end
-
- # A function definition. The only node that creates a new Scope.
- # A CodeNode does not have any children -- they're within the new scope.
- class CodeNode < Node
- top_sensitive
- attr_reader :params, :body, :bound
- attr_accessor :name, :proto
-
- def initialize(params, body, tag=nil)
- @params = params
- @body = body
- @bound = tag == :boundfunc
- end
-
- def compile_node(o)
- shared_scope = o.delete(:shared_scope)
- top = o.delete(:top)
- o[:scope] = shared_scope || Scope.new(o[:scope], @body, self)
- o[:return] = true
- o[:top] = true
- o[:indent] = idt(@bound ? 2 : 1)
- o.delete(:no_wrap)
- o.delete(:globals)
- if @params.last.is_a?(SplatNode)
- splat = @params.pop
- splat.index = @params.length
- @body.unshift(splat)
- end
- @params.each {|id| o[:scope].parameter(id.to_s) }
- code = @body.empty? ? "" : "\n#{@body.compile_with_declarations(o)}\n"
- name_part = @name ? " #{@name}" : ''
- func = "function#{@bound ? '' : name_part}(#{@params.join(', ')}) {#{code}#{idt(@bound ? 1 : 0)}}"
- func = "(#{func})" if top && !@bound
- return write(func) unless @bound
- inner = "(function#{name_part}() {\n#{idt(2)}return __func.apply(__this, arguments);\n#{idt(1)}});"
- write("(function(__this) {\n#{idt(1)}var __func = #{func};\n#{idt(1)}return #{inner}\n#{idt}})(this)")
- end
- end
-
- # A splat, either as a parameter to a function, an argument to a call,
- # or in a destructuring assignment.
- class SplatNode < Node
- children :name
- attr_accessor :index
-
- def initialize(name)
- @name = name
- end
-
- def compile_node(o={})
- write(@index ? compile_param(o) : @name.compile(o))
- end
-
- def compile_param(o)
- o[:scope].find(@name)
- "#{@name} = Array.prototype.slice.call(arguments, #{@index})"
- end
-
- def compile_value(o, name, index)
- "Array.prototype.slice.call(#{name}, #{index})"
- end
-
- end
-
- # A while loop, the only sort of low-level loop exposed by CoffeeScript. From
- # it, all other loops can be manufactured.
- class WhileNode < Node
- top_sensitive
- children :condition, :body
- statement
-
- def initialize(condition, body)
- @condition, @body = condition, body
- end
-
- def compile_node(o)
- returns = o.delete(:return)
- top = o.delete(:top) && !returns
- o[:indent] = idt(1)
- o[:top] = true
- cond = @condition.compile(o)
- set = ''
- if !top
- rvar = o[:scope].free_variable
- set = "#{idt}#{rvar} = [];\n"
- @body = PushNode.wrap(rvar, @body)
- end
- post = returns ? "\n#{idt}return #{rvar};" : ''
- return write("#{set}#{idt}while (#{cond}) null;#{post}") if @body.nil?
- write("#{set}#{idt}while (#{cond}) {\n#{@body.compile(o)}\n#{idt}}#{post}")
- end
- end
-
- # Simple Arithmetic and logical operations. Performs some conversion from
- # CoffeeScript operations into their JavaScript equivalents.
- class OpNode < Node
- children :first, :second
- attr_reader :operator
- attr_accessor :second
-
- CONVERSIONS = {
- :== => "===",
- :'!=' => "!==",
- :and => '&&',
- :or => '||',
- :is => '===',
- :isnt => "!==",
- :not => '!'
- }
- CHAINABLE = [:<, :>, :>=, :<=, :===, :'!==']
- ASSIGNMENT = [:'||=', :'&&=', :'?=']
- PREFIX_OPERATORS = [:typeof, :delete]
-
- def initialize(operator, first, second=nil, flip=false)
- @first, @second, @flip = first, second, flip
- @operator = CONVERSIONS[operator.to_sym] || operator
- end
-
- def unary?
- @second.nil?
- end
-
- def chainable?
- CHAINABLE.include?(operator.to_sym)
- end
-
- def compile_node(o)
- return write(compile_chain(o)) if chainable? && @first.unwrap.is_a?(OpNode) && @first.unwrap.chainable?
- return write(compile_assignment(o)) if ASSIGNMENT.include?(@operator.to_sym)
- return write(compile_unary(o)) if unary?
- return write(compile_existence(o)) if @operator == '?'
- write("#{@first.compile(o)} #{@operator} #{@second.compile(o)}")
- end
-
- # Mimic Python's chained comparisons. See:
- # http://docs.python.org/reference/expressions.html#notin
- def compile_chain(o)
- shared = @first.unwrap.second
- @first.second, shared = *shared.compile_reference(o) if shared.is_a?(CallNode)
- "(#{@first.compile(o)}) && (#{shared.compile(o)} #{@operator} #{@second.compile(o)})"
- end
-
- def compile_assignment(o)
- first, second = @first.compile(o), @second.compile(o)
- o[:scope].find(first) if @first.unwrap.is_a?(Value)
- return "#{first} = #{ExistenceNode.compile_test(o, @first)} ? #{first} : #{second}" if @operator == '?='
- "#{first} = #{first} #{@operator[0..1]} #{second}"
- end
-
- def compile_existence(o)
- first, second = @first.compile(o), @second.compile(o)
- "#{ExistenceNode.compile_test(o, @first)} ? #{first} : #{second}"
- end
-
- def compile_unary(o)
- space = PREFIX_OPERATORS.include?(@operator.to_sym) ? ' ' : ''
- parts = [@operator.to_s, space, @first.compile(o)]
- parts.reverse! if @flip
- parts.join('')
- end
- end
-
- # A try/catch/finally block.
- class TryNode < Node
- children :try, :recovery, :finally
- attr_reader :error
- statement
-
- def initialize(try, error, recovery, finally=nil)
- @try, @error, @recovery, @finally = try, error, recovery, finally
- end
-
- def compile_node(o)
- o[:indent] = idt(1)
- o[:top] = true
- error_part = @error ? " (#{@error}) " : ' '
- catch_part = @recovery && " catch#{error_part}{\n#{@recovery.compile(o)}\n#{idt}}"
- finally_part = @finally && " finally {\n#{@finally.compile(o.merge(:return => nil))}\n#{idt}}"
- write("#{idt}try {\n#{@try.compile(o)}\n#{idt}}#{catch_part}#{finally_part}")
- end
- end
-
- # Throw an exception.
- class ThrowNode < Node
- children :expression
- statement_only
-
- def initialize(expression)
- @expression = expression
- end
-
- def compile_node(o)
- write("#{idt}throw #{@expression.compile(o)};")
- end
- end
-
- # Check an expression for existence (meaning not null or undefined).
- class ExistenceNode < Node
- children :expression
-
- def self.compile_test(o, variable)
- first, second = variable, variable
- first, second = *variable.compile_reference(o) if variable.is_a?(CallNode)
- "(typeof #{first.compile(o)} !== \"undefined\" && #{second.compile(o)} !== null)"
- end
-
- def initialize(expression)
- @expression = expression
- end
-
- def compile_node(o)
- write(ExistenceNode.compile_test(o, @expression))
- end
- end
-
- # An extra set of parentheses, specified explicitly in the source.
- class ParentheticalNode < Node
- children :expressions
-
- def initialize(expressions, line=nil)
- @expressions = expressions.unwrap
- @line = line
- end
-
- def compile_node(o)
- compiled = @expressions.compile(o)
- compiled = compiled[0...-1] if compiled[-1..-1] == ';'
- write("(#{compiled})")
- end
- end
-
- # The replacement for the for loop is an array comprehension (that compiles)
- # into a for loop. Also acts as an expression, able to return the result
- # of the comprehenion. Unlike Python array comprehensions, it's able to pass
- # the current index of the loop as a second parameter.
- class ForNode < Node
- top_sensitive
- children :body, :source, :filter
- attr_reader :name, :index, :step
- statement
-
- def initialize(body, source, name, index=nil)
- @body, @name, @index = body, name, index
- @source = source[:source]
- @filter = source[:filter]
- @step = source[:step]
- @object = !!source[:object]
- @name, @index = @index, @name if @object
- end
-
- def compile_node(o)
- top_level = o.delete(:top) && !o[:return]
- range = @source.is_a?(ValueNode) && @source.base.is_a?(RangeNode) && @source.properties.empty?
- source = range ? @source.base : @source
- scope = o[:scope]
- name_found = @name && scope.find(@name)
- index_found = @index && scope.find(@index)
- body_dent = idt(1)
- rvar = scope.free_variable unless top_level
- svar = scope.free_variable
- ivar = range ? name : @index ? @index : scope.free_variable
- var_part = ''
- body = Expressions.wrap(@body)
- if range
- index_var = scope.free_variable
- source_part = source.compile_variables(o)
- for_part = "#{index_var}=0, #{source.compile(o.merge(:index => ivar, :step => @step))}, #{index_var}++"
- else
- index_var = nil
- source_part = "#{svar} = #{@source.compile(o)};\n#{idt}"
- step_part = @step ? "#{ivar} += #{@step.compile(o)}" : "#{ivar}++"
- for_part = @object ? "#{ivar} in #{svar}" : "#{ivar} = 0; #{ivar} < #{svar}.length; #{step_part}"
- var_part = "#{body_dent}#{@name} = #{svar}[#{ivar}];\n" if @name
- end
- set_result = rvar ? "#{idt}#{rvar} = []; " : idt
- return_result = rvar || ''
- body = ClosureNode.wrap(body, true) if top_level && contains? {|n| n.is_a? CodeNode }
- body = PushNode.wrap(rvar, body) unless top_level
- if o[:return]
- return_result = "return #{return_result}"
- o.delete(:return)
- body = IfNode.new(@filter, body, nil, :statement => true) if @filter
- elsif @filter
- body = Expressions.wrap(IfNode.new(@filter, body))
- end
- if @object
- o[:scope].assign("__hasProp", "Object.prototype.hasOwnProperty", true)
- body = Expressions.wrap(IfNode.new(
- CallNode.new(
- ValueNode.new(LiteralNode.wrap("__hasProp"), [AccessorNode.new(Value.new('call'))]),
- [LiteralNode.wrap(svar), LiteralNode.wrap(ivar)]
- ),
- Expressions.wrap(body), nil, {:statement => true}
- ))
- end
-
- return_result = "\n#{idt}#{return_result};" unless top_level
- body = body.compile(o.merge(:indent => body_dent, :top => true))
- vars = range ? @name : "#{@name}, #{ivar}"
- return write(set_result + source_part + "for (#{for_part}) {\n#{var_part}#{body}\n#{idt}}\n#{idt}#{return_result}")
- end
- end
-
- # If/else statements. Switch/whens get compiled into these. Acts as an
- # expression by pushing down requested returns to the expression bodies.
- # Single-expression IfNodes are compiled into ternary operators if possible,
- # because ternaries are first-class returnable assignable expressions.
- class IfNode < Node
- children :condition, :body, :else_body
-
- def initialize(condition, body, else_body=nil, tags={})
- @condition = condition
- @body = body && body.unwrap
- @else_body = else_body && else_body.unwrap
- @tags = tags
- @multiple = true if @condition.is_a?(Array)
- @condition = OpNode.new("!", ParentheticalNode.new(@condition)) if @tags[:invert]
- end
-
- def <<(else_body)
- eb = else_body.unwrap
- @else_body ? @else_body << eb : @else_body = eb
- self
- end
-
- def add_comment(comment)
- @comment = comment
- self
- end
-
- def force_statement
- @tags[:statement] = true
- self
- end
-
- # Rewrite a chain of IfNodes with their switch condition for equality.
- def rewrite_condition(expression)
- @condition = @multiple ? @condition.map {|c| OpNode.new("is", expression, c) } :
- OpNode.new("is", expression, @condition)
- @else_body.rewrite_condition(expression) if chain?
- self
- end
-
- # Rewrite a chain of IfNodes to add a default case as the final else.
- def add_else(exprs)
- chain? ? @else_body.add_else(exprs) : @else_body = (exprs && exprs.unwrap)
- self
- end
-
- # If the else_body is an IfNode itself, then we've got an if-else chain.
- def chain?
- @chain ||= @else_body && @else_body.is_a?(IfNode)
- end
-
- # The IfNode only compiles into a statement if either of the bodies needs
- # to be a statement.
- def statement?
- @is_statement ||= !!(@comment || @tags[:statement] || @body.statement? || (@else_body && @else_body.statement?))
- end
-
- def compile_condition(o)
- [@condition].flatten.map {|c| c.compile(o) }.join(' || ')
- end
-
- def compile_node(o)
- write(statement? ? compile_statement(o) : compile_ternary(o))
- end
-
- # Compile the IfNode as a regular if-else statement. Flattened chains
- # force sub-else bodies into statement form.
- def compile_statement(o)
- child = o.delete(:chain_child)
- cond_o = o.dup
- cond_o.delete(:return)
- o[:indent] = idt(1)
- o[:top] = true
- if_dent = child ? '' : idt
- com_dent = child ? idt : ''
- prefix = @comment ? @comment.compile(cond_o) + "\n#{com_dent}" : ''
- body = Expressions.wrap(@body).compile(o)
- if_part = "#{prefix}#{if_dent}if (#{compile_condition(cond_o)}) {\n#{body}\n#{idt}}"
- return if_part unless @else_body
- else_part = chain? ?
- " else #{@else_body.compile(o.merge(:indent => idt, :chain_child => true))}" :
- " else {\n#{Expressions.wrap(@else_body).compile(o)}\n#{idt}}"
- if_part + else_part
- end
-
- # Compile the IfNode into a ternary operator.
- def compile_ternary(o)
- if_part = "#{@condition.compile(o)} ? #{@body.compile(o)}"
- else_part = @else_body ? @else_body.compile(o) : 'null'
- "#{if_part} : #{else_part}"
- end
- end
-
-end
29 lib/coffee_script/parse_error.rb
View
@@ -1,29 +0,0 @@
-module CoffeeScript
-
- # Racc will raise this Exception whenever a syntax error occurs. The main
- # benefit over the Racc::ParseError is that the CoffeeScript::ParseError is
- # line-number aware.
- class ParseError < Racc::ParseError
-
- TOKEN_MAP = {
- 'INDENT' => 'indent',
- 'OUTDENT' => 'outdent',
- "\n" => 'newline'
- }
-
- def initialize(token_id, value, stack=nil, message=nil)
- @token_id, @value, @stack, @message = token_id, value, stack, message
- end
-
- def message
- line = @value.respond_to?(:line) ? @value.line : "END"
- line_part = "line #{line}:"
- id_part = @token_id != @value.to_s ? " unexpected #{@token_id.to_s.downcase}" : ""
- val_part = @message || "for #{TOKEN_MAP[@value.to_s] || "'#{@value}'"}"
- "#{line_part} syntax error, #{val_part}#{id_part}"
- end
- alias_method :inspect, :message
-
- end
-
-end
2,628 lib/coffee_script/parser.rb
View
@@ -1,2628 +0,0 @@
-#
-# DO NOT MODIFY!!!!
-# This file is automatically generated by Racc 1.4.6
-# from Racc grammer file "".
-#
-
-require 'racc/parser.rb'
-
-module CoffeeScript
-
-class Parser < Racc::Parser
-
-module_eval(<<'...end grammar.y/module_eval...', 'grammar.y', 463)
- # Lex and parse a CoffeeScript.
- def parse(code)
- # Uncomment the following line to enable grammar debugging, in combination
- # with the -g flag in the Rake build task.
- # @yydebug = true
- @tokens = Lexer.new.tokenize(code)
- do_parse
- end
-
- # Retrieve the next token from the list.
- def next_token
- @tokens.shift
- end
-
- # Raise a custom error class that knows about line numbers.
- def on_error(error_token_id, error_value, value_stack)
- raise ParseError.new(token_to_str(error_token_id), error_value, value_stack)
- end
-
-...end grammar.y/module_eval...
-##### State transition tables begin ###
-
-clist = [
-'136,200,144,29,32,35,39,43,46,52,57,62,65,163,60,182,163,8,14,60,-186',
-'-186,281,-186,-186,105,106,107,289,290,58,66,132,137,103,264,104,152',
-'214,215,293,167,60,50,302,8,14,202,55,200,292,163,199,72,3,111,172,173',
-'151,155,158,161,165,166,131,135,140,143,147,150,154,157,160,164,169',
-'130,134,139,142,146,149,153,156,159,162,168,129,133,138,141,145,148',
-'181,8,14,202,12,27,252,33,36,12,41,206,29,32,35,39,43,46,52,57,62,65',
-'60,273,289,290,2,211,186,21,26,180,296,96,98,42,96,98,53,58,66,67,95',
-'8,14,95,7,13,60,22,200,34,37,60,269,116,50,55,114,8,14,208,209,74,5',
-'10,16,19,24,314,264,8,14,45,48,8,14,50,50,163,50,298,99,163,96,98,-186',
-'-186,96,98,151,155,187,95,8,14,202,95,8,14,192,72,3,188,264,78,27,259',
-'33,36,12,41,50,29,32,35,39,43,46,52,57,62,65,81,8,14,60,2,50,60,21,26',
-'50,60,99,196,42,96,98,53,58,66,67,214,215,81,95,7,13,197,22,198,34,37',
-'122,285,60,50,55,283,319,105,106,107,74,5,10,16,19,24,103,163,104,315',
-'45,48,163,282,-186,-186,78,50,210,151,155,158,161,165,166,131,135,140',
-'143,147,150,154,157,105,106,107,280,126,72,3,213,126,103,27,104,33,36',
-'12,41,,29,32,35,39,43,46,52,57,62,65,105,106,107,,2,,,21,26,103,,104',
-',42,163,,53,58,66,67,,151,155,,7,13,,22,,34,37,163,,,50,55,,167,-186',
-'-186,,74,5,10,16,19,24,163,,,,45,48,,151,155,158,161,165,166,131,135',
-'140,143,147,150,154,157,160,164,169,130,134,139,142,146,,,,72,3,8,14',
-'192,27,190,33,36,12,41,,29,32,35,39,43,46,52,57,62,65,105,106,107,,2',
-',,21,26,103,,104,,42,163,,53,58,66,67,,-186,-186,,7,13,,22,,34,37,163',
-',,50,55,,167,151,155,,74,5,10,16,19,24,163,,,,45,48,,151,155,158,161',
-'165,166,131,135,140,143,147,150,154,157,160,164,169,130,134,139,142',
-'146,,,,72,3,,,,27,,33,36,12,41,,29,32,35,39,43,46,52,57,62,65,105,106',
-'107,,2,,,21,26,103,,104,,42,163,,53,58,66,67,,-186,-186,,7,13,,22,,34',
-'37,163,,,50,55,,167,-186,-186,,74,5,10,16,19,24,163,,,,45,48,,151,155',
-'158,161,165,166,131,135,140,143,147,150,154,157,160,164,169,130,134',
-'139,142,146,,,,72,3,,,,27,,33,36,12,41,,29,32,35,39,43,46,52,57,62,65',
-',,,,2,,,21,26,,,,,42,,,53,58,66,67,,,,,7,13,,22,,34,37,,,,50,55,,167',
-',,,74,5,10,16,19,24,163,,,,45,48,,151,155,158,161,165,166,131,135,140',
-'143,147,150,154,157,160,164,169,130,134,139,142,146,,,,72,3,,,,27,,33',
-'36,12,41,,29,32,35,39,43,46,52,57,62,65,,,,,2,,,21,26,,,,,42,,,53,58',
-'66,67,,,,,7,13,,22,,34,37,,,,50,55,,167,,,,74,5,10,16,19,24,163,,,,45',
-'48,,151,155,158,161,165,166,131,135,140,143,147,150,154,157,160,164',
-'169,130,134,139,142,146,,,,72,3,,,,27,,33,36,12,41,,29,32,35,39,43,46',
-'52,57,62,65,,,,,2,,,21,26,,,,,42,,,53,58,66,67,,,,,7,13,,22,,34,37,',
-',,50,55,,167,,,,74,5,10,16,19,24,163,,,,45,48,,151,155,158,161,165,166',
-'131,135,140,143,147,150,154,157,160,164,169,130,134,139,142,146,,,,72',
-'3,,,,27,,33,36,12,41,,29,32,35,39,43,46,52,57,62,65,,,,,2,,,21,26,,',
-',,42,,,53,58,66,67,,,,,7,13,,22,,34,37,,,,50,55,,167,,,,74,5,10,16,19',
-'24,163,,,,45,48,,151,155,158,161,165,166,131,135,140,143,147,150,154',
-'157,160,164,169,130,134,139,142,146,,,,72,3,,,,27,,33,36,12,41,,29,32',
-'35,39,43,46,52,57,62,65,,,,,2,,,21,26,,,,,42,,,53,58,66,67,,,,,7,13',
-',22,,34,37,,,,50,55,,167,,,,74,5,10,16,19,24,163,,,,45,48,,151,155,158',
-'161,165,166,131,135,140,143,147,150,154,157,160,164,169,130,134,139',
-'142,146,,,,72,3,,,,27,,33,36,12,41,,29,32,35,39,43,46,52,57,62,65,,',
-',,2,,,21,26,,,,,42,,,53,58,66,67,,,,,7,13,,22,,34,37,,,,50,55,,167,',
-',,74,5,10,16,19,24,163,,,,45,48,,151,155,158,161,165,166,131,135,140',
-'143,147,150,154,157,160,164,169,130,,,,,,,,72,3,,,,27,,33,36,12,41,',
-'29,32,35,39,43,46,52,57,62,65,,,,,2,,,21,26,,,,,42,,,53,58,66,67,,,',
-',7,13,,22,,34,37,,,,50,55,,167,,,,74,5,10,16,19,24,163,,,,45,48,,151',
-'155,158,161,165,166,131,135,140,143,147,150,154,157,160,164,169,130',
-',,,,,,,72,3,,,,27,,33,36,12,41,,29,32,35,39,43,46,52,57,62,65,,,,,2',
-',,21,26,,,,,42,,,53,58,66,67,,,,,7,13,,22,,34,37,,,,50,55,,167,,,,74',
-'5,10,16,19,24,163,,,,45,48,,151,155,158,161,165,166,131,135,140,143',
-'147,150,154,157,160,164,169,130,,,,,,,,72,3,,,,27,,33,36,12,41,,29,32',
-'35,39,43,46,52,57,62,65,,,,,2,,,21,26,,,,,42,,,53,58,66,67,,,,,7,13',
-',22,,34,37,,,,50,55,,,,,,74,5,10,16,19,24,163,,,305,45,48,,151,155,158',
-'161,165,166,131,135,140,143,147,150,154,157,,,,,,,,,,,,72,3,,,,27,,33',
-'36,12,41,,29,32,35,39,43,46,52,57,62,65,,,,,2,,,21,26,,,,,42,,,53,58',
-'66,67,,,,,7,13,,22,,34,37,,,,50,55,,,,,,74,5,10,16,19,24,163,,,,45,48',
-',151,155,158,161,165,166,131,135,140,143,147,150,154,157,,,,,,,,,,,',
-'72,3,,,,27,,33,36,12,41,,29,32,35,39,43,46,52,57,62,65,,,,,2,,,21,26',
-',,,,42,,,53,58,66,67,,,,,7,13,,22,,34,37,,,,50,55,,,,,,74,5,10,16,19',
-'24,163,,,,45,48,,151,155,158,161,165,166,131,135,140,143,147,150,154',
-'157,,,,,,,,,,,,72,3,,,,27,,33,36,12,41,,29,32,35,39,43,46,52,57,62,65',
-',,,,2,,,21,26,,,,,42,,,53,58,66,67,,,,,7,13,,22,,34,37,,,,50,55,,,,',
-',74,5,10,16,19,24,163,,,,45,48,,151,155,158,161,165,166,131,135,163',
-',,,,,,151,155,158,161,165,166,131,135,,,72,3,,,,27,,33,36,12,41,,29',
-'32,35,39,43,46,52,57,62,65,,,,,2,,,21,26,,,,,42,,,53,58,66,67,,,,,7',
-'13,,22,,34,37,,,,50,55,114,,,,,74,5,10,16,19,24,163,,,,45,48,,151,155',
-'158,161,165,166,131,135,163,,,,,,,151,155,158,161,165,166,131,135,,',
-'72,3,,,,27,,33,36,12,41,,29,32,35,39,43,46,52,57,62,65,,,,,2,,,21,26',
-',,,,42,,,53,58,66,67,,,,,7,13,,22,,34,37,,,,50,55,,,,,,74,5,10,16,19',
-'24,163,,,,45,48,,151,155,158,161,165,166,131,135,163,,,,,,,151,155,158',
-'161,165,166,131,135,,,72,3,,,,27,,33,36,12,41,,29,32,35,39,43,46,52',
-'57,62,65,,,,,2,,,21,26,,,,,42,,,53,58,66,67,,,,,7,13,,22,,34,37,,,,50',
-'55,,,,,,74,5,10,16,19,24,163,,,,45,48,163,151,155,158,161,165,166,151',
-'155,158,161,165,166,,,,,,,,,,,,,,72,3,,,,27,,33,36,12,41,,29,32,35,39',
-'43,46,52,57,62,65,,,,,2,,,21,26,,,,,42,,,53,58,66,67,,,,,7,13,,22,,34',
-'37,,,,50,55,,,,,,74,5,10,16,19,24,,,,,45,48,,,,,,,,,,,,,,,,,,,,,,,,',
-',,72,3,,,,27,,33,36,12,41,,29,32,35,39,43,46,52,57,62,65,,,,,2,,,21',
-'26,,,,,42,,,53,58,66,67,,,,,7,13,,22,,34,37,,,,50,55,,,,,,74,5,10,16',
-'19,24,,,,,45,48,,,,,,,,,,,,,,,,,,,,,,,,,,,72,3,,,,27,,33,36,12,41,,29',
-'32,35,39,43,46,52,57,62,65,,,,,2,,,21,26,,,,,42,,,53,58,66,67,,,,,7',
-'13,,22,,34,37,,,,50,55,,,,,,74,5,10,16,19,24,,,,,45,48,,,,,,,,,,,,,',
-',,,,,,,,,,,,,72,3,,,,27,,33,36,12,41,,29,32,35,39,43,46,52,57,62,65',
-',,,,2,,,21,26,,,,,42,,,53,58,66,67,,,,,7,13,,22,,34,37,,,,50,55,,,,',
-',74,5,10,16,19,24,,,,,45,48,,,,,,,,,,,,,,,,,,,,,,,,,,,72,3,,,,27,,33',
-'36,12,41,,29,32,35,39,43,46,52,57,62,65,,,,,2,,,21,26,,,,,42,,,53,58',
-'66,67,,,,,7,13,,22,,34,37,,,,50,55,,,,,,74,5,10,16,19,24,,,,,45,48,',
-',,,,,,,,,,,,,,,,,,,,,,,,,72,3,,,,27,,33,36,12,41,,29,32,35,39,43,46',
-'52,57,62,65,,,,,2,,,21,26,,,,,42,,,53,58,66,67,,,,,7,13,,22,,34,37,',
-',,50,55,,124,,,,74,5,10,16,19,24,,,,,45,48,,,,,,,,,,,,,,,,,,,,,,,,,',
-',72,3,,,,27,,33,36,12,41,,29,32,35,39,43,46,52,57,62,65,,,,,2,,,21,26',
-',,,,42,,,53,58,66,67,,,,,7,13,,22,,34,37,,,,50,55,278,,,,,74,5,10,16',
-'19,24,,,,,45,48,,,,,,,,,,,,,,,,,,,,,,,,,,,72,3,8,14,,27,,33,36,12,41',
-',29,32,35,39,43,46,52,57,62,65,,,,,2,,,21,26,,,,,42,,,53,58,66,67,,',
-',,7,13,,22,,34,37,,,,50,55,,,,,,74,5,10,16,19,24,,,,,45,48,,,,,,,,,',
-',,,,,,,,,,,,,,,,,72,3,,,,27,,33,36,12,41,,29,32,35,39,43,46,52,57,62',
-'65,,,,,2,,,21,26,,,,,42,,,53,58,66,67,,,,,7,13,,22,,34,37,,,,50,55,',
-',,,,74,5,10,16,19,24,,,,,45,48,,,,,,,,,,,,,,,,,,,,,,,,,,,72,3,,,,27',
-',33,36,12,41,,29,32,35,39,43,46,52,57,62,65,,,,,2,,,21,26,,,,,42,,,53',
-'58,66,67,,,,,7,13,,22,,34,37,,,,50,55,,,,,,74,5,10,16,19,24,,,,,45,48',
-',,,,,,,,,,,,,,,,,,,,,,,,,,72,3,,,,27,,33,36,12,41,,29,32,35,39,43,46',
-'52,57,62,65,,,,,2,,,21,26,,,,,42,,,53,58,66,67,,,,,7,13,,22,,34,37,',
-',,50,55,,,,,,74,5,10,16,19,24,,,,,45,48,,,,,,,,,,,,,,,,,,,,,,,,,,,72',
-'3,,,,27,,33,36,12,41,,29,32,35,39,43,46,52,57,62,65,,,,,2,,,21,26,,',
-',,42,,,53,58,66,67,,,,,7,13,,22,,34,37,,,,50,55,,,,,,74,5,10,16,19,24',
-',,,,45,48,,,,,,,,,,,,,,,,,,,,,,,,,,,72,3,,,,27,,33,36,12,41,,29,32,35',
-'39,43,46,52,57,62,65,,,,,2,,,21,26,,,,,42,,,53,58,66,67,,,,,7,13,,22',
-',34,37,,,,50,55,,,,,,74,5,10,16,19,24,,,,,45,48,,,,,,,,,,,,,,,,,,,,',
-',,,,,,72,3,,,,27,,33,36,12,41,,29,32,35,39,43,46,52,57,62,65,,,,,2,',
-',21,26,,,,,42,,,53,58,66,67,,,,,7,13,,22,,34,37,,,,50,55,,,,,,74,5,10',
-'16,19,24,,,,,45,48,,,,,,,,,,,,,,,,,,,,,,,,,,,72,3,,,,27,,33,36,12,41',
-',29,32,35,39,43,46,52,57,62,65,,,,,2,,,21,26,,,,,42,,,53,58,66,67,,',
-',,7,13,,22,,34,37,,,,50,55,,,,,,74,5,10,16,19,24,,,,,45,48,,,,,,,,,',
-',,,,,,,,,,,,,,,,,72,3,,,,27,,33,36,12,41,,29,32,35,39,43,46,52,57,62',
-'65,,,,,2,,,21,26,,,,,42,,,53,58,66,67,,,,,7,13,,22,,34,37,,,,50,55,',
-',,,,74,5,10,16,19,24,,,,,45,48,,,,,,,,,,,,,,,,,,,,,,,,,,,72,3,,,,27',
-',33,36,12,41,,29,32,35,39,43,46,52,57,62,65,,,,,2,,,21,26,,,,,42,,,53',
-'58,66,67,,,,,7,13,,22,,34,37,,,,50,55,,,,,,74,5,10,16,19,24,,,,,45,48',
-',,,,,,,,,,,,,,,,,,,,,,,,,,72,3,,,,27,,33,36,12,41,,29,32,35,39,43,46',
-'52,57,62,65,,,,,2,,,21,26,,,,,42,,,53,58,66,67,,,,,7,13,,22,,34,37,',
-',,50,55,,,,,,74,5,10,16,19,24,,,,,45,48,,,,,,,,,,,,,,,,,,,,,,,,,,,72',
-'3,,,,27,,33,36,12,41,,29,32,35,39,43,46,52,57,62,65,,,,,2,,,21,26,,',
-',,42,,,53,58,66,67,,,,,7,13,,22,,34,37,,,,50,55,,,,,,74,5,10,16,19,24',
-',,,,45,48,,,,,,,,,,,,,,,,,,,,,,,,,,,72,3,,,,27,,33,36,12,41,,29,32,35',
-'39,43,46,52,57,62,65,,,,,2,,,21,26,,,,,42,,,53,58,66,67,,,,,7,13,,22',
-',34,37,,,,50,55,,,,,,74,5,10,16,19,24,,,,,45,48,,,,,,,,,,,,,,,,,,,,',
-',,,,,,72,3,,,,27,,33,36,12,41,,29,32,35,39,43,46,52,57,62,65,,,,,2,',
-',21,26,,,,,42,,,53,58,66,67,,,,,7,13,,22,,34,37,,,,50,55,,,,,,74,5,10',
-'16,19,24,,,,,45,48,,,,,,,,,,,,,,,,,,,,,,,,,,,72,3,,,,27,,33,36,12,41',
-',29,32,35,39,43,46,52,57,62,65,,,,,2,,,21,26,,,,,42,,,53,58,66,67,,',
-',,7,13,,22,,34,37,,,,50,55,,,,,,74,5,10,16,19,24,,,,,45,48,,,,,,,,,',
-',,,,,,,,,,,,,,,,,72,3,,,,27,,33,36,12,41,,29,32,35,39,43,46,52,57,62',
-'65,,,,,2,,,21,26,,,,,42,,,53,58,66,67,,,,,7,13,,22,,34,37,,,,50,55,',
-',,,,74,5,10,16,19,24,,,,,45,48,,,,,,,,,,,,,,,,,,,,,,,,,,,72,3,,,,27',
-',33,36,12,41,,29,32,35,39,43,46,52,57,62,65,,,,,2,,,21,26,,,,,42,,,53',
-'58,66,67,,,,,7,13,,22,,34,37,,,,50,55,,,,,,74,5,10,16,19,24,,,,,45,48',
-',,,,,,,,,,,,,,,,,,,,,,,,,,72,3,,,,27,,33,36,12,41,,29,32,35,39,43,46',
-'52,57,62,65,,,,,2,,,21,26,,,,,42,,,53,58,66,67,,,,,7,13,,22,,34,37,',
-',,50,55,,,,,,74,5,10,16,19,24,,,,,45,48,,,,,,,,,,,,,,,,,,,,,,,,,,,72',
-'3,,,,27,,33,36,12,41,,29,32,35,39,43,46,52,57,62,65,,,,,2,,,21,26,,',
-',,42,,,53,58,66,67,,,,,7,13,,22,,34,37,,,,50,55,,,,,,74,5,10,16,19,24',
-',,,,45,48,,,,,,,,,,,,,,,,,,,,,,,,,,,72,3,,,,27,,33,36,12,41,,29,32,35',
-'39,43,46,52,57,62,65,,,,,2,,,21,26,,,,,42,,,53,58,66,67,,,,,7,13,,22',
-',34,37,,,,50,55,,,,,,74,5,10,16,19,24,,,,,45,48,,,,,,,,,,,,,,,,,,,,',
-',,,,,,72,3,,,,27,,33,36,12,41,,29,32,35,39,43,46,52,57,62,65,,,,,2,',
-',21,26,,,,,42,,,53,58,66,67,,,,,7,13,,22,,34,37,,,,50,55,,,,,,74,5,10',
-'16,19,24,,,,,45,48,,,,,,,,,,,,,,,,,,,,,,,,,,,72,3,,,,27,,33,36,12,41',
-',29,32,35,39,43,46,52,57,62,65,,,,,2,,,21,26,,,,,42,,,53,58,66,67,,',
-',,7,13,,22,,34,37,,,,50,55,,,,,,74,5,10,16,19,24,,,,,45,48,,,,,,,,,',
-',,,,,,,,,,,,,,,,,72,3,,,,27,,33,36,12,41,,29,32,35,39,43,46,52,57,62',
-'65,,,,,2,,,21,26,,,,,42,,,53,58,66,67,,,,,7,13,,22,,34,37,,,,50,55,',
-',,,,74,5,10,16,19,24,,,,,45,48,,,,,,,,,,,,,,,,,,,,,,,,,,,72,3,,,,27',
-',33,36,12,41,,29,32,35,39,43,46,52,57,62,65,,,,,2,,,21,26,,,,,42,,,53',
-'58,66,67,,,,,7,13,,22,,34,37,,,,50,55,,,,,,74,5,10,16,19,24,,,,,45,48',
-',,,,,,,,,,,,,,,,,,,,,,,,,,72,3,,,,27,,33,36,12,41,,29,32,35,39,43,46',
-'52,57,62,65,,,,,2,,,21,26,,,,,42,,,53,58,66,67,,,,,7,13,,22,,34,37,',
-',,50,55,,,,,,74,5,10,16,19,24,,,,,45,48,,,,,,,,,,,,,,,,,,,,,,,,,,,72',
-'3,,,,27,,33,36,12,41,,29,32,35,39,43,46,52,57,62,65,,,,,2,,,21,26,,',
-',,42,,,53,58,66,67,,,,,7,13,,22,,34,37,,,,50,55,,,,,,74,5,10,16,19,24',
-',,,,45,48,,,,,,,,,,,,,,,,,,,,,,,,,,,72,3,,,,27,,33,36,12,41,,29,32,35',
-'39,43,46,52,57,62,65,,,,,2,,,21,26,,,,,42,,,53,58,66,67,,,,,7,13,,22',
-',34,37,,,,50,55,,,,,,74,5,10,16,19,24,,,,,45,48,,,,,,,,,,,,,,,,,,,,',
-',,,,,,72,3,,,,27,,33,36,12,41,,29,32,35,39,43,46,52,57,62,65,,,,,2,',
-',21,26,,,,,42,,,53,58,66,67,,,,,7,13,,22,,34,37,,,,50,55,,,,,,74,5,10',
-'16,19,24,,,,,45,48,,,,,,,,,,,,,,,,,,,,,,,,,,,72,3,,,,27,,33,36,12,41',
-',29,32,35,39,43,46,52,57,62,65,,,,,2,,,21,26,,,,,42,,,53,58,66,67,,',
-',,7,13,,22,,34,37,,,,50,55,,,,,,74,5,10,16,19,24,,,,,45,48,,,,,,,,,',
-',,,,,,,,,,,,,,,,,72,3,,,,27,,33,36,12,41,,29,32,35,39,43,46,52,57,62',
-'65,,,,,2,,,21,26,,,,,42,,,53,58,66,67,,,,,7,13,,22,,34,37,,,,50,55,',
-',,,,74,5,10,16,19,24,,,,,45,48,,,,,,,,,,,,,,,,,,,,,,,,,,,72,3,,,,27',
-',33,36,12,41,,29,32,35,39,43,46,52,57,62,65,,,,,2,,,21,26,,,,,42,,,53',
-'58,66,67,,,,,7,13,,22,,34,37,,,,50,55,,,,,,74,5,10,16,19,24,,,,,45,48',
-',,,,,,,,,,,,,,,,,,,,,,,,,,72,3,,,,27,,33,36,12,41,,29,32,35,39,43,46',
-'52,57,62,65,,,,,2,,,21,26,,,,,42,,,53,58,66,67,,,,,7,13,,22,,34,37,',
-',,50,55,,,,,,74,5,10,16,19,24,,,,,45,48,,,,,,,,,,,,,,,,,,,,,,,,,,,72',
-'3,,,,27,,33,36,12,41,,29,32,35,39,43,46,52,57,62,65,,,,,2,,,21,26,,',
-',,42,,,53,58,66,67,,,,,7,13,,22,,34,37,,,,50,55,,,,,,74,5,10,16,19,24',
-',,,,45,48,,,,,,,,,,,,,,,,,,,,,,,,,,,72,3,,,,27,,33,36,12,41,,29,32,35',
-'39,43,46,52,57,62,65,,,,,2,,,21,26,,,,,42,,,53,58,66,67,,,,,7,13,,22',
-',34,37,,,,50,55,,,,,,74,5,10,16,19,24,,,,,45,48,,,,,,,,,,,,,,,,,,,,',
-',,,,,,72,3,,,,27,,33,36,12,41,,29,32,35,39,43,46,52,57,62,65,,,,,2,',
-',21,26,,,,,42,,,53,58,66,67,,,,,7,13,,22,,34,37,,,,50,55,,,,,,74,5,10',
-'16,19,24,,,,,45,48,,,,,,,,,,,,,,,,,,,,,,,,,,,72,3,,,,27,,33,36,12,41',
-',29,32,35,39,43,46,52,57,62,65,,,,,2,,,21,26,,,,,42,,,53,58,66,67,,',
-',,7,13,,22,,34,37,,,,50,55,,,,,,74,5,10,16,19,24,,,,,45,48,,,,,,,,,',
-',,,,,,,,,,,,,,,,,72,3,,,,27,,33,36,12,41,,29,32,35,39,43,46,52,57,62',
-'65,,,,,2,,,21,26,,,,,42,,,53,58,66,67,,,,,7,13,,22,,34,37,,,,50,55,114',
-',,,,74,5,10,16,19,24,,,,,45,48,,,,,,,,,,,,,,,,,,,,,,,,,,,72,3,,,,27',
-',33,36,12,41,,29,32,35,39,43,46,52,57,62,65,,,,,2,,,21,26,,,,,42,,,53',
-'58,66,67,,,,,7,13,,22,,34,37,,,,50,55,60,,,,,74,5,10,16,19,24,,,,,45',
-'48,,,,,,,,,,,,,,,,,,,,,,,,,,,72,3,8,14,,27,,33,36,12,41,,29,32,35,39',
-'43,46,52,57,62,65,,,,,2,,,21,26,,,,,42,,,53,58,66,67,,,,,7,13,,22,,34',
-'37,,,,50,55,,,,,,74,5,10,16,19,24,,,,,45,48,,,,,,,,,,,,,,,,,,,,,,,,',
-',,72,3,,,,27,,33,36,12,41,,29,32,35,39,43,46,52,57,62,65,,,,,2,,,21',
-'26,,,,,42,,,53,58,66,67,,,,,7,13,,22,,34,37,,,,50,55,,,,,,74,5,10,16',
-'19,24,,,,,45,48,,,,,,,,,,,,,,,,,,,,,,,,,,,72,3,,,,27,,33,36,12,41,,29',
-'32,35,39,43,46,52,57,62,65,,,,,2,,,21,26,,,,,42,,,53,58,66,67,,,,,7',
-'13,,22,,34,37,,,,50,55,,,,,,74,5,10,16,19,24,,,,,45,48,,,,,,,,,,,,,',
-',,,,,,,,,,,,,72,3,,,,27,,33,36,12,41,,29,32,35,39,43,46,52,57,62,65',
-',,,,2,,,21,26,,,,,42,,,53,58,66,67,,,,,7,13,,22,,34,37,,,,50,55,,,,',
-',74,5,10,16,19,24,,,,,45,48,,,,,,,,,,,,,,,,,,,,,,,,,,,72,3,,,,27,,33',
-'36,12,41,,29,32,35,39,43,46,52,57,62,65,,,,,2,,,21,26,,,,,42,,,53,58',
-'66,67,,,,,7,13,,22,,34,37,,,,50,55,,,,,,74,5,10,16,19,24,,,,,45,48,',
-',,,,,,,,,,,,,,,,,,,,,,,,,72,3,,,,27,,33,36,12,41,,29,32,35,39,43,46',
-'52,57,62,65,,,,,2,,,21,26,,,,,42,,,53,58,66,67,,,,,7,13,,22,,34,37,',