haml 3.0.25 → 3.1.0.alpha.2

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of haml might be problematic. Click here for more details.

Files changed (212) hide show
  1. data/.yardopts +1 -1
  2. data/CONTRIBUTING +0 -1
  3. data/EDGE_GEM_VERSION +1 -0
  4. data/MIT-LICENSE +1 -1
  5. data/README.md +10 -175
  6. data/Rakefile +56 -84
  7. data/VERSION +1 -1
  8. data/VERSION_NAME +1 -1
  9. data/init.rb +1 -1
  10. data/lib/haml.rb +14 -12
  11. data/lib/haml/engine.rb +1 -1
  12. data/lib/haml/exec.rb +19 -316
  13. data/lib/haml/helpers/action_view_extensions.rb +1 -1
  14. data/lib/haml/html.rb +69 -76
  15. data/lib/haml/precompiler.rb +34 -41
  16. data/lib/haml/railtie.rb +4 -6
  17. data/lib/haml/template/plugin.rb +6 -16
  18. data/lib/haml/util.rb +91 -107
  19. data/lib/haml/version.rb +7 -0
  20. data/test/benchmark.rb +2 -9
  21. data/test/haml/engine_test.rb +195 -92
  22. data/test/haml/html2haml/erb_tests.rb +0 -14
  23. data/test/haml/util_test.rb +32 -0
  24. data/test/test_helper.rb +0 -39
  25. metadata +96 -324
  26. data/bin/css2sass +0 -13
  27. data/bin/sass +0 -8
  28. data/bin/sass-convert +0 -7
  29. data/extra/haml-mode.el +0 -753
  30. data/extra/sass-mode.el +0 -207
  31. data/lib/haml/util/subset_map.rb +0 -101
  32. data/lib/sass.rb +0 -29
  33. data/lib/sass/callbacks.rb +0 -52
  34. data/lib/sass/css.rb +0 -294
  35. data/lib/sass/engine.rb +0 -720
  36. data/lib/sass/environment.rb +0 -143
  37. data/lib/sass/error.rb +0 -198
  38. data/lib/sass/files.rb +0 -160
  39. data/lib/sass/less.rb +0 -382
  40. data/lib/sass/plugin.rb +0 -279
  41. data/lib/sass/plugin/configuration.rb +0 -221
  42. data/lib/sass/plugin/generic.rb +0 -15
  43. data/lib/sass/plugin/merb.rb +0 -37
  44. data/lib/sass/plugin/rack.rb +0 -47
  45. data/lib/sass/plugin/rails.rb +0 -32
  46. data/lib/sass/plugin/staleness_checker.rb +0 -123
  47. data/lib/sass/repl.rb +0 -58
  48. data/lib/sass/script.rb +0 -63
  49. data/lib/sass/script/bool.rb +0 -18
  50. data/lib/sass/script/color.rb +0 -491
  51. data/lib/sass/script/css_lexer.rb +0 -29
  52. data/lib/sass/script/css_parser.rb +0 -31
  53. data/lib/sass/script/funcall.rb +0 -77
  54. data/lib/sass/script/functions.rb +0 -861
  55. data/lib/sass/script/interpolation.rb +0 -70
  56. data/lib/sass/script/lexer.rb +0 -337
  57. data/lib/sass/script/literal.rb +0 -236
  58. data/lib/sass/script/node.rb +0 -112
  59. data/lib/sass/script/number.rb +0 -423
  60. data/lib/sass/script/operation.rb +0 -95
  61. data/lib/sass/script/parser.rb +0 -401
  62. data/lib/sass/script/string.rb +0 -67
  63. data/lib/sass/script/string_interpolation.rb +0 -93
  64. data/lib/sass/script/unary_operation.rb +0 -57
  65. data/lib/sass/script/variable.rb +0 -48
  66. data/lib/sass/scss.rb +0 -17
  67. data/lib/sass/scss/css_parser.rb +0 -46
  68. data/lib/sass/scss/parser.rb +0 -855
  69. data/lib/sass/scss/rx.rb +0 -126
  70. data/lib/sass/scss/sass_parser.rb +0 -11
  71. data/lib/sass/scss/script_lexer.rb +0 -15
  72. data/lib/sass/scss/script_parser.rb +0 -25
  73. data/lib/sass/scss/static_parser.rb +0 -40
  74. data/lib/sass/selector.rb +0 -361
  75. data/lib/sass/selector/abstract_sequence.rb +0 -62
  76. data/lib/sass/selector/comma_sequence.rb +0 -82
  77. data/lib/sass/selector/sequence.rb +0 -237
  78. data/lib/sass/selector/simple.rb +0 -113
  79. data/lib/sass/selector/simple_sequence.rb +0 -136
  80. data/lib/sass/tree/charset_node.rb +0 -37
  81. data/lib/sass/tree/comment_node.rb +0 -128
  82. data/lib/sass/tree/debug_node.rb +0 -36
  83. data/lib/sass/tree/directive_node.rb +0 -75
  84. data/lib/sass/tree/extend_node.rb +0 -65
  85. data/lib/sass/tree/for_node.rb +0 -55
  86. data/lib/sass/tree/if_node.rb +0 -69
  87. data/lib/sass/tree/import_node.rb +0 -102
  88. data/lib/sass/tree/mixin_def_node.rb +0 -48
  89. data/lib/sass/tree/mixin_node.rb +0 -111
  90. data/lib/sass/tree/node.rb +0 -464
  91. data/lib/sass/tree/prop_node.rb +0 -220
  92. data/lib/sass/tree/root_node.rb +0 -163
  93. data/lib/sass/tree/rule_node.rb +0 -261
  94. data/lib/sass/tree/variable_node.rb +0 -39
  95. data/lib/sass/tree/warn_node.rb +0 -42
  96. data/lib/sass/tree/while_node.rb +0 -36
  97. data/test/haml/util/subset_map_test.rb +0 -91
  98. data/test/sass/callbacks_test.rb +0 -61
  99. data/test/sass/conversion_test.rb +0 -1218
  100. data/test/sass/css2sass_test.rb +0 -364
  101. data/test/sass/data/hsl-rgb.txt +0 -319
  102. data/test/sass/engine_test.rb +0 -2267
  103. data/test/sass/extend_test.rb +0 -1348
  104. data/test/sass/functions_test.rb +0 -556
  105. data/test/sass/less_conversion_test.rb +0 -653
  106. data/test/sass/more_results/more1.css +0 -9
  107. data/test/sass/more_results/more1_with_line_comments.css +0 -26
  108. data/test/sass/more_results/more_import.css +0 -29
  109. data/test/sass/more_templates/_more_partial.sass +0 -2
  110. data/test/sass/more_templates/more1.sass +0 -23
  111. data/test/sass/more_templates/more_import.sass +0 -11
  112. data/test/sass/plugin_test.rb +0 -433
  113. data/test/sass/results/alt.css +0 -4
  114. data/test/sass/results/basic.css +0 -9
  115. data/test/sass/results/compact.css +0 -5
  116. data/test/sass/results/complex.css +0 -86
  117. data/test/sass/results/compressed.css +0 -1
  118. data/test/sass/results/expanded.css +0 -19
  119. data/test/sass/results/import.css +0 -31
  120. data/test/sass/results/import_charset.css +0 -4
  121. data/test/sass/results/import_charset_1_8.css +0 -4
  122. data/test/sass/results/import_charset_ibm866.css +0 -4
  123. data/test/sass/results/line_numbers.css +0 -49
  124. data/test/sass/results/mixins.css +0 -95
  125. data/test/sass/results/multiline.css +0 -24
  126. data/test/sass/results/nested.css +0 -22
  127. data/test/sass/results/options.css +0 -1
  128. data/test/sass/results/parent_ref.css +0 -13
  129. data/test/sass/results/script.css +0 -16
  130. data/test/sass/results/scss_import.css +0 -31
  131. data/test/sass/results/scss_importee.css +0 -2
  132. data/test/sass/results/subdir/nested_subdir/nested_subdir.css +0 -1
  133. data/test/sass/results/subdir/subdir.css +0 -3
  134. data/test/sass/results/units.css +0 -11
  135. data/test/sass/results/warn.css +0 -0
  136. data/test/sass/results/warn_imported.css +0 -0
  137. data/test/sass/script_conversion_test.rb +0 -314
  138. data/test/sass/script_test.rb +0 -470
  139. data/test/sass/scss/css_test.rb +0 -916
  140. data/test/sass/scss/rx_test.rb +0 -156
  141. data/test/sass/scss/scss_test.rb +0 -1122
  142. data/test/sass/scss/test_helper.rb +0 -37
  143. data/test/sass/templates/_imported_charset_ibm866.sass +0 -4
  144. data/test/sass/templates/_imported_charset_utf8.sass +0 -4
  145. data/test/sass/templates/_partial.sass +0 -2
  146. data/test/sass/templates/alt.sass +0 -16
  147. data/test/sass/templates/basic.sass +0 -23
  148. data/test/sass/templates/bork1.sass +0 -2
  149. data/test/sass/templates/bork2.sass +0 -2
  150. data/test/sass/templates/bork3.sass +0 -2
  151. data/test/sass/templates/bork4.sass +0 -2
  152. data/test/sass/templates/compact.sass +0 -17
  153. data/test/sass/templates/complex.sass +0 -305
  154. data/test/sass/templates/compressed.sass +0 -15
  155. data/test/sass/templates/expanded.sass +0 -17
  156. data/test/sass/templates/import.sass +0 -12
  157. data/test/sass/templates/import_charset.sass +0 -7
  158. data/test/sass/templates/import_charset_1_8.sass +0 -4
  159. data/test/sass/templates/import_charset_ibm866.sass +0 -9
  160. data/test/sass/templates/importee.less +0 -2
  161. data/test/sass/templates/importee.sass +0 -19
  162. data/test/sass/templates/line_numbers.sass +0 -13
  163. data/test/sass/templates/mixin_bork.sass +0 -5
  164. data/test/sass/templates/mixins.sass +0 -76
  165. data/test/sass/templates/multiline.sass +0 -20
  166. data/test/sass/templates/nested.sass +0 -25
  167. data/test/sass/templates/nested_bork1.sass +0 -2
  168. data/test/sass/templates/nested_bork2.sass +0 -2
  169. data/test/sass/templates/nested_bork3.sass +0 -2
  170. data/test/sass/templates/nested_bork4.sass +0 -2
  171. data/test/sass/templates/nested_mixin_bork.sass +0 -6
  172. data/test/sass/templates/options.sass +0 -2
  173. data/test/sass/templates/parent_ref.sass +0 -25
  174. data/test/sass/templates/script.sass +0 -101
  175. data/test/sass/templates/scss_import.scss +0 -11
  176. data/test/sass/templates/scss_importee.scss +0 -1
  177. data/test/sass/templates/subdir/nested_subdir/_nested_partial.sass +0 -2
  178. data/test/sass/templates/subdir/nested_subdir/nested_subdir.sass +0 -3
  179. data/test/sass/templates/subdir/subdir.sass +0 -6
  180. data/test/sass/templates/units.sass +0 -11
  181. data/test/sass/templates/warn.sass +0 -3
  182. data/test/sass/templates/warn_imported.sass +0 -4
  183. data/vendor/fssm/LICENSE +0 -20
  184. data/vendor/fssm/README.markdown +0 -55
  185. data/vendor/fssm/Rakefile +0 -59
  186. data/vendor/fssm/VERSION.yml +0 -5
  187. data/vendor/fssm/example.rb +0 -9
  188. data/vendor/fssm/fssm.gemspec +0 -77
  189. data/vendor/fssm/lib/fssm.rb +0 -33
  190. data/vendor/fssm/lib/fssm/backends/fsevents.rb +0 -36
  191. data/vendor/fssm/lib/fssm/backends/inotify.rb +0 -26
  192. data/vendor/fssm/lib/fssm/backends/polling.rb +0 -25
  193. data/vendor/fssm/lib/fssm/backends/rubycocoa/fsevents.rb +0 -131
  194. data/vendor/fssm/lib/fssm/monitor.rb +0 -26
  195. data/vendor/fssm/lib/fssm/path.rb +0 -91
  196. data/vendor/fssm/lib/fssm/pathname.rb +0 -502
  197. data/vendor/fssm/lib/fssm/state/directory.rb +0 -57
  198. data/vendor/fssm/lib/fssm/state/file.rb +0 -24
  199. data/vendor/fssm/lib/fssm/support.rb +0 -63
  200. data/vendor/fssm/lib/fssm/tree.rb +0 -176
  201. data/vendor/fssm/profile/prof-cache.rb +0 -40
  202. data/vendor/fssm/profile/prof-fssm-pathname.html +0 -1231
  203. data/vendor/fssm/profile/prof-pathname.rb +0 -68
  204. data/vendor/fssm/profile/prof-plain-pathname.html +0 -988
  205. data/vendor/fssm/profile/prof.html +0 -2379
  206. data/vendor/fssm/spec/path_spec.rb +0 -75
  207. data/vendor/fssm/spec/root/duck/quack.txt +0 -0
  208. data/vendor/fssm/spec/root/file.css +0 -0
  209. data/vendor/fssm/spec/root/file.rb +0 -0
  210. data/vendor/fssm/spec/root/file.yml +0 -0
  211. data/vendor/fssm/spec/root/moo/cow.txt +0 -0
  212. data/vendor/fssm/spec/spec_helper.rb +0 -14
@@ -1,95 +0,0 @@
1
- require 'set'
2
- require 'sass/script/string'
3
- require 'sass/script/number'
4
- require 'sass/script/color'
5
- require 'sass/script/functions'
6
- require 'sass/script/unary_operation'
7
- require 'sass/script/interpolation'
8
- require 'sass/script/string_interpolation'
9
-
10
- module Sass::Script
11
- # A SassScript parse node representing a binary operation,
12
- # such as `$a + $b` or `"foo" + 1`.
13
- class Operation < Node
14
- attr_reader :operand1
15
- attr_reader :operand2
16
- attr_reader :operator
17
-
18
- # @param operand1 [Script::Node] The parse-tree node
19
- # for the right-hand side of the operator
20
- # @param operand2 [Script::Node] The parse-tree node
21
- # for the left-hand side of the operator
22
- # @param operator [Symbol] The operator to perform.
23
- # This should be one of the binary operator names in {Lexer::OPERATORS}
24
- def initialize(operand1, operand2, operator)
25
- @operand1 = operand1
26
- @operand2 = operand2
27
- @operator = operator
28
- super()
29
- end
30
-
31
- # @return [String] A human-readable s-expression representation of the operation
32
- def inspect
33
- "(#{@operator.inspect} #{@operand1.inspect} #{@operand2.inspect})"
34
- end
35
-
36
- # @see Node#to_sass
37
- def to_sass(opts = {})
38
- pred = Sass::Script::Parser.precedence_of(@operator)
39
- o1 = operand_to_sass @operand1, :left, opts
40
- o2 = operand_to_sass @operand2, :right, opts
41
- sep =
42
- case @operator
43
- when :comma; ", "
44
- when :concat; " "
45
- else; " #{Lexer::OPERATORS_REVERSE[@operator]} "
46
- end
47
- "#{o1}#{sep}#{o2}"
48
- end
49
-
50
- # Returns the operands for this operation.
51
- #
52
- # @return [Array<Node>]
53
- # @see Node#children
54
- def children
55
- [@operand1, @operand2]
56
- end
57
-
58
- protected
59
-
60
- # Evaluates the operation.
61
- #
62
- # @param environment [Sass::Environment] The environment in which to evaluate the SassScript
63
- # @return [Literal] The SassScript object that is the value of the operation
64
- # @raise [Sass::SyntaxError] if the operation is undefined for the operands
65
- def _perform(environment)
66
- literal1 = @operand1.perform(environment)
67
- literal2 = @operand2.perform(environment)
68
-
69
- if @operator == :concat && context == :equals
70
- literal1 = Sass::Script::String.new(literal1.value) if literal1.is_a?(Sass::Script::String)
71
- literal2 = Sass::Script::String.new(literal2.value) if literal2.is_a?(Sass::Script::String)
72
- end
73
-
74
- begin
75
- opts(literal1.send(@operator, literal2))
76
- rescue NoMethodError => e
77
- raise e unless e.name.to_s == @operator.to_s
78
- raise Sass::SyntaxError.new("Undefined operation: \"#{literal1} #{@operator} #{literal2}\".")
79
- end
80
- end
81
-
82
- private
83
-
84
- def operand_to_sass(op, side, opts)
85
- return op.to_sass(opts) unless op.is_a?(Operation)
86
-
87
- pred = Sass::Script::Parser.precedence_of(@operator)
88
- sub_pred = Sass::Script::Parser.precedence_of(op.operator)
89
- assoc = Sass::Script::Parser.associative?(@operator)
90
- return "(#{op.to_sass(opts)})" if sub_pred < pred ||
91
- (side == :right && sub_pred == pred && !assoc)
92
- op.to_sass(opts)
93
- end
94
- end
95
- end
@@ -1,401 +0,0 @@
1
- require 'sass/script/lexer'
2
-
3
- module Sass
4
- module Script
5
- # The parser for SassScript.
6
- # It parses a string of code into a tree of {Script::Node}s.
7
- class Parser
8
- # The line number of the parser's current position.
9
- #
10
- # @return [Fixnum]
11
- def line
12
- @lexer.line
13
- end
14
-
15
- # @param str [String, StringScanner] The source text to parse
16
- # @param line [Fixnum] The line on which the SassScript appears.
17
- # Used for error reporting
18
- # @param offset [Fixnum] The number of characters in on which the SassScript appears.
19
- # Used for error reporting
20
- # @param options [{Symbol => Object}] An options hash;
21
- # see {file:SASS_REFERENCE.md#sass_options the Sass options documentation}
22
- def initialize(str, line, offset, options = {})
23
- @options = options
24
- @lexer = lexer_class.new(str, line, offset, options)
25
- end
26
-
27
- # Parses a SassScript expression within an interpolated segment (`#{}`).
28
- # This means that it stops when it comes across an unmatched `}`,
29
- # which signals the end of an interpolated segment,
30
- # it returns rather than throwing an error.
31
- #
32
- # @return [Script::Node] The root node of the parse tree
33
- # @raise [Sass::SyntaxError] if the expression isn't valid SassScript
34
- def parse_interpolated
35
- expr = assert_expr :expr
36
- assert_tok :end_interpolation
37
- expr.options = @options
38
- expr
39
- rescue Sass::SyntaxError => e
40
- e.modify_backtrace :line => @lexer.line, :filename => @options[:filename]
41
- raise e
42
- end
43
-
44
- # Parses a SassScript expression.
45
- #
46
- # @return [Script::Node] The root node of the parse tree
47
- # @raise [Sass::SyntaxError] if the expression isn't valid SassScript
48
- def parse
49
- expr = assert_expr :expr
50
- assert_done
51
- expr.options = @options
52
- expr
53
- rescue Sass::SyntaxError => e
54
- e.modify_backtrace :line => @lexer.line, :filename => @options[:filename]
55
- raise e
56
- end
57
-
58
- # Parses a SassScript expression,
59
- # ending it when it encounters one of the given identifier tokens.
60
- #
61
- # @param [#include?(String)] A set of strings that delimit the expression.
62
- # @return [Script::Node] The root node of the parse tree
63
- # @raise [Sass::SyntaxError] if the expression isn't valid SassScript
64
- def parse_until(tokens)
65
- @stop_at = tokens
66
- expr = assert_expr :expr
67
- assert_done
68
- expr.options = @options
69
- expr
70
- rescue Sass::SyntaxError => e
71
- e.modify_backtrace :line => @lexer.line, :filename => @options[:filename]
72
- raise e
73
- end
74
-
75
- # Parses the argument list for a mixin include.
76
- #
77
- # @return [Array<Script::Node>] The root nodes of the arguments.
78
- # @raise [Sass::SyntaxError] if the argument list isn't valid SassScript
79
- def parse_mixin_include_arglist
80
- args = []
81
-
82
- if try_tok(:lparen)
83
- args = arglist || args
84
- assert_tok(:rparen)
85
- end
86
- assert_done
87
-
88
- args.each {|a| a.options = @options}
89
- args
90
- rescue Sass::SyntaxError => e
91
- e.modify_backtrace :line => @lexer.line, :filename => @options[:filename]
92
- raise e
93
- end
94
-
95
- # Parses the argument list for a mixin definition.
96
- #
97
- # @return [Array<Script::Node>] The root nodes of the arguments.
98
- # @raise [Sass::SyntaxError] if the argument list isn't valid SassScript
99
- def parse_mixin_definition_arglist
100
- args = defn_arglist!(false)
101
- assert_done
102
-
103
- args.each do |k, v|
104
- k.options = @options
105
- v.options = @options if v
106
- end
107
- args
108
- rescue Sass::SyntaxError => e
109
- e.modify_backtrace :line => @lexer.line, :filename => @options[:filename]
110
- raise e
111
- end
112
-
113
- # Parses a SassScript expression.
114
- #
115
- # @overload parse(str, line, offset, filename = nil)
116
- # @return [Script::Node] The root node of the parse tree
117
- # @see Parser#initialize
118
- # @see Parser#parse
119
- def self.parse(*args)
120
- new(*args).parse
121
- end
122
-
123
- PRECEDENCE = [
124
- :comma, :single_eq, :concat, :or, :and,
125
- [:eq, :neq],
126
- [:gt, :gte, :lt, :lte],
127
- [:plus, :minus],
128
- [:times, :div, :mod],
129
- ]
130
-
131
- ASSOCIATIVE = [:comma, :concat, :plus, :times]
132
-
133
- class << self
134
- # Returns an integer representing the precedence
135
- # of the given operator.
136
- # A lower integer indicates a looser binding.
137
- #
138
- # @private
139
- def precedence_of(op)
140
- PRECEDENCE.each_with_index do |e, i|
141
- return i if Array(e).include?(op)
142
- end
143
- raise "[BUG] Unknown operator #{op}"
144
- end
145
-
146
- # Returns whether or not the given operation is associative.
147
- #
148
- # @private
149
- def associative?(op)
150
- ASSOCIATIVE.include?(op)
151
- end
152
-
153
- private
154
-
155
- # Defines a simple left-associative production.
156
- # name is the name of the production,
157
- # sub is the name of the production beneath it,
158
- # and ops is a list of operators for this precedence level
159
- def production(name, sub, *ops)
160
- class_eval <<RUBY
161
- def #{name}
162
- interp = try_ops_after_interp(#{ops.inspect}, #{name.inspect}) and return interp
163
- return unless e = #{sub}
164
- while tok = try_tok(#{ops.map {|o| o.inspect}.join(', ')})
165
- interp = try_op_before_interp(tok, e) and return interp
166
- line = @lexer.line
167
- e = Operation.new(e, assert_expr(#{sub.inspect}), tok.type)
168
- e.line = line
169
- end
170
- e
171
- end
172
- RUBY
173
- end
174
-
175
- def unary(op, sub)
176
- class_eval <<RUBY
177
- def unary_#{op}
178
- return #{sub} unless tok = try_tok(:#{op})
179
- interp = try_op_before_interp(tok) and return interp
180
- line = @lexer.line
181
- op = UnaryOperation.new(assert_expr(:unary_#{op}), :#{op})
182
- op.line = line
183
- op
184
- end
185
- RUBY
186
- end
187
- end
188
-
189
- private
190
-
191
- # @private
192
- def lexer_class; Lexer; end
193
-
194
- production :expr, :interpolation, :comma
195
- production :equals, :interpolation, :single_eq
196
-
197
- def try_op_before_interp(op, prev = nil)
198
- return unless @lexer.peek && @lexer.peek.type == :begin_interpolation
199
- wb = @lexer.whitespace?(op)
200
- str = Script::String.new(Lexer::OPERATORS_REVERSE[op.type])
201
- str.line = @lexer.line
202
- interp = Script::Interpolation.new(prev, str, nil, wb, !:wa, :originally_text)
203
- interp.line = @lexer.line
204
- interpolation(interp)
205
- end
206
-
207
- def try_ops_after_interp(ops, name)
208
- return unless @lexer.after_interpolation?
209
- return unless op = try_tok(*ops)
210
- interp = try_op_before_interp(op) and return interp
211
-
212
- wa = @lexer.whitespace?
213
- str = Script::String.new(Lexer::OPERATORS_REVERSE[op.type])
214
- str.line = @lexer.line
215
- interp = Script::Interpolation.new(nil, str, assert_expr(name), !:wb, wa, :originally_text)
216
- interp.line = @lexer.line
217
- return interp
218
- end
219
-
220
- def interpolation(first = concat)
221
- e = first
222
- while interp = try_tok(:begin_interpolation)
223
- wb = @lexer.whitespace?(interp)
224
- line = @lexer.line
225
- mid = parse_interpolated
226
- wa = @lexer.whitespace?
227
- e = Script::Interpolation.new(e, mid, concat, wb, wa)
228
- e.line = line
229
- end
230
- e
231
- end
232
-
233
- def concat
234
- return unless e = or_expr
235
- while sub = or_expr
236
- e = node(Operation.new(e, sub, :concat))
237
- end
238
- e
239
- end
240
-
241
- production :or_expr, :and_expr, :or
242
- production :and_expr, :eq_or_neq, :and
243
- production :eq_or_neq, :relational, :eq, :neq
244
- production :relational, :plus_or_minus, :gt, :gte, :lt, :lte
245
- production :plus_or_minus, :times_div_or_mod, :plus, :minus
246
- production :times_div_or_mod, :unary_plus, :times, :div, :mod
247
-
248
- unary :plus, :unary_minus
249
- unary :minus, :unary_div
250
- unary :div, :unary_not # For strings, so /foo/bar works
251
- unary :not, :ident
252
-
253
- def ident
254
- return funcall unless @lexer.peek && @lexer.peek.type == :ident
255
- return if @stop_at && @stop_at.include?(@lexer.peek.value)
256
-
257
- name = @lexer.next
258
- if color = Color::HTML4_COLORS[name.value.downcase]
259
- return node(Color.new(color))
260
- end
261
- node(Script::String.new(name.value, :identifier))
262
- end
263
-
264
- def funcall
265
- return raw unless tok = try_tok(:funcall)
266
- args = fn_arglist || []
267
- assert_tok(:rparen)
268
- node(Script::Funcall.new(tok.value, args))
269
- end
270
-
271
- def defn_arglist!(must_have_default)
272
- return [] unless try_tok(:lparen)
273
- return [] if try_tok(:rparen)
274
- res = []
275
- loop do
276
- line = @lexer.line
277
- offset = @lexer.offset + 1
278
- c = assert_tok(:const)
279
- var = Script::Variable.new(c.value)
280
- if tok = (try_tok(:colon) || try_tok(:single_eq))
281
- val = assert_expr(:concat)
282
-
283
- if tok.type == :single_eq
284
- val.context = :equals
285
- val.options = @options
286
- Script.equals_warning("mixin argument defaults", "$#{c.value}",
287
- val.to_sass, false, line, offset, @options[:filename])
288
- end
289
- must_have_default = true
290
- elsif must_have_default
291
- raise SyntaxError.new("Required argument #{var.inspect} must come before any optional arguments.")
292
- end
293
- res << [var, val]
294
- break unless try_tok(:comma)
295
- end
296
- assert_tok(:rparen)
297
- res
298
- end
299
-
300
- def fn_arglist
301
- return unless e = equals
302
- return [e] unless try_tok(:comma)
303
- [e, *assert_expr(:fn_arglist)]
304
- end
305
-
306
- def arglist
307
- return unless e = interpolation
308
- return [e] unless try_tok(:comma)
309
- [e, *assert_expr(:arglist)]
310
- end
311
-
312
- def raw
313
- return special_fun unless tok = try_tok(:raw)
314
- node(Script::String.new(tok.value))
315
- end
316
-
317
- def special_fun
318
- return paren unless tok = try_tok(:special_fun)
319
- first = node(Script::String.new(tok.value.first))
320
- Haml::Util.enum_slice(tok.value[1..-1], 2).inject(first) do |l, (i, r)|
321
- Script::Interpolation.new(
322
- l, i, r && node(Script::String.new(r)),
323
- false, false)
324
- end
325
- end
326
-
327
- def paren
328
- return variable unless try_tok(:lparen)
329
- was_in_parens = @in_parens
330
- @in_parens = true
331
- e = assert_expr(:expr)
332
- assert_tok(:rparen)
333
- return e
334
- ensure
335
- @in_parens = was_in_parens
336
- end
337
-
338
- def variable
339
- return string unless c = try_tok(:const)
340
- node(Variable.new(*c.value))
341
- end
342
-
343
- def string
344
- return number unless first = try_tok(:string)
345
- return first.value unless try_tok(:begin_interpolation)
346
- line = @lexer.line
347
- mid = parse_interpolated
348
- last = assert_expr(:string)
349
- interp = StringInterpolation.new(first.value, mid, last)
350
- interp.line = line
351
- interp
352
- end
353
-
354
- def number
355
- return literal unless tok = try_tok(:number)
356
- num = tok.value
357
- num.original = num.to_s unless @in_parens
358
- num
359
- end
360
-
361
- def literal
362
- (t = try_tok(:color, :bool)) && (return t.value)
363
- end
364
-
365
- # It would be possible to have unified #assert and #try methods,
366
- # but detecting the method/token difference turns out to be quite expensive.
367
-
368
- EXPR_NAMES = {
369
- :string => "string",
370
- :default => "expression (e.g. 1px, bold)",
371
- :arglist => "mixin argument",
372
- :fn_arglist => "function argument",
373
- }
374
-
375
- def assert_expr(name)
376
- (e = send(name)) && (return e)
377
- @lexer.expected!(EXPR_NAMES[name] || EXPR_NAMES[:default])
378
- end
379
-
380
- def assert_tok(*names)
381
- (t = try_tok(*names)) && (return t)
382
- @lexer.expected!(names.map {|tok| Lexer::TOKEN_NAMES[tok] || tok}.join(" or "))
383
- end
384
-
385
- def try_tok(*names)
386
- peeked = @lexer.peek
387
- peeked && names.include?(peeked.type) && @lexer.next
388
- end
389
-
390
- def assert_done
391
- return if @lexer.done?
392
- @lexer.expected!(EXPR_NAMES[:default])
393
- end
394
-
395
- def node(node)
396
- node.line = @lexer.line
397
- node
398
- end
399
- end
400
- end
401
- end