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.
Files changed (225) hide show
  1. data/README.md +79 -0
  2. data/lib/haml/more/coffee_script.rb +137 -0
  3. data/lib/haml/more/content_for.rb +25 -0
  4. data/lib/haml/more.rb +45 -0
  5. data/lib/haml-more.rb +1 -0
  6. data/lib/sass/more.rb +16 -0
  7. data/lib/sass-more.rb +1 -0
  8. data/spec/sass/more_spec.rb +21 -0
  9. data/vendor/coffee-script/Cakefile +57 -0
  10. data/vendor/coffee-script/LICENSE +22 -0
  11. data/vendor/coffee-script/README +41 -0
  12. data/vendor/coffee-script/Rakefile +20 -0
  13. data/vendor/coffee-script/bin/cake +7 -0
  14. data/vendor/coffee-script/bin/coffee +7 -0
  15. data/vendor/coffee-script/documentation/coffee/aliases.coffee +9 -0
  16. data/vendor/coffee-script/documentation/coffee/arguments.coffee +4 -0
  17. data/vendor/coffee-script/documentation/coffee/array_comprehensions.coffee +7 -0
  18. data/vendor/coffee-script/documentation/coffee/assignment.coffee +2 -0
  19. data/vendor/coffee-script/documentation/coffee/cake_tasks.coffee +5 -0
  20. data/vendor/coffee-script/documentation/coffee/comparisons.coffee +5 -0
  21. data/vendor/coffee-script/documentation/coffee/conditionals.coffee +9 -0
  22. data/vendor/coffee-script/documentation/coffee/embedded.coffee +5 -0
  23. data/vendor/coffee-script/documentation/coffee/existence.coffee +8 -0
  24. data/vendor/coffee-script/documentation/coffee/expressions.coffee +9 -0
  25. data/vendor/coffee-script/documentation/coffee/expressions_assignment.coffee +1 -0
  26. data/vendor/coffee-script/documentation/coffee/expressions_comprehension.coffee +3 -0
  27. data/vendor/coffee-script/documentation/coffee/expressions_try.coffee +6 -0
  28. data/vendor/coffee-script/documentation/coffee/fat_arrow.coffee +6 -0
  29. data/vendor/coffee-script/documentation/coffee/functions.coffee +2 -0
  30. data/vendor/coffee-script/documentation/coffee/heredocs.coffee +5 -0
  31. data/vendor/coffee-script/documentation/coffee/multiple_return_values.coffee +5 -0
  32. data/vendor/coffee-script/documentation/coffee/object_comprehensions.coffee +4 -0
  33. data/vendor/coffee-script/documentation/coffee/object_extraction.coffee +13 -0
  34. data/vendor/coffee-script/documentation/coffee/objects_and_arrays.coffee +13 -0
  35. data/vendor/coffee-script/documentation/coffee/overview.coffee +29 -0
  36. data/vendor/coffee-script/documentation/coffee/parallel_assignment.coffee +4 -0
  37. data/vendor/coffee-script/documentation/coffee/range_comprehensions.coffee +6 -0
  38. data/vendor/coffee-script/documentation/coffee/scope.coffee +5 -0
  39. data/vendor/coffee-script/documentation/coffee/slices.coffee +6 -0
  40. data/vendor/coffee-script/documentation/coffee/soaks.coffee +1 -0
  41. data/vendor/coffee-script/documentation/coffee/splats.coffee +25 -0
  42. data/vendor/coffee-script/documentation/coffee/splices.coffee +5 -0
  43. data/vendor/coffee-script/documentation/coffee/strings.coffee +8 -0
  44. data/vendor/coffee-script/documentation/coffee/super.coffee +34 -0
  45. data/vendor/coffee-script/documentation/coffee/switch.coffee +10 -0
  46. data/vendor/coffee-script/documentation/coffee/try.coffee +7 -0
  47. data/vendor/coffee-script/documentation/coffee/while.coffee +10 -0
  48. data/vendor/coffee-script/documentation/css/docs.css +213 -0
  49. data/vendor/coffee-script/documentation/css/idle.css +63 -0
  50. data/vendor/coffee-script/documentation/css/logo.png +0 -0
  51. data/vendor/coffee-script/documentation/index.html.erb +967 -0
  52. data/vendor/coffee-script/documentation/js/aliases.js +14 -0
  53. data/vendor/coffee-script/documentation/js/arguments.js +8 -0
  54. data/vendor/coffee-script/documentation/js/array_comprehensions.js +26 -0
  55. data/vendor/coffee-script/documentation/js/assignment.js +5 -0
  56. data/vendor/coffee-script/documentation/js/cake_tasks.js +14 -0
  57. data/vendor/coffee-script/documentation/js/comparisons.js +5 -0
  58. data/vendor/coffee-script/documentation/js/conditionals.js +12 -0
  59. data/vendor/coffee-script/documentation/js/embedded.js +6 -0
  60. data/vendor/coffee-script/documentation/js/existence.js +7 -0
  61. data/vendor/coffee-script/documentation/js/expressions.js +13 -0
  62. data/vendor/coffee-script/documentation/js/expressions_assignment.js +4 -0
  63. data/vendor/coffee-script/documentation/js/expressions_comprehension.js +12 -0
  64. data/vendor/coffee-script/documentation/js/expressions_try.js +9 -0
  65. data/vendor/coffee-script/documentation/js/fat_arrow.js +15 -0
  66. data/vendor/coffee-script/documentation/js/functions.js +9 -0
  67. data/vendor/coffee-script/documentation/js/heredocs.js +4 -0
  68. data/vendor/coffee-script/documentation/js/intro.js +7 -0
  69. data/vendor/coffee-script/documentation/js/multiple_return_values.js +11 -0
  70. data/vendor/coffee-script/documentation/js/object_comprehensions.js +17 -0
  71. data/vendor/coffee-script/documentation/js/object_extraction.js +17 -0
  72. data/vendor/coffee-script/documentation/js/objects_and_arrays.js +10 -0
  73. data/vendor/coffee-script/documentation/js/overview.js +43 -0
  74. data/vendor/coffee-script/documentation/js/parallel_assignment.js +8 -0
  75. data/vendor/coffee-script/documentation/js/punctuation.js +8 -0
  76. data/vendor/coffee-script/documentation/js/range_comprehensions.js +21 -0
  77. data/vendor/coffee-script/documentation/js/scope.js +10 -0
  78. data/vendor/coffee-script/documentation/js/slices.js +6 -0
  79. data/vendor/coffee-script/documentation/js/soaks.js +4 -0
  80. data/vendor/coffee-script/documentation/js/splats.js +16 -0
  81. data/vendor/coffee-script/documentation/js/splices.js +5 -0
  82. data/vendor/coffee-script/documentation/js/strings.js +9 -0
  83. data/vendor/coffee-script/documentation/js/super.js +37 -0
  84. data/vendor/coffee-script/documentation/js/switch.js +18 -0
  85. data/vendor/coffee-script/documentation/js/try.js +10 -0
  86. data/vendor/coffee-script/documentation/js/while.js +22 -0
  87. data/vendor/coffee-script/documentation/underscore.html +627 -0
  88. data/vendor/coffee-script/examples/beautiful_code/binary_search.coffee +16 -0
  89. data/vendor/coffee-script/examples/beautiful_code/quicksort_runtime.coffee +13 -0
  90. data/vendor/coffee-script/examples/beautiful_code/regular_expression_matcher.coffee +34 -0
  91. data/vendor/coffee-script/examples/blocks.coffee +57 -0
  92. data/vendor/coffee-script/examples/code.coffee +173 -0
  93. data/vendor/coffee-script/examples/computer_science/README +4 -0
  94. data/vendor/coffee-script/examples/computer_science/binary_search.coffee +25 -0
  95. data/vendor/coffee-script/examples/computer_science/bubble_sort.coffee +11 -0
  96. data/vendor/coffee-script/examples/computer_science/linked_list.coffee +106 -0
  97. data/vendor/coffee-script/examples/computer_science/luhn_algorithm.coffee +36 -0
  98. data/vendor/coffee-script/examples/computer_science/merge_sort.coffee +19 -0
  99. data/vendor/coffee-script/examples/computer_science/selection_sort.coffee +23 -0
  100. data/vendor/coffee-script/examples/poignant.coffee +186 -0
  101. data/vendor/coffee-script/examples/potion.coffee +205 -0
  102. data/vendor/coffee-script/examples/underscore.coffee +603 -0
  103. data/vendor/coffee-script/examples/web_server.coffee +12 -0
  104. data/vendor/coffee-script/extras/CoffeeScript.tmbundle/Preferences/CoffeeScript.tmPreferences +24 -0
  105. data/vendor/coffee-script/extras/CoffeeScript.tmbundle/Syntaxes/CoffeeScript.tmLanguage +361 -0
  106. data/vendor/coffee-script/extras/CoffeeScript.tmbundle/info.plist +10 -0
  107. data/vendor/coffee-script/extras/EXTRAS +20 -0
  108. data/vendor/coffee-script/extras/coffee.vim +117 -0
  109. data/vendor/coffee-script/index.html +1847 -0
  110. data/vendor/coffee-script/lib/bin/cake +7 -0
  111. data/vendor/coffee-script/lib/bin/coffee +7 -0
  112. data/vendor/coffee-script/lib/cake.js +80 -0
  113. data/vendor/coffee-script/lib/coffee-script.js +61 -0
  114. data/vendor/coffee-script/lib/command_line.js +201 -0
  115. data/vendor/coffee-script/lib/grammar.js +564 -0
  116. data/vendor/coffee-script/lib/lexer.js +405 -0
  117. data/vendor/coffee-script/lib/narwhal.js +44 -0
  118. data/vendor/coffee-script/lib/nodes.js +1328 -0
  119. data/vendor/coffee-script/lib/optparse.js +117 -0
  120. data/vendor/coffee-script/lib/parser.js +536 -0
  121. data/vendor/coffee-script/lib/repl.js +32 -0
  122. data/vendor/coffee-script/lib/rewriter.js +383 -0
  123. data/vendor/coffee-script/lib/scope.js +114 -0
  124. data/vendor/coffee-script/package.json +7 -0
  125. data/vendor/coffee-script/src/cake.coffee +45 -0
  126. data/vendor/coffee-script/src/coffee-script.coffee +45 -0
  127. data/vendor/coffee-script/src/command_line.coffee +130 -0
  128. data/vendor/coffee-script/src/grammar.coffee +456 -0
  129. data/vendor/coffee-script/src/lexer.coffee +327 -0
  130. data/vendor/coffee-script/src/narwhal.coffee +42 -0
  131. data/vendor/coffee-script/src/nodes.coffee +1045 -0
  132. data/vendor/coffee-script/src/optparse.coffee +79 -0
  133. data/vendor/coffee-script/src/repl.coffee +23 -0
  134. data/vendor/coffee-script/src/rewriter.coffee +253 -0
  135. data/vendor/coffee-script/src/scope.coffee +75 -0
  136. data/vendor/coffee-script/test/test_arguments.coffee +34 -0
  137. data/vendor/coffee-script/test/test_array_comprehension.coffee +42 -0
  138. data/vendor/coffee-script/test/test_assignment.coffee +26 -0
  139. data/vendor/coffee-script/test/test_blocks.coffee +4 -0
  140. data/vendor/coffee-script/test/test_calling_super.coffee +42 -0
  141. data/vendor/coffee-script/test/test_chained_calls.coffee +25 -0
  142. data/vendor/coffee-script/test/test_destructuring_assignment.coffee +62 -0
  143. data/vendor/coffee-script/test/test_everything.coffee +29 -0
  144. data/vendor/coffee-script/test/test_exceptions.coffee +2 -0
  145. data/vendor/coffee-script/test/test_existence.coffee +81 -0
  146. data/vendor/coffee-script/test/test_expressions.coffee +30 -0
  147. data/vendor/coffee-script/test/test_fancy_if_statement.coffee +26 -0
  148. data/vendor/coffee-script/test/test_functions.coffee +80 -0
  149. data/vendor/coffee-script/test/test_funky_comments.coffee +25 -0
  150. data/vendor/coffee-script/test/test_heredocs.coffee +46 -0
  151. data/vendor/coffee-script/test/test_lexical_scope.coffee +10 -0
  152. data/vendor/coffee-script/test/test_literals.coffee +56 -0
  153. data/vendor/coffee-script/test/test_nested_comprehensions.coffee +11 -0
  154. data/vendor/coffee-script/test/test_newline_escaping.coffee +6 -0
  155. data/vendor/coffee-script/test/test_operations.coffee +18 -0
  156. data/vendor/coffee-script/test/test_range_comprehension.coffee +20 -0
  157. data/vendor/coffee-script/test/test_ranges_and_slices.coffee +16 -0
  158. data/vendor/coffee-script/test/test_splats.coffee +47 -0
  159. data/vendor/coffee-script/test/test_splices.coffee +5 -0
  160. data/vendor/coffee-script/test/test_switch.coffee +64 -0
  161. data/vendor/coffee-script/test/test_while.coffee +30 -0
  162. data/vendor/coffee-script/vendor/jison/Jakefile +31 -0
  163. data/vendor/coffee-script/vendor/jison/README.md +347 -0
  164. data/vendor/coffee-script/vendor/jison/bin/jison +3 -0
  165. data/vendor/coffee-script/vendor/jison/bin/json2jison +3 -0
  166. data/vendor/coffee-script/vendor/jison/examples/ansic.jison +415 -0
  167. data/vendor/coffee-script/vendor/jison/examples/basic.json +8 -0
  168. data/vendor/coffee-script/vendor/jison/examples/basic2.json +9 -0
  169. data/vendor/coffee-script/vendor/jison/examples/basic2_lex.json +16 -0
  170. data/vendor/coffee-script/vendor/jison/examples/basic_lex.json +15 -0
  171. data/vendor/coffee-script/vendor/jison/examples/calculator.jison +38 -0
  172. data/vendor/coffee-script/vendor/jison/examples/calculator.jisonlex +14 -0
  173. data/vendor/coffee-script/vendor/jison/examples/calculator.json +42 -0
  174. data/vendor/coffee-script/vendor/jison/examples/classy.json +105 -0
  175. data/vendor/coffee-script/vendor/jison/examples/classy_ast.json +126 -0
  176. data/vendor/coffee-script/vendor/jison/examples/dism.json +25 -0
  177. data/vendor/coffee-script/vendor/jison/examples/dism_lr0.json +26 -0
  178. data/vendor/coffee-script/vendor/jison/examples/json.js +80 -0
  179. data/vendor/coffee-script/vendor/jison/examples/json_ast.js +83 -0
  180. data/vendor/coffee-script/vendor/jison/examples/precedence.json +26 -0
  181. data/vendor/coffee-script/vendor/jison/examples/reduce_conflict.json +13 -0
  182. data/vendor/coffee-script/vendor/jison/lib/jison/bnf.js +43 -0
  183. data/vendor/coffee-script/vendor/jison/lib/jison/jisonlex.js +18 -0
  184. data/vendor/coffee-script/vendor/jison/lib/jison/json2jison.js +146 -0
  185. data/vendor/coffee-script/vendor/jison/lib/jison/lexer.js +224 -0
  186. data/vendor/coffee-script/vendor/jison/lib/jison/util/bnf-parser.js +383 -0
  187. data/vendor/coffee-script/vendor/jison/lib/jison/util/lex-parser.js +407 -0
  188. data/vendor/coffee-script/vendor/jison/lib/jison/util/set.js +94 -0
  189. data/vendor/coffee-script/vendor/jison/lib/jison/util/typal.js +90 -0
  190. data/vendor/coffee-script/vendor/jison/lib/jison.js +1414 -0
  191. data/vendor/coffee-script/vendor/jison/package.json +14 -0
  192. data/vendor/coffee-script/vendor/jison/src/bnf.jison +110 -0
  193. data/vendor/coffee-script/vendor/jison/src/bnf.jisonlex +25 -0
  194. data/vendor/coffee-script/vendor/jison/src/bnf.lex.json +24 -0
  195. data/vendor/coffee-script/vendor/jison/src/jisonlex.jison +129 -0
  196. data/vendor/coffee-script/vendor/jison/src/jisonlex.jisonlex +31 -0
  197. data/vendor/coffee-script/vendor/jison/src/jisonlex.lex.json +30 -0
  198. data/vendor/coffee-script/vendor/jison/tests/all-tests.js +8 -0
  199. data/vendor/coffee-script/vendor/jison/tests/grammar/bnf.js +91 -0
  200. data/vendor/coffee-script/vendor/jison/tests/grammar/bnf_parse.js +65 -0
  201. data/vendor/coffee-script/vendor/jison/tests/grammar/grammar-tests.js +10 -0
  202. data/vendor/coffee-script/vendor/jison/tests/grammar/json2jison.js +24 -0
  203. data/vendor/coffee-script/vendor/jison/tests/grammar/lex/ansic.jisonlex +115 -0
  204. data/vendor/coffee-script/vendor/jison/tests/grammar/lex/bnf.jisonlex +25 -0
  205. data/vendor/coffee-script/vendor/jison/tests/grammar/lex/bnf.lex.json +24 -0
  206. data/vendor/coffee-script/vendor/jison/tests/grammar/lex/lex_grammar.jisonlex +31 -0
  207. data/vendor/coffee-script/vendor/jison/tests/grammar/lex/lex_grammar.lex.json +30 -0
  208. data/vendor/coffee-script/vendor/jison/tests/grammar/lex.jison +119 -0
  209. data/vendor/coffee-script/vendor/jison/tests/grammar/lex.js +58 -0
  210. data/vendor/coffee-script/vendor/jison/tests/grammar/lex_parse.js +117 -0
  211. data/vendor/coffee-script/vendor/jison/tests/lexer/lexer-tests.js +6 -0
  212. data/vendor/coffee-script/vendor/jison/tests/lexer/regexplexer.js +417 -0
  213. data/vendor/coffee-script/vendor/jison/tests/parser/actions.js +311 -0
  214. data/vendor/coffee-script/vendor/jison/tests/parser/api.js +236 -0
  215. data/vendor/coffee-script/vendor/jison/tests/parser/generator.js +196 -0
  216. data/vendor/coffee-script/vendor/jison/tests/parser/lalr.js +183 -0
  217. data/vendor/coffee-script/vendor/jison/tests/parser/lr0.js +72 -0
  218. data/vendor/coffee-script/vendor/jison/tests/parser/lr1.js +119 -0
  219. data/vendor/coffee-script/vendor/jison/tests/parser/parser-tests.js +14 -0
  220. data/vendor/coffee-script/vendor/jison/tests/parser/precedence.js +237 -0
  221. data/vendor/coffee-script/vendor/jison/tests/parser/slr.js +52 -0
  222. data/vendor/coffee-script/vendor/jison/tests/parser/tables.js +126 -0
  223. data/vendor/coffee-script/vendor/jison/tests/performance.js +110 -0
  224. data/vendor/coffee-script/vendor/jison/tests/setup.js +3 -0
  225. 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,4 @@
1
+ results: [1, 2, 3].map (x) ->
2
+ x * x
3
+
4
+ ok results.join(' ') is '1 4 9', 'basic block syntax'
@@ -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"