haml-edge 2.3.179 → 2.3.180

Sign up to get free protection for your applications and to get access to all the features.
Files changed (92) hide show
  1. data/EDGE_GEM_VERSION +1 -1
  2. data/README.md +88 -149
  3. data/VERSION +1 -1
  4. data/bin/css2sass +7 -1
  5. data/bin/sass-convert +7 -0
  6. data/lib/haml/exec.rb +95 -22
  7. data/lib/haml/template.rb +1 -1
  8. data/lib/haml/util.rb +50 -0
  9. data/lib/sass.rb +1 -1
  10. data/lib/sass/css.rb +38 -210
  11. data/lib/sass/engine.rb +121 -47
  12. data/lib/sass/files.rb +28 -19
  13. data/lib/sass/plugin.rb +32 -43
  14. data/lib/sass/repl.rb +1 -1
  15. data/lib/sass/script.rb +25 -6
  16. data/lib/sass/script/bool.rb +1 -0
  17. data/lib/sass/script/color.rb +2 -2
  18. data/lib/sass/script/css_lexer.rb +22 -0
  19. data/lib/sass/script/css_parser.rb +28 -0
  20. data/lib/sass/script/funcall.rb +17 -9
  21. data/lib/sass/script/functions.rb +46 -1
  22. data/lib/sass/script/interpolation.rb +42 -0
  23. data/lib/sass/script/lexer.rb +142 -34
  24. data/lib/sass/script/literal.rb +28 -12
  25. data/lib/sass/script/node.rb +57 -1
  26. data/lib/sass/script/number.rb +18 -3
  27. data/lib/sass/script/operation.rb +44 -8
  28. data/lib/sass/script/parser.rb +149 -24
  29. data/lib/sass/script/string.rb +50 -2
  30. data/lib/sass/script/unary_operation.rb +25 -10
  31. data/lib/sass/script/variable.rb +20 -11
  32. data/lib/sass/scss.rb +14 -0
  33. data/lib/sass/scss/css_parser.rb +39 -0
  34. data/lib/sass/scss/parser.rb +683 -0
  35. data/lib/sass/scss/rx.rb +112 -0
  36. data/lib/sass/scss/script_lexer.rb +13 -0
  37. data/lib/sass/scss/script_parser.rb +25 -0
  38. data/lib/sass/tree/comment_node.rb +58 -16
  39. data/lib/sass/tree/debug_node.rb +7 -2
  40. data/lib/sass/tree/directive_node.rb +38 -34
  41. data/lib/sass/tree/for_node.rb +6 -0
  42. data/lib/sass/tree/if_node.rb +13 -0
  43. data/lib/sass/tree/import_node.rb +26 -7
  44. data/lib/sass/tree/mixin_def_node.rb +18 -0
  45. data/lib/sass/tree/mixin_node.rb +16 -1
  46. data/lib/sass/tree/node.rb +98 -27
  47. data/lib/sass/tree/prop_node.rb +97 -20
  48. data/lib/sass/tree/root_node.rb +37 -0
  49. data/lib/sass/tree/rule_node.rb +88 -60
  50. data/lib/sass/tree/variable_node.rb +9 -5
  51. data/lib/sass/tree/while_node.rb +4 -0
  52. data/test/haml/results/filters.xhtml +1 -1
  53. data/test/haml/util_test.rb +28 -0
  54. data/test/sass/conversion_test.rb +884 -0
  55. data/test/sass/css2sass_test.rb +46 -21
  56. data/test/sass/engine_test.rb +680 -160
  57. data/test/sass/functions_test.rb +27 -0
  58. data/test/sass/more_results/more_import.css +1 -1
  59. data/test/sass/more_templates/more_import.sass +3 -3
  60. data/test/sass/plugin_test.rb +28 -8
  61. data/test/sass/results/compact.css +1 -1
  62. data/test/sass/results/complex.css +5 -5
  63. data/test/sass/results/compressed.css +1 -1
  64. data/test/sass/results/expanded.css +1 -1
  65. data/test/sass/results/import.css +3 -1
  66. data/test/sass/results/mixins.css +12 -12
  67. data/test/sass/results/nested.css +1 -1
  68. data/test/sass/results/parent_ref.css +4 -4
  69. data/test/sass/results/script.css +3 -3
  70. data/test/sass/results/scss_import.css +15 -0
  71. data/test/sass/results/scss_importee.css +2 -0
  72. data/test/sass/script_conversion_test.rb +153 -0
  73. data/test/sass/script_test.rb +44 -54
  74. data/test/sass/scss/css_test.rb +811 -0
  75. data/test/sass/scss/rx_test.rb +156 -0
  76. data/test/sass/scss/scss_test.rb +871 -0
  77. data/test/sass/scss/test_helper.rb +37 -0
  78. data/test/sass/templates/alt.sass +2 -2
  79. data/test/sass/templates/bork1.sass +1 -1
  80. data/test/sass/templates/import.sass +4 -4
  81. data/test/sass/templates/importee.sass +3 -3
  82. data/test/sass/templates/line_numbers.sass +1 -1
  83. data/test/sass/templates/mixins.sass +2 -2
  84. data/test/sass/templates/nested_mixin_bork.sass +1 -1
  85. data/test/sass/templates/options.sass +1 -1
  86. data/test/sass/templates/parent_ref.sass +2 -2
  87. data/test/sass/templates/script.sass +69 -69
  88. data/test/sass/templates/scss_import.scss +10 -0
  89. data/test/sass/templates/scss_importee.scss +1 -0
  90. data/test/sass/templates/units.sass +10 -10
  91. data/test/test_helper.rb +4 -4
  92. metadata +27 -2
@@ -2,7 +2,7 @@ module Sass::Script
2
2
  # Methods in this module are accessible from the SassScript context.
3
3
  # For example, you can write
4
4
  #
5
- # !color = hsl(120deg, 100%, 50%)
5
+ # $color = hsl(120deg, 100%, 50%)
6
6
  #
7
7
  # and it will call {Sass::Script::Functions#hsl}.
8
8
  #
@@ -80,6 +80,14 @@ module Sass::Script
80
80
  # \{#transparentize} / \{#fade_out #fade-out}
81
81
  # : Makes a color more transparent.
82
82
  #
83
+ # ## String Functions
84
+ #
85
+ # \{#unquote}
86
+ # : Removes the quotes from a string.
87
+ #
88
+ # \{#quote}
89
+ # : Adds quotes to a string.
90
+ #
83
91
  # ## Number Functions
84
92
  #
85
93
  # \{#percentage}
@@ -170,6 +178,8 @@ module Sass::Script
170
178
  # assert_type value, :Number
171
179
  #
172
180
  # Valid types are `:Bool`, `:Color`, `:Number`, and `:String`.
181
+ # Note that `:String` will match both double-quoted strings
182
+ # and unquoted identifiers.
173
183
  #
174
184
  # @param value [Sass::Script::Literal] A SassScript value
175
185
  # @param type [Symbol] The name of the type the value is expected to be
@@ -608,6 +618,36 @@ module Sass::Script
608
618
  adjust_hue color, Number.new(180)
609
619
  end
610
620
 
621
+ # Removes quotes from a string if the string is quoted,
622
+ # or returns the same string if it's not.
623
+ #
624
+ # @param str [String]
625
+ # @return [String]
626
+ # @raise [ArgumentError] if `str` isn't a string
627
+ # @see #quote
628
+ # @example
629
+ # unquote("foo") => foo
630
+ # unquote(foo) => foo
631
+ def unquote(str)
632
+ assert_type str, :String
633
+ Sass::Script::String.new(str.value, :identifier)
634
+ end
635
+
636
+ # Add quotes to a string if the string isn't quoted,
637
+ # or returns the same string if it is.
638
+ #
639
+ # @param str [String]
640
+ # @return [String]
641
+ # @raise [ArgumentError] if `str` isn't a string
642
+ # @see #unquote
643
+ # @example
644
+ # quote("foo") => "foo"
645
+ # quote(foo) => "foo"
646
+ def quote(str)
647
+ assert_type str, :String
648
+ Sass::Script::String.new(str.value, :string)
649
+ end
650
+
611
651
  # Converts a decimal number to a percentage.
612
652
  # For example:
613
653
  #
@@ -675,6 +715,11 @@ module Sass::Script
675
715
  numeric_transformation(value) {|n| n.abs}
676
716
  end
677
717
 
718
+ def unquote(value)
719
+ assert_type value, :String
720
+ Sass::Script::String.new(value.value)
721
+ end
722
+
678
723
  private
679
724
 
680
725
  # This method implements the pattern of transforming a numeric value into
@@ -0,0 +1,42 @@
1
+ module Sass::Script
2
+ class Interpolation < Node
3
+ def initialize(before, mid, after, wb, wa)
4
+ @before = before
5
+ @mid = mid
6
+ @after = after
7
+ @whitespace_before = wb
8
+ @whitespace_after = wa
9
+ end
10
+
11
+ def inspect
12
+ "(interpolation #{@before.inspect} #{@mid.inspect} #{after.inspect})"
13
+ end
14
+
15
+ def to_sass
16
+ res = ""
17
+ res << @before.to_sass if @before
18
+ res << ' ' if @before && @whitespace_before
19
+ res << '#{' << @mid.to_sass << '}'
20
+ res << ' ' if @after && @whitespace_after
21
+ res << @after.to_sass if @after
22
+ res
23
+ end
24
+
25
+ def children
26
+ [@before, @mid, @after].compact
27
+ end
28
+
29
+ protected
30
+
31
+ def _perform(environment)
32
+ res = ""
33
+ res << @before.perform(environment).to_s if @before
34
+ res << " " if @before && @whitespace_before
35
+ val = @mid.perform(environment)
36
+ res << (val.is_a?(Sass::Script::String) ? val.value : val.to_s)
37
+ res << " " if @after && @whitespace_after
38
+ res << @after.perform(environment).to_s if @after
39
+ Sass::Script::String.new(res)
40
+ end
41
+ end
42
+ end
@@ -1,3 +1,5 @@
1
+ require 'sass/scss/rx'
2
+
1
3
  require 'strscan'
2
4
 
3
5
  module Sass
@@ -6,6 +8,8 @@ module Sass
6
8
  # It takes a raw string and converts it to individual tokens
7
9
  # that are easier to parse.
8
10
  class Lexer
11
+ include Sass::SCSS::RX
12
+
9
13
  # A struct containing information about an individual token.
10
14
  #
11
15
  # `type`: \[`Symbol`\]
@@ -19,7 +23,21 @@ module Sass
19
23
  #
20
24
  # `offset`: \[`Fixnum`\]
21
25
  # : The number of bytes into the line the SassScript token appeared.
22
- Token = Struct.new(:type, :value, :line, :offset)
26
+ #
27
+ # `pos`: \[`Fixnum`\]
28
+ # : The scanner position at which the SassScript token appeared.
29
+ Token = Struct.new(:type, :value, :line, :offset, :pos)
30
+
31
+ # The line number of the lexer's current position.
32
+ #
33
+ # @return [Fixnum]
34
+ attr_reader :line
35
+
36
+ # The number of bytes into the current line
37
+ # of the lexer's current position.
38
+ #
39
+ # @return [Fixnum]
40
+ attr_reader :offset
23
41
 
24
42
  # A hash from operator strings to the corresponding token types.
25
43
  # @private
@@ -30,6 +48,7 @@ module Sass
30
48
  '/' => :div,
31
49
  '%' => :mod,
32
50
  '=' => :single_eq,
51
+ ':' => :colon,
33
52
  '(' => :lparen,
34
53
  ')' => :rparen,
35
54
  ',' => :comma,
@@ -44,23 +63,43 @@ module Sass
44
63
  '<' => :lt,
45
64
  '#{' => :begin_interpolation,
46
65
  '}' => :end_interpolation,
66
+ ';' => :semicolon,
67
+ '{' => :lcurly,
47
68
  }
48
69
 
70
+ # @private
71
+ OPERATORS_REVERSE = Haml::Util.map_hash(OPERATORS) {|k, v| [v, k]}
72
+
73
+ # @private
74
+ TOKEN_NAMES = Haml::Util.map_hash(OPERATORS_REVERSE) {|k, v| [k, v.inspect]}.merge({
75
+ :const => "variable (e.g. $foo)",
76
+ :ident => "identifier (e.g. middle)",
77
+ :bool => "boolean (e.g. true, false)",
78
+ })
79
+
49
80
  # A list of operator strings ordered with longer names first
50
81
  # so that `>` and `<` don't clobber `>=` and `<=`.
51
82
  # @private
52
83
  OP_NAMES = OPERATORS.keys.sort_by {|o| -o.size}
53
84
 
85
+ # A sub-list of {OP_NAMES} that only includes operators
86
+ # with identifier names.
87
+ # @private
88
+ IDENT_OP_NAMES = OP_NAMES.select {|k, v| k =~ /^\w+/}
89
+
54
90
  # A hash of regular expressions that are used for tokenizing.
55
91
  # @private
56
92
  REGULAR_EXPRESSIONS = {
57
- :whitespace => /\s*/,
58
- :variable => /!([\w-]+)/,
59
- :ident => /(\\.|[^\s\\+*\/%(),=!])+/,
93
+ :whitespace => /\s+/,
94
+ :comment => COMMENT,
95
+ :single_line_comment => SINGLE_LINE_COMMENT,
96
+ :variable => /([!\$])(#{IDENT})/,
97
+ :ident => IDENT,
60
98
  :number => /(-)?(?:(\d*\.\d+)|(\d+))([a-zA-Z%]+)?/,
61
- :color => /\##{"([0-9a-fA-F]{1,2})" * 3}|(#{Color::HTML4_COLORS.keys.join("|")})(?![^\s+*\/%),=!])/,
99
+ :color => HEXCOLOR,
62
100
  :bool => /(true|false)\b/,
63
- :op => %r{(#{Regexp.union(*OP_NAMES.map{|s| Regexp.new(Regexp.escape(s) + (s =~ /\w$/ ? '(?:\b|$)' : ''))})})}
101
+ :ident_op => %r{(#{Regexp.union(*IDENT_OP_NAMES.map{|s| Regexp.new(Regexp.escape(s) + '(?:\b|$)')})})},
102
+ :op => %r{(#{Regexp.union(*OP_NAMES)})},
64
103
  }
65
104
 
66
105
  class << self
@@ -109,6 +148,18 @@ module Sass
109
148
  return tok
110
149
  end
111
150
 
151
+ # Returns whether or not there's whitespace before the next token.
152
+ #
153
+ # @return [Boolean]
154
+ def whitespace?(tok = @tok)
155
+ if tok
156
+ @scanner.string[0...tok.pos] =~ /\s$/
157
+ else
158
+ @scanner.string[@scanner.pos, 1] =~ /^\s/ ||
159
+ @scanner.string[@scanner.pos - 1, 1] =~ /\s$/
160
+ end
161
+ end
162
+
112
163
  # Returns the next token without moving the lexer forward.
113
164
  #
114
165
  # @return [Token] The next token
@@ -116,83 +167,140 @@ module Sass
116
167
  @tok ||= read_token
117
168
  end
118
169
 
170
+ # Rewinds the underlying StringScanner
171
+ # to before the token returned by \{#peek}.
172
+ def unpeek!
173
+ @scanner.pos = @tok.pos if @tok
174
+ end
175
+
119
176
  # @return [Boolean] Whether or not there's more source text to lex.
120
177
  def done?
121
- whitespace unless after_interpolation?
178
+ whitespace unless after_interpolation? && @interpolation_stack.last
122
179
  @scanner.eos? && @tok.nil?
123
180
  end
124
181
 
182
+ def expected!(name)
183
+ unpeek!
184
+ Sass::SCSS::Parser.expected(@scanner, name, @line)
185
+ end
186
+
187
+ def str
188
+ old_pos = @tok ? @tok.pos : @scanner.pos
189
+ yield
190
+ new_pos = @tok ? @tok.pos : @scanner.pos
191
+ @scanner.string[old_pos...new_pos]
192
+ end
193
+
125
194
  private
126
195
 
127
196
  def read_token
128
197
  return if done?
198
+ return unless value = token
129
199
 
130
- value = token
131
- unless value
132
- raise SyntaxError.new("Syntax error in '#{@scanner.string}' at character #{current_position}.")
133
- end
134
- Token.new(value.first, value.last, @line, last_match_position)
200
+ value.last.line = @line if value.last.is_a?(Script::Node)
201
+ Token.new(value.first, value.last, @line,
202
+ current_position - @scanner.matched_size,
203
+ @scanner.pos - @scanner.matched_size)
135
204
  end
136
205
 
137
206
  def whitespace
138
- @scanner.scan(REGULAR_EXPRESSIONS[:whitespace])
207
+ nil while scan(REGULAR_EXPRESSIONS[:whitespace]) ||
208
+ scan(REGULAR_EXPRESSIONS[:comment]) ||
209
+ scan(REGULAR_EXPRESSIONS[:single_line_comment])
139
210
  end
140
211
 
141
212
  def token
142
- return string(@interpolation_stack.pop, true) if after_interpolation?
143
- variable || string(:double, false) || string(:single, false) || number || color || bool || op || ident
213
+ if after_interpolation? && (interp_type = @interpolation_stack.pop)
214
+ return string(interp_type, true)
215
+ end
216
+
217
+ variable || string(:double, false) || string(:single, false) || number ||
218
+ color || bool || raw(URI) || raw(UNICODERANGE) || special_fun ||
219
+ ident_op || ident || op
144
220
  end
145
221
 
146
222
  def variable
147
- return unless @scanner.scan(REGULAR_EXPRESSIONS[:variable])
148
- [:const, @scanner[1]]
223
+ _variable(REGULAR_EXPRESSIONS[:variable])
224
+ end
225
+
226
+ def _variable(rx)
227
+ line = @line
228
+ offset = @offset
229
+ return unless scan(rx)
230
+ if @scanner[1] == '!' && @scanner[2] != 'important'
231
+ Script.var_warning(@scanner[2], line, offset + 1, @options[:filename])
232
+ end
233
+
234
+ [:const, @scanner[2]]
149
235
  end
150
236
 
151
237
  def ident
152
- return unless s = @scanner.scan(REGULAR_EXPRESSIONS[:ident])
238
+ return unless s = scan(REGULAR_EXPRESSIONS[:ident])
153
239
  [:ident, s.gsub(/\\(.)/, '\1')]
154
240
  end
155
241
 
156
242
  def string(re, open)
157
- return unless @scanner.scan(STRING_REGULAR_EXPRESSIONS[[re, open]])
243
+ return unless scan(STRING_REGULAR_EXPRESSIONS[[re, open]])
158
244
  @interpolation_stack << re if @scanner[2].empty? # Started an interpolated section
159
- [:string, Script::String.new(@scanner[1].gsub(/\\([^0-9a-f])/, '\1').gsub(/\\([0-9a-f]{1,4})/, "\\\\\\1"))]
245
+ [:string, Script::String.new(@scanner[1].gsub(/\\([^0-9a-f])/, '\1').gsub(/\\([0-9a-f]{1,4})/, "\\\\\\1"), :string)]
160
246
  end
161
247
 
162
248
  def number
163
- return unless @scanner.scan(REGULAR_EXPRESSIONS[:number])
249
+ return unless scan(REGULAR_EXPRESSIONS[:number])
164
250
  value = @scanner[2] ? @scanner[2].to_f : @scanner[3].to_i
165
251
  value = -value if @scanner[1]
166
252
  [:number, Script::Number.new(value, Array(@scanner[4]))]
167
253
  end
168
254
 
169
255
  def color
170
- return unless @scanner.scan(REGULAR_EXPRESSIONS[:color])
171
- value = if @scanner[4]
172
- color = Color::HTML4_COLORS[@scanner[4].downcase]
173
- else
174
- (1..3).map {|i| @scanner[i]}.map {|num| num.ljust(2, num).to_i(16)}
175
- end
256
+ return unless s = scan(REGULAR_EXPRESSIONS[:color])
257
+ value = s.scan(/^#(..?)(..?)(..?)$/).first.
258
+ map {|num| num.ljust(2, num).to_i(16)}
176
259
  [:color, Script::Color.new(value)]
177
260
  end
178
261
 
179
262
  def bool
180
- return unless s = @scanner.scan(REGULAR_EXPRESSIONS[:bool])
263
+ return unless s = scan(REGULAR_EXPRESSIONS[:bool])
181
264
  [:bool, Script::Bool.new(s == 'true')]
182
265
  end
183
266
 
267
+ def special_fun
268
+ return unless str1 = scan(/(calc|expression|progid:[a-z\.]*)\(/i)
269
+ str2, _ = Haml::Shared.balance(@scanner, ?(, ?), 1)
270
+ c = str2.count("\n")
271
+ @line += c
272
+ @offset = (c == 0 ? @offset + str2.size : str2[/\n(.*)/, 1].size)
273
+ [:special_fun,
274
+ Haml::Util.merge_adjacent_strings(
275
+ [str1] + Sass::Engine.parse_interp(str2, @line, @options))]
276
+ end
277
+
278
+ def ident_op
279
+ return unless op = scan(REGULAR_EXPRESSIONS[:ident_op])
280
+ [OPERATORS[op]]
281
+ end
282
+
184
283
  def op
185
- prev_chr = @scanner.string[@scanner.pos - 1].chr
186
- return unless op = @scanner.scan(REGULAR_EXPRESSIONS[:op])
284
+ return unless op = scan(REGULAR_EXPRESSIONS[:op])
285
+ @interpolation_stack << nil if op == :begin_interpolation
187
286
  [OPERATORS[op]]
188
287
  end
189
288
 
190
- def current_position
191
- @offset + @scanner.pos + 1
289
+ def raw(rx)
290
+ return unless val = scan(rx)
291
+ [:raw, val]
292
+ end
293
+
294
+ def scan(re)
295
+ return unless str = @scanner.scan(re)
296
+ c = str.count("\n")
297
+ @line += c
298
+ @offset = (c == 0 ? @offset + str.size : str[/\n(.*)/, 1].size)
299
+ str
192
300
  end
193
301
 
194
- def last_match_position
195
- current_position - @scanner.matched_size
302
+ def current_position
303
+ @offset + 1
196
304
  end
197
305
 
198
306
  def after_interpolation?
@@ -21,14 +21,7 @@ module Sass::Script
21
21
  # @param value [Object] The object for \{#value}
22
22
  def initialize(value = nil)
23
23
  @value = value
24
- end
25
-
26
- # Evaluates the literal.
27
- #
28
- # @param environment [Sass::Environment] The environment in which to evaluate the SassScript
29
- # @return [Literal] This literal
30
- def perform(environment)
31
- self
24
+ super()
32
25
  end
33
26
 
34
27
  # Returns an empty array.
@@ -109,7 +102,7 @@ MSG
109
102
  Sass::Script::Bool.new(!to_bool)
110
103
  end
111
104
 
112
- # The SassScript default operation (e.g. `!a !b`, `"foo" "bar"`).
105
+ # The SassScript default operation (e.g. `$a $b`, `"foo" "bar"`).
113
106
  #
114
107
  # @param other [Literal] The right-hand side of the operator
115
108
  # @return [Script::String] A string containing both literals
@@ -118,7 +111,7 @@ MSG
118
111
  Sass::Script::String.new("#{self.to_s} #{other.to_s}")
119
112
  end
120
113
 
121
- # The SassScript `,` operation (e.g. `!a, !b`, `"foo", "bar"`).
114
+ # The SassScript `,` operation (e.g. `$a, $b`, `"foo", "bar"`).
122
115
  #
123
116
  # @param other [Literal] The right-hand side of the operator
124
117
  # @return [Script::String] A string containing both literals
@@ -133,6 +126,9 @@ MSG
133
126
  # @return [Script::String] A string containing both literals
134
127
  # without any separation
135
128
  def plus(other)
129
+ if other.is_a?(Sass::Script::String)
130
+ return Sass::Script::String.new(self.to_s + other.value, other.type)
131
+ end
136
132
  Sass::Script::String.new(self.to_s + other.to_s)
137
133
  end
138
134
 
@@ -154,7 +150,16 @@ MSG
154
150
  Sass::Script::String.new("#{self.to_s}/#{other.to_s}")
155
151
  end
156
152
 
157
- # The SassScript unary `-` operation (e.g. `-!a`).
153
+ # The SassScript unary `+` operation (e.g. `+$a`).
154
+ #
155
+ # @param other [Literal] The right-hand side of the operator
156
+ # @return [Script::String] A string containing the literal
157
+ # preceded by `"+"`
158
+ def unary_plus
159
+ Sass::Script::String.new("+#{self.to_s}")
160
+ end
161
+
162
+ # The SassScript unary `-` operation (e.g. `-$a`).
158
163
  #
159
164
  # @param other [Literal] The right-hand side of the operator
160
165
  # @return [Script::String] A string containing the literal
@@ -163,7 +168,7 @@ MSG
163
168
  Sass::Script::String.new("-#{self.to_s}")
164
169
  end
165
170
 
166
- # The SassScript unary `/` operation (e.g. `/!a`).
171
+ # The SassScript unary `/` operation (e.g. `/$a`).
167
172
  #
168
173
  # @param other [Literal] The right-hand side of the operator
169
174
  # @return [Script::String] A string containing the literal
@@ -206,5 +211,16 @@ MSG
206
211
  def to_s
207
212
  raise Sass::SyntaxError.new("[BUG] All subclasses of Sass::Literal must implement #to_s.")
208
213
  end
214
+ alias_method :to_sass, :to_s
215
+
216
+ protected
217
+
218
+ # Evaluates the literal.
219
+ #
220
+ # @param environment [Sass::Environment] The environment in which to evaluate the SassScript
221
+ # @return [Literal] This literal
222
+ def _perform(environment)
223
+ self
224
+ end
209
225
  end
210
226
  end