spade 0.0.8.1 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +0 -1
- data/.gitmodules +4 -4
- data/README.md +4 -0
- data/bin/spade +1 -1
- data/lib/spade.rb +0 -51
- data/lib/spade/cli.rb +10 -4
- data/lib/spade/version.rb +1 -1
- data/spade.gemspec +4 -21
- metadata +13 -482
- data/Gemfile +0 -3
- data/Gemfile.lock +0 -40
- data/lib/index.js +0 -14
- data/lib/node/loader.js +0 -146
- data/lib/node/sandbox.js +0 -44
- data/lib/spade.js +0 -1130
- data/lib/spade/bundle.rb +0 -171
- data/lib/spade/cli/base.rb +0 -354
- data/lib/spade/cli/owner.rb +0 -45
- data/lib/spade/cli/project_generator.rb +0 -58
- data/lib/spade/compiler.rb +0 -34
- data/lib/spade/console.rb +0 -39
- data/lib/spade/context.rb +0 -116
- data/lib/spade/credentials.rb +0 -36
- data/lib/spade/dependency_installer.rb +0 -103
- data/lib/spade/environment.rb +0 -35
- data/lib/spade/exports.rb +0 -71
- data/lib/spade/installer.rb +0 -40
- data/lib/spade/loader.rb +0 -238
- data/lib/spade/local.rb +0 -46
- data/lib/spade/package.rb +0 -157
- data/lib/spade/reactor.rb +0 -159
- data/lib/spade/remote.rb +0 -99
- data/lib/spade/repository.rb +0 -18
- data/lib/spade/server.rb +0 -66
- data/lib/spade/shell.rb +0 -36
- data/lib/spade/templates/project/LICENSE +0 -19
- data/lib/spade/templates/project/README.md +0 -21
- data/lib/spade/templates/project/lib/main.js +0 -9
- data/lib/spade/templates/project/project.json +0 -31
- data/lib/spade/templates/project/tests/main-test.js +0 -8
- data/package.json +0 -27
- data/packages/coffee-script/.gitignore +0 -8
- data/packages/coffee-script/.npmignore +0 -11
- data/packages/coffee-script/Cakefile +0 -229
- data/packages/coffee-script/LICENSE +0 -22
- data/packages/coffee-script/README +0 -47
- data/packages/coffee-script/Rakefile +0 -78
- data/packages/coffee-script/bin/cake +0 -7
- data/packages/coffee-script/bin/coffee +0 -7
- data/packages/coffee-script/documentation/coffee/aliases.coffee +0 -11
- data/packages/coffee-script/documentation/coffee/array_comprehensions.coffee +0 -2
- data/packages/coffee-script/documentation/coffee/block_comment.coffee +0 -6
- data/packages/coffee-script/documentation/coffee/cake_tasks.coffee +0 -9
- data/packages/coffee-script/documentation/coffee/classes.coffee +0 -25
- data/packages/coffee-script/documentation/coffee/comparisons.coffee +0 -5
- data/packages/coffee-script/documentation/coffee/conditionals.coffee +0 -13
- data/packages/coffee-script/documentation/coffee/default_args.coffee +0 -8
- data/packages/coffee-script/documentation/coffee/do.coffee +0 -4
- data/packages/coffee-script/documentation/coffee/embedded.coffee +0 -5
- data/packages/coffee-script/documentation/coffee/existence.coffee +0 -10
- data/packages/coffee-script/documentation/coffee/expressions.coffee +0 -9
- data/packages/coffee-script/documentation/coffee/expressions_assignment.coffee +0 -3
- data/packages/coffee-script/documentation/coffee/expressions_comprehension.coffee +0 -3
- data/packages/coffee-script/documentation/coffee/expressions_try.coffee +0 -7
- data/packages/coffee-script/documentation/coffee/fat_arrow.coffee +0 -6
- data/packages/coffee-script/documentation/coffee/functions.coffee +0 -2
- data/packages/coffee-script/documentation/coffee/heredocs.coffee +0 -7
- data/packages/coffee-script/documentation/coffee/heregexes.coffee +0 -11
- data/packages/coffee-script/documentation/coffee/interpolation.coffee +0 -6
- data/packages/coffee-script/documentation/coffee/multiple_return_values.coffee +0 -7
- data/packages/coffee-script/documentation/coffee/object_comprehensions.coffee +0 -4
- data/packages/coffee-script/documentation/coffee/object_extraction.coffee +0 -13
- data/packages/coffee-script/documentation/coffee/objects_and_arrays.coffee +0 -19
- data/packages/coffee-script/documentation/coffee/objects_reserved.coffee +0 -5
- data/packages/coffee-script/documentation/coffee/overview.coffee +0 -28
- data/packages/coffee-script/documentation/coffee/parallel_assignment.coffee +0 -6
- data/packages/coffee-script/documentation/coffee/patterns_and_splats.coffee +0 -7
- data/packages/coffee-script/documentation/coffee/prototypes.coffee +0 -3
- data/packages/coffee-script/documentation/coffee/range_comprehensions.coffee +0 -2
- data/packages/coffee-script/documentation/coffee/scope.coffee +0 -5
- data/packages/coffee-script/documentation/coffee/slices.coffee +0 -7
- data/packages/coffee-script/documentation/coffee/soaks.coffee +0 -1
- data/packages/coffee-script/documentation/coffee/splats.coffee +0 -27
- data/packages/coffee-script/documentation/coffee/splices.coffee +0 -5
- data/packages/coffee-script/documentation/coffee/strings.coffee +0 -8
- data/packages/coffee-script/documentation/coffee/switch.coffee +0 -10
- data/packages/coffee-script/documentation/coffee/try.coffee +0 -8
- data/packages/coffee-script/documentation/coffee/while.coffee +0 -10
- data/packages/coffee-script/documentation/css/docs.css +0 -374
- data/packages/coffee-script/documentation/css/idle.css +0 -64
- data/packages/coffee-script/documentation/docs/browser.html +0 -25
- data/packages/coffee-script/documentation/docs/cake.html +0 -43
- data/packages/coffee-script/documentation/docs/coffee-script.html +0 -51
- data/packages/coffee-script/documentation/docs/command.html +0 -161
- data/packages/coffee-script/documentation/docs/docco.css +0 -186
- data/packages/coffee-script/documentation/docs/grammar.html +0 -399
- data/packages/coffee-script/documentation/docs/helpers.html +0 -31
- data/packages/coffee-script/documentation/docs/index.html +0 -3
- data/packages/coffee-script/documentation/docs/lexer.html +0 -490
- data/packages/coffee-script/documentation/docs/nodes.html +0 -1338
- data/packages/coffee-script/documentation/docs/optparse.html +0 -78
- data/packages/coffee-script/documentation/docs/repl.html +0 -24
- data/packages/coffee-script/documentation/docs/rewriter.html +0 -251
- data/packages/coffee-script/documentation/docs/scope.html +0 -54
- data/packages/coffee-script/documentation/docs/underscore.html +0 -295
- data/packages/coffee-script/documentation/images/background.png +0 -0
- data/packages/coffee-script/documentation/images/banding.png +0 -0
- data/packages/coffee-script/documentation/images/button_bg.png +0 -0
- data/packages/coffee-script/documentation/images/button_bg_dark.gif +0 -0
- data/packages/coffee-script/documentation/images/button_bg_green.gif +0 -0
- data/packages/coffee-script/documentation/images/favicon.ico +0 -0
- data/packages/coffee-script/documentation/images/logo.png +0 -0
- data/packages/coffee-script/documentation/images/screenshadow.png +0 -0
- data/packages/coffee-script/documentation/index.html.erb +0 -1607
- data/packages/coffee-script/documentation/js/aliases.js +0 -17
- data/packages/coffee-script/documentation/js/array_comprehensions.js +0 -6
- data/packages/coffee-script/documentation/js/block_comment.js +0 -4
- data/packages/coffee-script/documentation/js/cake_tasks.js +0 -10
- data/packages/coffee-script/documentation/js/classes.js +0 -44
- data/packages/coffee-script/documentation/js/comparisons.js +0 -3
- data/packages/coffee-script/documentation/js/conditionals.js +0 -12
- data/packages/coffee-script/documentation/js/default_args.js +0 -7
- data/packages/coffee-script/documentation/js/do.js +0 -10
- data/packages/coffee-script/documentation/js/embedded.js +0 -4
- data/packages/coffee-script/documentation/js/existence.js +0 -6
- data/packages/coffee-script/documentation/js/expressions.js +0 -15
- data/packages/coffee-script/documentation/js/expressions_assignment.js +0 -2
- data/packages/coffee-script/documentation/js/expressions_comprehension.js +0 -9
- data/packages/coffee-script/documentation/js/expressions_try.js +0 -7
- data/packages/coffee-script/documentation/js/fat_arrow.js +0 -9
- data/packages/coffee-script/documentation/js/functions.js +0 -7
- data/packages/coffee-script/documentation/js/heredocs.js +0 -2
- data/packages/coffee-script/documentation/js/heregexes.js +0 -2
- data/packages/coffee-script/documentation/js/interpolation.js +0 -4
- data/packages/coffee-script/documentation/js/multiple_return_values.js +0 -5
- data/packages/coffee-script/documentation/js/object_comprehensions.js +0 -15
- data/packages/coffee-script/documentation/js/object_extraction.js +0 -10
- data/packages/coffee-script/documentation/js/objects_and_arrays.js +0 -17
- data/packages/coffee-script/documentation/js/objects_reserved.js +0 -4
- data/packages/coffee-script/documentation/js/overview.js +0 -35
- data/packages/coffee-script/documentation/js/parallel_assignment.js +0 -4
- data/packages/coffee-script/documentation/js/patterns_and_splats.js +0 -4
- data/packages/coffee-script/documentation/js/prototypes.js +0 -3
- data/packages/coffee-script/documentation/js/range_comprehensions.js +0 -9
- data/packages/coffee-script/documentation/js/scope.js +0 -8
- data/packages/coffee-script/documentation/js/slices.js +0 -4
- data/packages/coffee-script/documentation/js/soaks.js +0 -2
- data/packages/coffee-script/documentation/js/splats.js +0 -15
- data/packages/coffee-script/documentation/js/splices.js +0 -3
- data/packages/coffee-script/documentation/js/strings.js +0 -2
- data/packages/coffee-script/documentation/js/switch.js +0 -23
- data/packages/coffee-script/documentation/js/try.js +0 -8
- data/packages/coffee-script/documentation/js/while.js +0 -18
- data/packages/coffee-script/documentation/vendor/jquery-1.4.2.js +0 -6240
- data/packages/coffee-script/examples/beautiful_code/binary_search.coffee +0 -16
- data/packages/coffee-script/examples/beautiful_code/quicksort_runtime.coffee +0 -13
- data/packages/coffee-script/examples/beautiful_code/regular_expression_matcher.coffee +0 -34
- data/packages/coffee-script/examples/blocks.coffee +0 -54
- data/packages/coffee-script/examples/code.coffee +0 -167
- data/packages/coffee-script/examples/computer_science/README +0 -4
- data/packages/coffee-script/examples/computer_science/binary_search.coffee +0 -25
- data/packages/coffee-script/examples/computer_science/bubble_sort.coffee +0 -11
- data/packages/coffee-script/examples/computer_science/linked_list.coffee +0 -108
- data/packages/coffee-script/examples/computer_science/luhn_algorithm.coffee +0 -36
- data/packages/coffee-script/examples/computer_science/merge_sort.coffee +0 -19
- data/packages/coffee-script/examples/computer_science/selection_sort.coffee +0 -23
- data/packages/coffee-script/examples/poignant.coffee +0 -181
- data/packages/coffee-script/examples/potion.coffee +0 -206
- data/packages/coffee-script/examples/underscore.coffee +0 -682
- data/packages/coffee-script/examples/web_server.coffee +0 -12
- data/packages/coffee-script/extras/EXTRAS +0 -7
- data/packages/coffee-script/extras/coffee-script.js +0 -8
- data/packages/coffee-script/extras/jsl.conf +0 -44
- data/packages/coffee-script/index.html +0 -2515
- data/packages/coffee-script/lib/browser.js +0 -52
- data/packages/coffee-script/lib/cake.js +0 -76
- data/packages/coffee-script/lib/coffee-script.js +0 -82
- data/packages/coffee-script/lib/command.js +0 -263
- data/packages/coffee-script/lib/grammar.js +0 -581
- data/packages/coffee-script/lib/helpers.js +0 -66
- data/packages/coffee-script/lib/index.js +0 -8
- data/packages/coffee-script/lib/lexer.js +0 -633
- data/packages/coffee-script/lib/nodes.js +0 -2165
- data/packages/coffee-script/lib/optparse.js +0 -111
- data/packages/coffee-script/lib/parser.js +0 -649
- data/packages/coffee-script/lib/repl.js +0 -42
- data/packages/coffee-script/lib/rewriter.js +0 -353
- data/packages/coffee-script/lib/scope.js +0 -120
- data/packages/coffee-script/lib/spade-format.js +0 -45
- data/packages/coffee-script/package.json +0 -26
- data/packages/coffee-script/src/browser.coffee +0 -43
- data/packages/coffee-script/src/cake.coffee +0 -69
- data/packages/coffee-script/src/coffee-script.coffee +0 -92
- data/packages/coffee-script/src/command.coffee +0 -214
- data/packages/coffee-script/src/grammar.coffee +0 -590
- data/packages/coffee-script/src/helpers.coffee +0 -56
- data/packages/coffee-script/src/index.coffee +0 -2
- data/packages/coffee-script/src/lexer.coffee +0 -653
- data/packages/coffee-script/src/nodes.coffee +0 -1754
- data/packages/coffee-script/src/optparse.coffee +0 -99
- data/packages/coffee-script/src/repl.coffee +0 -42
- data/packages/coffee-script/src/rewriter.coffee +0 -326
- data/packages/coffee-script/src/scope.coffee +0 -94
- data/packages/coffee-script/test/arguments.coffee +0 -127
- data/packages/coffee-script/test/assignment.coffee +0 -98
- data/packages/coffee-script/test/break.coffee +0 -18
- data/packages/coffee-script/test/comments.coffee +0 -201
- data/packages/coffee-script/test/conditionals.coffee +0 -181
- data/packages/coffee-script/test/exception_handling.coffee +0 -90
- data/packages/coffee-script/test/helpers.coffee +0 -96
- data/packages/coffee-script/test/importing.coffee +0 -18
- data/packages/coffee-script/test/operators.coffee +0 -225
- data/packages/coffee-script/test/ranges_slices_and_splices.coffee +0 -186
- data/packages/coffee-script/test/regular_expressions.coffee +0 -56
- data/packages/coffee-script/test/test.html +0 -123
- data/packages/coffee-script/test/test_chaining.coffee +0 -77
- data/packages/coffee-script/test/test_classes.coffee +0 -372
- data/packages/coffee-script/test/test_compilation.coffee +0 -26
- data/packages/coffee-script/test/test_comprehensions.coffee +0 -318
- data/packages/coffee-script/test/test_existence.coffee +0 -165
- data/packages/coffee-script/test/test_functions.coffee +0 -379
- data/packages/coffee-script/test/test_heredocs.coffee +0 -111
- data/packages/coffee-script/test/test_literals.coffee +0 -270
- data/packages/coffee-script/test/test_option_parser.coffee +0 -27
- data/packages/coffee-script/test/test_pattern_matching.coffee +0 -162
- data/packages/coffee-script/test/test_returns.coffee +0 -63
- data/packages/coffee-script/test/test_splats.coffee +0 -102
- data/packages/coffee-script/test/test_strings.coffee +0 -118
- data/packages/coffee-script/test/test_switch.coffee +0 -103
- data/packages/coffee-script/test/test_while.coffee +0 -71
- data/packages/ivory/LICENSE.txt +0 -1
- data/packages/ivory/README.md +0 -19
- data/packages/ivory/lib/buffer.js +0 -111
- data/packages/ivory/lib/events.js +0 -137
- data/packages/ivory/lib/fs.js +0 -266
- data/packages/ivory/lib/main.js +0 -13
- data/packages/ivory/lib/path.js +0 -158
- data/packages/ivory/lib/ruby/buffer.rb +0 -145
- data/packages/ivory/lib/ruby/constants.rb +0 -585
- data/packages/ivory/lib/ruby/events.rb +0 -32
- data/packages/ivory/lib/ruby/fs.rb +0 -245
- data/packages/ivory/lib/ruby/process.rb +0 -28
- data/packages/ivory/lib/stream.js +0 -115
- data/packages/ivory/lib/util.js +0 -414
- data/packages/ivory/package.json +0 -11
- data/packages/jquery/main.js +0 -7179
- data/packages/jquery/package.json +0 -10
- data/packages/json/lib/main.js +0 -14
- data/packages/json/package.json +0 -8
- data/packages/lproj/README.md +0 -77
- data/packages/lproj/examples/demo-app/en.lproj/localized.strings +0 -2
- data/packages/lproj/examples/demo-app/fr.lproj/localized.strings +0 -3
- data/packages/lproj/examples/demo-app/index.html +0 -8
- data/packages/lproj/examples/demo-app/lib/main.js +0 -7
- data/packages/lproj/examples/demo-app/package.json +0 -9
- data/packages/lproj/lib/main.js +0 -78
- data/packages/lproj/lib/strings-format.js +0 -6
- data/packages/lproj/package.json +0 -9
- data/packages/optparse/README.md +0 -161
- data/packages/optparse/TODO +0 -1
- data/packages/optparse/examples/browser-test.html +0 -75
- data/packages/optparse/examples/nodejs-test.js +0 -90
- data/packages/optparse/lib/optparse.js +0 -309
- data/packages/optparse/package.json +0 -13
- data/packages/optparse/seed.yml +0 -5
- data/packages/text/lib/main.js +0 -8
- data/packages/text/package.json +0 -9
- data/packages/web-file/README.md +0 -7
- data/packages/web-file/lib/errors.js +0 -32
- data/packages/web-file/lib/file-reader.js +0 -10
- data/packages/web-file/lib/file-system.js +0 -234
- data/packages/web-file/lib/file-writer.js +0 -10
- data/packages/web-file/lib/file.js +0 -9
- data/packages/web-file/lib/main.js +0 -34
- data/packages/web-file/lib/platform.js +0 -25
- data/packages/web-file/lib/ruby/file.rb +0 -252
- data/packages/web-file/lib/ruby/file_reader.rb +0 -69
- data/packages/web-file/lib/ruby/file_system.rb +0 -134
- data/packages/web-file/lib/ruby/file_writer.rb +0 -78
- data/packages/web-file/package.json +0 -12
- data/packages/web-typed-array/README.md +0 -7
- data/packages/web-typed-array/lib/array-buffer-view.js +0 -9
- data/packages/web-typed-array/lib/array-buffer.js +0 -7
- data/packages/web-typed-array/lib/main.js +0 -33
- data/packages/web-typed-array/lib/platform.js +0 -20
- data/packages/web-typed-array/lib/ruby/array_buffer.rb +0 -31
- data/packages/web-typed-array/lib/ruby/array_buffer_view.rb +0 -130
- data/packages/web-typed-array/lib/ruby/typed_array.rb +0 -133
- data/packages/web-typed-array/lib/typed-array.js +0 -26
- data/packages/web-typed-array/package.json +0 -9
- data/spec/cli/build_spec.rb +0 -59
- data/spec/cli/install_spec.rb +0 -120
- data/spec/cli/installed_spec.rb +0 -55
- data/spec/cli/list_spec.rb +0 -75
- data/spec/cli/login_spec.rb +0 -76
- data/spec/cli/new_spec.rb +0 -5
- data/spec/cli/owner_spec.rb +0 -115
- data/spec/cli/push_spec.rb +0 -74
- data/spec/cli/uninstall_spec.rb +0 -58
- data/spec/cli/unpack_spec.rb +0 -73
- data/spec/cli/unyank_spec.rb +0 -74
- data/spec/cli/update_spec.rb +0 -8
- data/spec/cli/yank_spec.rb +0 -74
- data/spec/credentials_spec.rb +0 -24
- data/spec/fixtures/coffee-1.0.1.pre.spd +0 -0
- data/spec/fixtures/core-test-0.4.3.spd +0 -0
- data/spec/fixtures/core-test/bin/cot +0 -3
- data/spec/fixtures/core-test/lib/main.js +0 -1
- data/spec/fixtures/core-test/resources/runner.css +0 -0
- data/spec/fixtures/core-test/tests/test.js +0 -1
- data/spec/fixtures/ivory-0.0.1.spd +0 -0
- data/spec/fixtures/jquery-1.4.3.spd +0 -0
- data/spec/fixtures/optparse-1.0.1.spd +0 -0
- data/spec/fixtures/package.json +0 -30
- data/spec/gauntlet_spec.rb +0 -27
- data/spec/javascript/async-test.js +0 -123
- data/spec/javascript/compiler/javascript.js +0 -13
- data/spec/javascript/compiler/ruby.js +0 -14
- data/spec/javascript/loader-test.js +0 -64
- data/spec/javascript/normalize-test.js +0 -73
- data/spec/javascript/packages-test.js +0 -44
- data/spec/javascript/relative-require-test.js +0 -72
- data/spec/javascript/require-test.js +0 -117
- data/spec/javascript/sandbox/compile.js +0 -37
- data/spec/javascript/sandbox/creation.js +0 -44
- data/spec/javascript/sandbox/format.js +0 -79
- data/spec/javascript/sandbox/misc.js +0 -57
- data/spec/javascript/sandbox/preprocessor.js +0 -81
- data/spec/javascript/sandbox/require.js +0 -48
- data/spec/javascript/sandbox/run-command.js +0 -21
- data/spec/javascript/spade/externs.js +0 -14
- data/spec/javascript/spade/load-factory.js +0 -15
- data/spec/javascript/spade/misc.js +0 -23
- data/spec/javascript/spade/ready.js +0 -12
- data/spec/javascript/spade/register.js +0 -13
- data/spec/javascript_spec.rb +0 -7
- data/spec/package_spec.rb +0 -267
- data/spec/spec_helper.rb +0 -30
- data/spec/support/cli.rb +0 -94
- data/spec/support/core_test.rb +0 -59
- data/spec/support/fake.rb +0 -44
- data/spec/support/fake_gem_server.rb +0 -66
- data/spec/support/fake_gemcutter.rb +0 -49
- data/spec/support/matchers.rb +0 -31
- data/spec/support/path.rb +0 -54
- data/test-spade.html +0 -8
@@ -1,56 +0,0 @@
|
|
1
|
-
# This file contains the common helper functions that we'd like to share among
|
2
|
-
# the **Lexer**, **Rewriter**, and the **Nodes**. Merge objects, flatten
|
3
|
-
# arrays, count characters, that sort of thing.
|
4
|
-
|
5
|
-
# Peek at the beginning of a given string to see if it matches a sequence.
|
6
|
-
exports.starts = (string, literal, start) ->
|
7
|
-
literal is string.substr start, literal.length
|
8
|
-
|
9
|
-
# Peek at the end of a given string to see if it matches a sequence.
|
10
|
-
exports.ends = (string, literal, back) ->
|
11
|
-
len = literal.length
|
12
|
-
literal is string.substr string.length - len - (back or 0), len
|
13
|
-
|
14
|
-
# Trim out all falsy values from an array.
|
15
|
-
exports.compact = (array) ->
|
16
|
-
item for item in array when item
|
17
|
-
|
18
|
-
# Count the number of occurrences of a string in a string.
|
19
|
-
exports.count = (string, substr) ->
|
20
|
-
num = pos = 0
|
21
|
-
return 1/0 unless substr.length
|
22
|
-
num++ while pos = 1 + string.indexOf substr, pos
|
23
|
-
num
|
24
|
-
|
25
|
-
# Merge objects, returning a fresh copy with attributes from both sides.
|
26
|
-
# Used every time `Base#compile` is called, to allow properties in the
|
27
|
-
# options hash to propagate down the tree without polluting other branches.
|
28
|
-
exports.merge = (options, overrides) ->
|
29
|
-
extend (extend {}, options), overrides
|
30
|
-
|
31
|
-
# Extend a source object with the properties of another object (shallow copy).
|
32
|
-
extend = exports.extend = (object, properties) ->
|
33
|
-
for key, val of properties
|
34
|
-
object[key] = val
|
35
|
-
object
|
36
|
-
|
37
|
-
# Return a flattened version of an array.
|
38
|
-
# Handy for getting a list of `children` from the nodes.
|
39
|
-
exports.flatten = flatten = (array) ->
|
40
|
-
flattened = []
|
41
|
-
for element in array
|
42
|
-
if element instanceof Array
|
43
|
-
flattened = flattened.concat flatten element
|
44
|
-
else
|
45
|
-
flattened.push element
|
46
|
-
flattened
|
47
|
-
|
48
|
-
# Delete a key from an object, returning the value. Useful when a node is
|
49
|
-
# looking for a particular method in an options hash.
|
50
|
-
exports.del = (obj, key) ->
|
51
|
-
val = obj[key]
|
52
|
-
delete obj[key]
|
53
|
-
val
|
54
|
-
|
55
|
-
# Gets the last item of an array(-like) object.
|
56
|
-
exports.last = (array, back) -> array[array.length - (back or 0) - 1]
|
@@ -1,653 +0,0 @@
|
|
1
|
-
# The CoffeeScript Lexer. Uses a series of token-matching regexes to attempt
|
2
|
-
# matches against the beginning of the source code. When a match is found,
|
3
|
-
# a token is produced, we consume the match, and start again. Tokens are in the
|
4
|
-
# form:
|
5
|
-
#
|
6
|
-
# [tag, value, lineNumber]
|
7
|
-
#
|
8
|
-
# Which is a format that can be fed directly into [Jison](http://github.com/zaach/jison).
|
9
|
-
|
10
|
-
{Rewriter} = require './rewriter'
|
11
|
-
|
12
|
-
# Import the helpers we need.
|
13
|
-
{count, starts, compact, last} = require './helpers'
|
14
|
-
|
15
|
-
# The Lexer Class
|
16
|
-
# ---------------
|
17
|
-
|
18
|
-
# The Lexer class reads a stream of CoffeeScript and divvies it up into tagged
|
19
|
-
# tokens. Some potential ambiguity in the grammar has been avoided by
|
20
|
-
# pushing some extra smarts into the Lexer.
|
21
|
-
exports.Lexer = class Lexer
|
22
|
-
|
23
|
-
# **tokenize** is the Lexer's main method. Scan by attempting to match tokens
|
24
|
-
# one at a time, using a regular expression anchored at the start of the
|
25
|
-
# remaining code, or a custom recursive token-matching method
|
26
|
-
# (for interpolations). When the next token has been recorded, we move forward
|
27
|
-
# within the code past the token, and begin again.
|
28
|
-
#
|
29
|
-
# Each tokenizing method is responsible for returning the number of characters
|
30
|
-
# it has consumed.
|
31
|
-
#
|
32
|
-
# Before returning the token stream, run it through the [Rewriter](rewriter.html)
|
33
|
-
# unless explicitly asked not to.
|
34
|
-
tokenize: (code, opts = {}) ->
|
35
|
-
code = code.replace(/\r/g, '').replace TRAILING_SPACES, ''
|
36
|
-
|
37
|
-
@code = code # The remainder of the source code.
|
38
|
-
@line = opts.line or 0 # The current line.
|
39
|
-
@indent = 0 # The current indentation level.
|
40
|
-
@indebt = 0 # The over-indentation at the current level.
|
41
|
-
@outdebt = 0 # The under-outdentation at the current level.
|
42
|
-
@indents = [] # The stack of all current indentation levels.
|
43
|
-
@tokens = [] # Stream of parsed tokens in the form `['TYPE', value, line]`.
|
44
|
-
|
45
|
-
# At every position, run through this list of attempted matches,
|
46
|
-
# short-circuiting if any of them succeed. Their order determines precedence:
|
47
|
-
# `@literalToken` is the fallback catch-all.
|
48
|
-
i = 0
|
49
|
-
while @chunk = code.slice i
|
50
|
-
i += @identifierToken() or
|
51
|
-
@commentToken() or
|
52
|
-
@whitespaceToken() or
|
53
|
-
@lineToken() or
|
54
|
-
@heredocToken() or
|
55
|
-
@stringToken() or
|
56
|
-
@numberToken() or
|
57
|
-
@regexToken() or
|
58
|
-
@jsToken() or
|
59
|
-
@literalToken()
|
60
|
-
|
61
|
-
@closeIndentation()
|
62
|
-
return @tokens if opts.rewrite is off
|
63
|
-
(new Rewriter).rewrite @tokens
|
64
|
-
|
65
|
-
# Tokenizers
|
66
|
-
# ----------
|
67
|
-
|
68
|
-
# Matches identifying literals: variables, keywords, method names, etc.
|
69
|
-
# Check to ensure that JavaScript reserved words aren't being used as
|
70
|
-
# identifiers. Because CoffeeScript reserves a handful of keywords that are
|
71
|
-
# allowed in JavaScript, we're careful not to tag them as keywords when
|
72
|
-
# referenced as property names here, so you can still do `jQuery.is()` even
|
73
|
-
# though `is` means `===` otherwise.
|
74
|
-
identifierToken: ->
|
75
|
-
return 0 unless match = IDENTIFIER.exec @chunk
|
76
|
-
[input, id, colon] = match
|
77
|
-
|
78
|
-
if id is 'own' and @tag() is 'FOR'
|
79
|
-
@token 'OWN', id
|
80
|
-
return id.length
|
81
|
-
forcedIdentifier = colon or
|
82
|
-
(prev = last @tokens) and not prev.spaced and prev[0] in ['.', '?.', '@', '::']
|
83
|
-
tag = 'IDENTIFIER'
|
84
|
-
|
85
|
-
if id in JS_KEYWORDS or
|
86
|
-
not forcedIdentifier and id in COFFEE_KEYWORDS
|
87
|
-
tag = id.toUpperCase()
|
88
|
-
if tag is 'WHEN' and @tag() in LINE_BREAK
|
89
|
-
tag = 'LEADING_WHEN'
|
90
|
-
else if tag is 'FOR'
|
91
|
-
@seenFor = yes
|
92
|
-
else if tag is 'UNLESS'
|
93
|
-
tag = 'IF'
|
94
|
-
else if tag in UNARY
|
95
|
-
tag = 'UNARY'
|
96
|
-
else if tag in RELATION
|
97
|
-
if tag isnt 'INSTANCEOF' and @seenFor
|
98
|
-
tag = 'FOR' + tag
|
99
|
-
@seenFor = no
|
100
|
-
else
|
101
|
-
tag = 'RELATION'
|
102
|
-
if @value() is '!'
|
103
|
-
@tokens.pop()
|
104
|
-
id = '!' + id
|
105
|
-
|
106
|
-
if id in JS_FORBIDDEN
|
107
|
-
if forcedIdentifier
|
108
|
-
tag = 'IDENTIFIER'
|
109
|
-
id = new String id
|
110
|
-
id.reserved = yes
|
111
|
-
else if id in RESERVED
|
112
|
-
@identifierError id
|
113
|
-
|
114
|
-
unless forcedIdentifier
|
115
|
-
id = COFFEE_ALIASES[id] if COFFEE_ALIASES.hasOwnProperty id
|
116
|
-
tag = switch id
|
117
|
-
when '!' then 'UNARY'
|
118
|
-
when '==', '!=' then 'COMPARE'
|
119
|
-
when '&&', '||' then 'LOGIC'
|
120
|
-
when 'true', 'false', 'null', 'undefined' then 'BOOL'
|
121
|
-
when 'break', 'continue', 'debugger' then 'STATEMENT'
|
122
|
-
else tag
|
123
|
-
|
124
|
-
@token tag, id
|
125
|
-
@token ':', ':' if colon
|
126
|
-
input.length
|
127
|
-
|
128
|
-
# Matches numbers, including decimals, hex, and exponential notation.
|
129
|
-
# Be careful not to interfere with ranges-in-progress.
|
130
|
-
numberToken: ->
|
131
|
-
return 0 unless match = NUMBER.exec @chunk
|
132
|
-
number = match[0]
|
133
|
-
@token 'NUMBER', number
|
134
|
-
number.length
|
135
|
-
|
136
|
-
# Matches strings, including multi-line strings. Ensures that quotation marks
|
137
|
-
# are balanced within the string's contents, and within nested interpolations.
|
138
|
-
stringToken: ->
|
139
|
-
switch @chunk.charAt 0
|
140
|
-
when "'"
|
141
|
-
return 0 unless match = SIMPLESTR.exec @chunk
|
142
|
-
@token 'STRING', (string = match[0]).replace MULTILINER, '\\\n'
|
143
|
-
when '"'
|
144
|
-
return 0 unless string = @balancedString @chunk, '"'
|
145
|
-
if 0 < string.indexOf '#{', 1
|
146
|
-
@interpolateString string.slice 1, -1
|
147
|
-
else
|
148
|
-
@token 'STRING', @escapeLines string
|
149
|
-
else
|
150
|
-
return 0
|
151
|
-
@line += count string, '\n'
|
152
|
-
string.length
|
153
|
-
|
154
|
-
# Matches heredocs, adjusting indentation to the correct level, as heredocs
|
155
|
-
# preserve whitespace, but ignore indentation to the left.
|
156
|
-
heredocToken: ->
|
157
|
-
return 0 unless match = HEREDOC.exec @chunk
|
158
|
-
heredoc = match[0]
|
159
|
-
quote = heredoc.charAt 0
|
160
|
-
doc = @sanitizeHeredoc match[2], quote: quote, indent: null
|
161
|
-
if quote is '"' and 0 <= doc.indexOf '#{'
|
162
|
-
@interpolateString doc, heredoc: yes
|
163
|
-
else
|
164
|
-
@token 'STRING', @makeString doc, quote, yes
|
165
|
-
@line += count heredoc, '\n'
|
166
|
-
heredoc.length
|
167
|
-
|
168
|
-
# Matches and consumes comments.
|
169
|
-
commentToken: ->
|
170
|
-
return 0 unless match = @chunk.match COMMENT
|
171
|
-
[comment, here] = match
|
172
|
-
@line += count comment, '\n'
|
173
|
-
if here
|
174
|
-
@token 'HERECOMMENT', @sanitizeHeredoc here,
|
175
|
-
herecomment: true, indent: Array(@indent + 1).join(' ')
|
176
|
-
@token 'TERMINATOR', '\n'
|
177
|
-
comment.length
|
178
|
-
|
179
|
-
# Matches JavaScript interpolated directly into the source via backticks.
|
180
|
-
jsToken: ->
|
181
|
-
return 0 unless @chunk.charAt(0) is '`' and match = JSTOKEN.exec @chunk
|
182
|
-
@token 'JS', (script = match[0]).slice 1, -1
|
183
|
-
script.length
|
184
|
-
|
185
|
-
# Matches regular expression literals. Lexing regular expressions is difficult
|
186
|
-
# to distinguish from division, so we borrow some basic heuristics from
|
187
|
-
# JavaScript and Ruby.
|
188
|
-
regexToken: ->
|
189
|
-
return 0 if @chunk.charAt(0) isnt '/'
|
190
|
-
return @heregexToken match if match = HEREGEX.exec @chunk
|
191
|
-
prev = last @tokens
|
192
|
-
return 0 if prev and (prev[0] in (if prev.spaced then NOT_REGEX else NOT_SPACED_REGEX))
|
193
|
-
return 0 unless match = REGEX.exec @chunk
|
194
|
-
[regex] = match
|
195
|
-
@token 'REGEX', if regex is '//' then '/(?:)/' else regex
|
196
|
-
regex.length
|
197
|
-
|
198
|
-
# Matches multiline extended regular expressions.
|
199
|
-
heregexToken: (match) ->
|
200
|
-
[heregex, body, flags] = match
|
201
|
-
if 0 > body.indexOf '#{'
|
202
|
-
re = body.replace(HEREGEX_OMIT, '').replace(/\//g, '\\/')
|
203
|
-
@token 'REGEX', "/#{ re or '(?:)' }/#{flags}"
|
204
|
-
return heregex.length
|
205
|
-
@token 'IDENTIFIER', 'RegExp'
|
206
|
-
@tokens.push ['CALL_START', '(']
|
207
|
-
tokens = []
|
208
|
-
for [tag, value] in @interpolateString(body, regex: yes)
|
209
|
-
if tag is 'TOKENS'
|
210
|
-
tokens.push value...
|
211
|
-
else
|
212
|
-
continue unless value = value.replace HEREGEX_OMIT, ''
|
213
|
-
value = value.replace /\\/g, '\\\\'
|
214
|
-
tokens.push ['STRING', @makeString(value, '"', yes)]
|
215
|
-
tokens.push ['+', '+']
|
216
|
-
tokens.pop()
|
217
|
-
@tokens.push ['STRING', '""'], ['+', '+'] unless tokens[0]?[0] is 'STRING'
|
218
|
-
@tokens.push tokens...
|
219
|
-
@tokens.push [',', ','], ['STRING', '"' + flags + '"'] if flags
|
220
|
-
@token ')', ')'
|
221
|
-
heregex.length
|
222
|
-
|
223
|
-
# Matches newlines, indents, and outdents, and determines which is which.
|
224
|
-
# If we can detect that the current line is continued onto the the next line,
|
225
|
-
# then the newline is suppressed:
|
226
|
-
#
|
227
|
-
# elements
|
228
|
-
# .each( ... )
|
229
|
-
# .map( ... )
|
230
|
-
#
|
231
|
-
# Keeps track of the level of indentation, because a single outdent token
|
232
|
-
# can close multiple indents, so we need to know how far in we happen to be.
|
233
|
-
lineToken: ->
|
234
|
-
return 0 unless match = MULTI_DENT.exec @chunk
|
235
|
-
indent = match[0]
|
236
|
-
@line += count indent, '\n'
|
237
|
-
prev = last @tokens, 1
|
238
|
-
size = indent.length - 1 - indent.lastIndexOf '\n'
|
239
|
-
noNewlines = @unfinished()
|
240
|
-
if size - @indebt is @indent
|
241
|
-
if noNewlines then @suppressNewlines() else @newlineToken()
|
242
|
-
return indent.length
|
243
|
-
if size > @indent
|
244
|
-
if noNewlines
|
245
|
-
@indebt = size - @indent
|
246
|
-
@suppressNewlines()
|
247
|
-
return indent.length
|
248
|
-
diff = size - @indent + @outdebt
|
249
|
-
@token 'INDENT', diff
|
250
|
-
@indents.push diff
|
251
|
-
@outdebt = @indebt = 0
|
252
|
-
else
|
253
|
-
@indebt = 0
|
254
|
-
@outdentToken @indent - size, noNewlines
|
255
|
-
@indent = size
|
256
|
-
indent.length
|
257
|
-
|
258
|
-
# Record an outdent token or multiple tokens, if we happen to be moving back
|
259
|
-
# inwards past several recorded indents.
|
260
|
-
outdentToken: (moveOut, noNewlines, close) ->
|
261
|
-
while moveOut > 0
|
262
|
-
len = @indents.length - 1
|
263
|
-
if @indents[len] is undefined
|
264
|
-
moveOut = 0
|
265
|
-
else if @indents[len] is @outdebt
|
266
|
-
moveOut -= @outdebt
|
267
|
-
@outdebt = 0
|
268
|
-
else if @indents[len] < @outdebt
|
269
|
-
@outdebt -= @indents[len]
|
270
|
-
moveOut -= @indents[len]
|
271
|
-
else
|
272
|
-
dent = @indents.pop() - @outdebt
|
273
|
-
moveOut -= dent
|
274
|
-
@outdebt = 0
|
275
|
-
@token 'OUTDENT', dent
|
276
|
-
@outdebt -= moveOut if dent
|
277
|
-
@token 'TERMINATOR', '\n' unless @tag() is 'TERMINATOR' or noNewlines
|
278
|
-
this
|
279
|
-
|
280
|
-
# Matches and consumes non-meaningful whitespace. Tag the previous token
|
281
|
-
# as being "spaced", because there are some cases where it makes a difference.
|
282
|
-
whitespaceToken: ->
|
283
|
-
return 0 unless (match = WHITESPACE.exec @chunk) or
|
284
|
-
(nline = @chunk.charAt(0) is '\n')
|
285
|
-
prev = last @tokens
|
286
|
-
prev[if match then 'spaced' else 'newLine'] = true if prev
|
287
|
-
if match then match[0].length else 0
|
288
|
-
|
289
|
-
# Generate a newline token. Consecutive newlines get merged together.
|
290
|
-
newlineToken: ->
|
291
|
-
@token 'TERMINATOR', '\n' unless @tag() is 'TERMINATOR'
|
292
|
-
this
|
293
|
-
|
294
|
-
# Use a `\` at a line-ending to suppress the newline.
|
295
|
-
# The slash is removed here once its job is done.
|
296
|
-
suppressNewlines: ->
|
297
|
-
@tokens.pop() if @value() is '\\'
|
298
|
-
this
|
299
|
-
|
300
|
-
# We treat all other single characters as a token. E.g.: `( ) , . !`
|
301
|
-
# Multi-character operators are also literal tokens, so that Jison can assign
|
302
|
-
# the proper order of operations. There are some symbols that we tag specially
|
303
|
-
# here. `;` and newlines are both treated as a `TERMINATOR`, we distinguish
|
304
|
-
# parentheses that indicate a method call from regular parentheses, and so on.
|
305
|
-
literalToken: ->
|
306
|
-
if match = OPERATOR.exec @chunk
|
307
|
-
[value] = match
|
308
|
-
@tagParameters() if CODE.test value
|
309
|
-
else
|
310
|
-
value = @chunk.charAt 0
|
311
|
-
tag = value
|
312
|
-
prev = last @tokens
|
313
|
-
if value is '=' and prev
|
314
|
-
@assignmentError() if not prev[1].reserved and prev[1] in JS_FORBIDDEN
|
315
|
-
if prev[1] in ['||', '&&']
|
316
|
-
prev[0] = 'COMPOUND_ASSIGN'
|
317
|
-
prev[1] += '='
|
318
|
-
return value.length
|
319
|
-
if value is ';' then tag = 'TERMINATOR'
|
320
|
-
else if value in MATH then tag = 'MATH'
|
321
|
-
else if value in COMPARE then tag = 'COMPARE'
|
322
|
-
else if value in COMPOUND_ASSIGN then tag = 'COMPOUND_ASSIGN'
|
323
|
-
else if value in UNARY then tag = 'UNARY'
|
324
|
-
else if value in SHIFT then tag = 'SHIFT'
|
325
|
-
else if value in LOGIC or value is '?' and prev?.spaced then tag = 'LOGIC'
|
326
|
-
else if prev and not prev.spaced
|
327
|
-
if value is '(' and prev[0] in CALLABLE
|
328
|
-
prev[0] = 'FUNC_EXIST' if prev[0] is '?'
|
329
|
-
tag = 'CALL_START'
|
330
|
-
else if value is '[' and prev[0] in INDEXABLE
|
331
|
-
tag = 'INDEX_START'
|
332
|
-
switch prev[0]
|
333
|
-
when '?' then prev[0] = 'INDEX_SOAK'
|
334
|
-
when '::' then prev[0] = 'INDEX_PROTO'
|
335
|
-
@token tag, value
|
336
|
-
value.length
|
337
|
-
|
338
|
-
# Token Manipulators
|
339
|
-
# ------------------
|
340
|
-
|
341
|
-
# Sanitize a heredoc or herecomment by
|
342
|
-
# erasing all external indentation on the left-hand side.
|
343
|
-
sanitizeHeredoc: (doc, options) ->
|
344
|
-
{indent, herecomment} = options
|
345
|
-
return doc if herecomment and 0 > doc.indexOf '\n'
|
346
|
-
unless herecomment
|
347
|
-
while match = HEREDOC_INDENT.exec doc
|
348
|
-
attempt = match[1]
|
349
|
-
indent = attempt if indent is null or 0 < attempt.length < indent.length
|
350
|
-
doc = doc.replace /// \n #{indent} ///g, '\n' if indent
|
351
|
-
doc = doc.replace /^\n/, '' unless herecomment
|
352
|
-
doc
|
353
|
-
|
354
|
-
# A source of ambiguity in our grammar used to be parameter lists in function
|
355
|
-
# definitions versus argument lists in function calls. Walk backwards, tagging
|
356
|
-
# parameters specially in order to make things easier for the parser.
|
357
|
-
tagParameters: ->
|
358
|
-
return this if @tag() isnt ')'
|
359
|
-
stack = []
|
360
|
-
{tokens} = this
|
361
|
-
i = tokens.length
|
362
|
-
tokens[--i][0] = 'PARAM_END'
|
363
|
-
while tok = tokens[--i]
|
364
|
-
switch tok[0]
|
365
|
-
when ')'
|
366
|
-
stack.push tok
|
367
|
-
when '(', 'CALL_START'
|
368
|
-
if stack.length then stack.pop()
|
369
|
-
else
|
370
|
-
tok[0] = 'PARAM_START'
|
371
|
-
return this
|
372
|
-
this
|
373
|
-
|
374
|
-
# Close up all remaining open blocks at the end of the file.
|
375
|
-
closeIndentation: ->
|
376
|
-
@outdentToken @indent
|
377
|
-
|
378
|
-
# The error for when you try to use a forbidden word in JavaScript as
|
379
|
-
# an identifier.
|
380
|
-
identifierError: (word) ->
|
381
|
-
throw SyntaxError "Reserved word \"#{word}\" on line #{@line + 1}"
|
382
|
-
|
383
|
-
# The error for when you try to assign to a reserved word in JavaScript,
|
384
|
-
# like "function" or "default".
|
385
|
-
assignmentError: ->
|
386
|
-
throw SyntaxError "Reserved word \"#{@value()}\" on line #{@line + 1} can't be assigned"
|
387
|
-
|
388
|
-
# Matches a balanced group such as a single or double-quoted string. Pass in
|
389
|
-
# a series of delimiters, all of which must be nested correctly within the
|
390
|
-
# contents of the string. This method allows us to have strings within
|
391
|
-
# interpolations within strings, ad infinitum.
|
392
|
-
balancedString: (str, end) ->
|
393
|
-
stack = [end]
|
394
|
-
for i in [1...str.length]
|
395
|
-
switch letter = str.charAt i
|
396
|
-
when '\\'
|
397
|
-
i++
|
398
|
-
continue
|
399
|
-
when end
|
400
|
-
stack.pop()
|
401
|
-
unless stack.length
|
402
|
-
return str.slice 0, i + 1
|
403
|
-
end = stack[stack.length - 1]
|
404
|
-
continue
|
405
|
-
if end is '}' and letter in ['"', "'"]
|
406
|
-
stack.push end = letter
|
407
|
-
else if end is '}' and letter is '{'
|
408
|
-
stack.push end = '}'
|
409
|
-
else if end is '"' and prev is '#' and letter is '{'
|
410
|
-
stack.push end = '}'
|
411
|
-
prev = letter
|
412
|
-
throw new Error "missing #{ stack.pop() }, starting on line #{ @line + 1 }"
|
413
|
-
|
414
|
-
|
415
|
-
# Expand variables and expressions inside double-quoted strings using
|
416
|
-
# Ruby-like notation for substitution of arbitrary expressions.
|
417
|
-
#
|
418
|
-
# "Hello #{name.capitalize()}."
|
419
|
-
#
|
420
|
-
# If it encounters an interpolation, this method will recursively create a
|
421
|
-
# new Lexer, tokenize the interpolated contents, and merge them into the
|
422
|
-
# token stream.
|
423
|
-
interpolateString: (str, options = {}) ->
|
424
|
-
{heredoc, regex} = options
|
425
|
-
tokens = []
|
426
|
-
pi = 0
|
427
|
-
i = -1
|
428
|
-
while letter = str.charAt i += 1
|
429
|
-
if letter is '\\'
|
430
|
-
i += 1
|
431
|
-
continue
|
432
|
-
unless letter is '#' and str.charAt(i+1) is '{' and
|
433
|
-
(expr = @balancedString str.slice(i + 1), '}')
|
434
|
-
continue
|
435
|
-
tokens.push ['NEOSTRING', str.slice(pi, i)] if pi < i
|
436
|
-
inner = expr.slice(1, -1)
|
437
|
-
if inner.length
|
438
|
-
nested = new Lexer().tokenize inner, line: @line, rewrite: off
|
439
|
-
nested.pop()
|
440
|
-
nested.shift() if nested[0]?[0] is 'TERMINATOR'
|
441
|
-
if nested.length > 1
|
442
|
-
nested.unshift ['(', '(']
|
443
|
-
nested.push [')', ')']
|
444
|
-
tokens.push ['TOKENS', nested]
|
445
|
-
i += expr.length
|
446
|
-
pi = i + 1
|
447
|
-
tokens.push ['NEOSTRING', str.slice pi] if i > pi < str.length
|
448
|
-
return tokens if regex
|
449
|
-
return @token 'STRING', '""' unless tokens.length
|
450
|
-
tokens.unshift ['', ''] unless tokens[0][0] is 'NEOSTRING'
|
451
|
-
@token '(', '(' if interpolated = tokens.length > 1
|
452
|
-
for [tag, value], i in tokens
|
453
|
-
@token '+', '+' if i
|
454
|
-
if tag is 'TOKENS'
|
455
|
-
@tokens.push value...
|
456
|
-
else
|
457
|
-
@token 'STRING', @makeString value, '"', heredoc
|
458
|
-
@token ')', ')' if interpolated
|
459
|
-
tokens
|
460
|
-
|
461
|
-
# Helpers
|
462
|
-
# -------
|
463
|
-
|
464
|
-
# Add a token to the results, taking note of the line number.
|
465
|
-
token: (tag, value) ->
|
466
|
-
@tokens.push [tag, value, @line]
|
467
|
-
|
468
|
-
# Peek at a tag in the current token stream.
|
469
|
-
tag: (index, tag) ->
|
470
|
-
(tok = last @tokens, index) and if tag then tok[0] = tag else tok[0]
|
471
|
-
|
472
|
-
# Peek at a value in the current token stream.
|
473
|
-
value: (index, val) ->
|
474
|
-
(tok = last @tokens, index) and if val then tok[1] = val else tok[1]
|
475
|
-
|
476
|
-
# Are we in the midst of an unfinished expression?
|
477
|
-
unfinished: ->
|
478
|
-
LINE_CONTINUER.test(@chunk) or
|
479
|
-
(prev = last @tokens, 1) and prev[0] isnt '.' and
|
480
|
-
(value = @value()) and not value.reserved and
|
481
|
-
NO_NEWLINE.test(value) and not CODE.test(value) and not ASSIGNED.test(@chunk)
|
482
|
-
|
483
|
-
# Converts newlines for string literals.
|
484
|
-
escapeLines: (str, heredoc) ->
|
485
|
-
str.replace MULTILINER, if heredoc then '\\n' else ''
|
486
|
-
|
487
|
-
# Constructs a string token by escaping quotes and newlines.
|
488
|
-
makeString: (body, quote, heredoc) ->
|
489
|
-
return quote + quote unless body
|
490
|
-
body = body.replace /\\([\s\S])/g, (match, contents) ->
|
491
|
-
if contents in ['\n', quote] then contents else match
|
492
|
-
body = body.replace /// #{quote} ///g, '\\$&'
|
493
|
-
quote + @escapeLines(body, heredoc) + quote
|
494
|
-
|
495
|
-
# Constants
|
496
|
-
# ---------
|
497
|
-
|
498
|
-
# Keywords that CoffeeScript shares in common with JavaScript.
|
499
|
-
JS_KEYWORDS = [
|
500
|
-
'true', 'false', 'null', 'this'
|
501
|
-
'new', 'delete', 'typeof', 'in', 'instanceof'
|
502
|
-
'return', 'throw', 'break', 'continue', 'debugger'
|
503
|
-
'if', 'else', 'switch', 'for', 'while', 'do', 'try', 'catch', 'finally'
|
504
|
-
'class', 'extends', 'super'
|
505
|
-
]
|
506
|
-
|
507
|
-
# CoffeeScript-only keywords.
|
508
|
-
COFFEE_KEYWORDS = ['undefined', 'then', 'unless', 'until', 'loop', 'of', 'by', 'when']
|
509
|
-
COFFEE_KEYWORDS.push op for op of COFFEE_ALIASES =
|
510
|
-
and : '&&'
|
511
|
-
or : '||'
|
512
|
-
is : '=='
|
513
|
-
isnt : '!='
|
514
|
-
not : '!'
|
515
|
-
yes : 'true'
|
516
|
-
no : 'false'
|
517
|
-
on : 'true'
|
518
|
-
off : 'false'
|
519
|
-
|
520
|
-
# The list of keywords that are reserved by JavaScript, but not used, or are
|
521
|
-
# used by CoffeeScript internally. We throw an error when these are encountered,
|
522
|
-
# to avoid having a JavaScript error at runtime.
|
523
|
-
RESERVED = [
|
524
|
-
'case', 'default', 'function', 'var', 'void', 'with'
|
525
|
-
'const', 'let', 'enum', 'export', 'import', 'native'
|
526
|
-
'__hasProp', '__extends', '__slice', '__bind', '__indexOf'
|
527
|
-
]
|
528
|
-
|
529
|
-
# The superset of both JavaScript keywords and reserved words, none of which may
|
530
|
-
# be used as identifiers or properties.
|
531
|
-
JS_FORBIDDEN = JS_KEYWORDS.concat RESERVED
|
532
|
-
|
533
|
-
exports.RESERVED = RESERVED.concat(JS_KEYWORDS).concat(COFFEE_KEYWORDS)
|
534
|
-
|
535
|
-
# Token matching regexes.
|
536
|
-
IDENTIFIER = /// ^
|
537
|
-
( [$A-Za-z_][$\w]* )
|
538
|
-
( [^\n\S]* : (?!:) )? # Is this a property name?
|
539
|
-
///
|
540
|
-
|
541
|
-
NUMBER = ///
|
542
|
-
^ 0x[\da-f]+ | # hex
|
543
|
-
^ (?: \d+(\.\d+)? | \.\d+ ) (?:e[+-]?\d+)? # decimal
|
544
|
-
///i
|
545
|
-
|
546
|
-
HEREDOC = /// ^ ("""|''') ([\s\S]*?) (?:\n[^\n\S]*)? \1 ///
|
547
|
-
|
548
|
-
OPERATOR = /// ^ (
|
549
|
-
?: [-=]> # function
|
550
|
-
| [-+*/%<>&|^!?=]= # compound assign / compare
|
551
|
-
| >>>=? # zero-fill right shift
|
552
|
-
| ([-+:])\1 # doubles
|
553
|
-
| ([&|<>])\2=? # logic / shift
|
554
|
-
| \?\. # soak access
|
555
|
-
| \.{2,3} # range or splat
|
556
|
-
) ///
|
557
|
-
|
558
|
-
WHITESPACE = /^[^\n\S]+/
|
559
|
-
|
560
|
-
COMMENT = /^###([^#][\s\S]*?)(?:###[^\n\S]*|(?:###)?$)|^(?:\s*#(?!##[^#]).*)+/
|
561
|
-
|
562
|
-
CODE = /^[-=]>/
|
563
|
-
|
564
|
-
MULTI_DENT = /^(?:\n[^\n\S]*)+/
|
565
|
-
|
566
|
-
SIMPLESTR = /^'[^\\']*(?:\\.[^\\']*)*'/
|
567
|
-
|
568
|
-
JSTOKEN = /^`[^\\`]*(?:\\.[^\\`]*)*`/
|
569
|
-
|
570
|
-
# Regex-matching-regexes.
|
571
|
-
REGEX = /// ^
|
572
|
-
/ (?! \s ) # disallow leading whitespace
|
573
|
-
[^ [ / \n \\ ]* # every other thing
|
574
|
-
(?:
|
575
|
-
(?: \\[\s\S] # anything escaped
|
576
|
-
| \[ # character class
|
577
|
-
[^ \] \n \\ ]*
|
578
|
-
(?: \\[\s\S] [^ \] \n \\ ]* )*
|
579
|
-
]
|
580
|
-
) [^ [ / \n \\ ]*
|
581
|
-
)*
|
582
|
-
/ [imgy]{0,4} (?!\w)
|
583
|
-
///
|
584
|
-
|
585
|
-
HEREGEX = /// ^ /{3} ([\s\S]+?) /{3} ([imgy]{0,4}) (?!\w) ///
|
586
|
-
|
587
|
-
HEREGEX_OMIT = /\s+(?:#.*)?/g
|
588
|
-
|
589
|
-
# Token cleaning regexes.
|
590
|
-
MULTILINER = /\n/g
|
591
|
-
|
592
|
-
HEREDOC_INDENT = /\n+([^\n\S]*)/g
|
593
|
-
|
594
|
-
ASSIGNED = /^\s*@?([$A-Za-z_][$\w]*|['"].*['"])[^\n\S]*?[:=][^:=>]/
|
595
|
-
|
596
|
-
LINE_CONTINUER = /// ^ \s* (?: , | \??\.(?!\.) | :: ) ///
|
597
|
-
|
598
|
-
TRAILING_SPACES = /\s+$/
|
599
|
-
|
600
|
-
NO_NEWLINE = /// ^ (?: # non-capturing group
|
601
|
-
[-+*&|/%=<>!.\\][<>=&|]* | # symbol operators
|
602
|
-
and | or | is(?:nt)? | n(?:ot|ew) | # word operators
|
603
|
-
delete | typeof | instanceof
|
604
|
-
) $ ///
|
605
|
-
|
606
|
-
# Compound assignment tokens.
|
607
|
-
COMPOUND_ASSIGN = [
|
608
|
-
'-=', '+=', '/=', '*=', '%=', '||=', '&&=', '?=', '<<=', '>>=', '>>>=', '&=', '^=', '|='
|
609
|
-
]
|
610
|
-
|
611
|
-
# Unary tokens.
|
612
|
-
UNARY = ['!', '~', 'NEW', 'TYPEOF', 'DELETE', 'DO']
|
613
|
-
|
614
|
-
# Logical tokens.
|
615
|
-
LOGIC = ['&&', '||', '&', '|', '^']
|
616
|
-
|
617
|
-
# Bit-shifting tokens.
|
618
|
-
SHIFT = ['<<', '>>', '>>>']
|
619
|
-
|
620
|
-
# Comparison tokens.
|
621
|
-
COMPARE = ['==', '!=', '<', '>', '<=', '>=']
|
622
|
-
|
623
|
-
# Mathematical tokens.
|
624
|
-
MATH = ['*', '/', '%']
|
625
|
-
|
626
|
-
# Relational tokens that are negatable with `not` prefix.
|
627
|
-
RELATION = ['IN', 'OF', 'INSTANCEOF']
|
628
|
-
|
629
|
-
# Boolean tokens.
|
630
|
-
BOOL = ['TRUE', 'FALSE', 'NULL', 'UNDEFINED']
|
631
|
-
|
632
|
-
# Tokens which a regular expression will never immediately follow, but which
|
633
|
-
# a division operator might.
|
634
|
-
#
|
635
|
-
# See: http://www.mozilla.org/js/language/js20-2002-04/rationale/syntax.html#regular-expressions
|
636
|
-
#
|
637
|
-
# Our list is shorter, due to sans-parentheses method calls.
|
638
|
-
NOT_REGEX = ['NUMBER', 'REGEX', 'BOOL', '++', '--', ']']
|
639
|
-
|
640
|
-
# If the previous token is not spaced, there are more preceding tokens that
|
641
|
-
# force a division parse:
|
642
|
-
NOT_SPACED_REGEX = NOT_REGEX.concat ')', '}', 'THIS', 'IDENTIFIER', 'STRING'
|
643
|
-
|
644
|
-
# Tokens which could legitimately be invoked or indexed. A opening
|
645
|
-
# parentheses or bracket following these tokens will be recorded as the start
|
646
|
-
# of a function invocation or indexing operation.
|
647
|
-
CALLABLE = ['IDENTIFIER', 'STRING', 'REGEX', ')', ']', '}', '?', '::', '@', 'THIS', 'SUPER']
|
648
|
-
INDEXABLE = CALLABLE.concat 'NUMBER', 'BOOL'
|
649
|
-
|
650
|
-
# Tokens that, when immediately preceding a `WHEN`, indicate that the `WHEN`
|
651
|
-
# occurs at the start of a line. We disambiguate these from trailing whens to
|
652
|
-
# avoid an ambiguity in the grammar.
|
653
|
-
LINE_BREAK = ['INDENT', 'OUTDENT', 'TERMINATOR']
|