haml-more 0.4.0.a
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.md +79 -0
- data/lib/haml/more/coffee_script.rb +137 -0
- data/lib/haml/more/content_for.rb +25 -0
- data/lib/haml/more.rb +45 -0
- data/lib/haml-more.rb +1 -0
- data/lib/sass/more.rb +16 -0
- data/lib/sass-more.rb +1 -0
- data/spec/sass/more_spec.rb +21 -0
- data/vendor/coffee-script/Cakefile +57 -0
- data/vendor/coffee-script/LICENSE +22 -0
- data/vendor/coffee-script/README +41 -0
- data/vendor/coffee-script/Rakefile +20 -0
- data/vendor/coffee-script/bin/cake +7 -0
- data/vendor/coffee-script/bin/coffee +7 -0
- data/vendor/coffee-script/documentation/coffee/aliases.coffee +9 -0
- data/vendor/coffee-script/documentation/coffee/arguments.coffee +4 -0
- data/vendor/coffee-script/documentation/coffee/array_comprehensions.coffee +7 -0
- data/vendor/coffee-script/documentation/coffee/assignment.coffee +2 -0
- data/vendor/coffee-script/documentation/coffee/cake_tasks.coffee +5 -0
- data/vendor/coffee-script/documentation/coffee/comparisons.coffee +5 -0
- data/vendor/coffee-script/documentation/coffee/conditionals.coffee +9 -0
- data/vendor/coffee-script/documentation/coffee/embedded.coffee +5 -0
- data/vendor/coffee-script/documentation/coffee/existence.coffee +8 -0
- data/vendor/coffee-script/documentation/coffee/expressions.coffee +9 -0
- data/vendor/coffee-script/documentation/coffee/expressions_assignment.coffee +1 -0
- data/vendor/coffee-script/documentation/coffee/expressions_comprehension.coffee +3 -0
- data/vendor/coffee-script/documentation/coffee/expressions_try.coffee +6 -0
- data/vendor/coffee-script/documentation/coffee/fat_arrow.coffee +6 -0
- data/vendor/coffee-script/documentation/coffee/functions.coffee +2 -0
- data/vendor/coffee-script/documentation/coffee/heredocs.coffee +5 -0
- data/vendor/coffee-script/documentation/coffee/multiple_return_values.coffee +5 -0
- data/vendor/coffee-script/documentation/coffee/object_comprehensions.coffee +4 -0
- data/vendor/coffee-script/documentation/coffee/object_extraction.coffee +13 -0
- data/vendor/coffee-script/documentation/coffee/objects_and_arrays.coffee +13 -0
- data/vendor/coffee-script/documentation/coffee/overview.coffee +29 -0
- data/vendor/coffee-script/documentation/coffee/parallel_assignment.coffee +4 -0
- data/vendor/coffee-script/documentation/coffee/range_comprehensions.coffee +6 -0
- data/vendor/coffee-script/documentation/coffee/scope.coffee +5 -0
- data/vendor/coffee-script/documentation/coffee/slices.coffee +6 -0
- data/vendor/coffee-script/documentation/coffee/soaks.coffee +1 -0
- data/vendor/coffee-script/documentation/coffee/splats.coffee +25 -0
- data/vendor/coffee-script/documentation/coffee/splices.coffee +5 -0
- data/vendor/coffee-script/documentation/coffee/strings.coffee +8 -0
- data/vendor/coffee-script/documentation/coffee/super.coffee +34 -0
- data/vendor/coffee-script/documentation/coffee/switch.coffee +10 -0
- data/vendor/coffee-script/documentation/coffee/try.coffee +7 -0
- data/vendor/coffee-script/documentation/coffee/while.coffee +10 -0
- data/vendor/coffee-script/documentation/css/docs.css +213 -0
- data/vendor/coffee-script/documentation/css/idle.css +63 -0
- data/vendor/coffee-script/documentation/css/logo.png +0 -0
- data/vendor/coffee-script/documentation/index.html.erb +967 -0
- data/vendor/coffee-script/documentation/js/aliases.js +14 -0
- data/vendor/coffee-script/documentation/js/arguments.js +8 -0
- data/vendor/coffee-script/documentation/js/array_comprehensions.js +26 -0
- data/vendor/coffee-script/documentation/js/assignment.js +5 -0
- data/vendor/coffee-script/documentation/js/cake_tasks.js +14 -0
- data/vendor/coffee-script/documentation/js/comparisons.js +5 -0
- data/vendor/coffee-script/documentation/js/conditionals.js +12 -0
- data/vendor/coffee-script/documentation/js/embedded.js +6 -0
- data/vendor/coffee-script/documentation/js/existence.js +7 -0
- data/vendor/coffee-script/documentation/js/expressions.js +13 -0
- data/vendor/coffee-script/documentation/js/expressions_assignment.js +4 -0
- data/vendor/coffee-script/documentation/js/expressions_comprehension.js +12 -0
- data/vendor/coffee-script/documentation/js/expressions_try.js +9 -0
- data/vendor/coffee-script/documentation/js/fat_arrow.js +15 -0
- data/vendor/coffee-script/documentation/js/functions.js +9 -0
- data/vendor/coffee-script/documentation/js/heredocs.js +4 -0
- data/vendor/coffee-script/documentation/js/intro.js +7 -0
- data/vendor/coffee-script/documentation/js/multiple_return_values.js +11 -0
- data/vendor/coffee-script/documentation/js/object_comprehensions.js +17 -0
- data/vendor/coffee-script/documentation/js/object_extraction.js +17 -0
- data/vendor/coffee-script/documentation/js/objects_and_arrays.js +10 -0
- data/vendor/coffee-script/documentation/js/overview.js +43 -0
- data/vendor/coffee-script/documentation/js/parallel_assignment.js +8 -0
- data/vendor/coffee-script/documentation/js/punctuation.js +8 -0
- data/vendor/coffee-script/documentation/js/range_comprehensions.js +21 -0
- data/vendor/coffee-script/documentation/js/scope.js +10 -0
- data/vendor/coffee-script/documentation/js/slices.js +6 -0
- data/vendor/coffee-script/documentation/js/soaks.js +4 -0
- data/vendor/coffee-script/documentation/js/splats.js +16 -0
- data/vendor/coffee-script/documentation/js/splices.js +5 -0
- data/vendor/coffee-script/documentation/js/strings.js +9 -0
- data/vendor/coffee-script/documentation/js/super.js +37 -0
- data/vendor/coffee-script/documentation/js/switch.js +18 -0
- data/vendor/coffee-script/documentation/js/try.js +10 -0
- data/vendor/coffee-script/documentation/js/while.js +22 -0
- data/vendor/coffee-script/documentation/underscore.html +627 -0
- data/vendor/coffee-script/examples/beautiful_code/binary_search.coffee +16 -0
- data/vendor/coffee-script/examples/beautiful_code/quicksort_runtime.coffee +13 -0
- data/vendor/coffee-script/examples/beautiful_code/regular_expression_matcher.coffee +34 -0
- data/vendor/coffee-script/examples/blocks.coffee +57 -0
- data/vendor/coffee-script/examples/code.coffee +173 -0
- data/vendor/coffee-script/examples/computer_science/README +4 -0
- data/vendor/coffee-script/examples/computer_science/binary_search.coffee +25 -0
- data/vendor/coffee-script/examples/computer_science/bubble_sort.coffee +11 -0
- data/vendor/coffee-script/examples/computer_science/linked_list.coffee +106 -0
- data/vendor/coffee-script/examples/computer_science/luhn_algorithm.coffee +36 -0
- data/vendor/coffee-script/examples/computer_science/merge_sort.coffee +19 -0
- data/vendor/coffee-script/examples/computer_science/selection_sort.coffee +23 -0
- data/vendor/coffee-script/examples/poignant.coffee +186 -0
- data/vendor/coffee-script/examples/potion.coffee +205 -0
- data/vendor/coffee-script/examples/underscore.coffee +603 -0
- data/vendor/coffee-script/examples/web_server.coffee +12 -0
- data/vendor/coffee-script/extras/CoffeeScript.tmbundle/Preferences/CoffeeScript.tmPreferences +24 -0
- data/vendor/coffee-script/extras/CoffeeScript.tmbundle/Syntaxes/CoffeeScript.tmLanguage +361 -0
- data/vendor/coffee-script/extras/CoffeeScript.tmbundle/info.plist +10 -0
- data/vendor/coffee-script/extras/EXTRAS +20 -0
- data/vendor/coffee-script/extras/coffee.vim +117 -0
- data/vendor/coffee-script/index.html +1847 -0
- data/vendor/coffee-script/lib/bin/cake +7 -0
- data/vendor/coffee-script/lib/bin/coffee +7 -0
- data/vendor/coffee-script/lib/cake.js +80 -0
- data/vendor/coffee-script/lib/coffee-script.js +61 -0
- data/vendor/coffee-script/lib/command_line.js +201 -0
- data/vendor/coffee-script/lib/grammar.js +564 -0
- data/vendor/coffee-script/lib/lexer.js +405 -0
- data/vendor/coffee-script/lib/narwhal.js +44 -0
- data/vendor/coffee-script/lib/nodes.js +1328 -0
- data/vendor/coffee-script/lib/optparse.js +117 -0
- data/vendor/coffee-script/lib/parser.js +536 -0
- data/vendor/coffee-script/lib/repl.js +32 -0
- data/vendor/coffee-script/lib/rewriter.js +383 -0
- data/vendor/coffee-script/lib/scope.js +114 -0
- data/vendor/coffee-script/package.json +7 -0
- data/vendor/coffee-script/src/cake.coffee +45 -0
- data/vendor/coffee-script/src/coffee-script.coffee +45 -0
- data/vendor/coffee-script/src/command_line.coffee +130 -0
- data/vendor/coffee-script/src/grammar.coffee +456 -0
- data/vendor/coffee-script/src/lexer.coffee +327 -0
- data/vendor/coffee-script/src/narwhal.coffee +42 -0
- data/vendor/coffee-script/src/nodes.coffee +1045 -0
- data/vendor/coffee-script/src/optparse.coffee +79 -0
- data/vendor/coffee-script/src/repl.coffee +23 -0
- data/vendor/coffee-script/src/rewriter.coffee +253 -0
- data/vendor/coffee-script/src/scope.coffee +75 -0
- data/vendor/coffee-script/test/test_arguments.coffee +34 -0
- data/vendor/coffee-script/test/test_array_comprehension.coffee +42 -0
- data/vendor/coffee-script/test/test_assignment.coffee +26 -0
- data/vendor/coffee-script/test/test_blocks.coffee +4 -0
- data/vendor/coffee-script/test/test_calling_super.coffee +42 -0
- data/vendor/coffee-script/test/test_chained_calls.coffee +25 -0
- data/vendor/coffee-script/test/test_destructuring_assignment.coffee +62 -0
- data/vendor/coffee-script/test/test_everything.coffee +29 -0
- data/vendor/coffee-script/test/test_exceptions.coffee +2 -0
- data/vendor/coffee-script/test/test_existence.coffee +81 -0
- data/vendor/coffee-script/test/test_expressions.coffee +30 -0
- data/vendor/coffee-script/test/test_fancy_if_statement.coffee +26 -0
- data/vendor/coffee-script/test/test_functions.coffee +80 -0
- data/vendor/coffee-script/test/test_funky_comments.coffee +25 -0
- data/vendor/coffee-script/test/test_heredocs.coffee +46 -0
- data/vendor/coffee-script/test/test_lexical_scope.coffee +10 -0
- data/vendor/coffee-script/test/test_literals.coffee +56 -0
- data/vendor/coffee-script/test/test_nested_comprehensions.coffee +11 -0
- data/vendor/coffee-script/test/test_newline_escaping.coffee +6 -0
- data/vendor/coffee-script/test/test_operations.coffee +18 -0
- data/vendor/coffee-script/test/test_range_comprehension.coffee +20 -0
- data/vendor/coffee-script/test/test_ranges_and_slices.coffee +16 -0
- data/vendor/coffee-script/test/test_splats.coffee +47 -0
- data/vendor/coffee-script/test/test_splices.coffee +5 -0
- data/vendor/coffee-script/test/test_switch.coffee +64 -0
- data/vendor/coffee-script/test/test_while.coffee +30 -0
- data/vendor/coffee-script/vendor/jison/Jakefile +31 -0
- data/vendor/coffee-script/vendor/jison/README.md +347 -0
- data/vendor/coffee-script/vendor/jison/bin/jison +3 -0
- data/vendor/coffee-script/vendor/jison/bin/json2jison +3 -0
- data/vendor/coffee-script/vendor/jison/examples/ansic.jison +415 -0
- data/vendor/coffee-script/vendor/jison/examples/basic.json +8 -0
- data/vendor/coffee-script/vendor/jison/examples/basic2.json +9 -0
- data/vendor/coffee-script/vendor/jison/examples/basic2_lex.json +16 -0
- data/vendor/coffee-script/vendor/jison/examples/basic_lex.json +15 -0
- data/vendor/coffee-script/vendor/jison/examples/calculator.jison +38 -0
- data/vendor/coffee-script/vendor/jison/examples/calculator.jisonlex +14 -0
- data/vendor/coffee-script/vendor/jison/examples/calculator.json +42 -0
- data/vendor/coffee-script/vendor/jison/examples/classy.json +105 -0
- data/vendor/coffee-script/vendor/jison/examples/classy_ast.json +126 -0
- data/vendor/coffee-script/vendor/jison/examples/dism.json +25 -0
- data/vendor/coffee-script/vendor/jison/examples/dism_lr0.json +26 -0
- data/vendor/coffee-script/vendor/jison/examples/json.js +80 -0
- data/vendor/coffee-script/vendor/jison/examples/json_ast.js +83 -0
- data/vendor/coffee-script/vendor/jison/examples/precedence.json +26 -0
- data/vendor/coffee-script/vendor/jison/examples/reduce_conflict.json +13 -0
- data/vendor/coffee-script/vendor/jison/lib/jison/bnf.js +43 -0
- data/vendor/coffee-script/vendor/jison/lib/jison/jisonlex.js +18 -0
- data/vendor/coffee-script/vendor/jison/lib/jison/json2jison.js +146 -0
- data/vendor/coffee-script/vendor/jison/lib/jison/lexer.js +224 -0
- data/vendor/coffee-script/vendor/jison/lib/jison/util/bnf-parser.js +383 -0
- data/vendor/coffee-script/vendor/jison/lib/jison/util/lex-parser.js +407 -0
- data/vendor/coffee-script/vendor/jison/lib/jison/util/set.js +94 -0
- data/vendor/coffee-script/vendor/jison/lib/jison/util/typal.js +90 -0
- data/vendor/coffee-script/vendor/jison/lib/jison.js +1414 -0
- data/vendor/coffee-script/vendor/jison/package.json +14 -0
- data/vendor/coffee-script/vendor/jison/src/bnf.jison +110 -0
- data/vendor/coffee-script/vendor/jison/src/bnf.jisonlex +25 -0
- data/vendor/coffee-script/vendor/jison/src/bnf.lex.json +24 -0
- data/vendor/coffee-script/vendor/jison/src/jisonlex.jison +129 -0
- data/vendor/coffee-script/vendor/jison/src/jisonlex.jisonlex +31 -0
- data/vendor/coffee-script/vendor/jison/src/jisonlex.lex.json +30 -0
- data/vendor/coffee-script/vendor/jison/tests/all-tests.js +8 -0
- data/vendor/coffee-script/vendor/jison/tests/grammar/bnf.js +91 -0
- data/vendor/coffee-script/vendor/jison/tests/grammar/bnf_parse.js +65 -0
- data/vendor/coffee-script/vendor/jison/tests/grammar/grammar-tests.js +10 -0
- data/vendor/coffee-script/vendor/jison/tests/grammar/json2jison.js +24 -0
- data/vendor/coffee-script/vendor/jison/tests/grammar/lex/ansic.jisonlex +115 -0
- data/vendor/coffee-script/vendor/jison/tests/grammar/lex/bnf.jisonlex +25 -0
- data/vendor/coffee-script/vendor/jison/tests/grammar/lex/bnf.lex.json +24 -0
- data/vendor/coffee-script/vendor/jison/tests/grammar/lex/lex_grammar.jisonlex +31 -0
- data/vendor/coffee-script/vendor/jison/tests/grammar/lex/lex_grammar.lex.json +30 -0
- data/vendor/coffee-script/vendor/jison/tests/grammar/lex.jison +119 -0
- data/vendor/coffee-script/vendor/jison/tests/grammar/lex.js +58 -0
- data/vendor/coffee-script/vendor/jison/tests/grammar/lex_parse.js +117 -0
- data/vendor/coffee-script/vendor/jison/tests/lexer/lexer-tests.js +6 -0
- data/vendor/coffee-script/vendor/jison/tests/lexer/regexplexer.js +417 -0
- data/vendor/coffee-script/vendor/jison/tests/parser/actions.js +311 -0
- data/vendor/coffee-script/vendor/jison/tests/parser/api.js +236 -0
- data/vendor/coffee-script/vendor/jison/tests/parser/generator.js +196 -0
- data/vendor/coffee-script/vendor/jison/tests/parser/lalr.js +183 -0
- data/vendor/coffee-script/vendor/jison/tests/parser/lr0.js +72 -0
- data/vendor/coffee-script/vendor/jison/tests/parser/lr1.js +119 -0
- data/vendor/coffee-script/vendor/jison/tests/parser/parser-tests.js +14 -0
- data/vendor/coffee-script/vendor/jison/tests/parser/precedence.js +237 -0
- data/vendor/coffee-script/vendor/jison/tests/parser/slr.js +52 -0
- data/vendor/coffee-script/vendor/jison/tests/parser/tables.js +126 -0
- data/vendor/coffee-script/vendor/jison/tests/performance.js +110 -0
- data/vendor/coffee-script/vendor/jison/tests/setup.js +3 -0
- metadata +324 -0
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# Create an OptionParser with a list of valid options.
|
|
2
|
+
op: exports.OptionParser: (rules) ->
|
|
3
|
+
@banner: 'Usage: [Options]'
|
|
4
|
+
@options_title: 'Available options:'
|
|
5
|
+
@rules: build_rules(rules)
|
|
6
|
+
@actions: {}
|
|
7
|
+
this
|
|
8
|
+
|
|
9
|
+
# Add a callback to fire when a particular option is encountered.
|
|
10
|
+
op::add: (value, callback) ->
|
|
11
|
+
@actions[value]: callback
|
|
12
|
+
|
|
13
|
+
# Parse the argument array, calling defined callbacks, returning the remaining non-option arguments.
|
|
14
|
+
op::parse: (args) ->
|
|
15
|
+
results: []
|
|
16
|
+
args: args.concat []
|
|
17
|
+
while (arg: args.shift())
|
|
18
|
+
is_option: false
|
|
19
|
+
for rule in @rules
|
|
20
|
+
if rule.letter is arg or rule.flag is arg
|
|
21
|
+
callback: @actions[rule.name]
|
|
22
|
+
value: rule.argument and args.shift()
|
|
23
|
+
callback(value) if callback
|
|
24
|
+
is_option: true
|
|
25
|
+
break
|
|
26
|
+
results.push arg unless is_option
|
|
27
|
+
results
|
|
28
|
+
|
|
29
|
+
# Return the help text for this OptionParser, for --help and such.
|
|
30
|
+
op::help: ->
|
|
31
|
+
longest: 0
|
|
32
|
+
has_shorts: false
|
|
33
|
+
lines: [@banner, '', @options_title]
|
|
34
|
+
for rule in @rules
|
|
35
|
+
has_shorts: true if rule.letter
|
|
36
|
+
longest: rule.flag.length if rule.flag.length > longest
|
|
37
|
+
for rule in @rules
|
|
38
|
+
if has_shorts
|
|
39
|
+
text: if rule.letter then spaces(2) + rule.letter + ', ' else spaces(6)
|
|
40
|
+
text += spaces(longest, rule.flag) + spaces(3)
|
|
41
|
+
text += rule.description
|
|
42
|
+
lines.push text
|
|
43
|
+
lines.join('\n')
|
|
44
|
+
|
|
45
|
+
# Private:
|
|
46
|
+
|
|
47
|
+
# Regex matchers for option flags.
|
|
48
|
+
LONG_FLAG: /^(--[\w\-]+)/
|
|
49
|
+
SHORT_FLAG: /^(-\w+)/
|
|
50
|
+
OPTIONAL: /\[(.+)\]/
|
|
51
|
+
|
|
52
|
+
# Build rules from a list of valid switch tuples in the form:
|
|
53
|
+
# [letter-flag, long-flag, help], or [long-flag, help].
|
|
54
|
+
build_rules: (rules) ->
|
|
55
|
+
for tuple in rules
|
|
56
|
+
tuple.unshift(null) if tuple.length < 3
|
|
57
|
+
build_rule(tuple...)
|
|
58
|
+
|
|
59
|
+
# Build a rule from a short-letter-flag, long-form-flag, and help text.
|
|
60
|
+
build_rule: (letter, flag, description) ->
|
|
61
|
+
match: flag.match(OPTIONAL)
|
|
62
|
+
flag: flag.match(LONG_FLAG)[1]
|
|
63
|
+
{
|
|
64
|
+
name: flag.substr(2)
|
|
65
|
+
letter: letter
|
|
66
|
+
flag: flag
|
|
67
|
+
description: description
|
|
68
|
+
argument: !!(match and match[1])
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
# Space-pad a string with the specified number of characters.
|
|
72
|
+
spaces: (num, text) ->
|
|
73
|
+
builder: []
|
|
74
|
+
if text
|
|
75
|
+
return text if text.length >= num
|
|
76
|
+
num -= text.length
|
|
77
|
+
builder.push text
|
|
78
|
+
while num -= 1 then builder.push ' '
|
|
79
|
+
builder.join ''
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# A CoffeeScript port/version of the Node.js REPL.
|
|
2
|
+
|
|
3
|
+
# Required modules.
|
|
4
|
+
coffee: require 'coffee-script'
|
|
5
|
+
|
|
6
|
+
# Shortcut variables.
|
|
7
|
+
prompt: 'coffee> '
|
|
8
|
+
quit: -> process.exit(0)
|
|
9
|
+
|
|
10
|
+
# The main REPL function. Called everytime a line of code is entered.
|
|
11
|
+
# Attempt to evaluate the command. If there's an exception, print it.
|
|
12
|
+
readline: (code) ->
|
|
13
|
+
try
|
|
14
|
+
val: eval coffee.compile code, {no_wrap: true, globals: true}
|
|
15
|
+
p val if val isnt undefined
|
|
16
|
+
catch err
|
|
17
|
+
puts err.stack or err.toString()
|
|
18
|
+
print prompt
|
|
19
|
+
|
|
20
|
+
# Start up the REPL.
|
|
21
|
+
process.stdio.addListener 'data', readline
|
|
22
|
+
process.stdio.open()
|
|
23
|
+
print prompt
|
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
this.exports: this unless process?
|
|
2
|
+
|
|
3
|
+
# In order to keep the grammar simple, the stream of tokens that the Lexer
|
|
4
|
+
# emits is rewritten by the Rewriter, smoothing out ambiguities, mis-nested
|
|
5
|
+
# indentation, and single-line flavors of expressions.
|
|
6
|
+
exports.Rewriter: re: ->
|
|
7
|
+
|
|
8
|
+
# Tokens that must be balanced.
|
|
9
|
+
BALANCED_PAIRS: [['(', ')'], ['[', ']'], ['{', '}'], ['INDENT', 'OUTDENT'],
|
|
10
|
+
['PARAM_START', 'PARAM_END'], ['CALL_START', 'CALL_END'],
|
|
11
|
+
['INDEX_START', 'INDEX_END'], ['SOAKED_INDEX_START', 'SOAKED_INDEX_END']]
|
|
12
|
+
|
|
13
|
+
# Tokens that signal the start of a balanced pair.
|
|
14
|
+
EXPRESSION_START: pair[0] for pair in BALANCED_PAIRS
|
|
15
|
+
|
|
16
|
+
# Tokens that signal the end of a balanced pair.
|
|
17
|
+
EXPRESSION_TAIL: pair[1] for pair in BALANCED_PAIRS
|
|
18
|
+
|
|
19
|
+
# Tokens that indicate the close of a clause of an expression.
|
|
20
|
+
EXPRESSION_CLOSE: ['CATCH', 'WHEN', 'ELSE', 'FINALLY'].concat(EXPRESSION_TAIL)
|
|
21
|
+
|
|
22
|
+
# Tokens pairs that, in immediate succession, indicate an implicit call.
|
|
23
|
+
IMPLICIT_FUNC: ['IDENTIFIER', 'SUPER', ')', 'CALL_END', ']', 'INDEX_END']
|
|
24
|
+
IMPLICIT_BLOCK:['->', '=>', '{', '[', ',']
|
|
25
|
+
IMPLICIT_END: ['IF', 'UNLESS', 'FOR', 'WHILE', 'TERMINATOR', 'INDENT', 'OUTDENT']
|
|
26
|
+
IMPLICIT_CALL: ['IDENTIFIER', 'NUMBER', 'STRING', 'JS', 'REGEX', 'NEW', 'PARAM_START',
|
|
27
|
+
'TRY', 'DELETE', 'TYPEOF', 'SWITCH',
|
|
28
|
+
'TRUE', 'FALSE', 'YES', 'NO', 'ON', 'OFF', '!', '!!', 'NOT',
|
|
29
|
+
'@', '->', '=>', '[', '(', '{']
|
|
30
|
+
|
|
31
|
+
# The inverse mappings of token pairs we're trying to fix up.
|
|
32
|
+
INVERSES: {}
|
|
33
|
+
for pair in BALANCED_PAIRS
|
|
34
|
+
INVERSES[pair[0]]: pair[1]
|
|
35
|
+
INVERSES[pair[1]]: pair[0]
|
|
36
|
+
|
|
37
|
+
# Single-line flavors of block expressions that have unclosed endings.
|
|
38
|
+
# The grammar can't disambiguate them, so we insert the implicit indentation.
|
|
39
|
+
SINGLE_LINERS: ['ELSE', "->", "=>", 'TRY', 'FINALLY', 'THEN']
|
|
40
|
+
SINGLE_CLOSERS: ['TERMINATOR', 'CATCH', 'FINALLY', 'ELSE', 'OUTDENT', 'LEADING_WHEN', 'PARAM_START']
|
|
41
|
+
|
|
42
|
+
# Rewrite the token stream in multiple passes, one logical filter at
|
|
43
|
+
# a time. This could certainly be changed into a single pass through the
|
|
44
|
+
# stream, with a big ol' efficient switch, but it's much nicer like this.
|
|
45
|
+
re::rewrite: (tokens) ->
|
|
46
|
+
@tokens: tokens
|
|
47
|
+
@adjust_comments()
|
|
48
|
+
@remove_leading_newlines()
|
|
49
|
+
@remove_mid_expression_newlines()
|
|
50
|
+
@move_commas_outside_outdents()
|
|
51
|
+
@close_open_calls_and_indexes()
|
|
52
|
+
@add_implicit_indentation()
|
|
53
|
+
@add_implicit_parentheses()
|
|
54
|
+
@ensure_balance(BALANCED_PAIRS)
|
|
55
|
+
@rewrite_closing_parens()
|
|
56
|
+
@tokens
|
|
57
|
+
|
|
58
|
+
# Rewrite the token stream, looking one token ahead and behind.
|
|
59
|
+
# Allow the return value of the block to tell us how many tokens to move
|
|
60
|
+
# forwards (or backwards) in the stream, to make sure we don't miss anything
|
|
61
|
+
# as the stream changes length under our feet.
|
|
62
|
+
re::scan_tokens: (block) ->
|
|
63
|
+
i: 0
|
|
64
|
+
while true
|
|
65
|
+
break unless @tokens[i]
|
|
66
|
+
move: block(@tokens[i - 1], @tokens[i], @tokens[i + 1], i)
|
|
67
|
+
i += move
|
|
68
|
+
true
|
|
69
|
+
|
|
70
|
+
# Massage newlines and indentations so that comments don't have to be
|
|
71
|
+
# correctly indented, or appear on their own line.
|
|
72
|
+
re::adjust_comments: ->
|
|
73
|
+
@scan_tokens (prev, token, post, i) =>
|
|
74
|
+
return 1 unless token[0] is 'COMMENT'
|
|
75
|
+
before: @tokens[i - 2]
|
|
76
|
+
after: @tokens[i + 2]
|
|
77
|
+
if before and after and
|
|
78
|
+
((before[0] is 'INDENT' and after[0] is 'OUTDENT') or
|
|
79
|
+
(before[0] is 'OUTDENT' and after[0] is 'INDENT')) and
|
|
80
|
+
before[1] is after[1]
|
|
81
|
+
@tokens.splice(i + 2, 1)
|
|
82
|
+
@tokens.splice(i - 2, 1)
|
|
83
|
+
return 0
|
|
84
|
+
else if prev and prev[0] is 'TERMINATOR' and after and after[0] is 'INDENT'
|
|
85
|
+
@tokens.splice(i + 2, 1)
|
|
86
|
+
@tokens[i - 1]: after
|
|
87
|
+
return 1
|
|
88
|
+
else if prev and prev[0] isnt 'TERMINATOR' and prev[0] isnt 'INDENT' and prev[0] isnt 'OUTDENT'
|
|
89
|
+
@tokens.splice(i, 0, ['TERMINATOR', "\n", prev[2]])
|
|
90
|
+
return 2
|
|
91
|
+
else
|
|
92
|
+
return 1
|
|
93
|
+
|
|
94
|
+
# Leading newlines would introduce an ambiguity in the grammar, so we
|
|
95
|
+
# dispatch them here.
|
|
96
|
+
re::remove_leading_newlines: ->
|
|
97
|
+
@tokens.shift() if @tokens[0][0] is 'TERMINATOR'
|
|
98
|
+
|
|
99
|
+
# Some blocks occur in the middle of expressions -- when we're expecting
|
|
100
|
+
# this, remove their trailing newlines.
|
|
101
|
+
re::remove_mid_expression_newlines: ->
|
|
102
|
+
@scan_tokens (prev, token, post, i) =>
|
|
103
|
+
return 1 unless post and EXPRESSION_CLOSE.indexOf(post[0]) >= 0 and token[0] is 'TERMINATOR'
|
|
104
|
+
@tokens.splice(i, 1)
|
|
105
|
+
return 0
|
|
106
|
+
|
|
107
|
+
# Make sure that we don't accidentally break trailing commas, which need
|
|
108
|
+
# to go on the outside of expression closers.
|
|
109
|
+
re::move_commas_outside_outdents: ->
|
|
110
|
+
@scan_tokens (prev, token, post, i) =>
|
|
111
|
+
@tokens.splice(i, 1, token) if token[0] is 'OUTDENT' and prev[0] is ','
|
|
112
|
+
return 1
|
|
113
|
+
|
|
114
|
+
# We've tagged the opening parenthesis of a method call, and the opening
|
|
115
|
+
# bracket of an indexing operation. Match them with their close.
|
|
116
|
+
re::close_open_calls_and_indexes: ->
|
|
117
|
+
parens: [0]
|
|
118
|
+
brackets: [0]
|
|
119
|
+
@scan_tokens (prev, token, post, i) =>
|
|
120
|
+
switch token[0]
|
|
121
|
+
when 'CALL_START' then parens.push(0)
|
|
122
|
+
when 'INDEX_START' then brackets.push(0)
|
|
123
|
+
when '(' then parens[parens.length - 1] += 1
|
|
124
|
+
when '[' then brackets[brackets.length - 1] += 1
|
|
125
|
+
when ')'
|
|
126
|
+
if parens[parens.length - 1] is 0
|
|
127
|
+
parens.pop()
|
|
128
|
+
token[0]: 'CALL_END'
|
|
129
|
+
else
|
|
130
|
+
parens[parens.length - 1] -= 1
|
|
131
|
+
when ']'
|
|
132
|
+
if brackets[brackets.length - 1] == 0
|
|
133
|
+
brackets.pop()
|
|
134
|
+
token[0]: 'INDEX_END'
|
|
135
|
+
else
|
|
136
|
+
brackets[brackets.length - 1] -= 1
|
|
137
|
+
return 1
|
|
138
|
+
|
|
139
|
+
# Methods may be optionally called without parentheses, for simple cases.
|
|
140
|
+
# Insert the implicit parentheses here, so that the parser doesn't have to
|
|
141
|
+
# deal with them.
|
|
142
|
+
re::add_implicit_parentheses: ->
|
|
143
|
+
stack: [0]
|
|
144
|
+
@scan_tokens (prev, token, post, i) =>
|
|
145
|
+
tag: token[0]
|
|
146
|
+
stack.push(0) if tag is 'INDENT'
|
|
147
|
+
if tag is 'OUTDENT'
|
|
148
|
+
last: stack.pop()
|
|
149
|
+
stack[stack.length - 1] += last
|
|
150
|
+
if IMPLICIT_END.indexOf(tag) >= 0 or !post?
|
|
151
|
+
return 1 if tag is 'INDENT' and prev and IMPLICIT_BLOCK.indexOf(prev[0]) >= 0
|
|
152
|
+
if stack[stack.length - 1] > 0 or tag is 'INDENT'
|
|
153
|
+
idx: if tag is 'OUTDENT' then i + 1 else i
|
|
154
|
+
stack_pointer: if tag is 'INDENT' then 2 else 1
|
|
155
|
+
for tmp in [0...stack[stack.length - stack_pointer]]
|
|
156
|
+
@tokens.splice(idx, 0, ['CALL_END', ')', token[2]])
|
|
157
|
+
size: stack[stack.length - stack_pointer] + 1
|
|
158
|
+
stack[stack.length - stack_pointer]: 0
|
|
159
|
+
return size
|
|
160
|
+
return 1 unless prev and IMPLICIT_FUNC.indexOf(prev[0]) >= 0 and IMPLICIT_CALL.indexOf(tag) >= 0
|
|
161
|
+
@tokens.splice(i, 0, ['CALL_START', '(', token[2]])
|
|
162
|
+
stack[stack.length - 1] += 1
|
|
163
|
+
return 2
|
|
164
|
+
|
|
165
|
+
# Because our grammar is LALR(1), it can't handle some single-line
|
|
166
|
+
# expressions that lack ending delimiters. Use the lexer to add the implicit
|
|
167
|
+
# blocks, so it doesn't need to.
|
|
168
|
+
# ')' can close a single-line block, but we need to make sure it's balanced.
|
|
169
|
+
re::add_implicit_indentation: ->
|
|
170
|
+
@scan_tokens (prev, token, post, i) =>
|
|
171
|
+
return 1 unless SINGLE_LINERS.indexOf(token[0]) >= 0 and post[0] isnt 'INDENT' and
|
|
172
|
+
not (token[0] is 'ELSE' and post[0] is 'IF')
|
|
173
|
+
starter: token[0]
|
|
174
|
+
@tokens.splice(i + 1, 0, ['INDENT', 2, token[2]])
|
|
175
|
+
idx: i + 1
|
|
176
|
+
parens: 0
|
|
177
|
+
while true
|
|
178
|
+
idx += 1
|
|
179
|
+
tok: @tokens[idx]
|
|
180
|
+
if (not tok or
|
|
181
|
+
(SINGLE_CLOSERS.indexOf(tok[0]) >= 0 and tok[1] isnt ';') or
|
|
182
|
+
(tok[0] is ')' && parens is 0)) and
|
|
183
|
+
not (starter is 'ELSE' and tok[0] is 'ELSE')
|
|
184
|
+
insertion: if @tokens[idx - 1][0] is "," then idx - 1 else idx
|
|
185
|
+
@tokens.splice(insertion, 0, ['OUTDENT', 2, token[2]])
|
|
186
|
+
break
|
|
187
|
+
parens += 1 if tok[0] is '('
|
|
188
|
+
parens -= 1 if tok[0] is ')'
|
|
189
|
+
return 1 unless token[0] is 'THEN'
|
|
190
|
+
@tokens.splice(i, 1)
|
|
191
|
+
return 0
|
|
192
|
+
|
|
193
|
+
# Ensure that all listed pairs of tokens are correctly balanced throughout
|
|
194
|
+
# the course of the token stream.
|
|
195
|
+
re::ensure_balance: (pairs) ->
|
|
196
|
+
levels: {}
|
|
197
|
+
@scan_tokens (prev, token, post, i) =>
|
|
198
|
+
for pair in pairs
|
|
199
|
+
[open, close]: pair
|
|
200
|
+
levels[open] ||= 0
|
|
201
|
+
levels[open] += 1 if token[0] is open
|
|
202
|
+
levels[open] -= 1 if token[0] is close
|
|
203
|
+
throw new Error("too many " + token[1]) if levels[open] < 0
|
|
204
|
+
return 1
|
|
205
|
+
unclosed: key for key, value of levels when value > 0
|
|
206
|
+
throw new Error("unclosed " + unclosed[0]) if unclosed.length
|
|
207
|
+
|
|
208
|
+
# We'd like to support syntax like this:
|
|
209
|
+
# el.click((event) ->
|
|
210
|
+
# el.hide())
|
|
211
|
+
# In order to accomplish this, move outdents that follow closing parens
|
|
212
|
+
# inwards, safely. The steps to accomplish this are:
|
|
213
|
+
#
|
|
214
|
+
# 1. Check that all paired tokens are balanced and in order.
|
|
215
|
+
# 2. Rewrite the stream with a stack: if you see an '(' or INDENT, add it
|
|
216
|
+
# to the stack. If you see an ')' or OUTDENT, pop the stack and replace
|
|
217
|
+
# it with the inverse of what we've just popped.
|
|
218
|
+
# 3. Keep track of "debt" for tokens that we fake, to make sure we end
|
|
219
|
+
# up balanced in the end.
|
|
220
|
+
#
|
|
221
|
+
re::rewrite_closing_parens: ->
|
|
222
|
+
stack: []
|
|
223
|
+
debt: {}
|
|
224
|
+
(debt[key]: 0) for key, val of INVERSES
|
|
225
|
+
@scan_tokens (prev, token, post, i) =>
|
|
226
|
+
tag: token[0]
|
|
227
|
+
inv: INVERSES[token[0]]
|
|
228
|
+
# Push openers onto the stack.
|
|
229
|
+
if EXPRESSION_START.indexOf(tag) >= 0
|
|
230
|
+
stack.push(token)
|
|
231
|
+
return 1
|
|
232
|
+
# The end of an expression, check stack and debt for a pair.
|
|
233
|
+
else if EXPRESSION_TAIL.indexOf(tag) >= 0
|
|
234
|
+
# If the tag is already in our debt, swallow it.
|
|
235
|
+
if debt[inv] > 0
|
|
236
|
+
debt[inv] -= 1
|
|
237
|
+
@tokens.splice(i, 1)
|
|
238
|
+
return 0
|
|
239
|
+
else
|
|
240
|
+
# Pop the stack of open delimiters.
|
|
241
|
+
match: stack.pop()
|
|
242
|
+
mtag: match[0]
|
|
243
|
+
# Continue onwards if it's the expected tag.
|
|
244
|
+
if tag is INVERSES[mtag]
|
|
245
|
+
return 1
|
|
246
|
+
else
|
|
247
|
+
# Unexpected close, insert correct close, adding to the debt.
|
|
248
|
+
debt[mtag] += 1
|
|
249
|
+
val: if mtag is 'INDENT' then match[1] else INVERSES[mtag]
|
|
250
|
+
@tokens.splice(i, 0, [INVERSES[mtag], val])
|
|
251
|
+
return 1
|
|
252
|
+
else
|
|
253
|
+
return 1
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
this.exports: this unless process?
|
|
2
|
+
|
|
3
|
+
# Scope objects form a tree corresponding to the shape of the function
|
|
4
|
+
# definitions present in the script. They provide lexical scope, to determine
|
|
5
|
+
# whether a variable has been seen before or if it needs to be declared.
|
|
6
|
+
#
|
|
7
|
+
# Initialize a scope with its parent, for lookups up the chain,
|
|
8
|
+
# as well as the Expressions body where it should declare its variables,
|
|
9
|
+
# and the function that it wraps.
|
|
10
|
+
Scope: exports.Scope: (parent, expressions, method) ->
|
|
11
|
+
[@parent, @expressions, @method]: [parent, expressions, method]
|
|
12
|
+
@variables: {}
|
|
13
|
+
@temp_var: if @parent then @parent.temp_var else '_a'
|
|
14
|
+
this
|
|
15
|
+
|
|
16
|
+
# Look up a variable in lexical scope, or declare it if not found.
|
|
17
|
+
Scope::find: (name) ->
|
|
18
|
+
return true if @check name
|
|
19
|
+
@variables[name]: 'var'
|
|
20
|
+
false
|
|
21
|
+
|
|
22
|
+
# Define a local variable as originating from a parameter in current scope
|
|
23
|
+
# -- no var required.
|
|
24
|
+
Scope::parameter: (name) ->
|
|
25
|
+
@variables[name]: 'param'
|
|
26
|
+
|
|
27
|
+
# Just check to see if a variable has already been declared.
|
|
28
|
+
Scope::check: (name) ->
|
|
29
|
+
return true if @variables[name]
|
|
30
|
+
!!(@parent and @parent.check(name))
|
|
31
|
+
|
|
32
|
+
# You can reset a found variable on the immediate scope.
|
|
33
|
+
Scope::reset: (name) ->
|
|
34
|
+
delete @variables[name]
|
|
35
|
+
|
|
36
|
+
# Find an available, short, name for a compiler-generated variable.
|
|
37
|
+
Scope::free_variable: ->
|
|
38
|
+
while @check @temp_var
|
|
39
|
+
ordinal: 1 + parseInt @temp_var.substr(1), 36
|
|
40
|
+
@temp_var: '_' + ordinal.toString(36).replace(/\d/g, 'a')
|
|
41
|
+
@variables[@temp_var]: 'var'
|
|
42
|
+
@temp_var
|
|
43
|
+
|
|
44
|
+
# Ensure that an assignment is made at the top of scope (or top-level
|
|
45
|
+
# scope, if requested).
|
|
46
|
+
Scope::assign: (name, value, top_level) ->
|
|
47
|
+
return @parent.assign(name, value, top_level) if top_level and @parent
|
|
48
|
+
@variables[name]: {value: value, assigned: true}
|
|
49
|
+
|
|
50
|
+
# Does this scope reference any variables that need to be declared in the
|
|
51
|
+
# given function body?
|
|
52
|
+
Scope::has_declarations: (body) ->
|
|
53
|
+
body is @expressions and @declared_variables().length
|
|
54
|
+
|
|
55
|
+
# Does this scope reference any assignments that need to be declared at the
|
|
56
|
+
# top of the given function body?
|
|
57
|
+
Scope::has_assignments: (body) ->
|
|
58
|
+
body is @expressions and @assigned_variables().length
|
|
59
|
+
|
|
60
|
+
# Return the list of variables first declared in current scope.
|
|
61
|
+
Scope::declared_variables: ->
|
|
62
|
+
(key for key, val of @variables when val is 'var').sort()
|
|
63
|
+
|
|
64
|
+
# Return the list of variables that are supposed to be assigned at the top
|
|
65
|
+
# of scope.
|
|
66
|
+
Scope::assigned_variables: ->
|
|
67
|
+
key + ' = ' + val.value for key, val of @variables when val.assigned
|
|
68
|
+
|
|
69
|
+
# Compile the string representing all of the declared variables for this scope.
|
|
70
|
+
Scope::compiled_declarations: ->
|
|
71
|
+
@declared_variables().join ', '
|
|
72
|
+
|
|
73
|
+
# Compile the string performing all of the variable assignments for this scope.
|
|
74
|
+
Scope::compiled_assignments: ->
|
|
75
|
+
@assigned_variables().join ', '
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
area: (x, y, x1, y1) ->
|
|
2
|
+
(x - x1) * (x - y1)
|
|
3
|
+
|
|
4
|
+
x: y: 10
|
|
5
|
+
x1: y1: 20
|
|
6
|
+
|
|
7
|
+
ok area(x, y, x1, y1) is 100, 'basic arguments'
|
|
8
|
+
|
|
9
|
+
ok(area(x, y,
|
|
10
|
+
x1, y1) is 100, 'arguments on split lines')
|
|
11
|
+
|
|
12
|
+
ok(area(
|
|
13
|
+
x
|
|
14
|
+
y
|
|
15
|
+
x1
|
|
16
|
+
y1
|
|
17
|
+
) is 100, 'newline delimited arguments')
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
curried: ->
|
|
21
|
+
ok area.apply(this, arguments.concat(20, 20)) is 100, 'arguments converted into an array'
|
|
22
|
+
|
|
23
|
+
curried 10, 10
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
func: ->
|
|
27
|
+
arguments: 25
|
|
28
|
+
arguments
|
|
29
|
+
|
|
30
|
+
ok func(100) is 25, 'arguments as a regular identifier'
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
this.arguments: 10
|
|
34
|
+
ok @arguments is 10, 'arguments accessed as a property'
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
nums: n * n for n in [1, 2, 3] when n % 2 isnt 0
|
|
2
|
+
results: n * 2 for n in nums
|
|
3
|
+
|
|
4
|
+
ok results.join(',') is '2,18', 'basic array comprehension'
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
obj: {one: 1, two: 2, three: 3}
|
|
8
|
+
names: prop + '!' for prop of obj
|
|
9
|
+
odds: prop + '!' for prop, value of obj when value % 2 isnt 0
|
|
10
|
+
|
|
11
|
+
ok names.join(' ') is "one! two! three!", 'basic object comprehension'
|
|
12
|
+
ok odds.join(' ') is "one! three!", 'object comprehension with a filter'
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
evens: for num in [1, 2, 3, 4, 5, 6] when num % 2 is 0
|
|
16
|
+
num *= -1
|
|
17
|
+
num -= 2
|
|
18
|
+
num * -1
|
|
19
|
+
|
|
20
|
+
ok evens.join(', ') is '4, 6, 8', 'multiline array comprehension with filter'
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
ok 2 in evens, 'the in operator still works, standalone'
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
# Ensure that the closure wrapper preserves local variables.
|
|
27
|
+
obj: {}
|
|
28
|
+
|
|
29
|
+
methods: ['one', 'two', 'three']
|
|
30
|
+
|
|
31
|
+
for method in methods
|
|
32
|
+
name: method
|
|
33
|
+
obj[name]: ->
|
|
34
|
+
"I'm " + name
|
|
35
|
+
|
|
36
|
+
ok obj.one() is "I'm one"
|
|
37
|
+
ok obj.two() is "I'm two"
|
|
38
|
+
ok obj.three() is "I'm three"
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
array: [0..10]
|
|
42
|
+
ok(num % 2 is 0 for num in array by 2, 'naked ranges are expanded into arrays')
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
result: try
|
|
2
|
+
nonexistent * missing
|
|
3
|
+
catch error
|
|
4
|
+
true
|
|
5
|
+
|
|
6
|
+
result2: try nonexistent * missing catch error then true
|
|
7
|
+
|
|
8
|
+
ok result is true and result2 is true, 'can assign the result of a try/catch block'
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
get_x: -> 10
|
|
12
|
+
|
|
13
|
+
if x: get_x() then 100
|
|
14
|
+
|
|
15
|
+
ok x is 10, 'can assign a conditional statement'
|
|
16
|
+
|
|
17
|
+
x: if get_x() then 100
|
|
18
|
+
|
|
19
|
+
ok x is 100, 'can assign a conditional statement'
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
tester: ->
|
|
23
|
+
@example: -> puts 'example function'
|
|
24
|
+
this
|
|
25
|
+
|
|
26
|
+
ok tester().example.name is 'example'
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
Base: ->
|
|
2
|
+
Base::func: (string) ->
|
|
3
|
+
'zero/' + string
|
|
4
|
+
|
|
5
|
+
FirstChild: ->
|
|
6
|
+
FirstChild extends Base
|
|
7
|
+
FirstChild::func: (string) ->
|
|
8
|
+
super('one/') + string
|
|
9
|
+
|
|
10
|
+
SecondChild: ->
|
|
11
|
+
SecondChild extends FirstChild
|
|
12
|
+
SecondChild::func: (string) ->
|
|
13
|
+
super('two/') + string
|
|
14
|
+
|
|
15
|
+
ThirdChild: ->
|
|
16
|
+
@array: [1, 2, 3]
|
|
17
|
+
this
|
|
18
|
+
ThirdChild extends SecondChild
|
|
19
|
+
ThirdChild::func: (string) ->
|
|
20
|
+
super('three/') + string
|
|
21
|
+
|
|
22
|
+
result: (new ThirdChild()).func 'four'
|
|
23
|
+
|
|
24
|
+
ok result is 'zero/one/two/three/four', 'successfully set up and called a four-level inheritance chain'
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
TopClass: (arg) ->
|
|
28
|
+
@prop: 'top-' + arg
|
|
29
|
+
this
|
|
30
|
+
|
|
31
|
+
SuperClass: (arg) ->
|
|
32
|
+
super 'super-' + arg
|
|
33
|
+
this
|
|
34
|
+
|
|
35
|
+
SubClass: ->
|
|
36
|
+
super 'sub'
|
|
37
|
+
this
|
|
38
|
+
|
|
39
|
+
SuperClass extends TopClass
|
|
40
|
+
SubClass extends SuperClass
|
|
41
|
+
|
|
42
|
+
ok (new SubClass()).prop is 'top-super-sub', 'inheritance'
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
identity_wrap: (x) ->
|
|
2
|
+
-> x
|
|
3
|
+
|
|
4
|
+
result: identity_wrap(identity_wrap(true))()()
|
|
5
|
+
|
|
6
|
+
ok result, 'basic chained function calls'
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
str: 'god'
|
|
10
|
+
|
|
11
|
+
result: str.
|
|
12
|
+
split('').
|
|
13
|
+
reverse().
|
|
14
|
+
reverse().
|
|
15
|
+
reverse()
|
|
16
|
+
|
|
17
|
+
ok result.join('') is 'dog', 'chained accesses split on period/newline'
|
|
18
|
+
|
|
19
|
+
result: str
|
|
20
|
+
.split('')
|
|
21
|
+
.reverse()
|
|
22
|
+
.reverse()
|
|
23
|
+
.reverse()
|
|
24
|
+
|
|
25
|
+
ok result.join('') is 'dog', 'chained accesses split on newline/period'
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
a: -1
|
|
2
|
+
b: -2
|
|
3
|
+
|
|
4
|
+
[a, b]: [b, a]
|
|
5
|
+
|
|
6
|
+
ok a is -2
|
|
7
|
+
ok b is -1
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
arr: [1, 2, 3]
|
|
11
|
+
|
|
12
|
+
[a, b, c]: arr
|
|
13
|
+
|
|
14
|
+
ok a is 1
|
|
15
|
+
ok b is 2
|
|
16
|
+
ok c is 3
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
obj: {x: 10, y: 20, z: 30}
|
|
20
|
+
|
|
21
|
+
{x: a, y: b, z: c}: obj
|
|
22
|
+
|
|
23
|
+
ok a is 10
|
|
24
|
+
ok b is 20
|
|
25
|
+
ok c is 30
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
person: {
|
|
29
|
+
name: "Bob"
|
|
30
|
+
family: {
|
|
31
|
+
brother: {
|
|
32
|
+
addresses: [
|
|
33
|
+
"first"
|
|
34
|
+
{
|
|
35
|
+
street: "101 Deercreek Ln."
|
|
36
|
+
city: "Moquasset NY, 10021"
|
|
37
|
+
}
|
|
38
|
+
]
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
{name: a, family: {brother: {addresses: [one, {city: b}]}}}: person
|
|
44
|
+
|
|
45
|
+
ok a is "Bob"
|
|
46
|
+
ok b is "Moquasset NY, 10021"
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
test: {
|
|
50
|
+
person: {
|
|
51
|
+
address: [
|
|
52
|
+
"------"
|
|
53
|
+
"Street 101"
|
|
54
|
+
"Apt 101"
|
|
55
|
+
"City 101"
|
|
56
|
+
]
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
{person: {address: [ignore, addr...]}}: test
|
|
61
|
+
|
|
62
|
+
ok addr.join(', ') is "Street 101, Apt 101, City 101"
|