sass 3.1.0 → 3.3.0

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 (260) hide show
  1. checksums.yaml +7 -0
  2. data/CONTRIBUTING +1 -1
  3. data/MIT-LICENSE +2 -2
  4. data/README.md +29 -17
  5. data/Rakefile +43 -9
  6. data/VERSION +1 -1
  7. data/VERSION_DATE +1 -0
  8. data/VERSION_NAME +1 -1
  9. data/bin/sass +6 -1
  10. data/bin/sass-convert +6 -1
  11. data/bin/scss +6 -1
  12. data/ext/mkrf_conf.rb +27 -0
  13. data/lib/sass/cache_stores/base.rb +7 -3
  14. data/lib/sass/cache_stores/chain.rb +3 -2
  15. data/lib/sass/cache_stores/filesystem.rb +5 -7
  16. data/lib/sass/cache_stores/memory.rb +1 -1
  17. data/lib/sass/cache_stores/null.rb +2 -2
  18. data/lib/sass/callbacks.rb +2 -1
  19. data/lib/sass/css.rb +168 -53
  20. data/lib/sass/engine.rb +502 -174
  21. data/lib/sass/environment.rb +151 -111
  22. data/lib/sass/error.rb +7 -7
  23. data/lib/sass/exec.rb +176 -60
  24. data/lib/sass/features.rb +40 -0
  25. data/lib/sass/importers/base.rb +46 -7
  26. data/lib/sass/importers/deprecated_path.rb +51 -0
  27. data/lib/sass/importers/filesystem.rb +113 -30
  28. data/lib/sass/importers.rb +1 -0
  29. data/lib/sass/logger/base.rb +30 -0
  30. data/lib/sass/logger/log_level.rb +45 -0
  31. data/lib/sass/logger.rb +12 -0
  32. data/lib/sass/media.rb +213 -0
  33. data/lib/sass/plugin/compiler.rb +194 -104
  34. data/lib/sass/plugin/configuration.rb +18 -25
  35. data/lib/sass/plugin/merb.rb +1 -1
  36. data/lib/sass/plugin/staleness_checker.rb +37 -11
  37. data/lib/sass/plugin.rb +10 -13
  38. data/lib/sass/railtie.rb +2 -1
  39. data/lib/sass/repl.rb +5 -6
  40. data/lib/sass/script/css_lexer.rb +8 -4
  41. data/lib/sass/script/css_parser.rb +5 -2
  42. data/lib/sass/script/functions.rb +1547 -618
  43. data/lib/sass/script/lexer.rb +122 -72
  44. data/lib/sass/script/parser.rb +304 -135
  45. data/lib/sass/script/tree/funcall.rb +306 -0
  46. data/lib/sass/script/{interpolation.rb → tree/interpolation.rb} +43 -13
  47. data/lib/sass/script/tree/list_literal.rb +77 -0
  48. data/lib/sass/script/tree/literal.rb +45 -0
  49. data/lib/sass/script/tree/map_literal.rb +64 -0
  50. data/lib/sass/script/{node.rb → tree/node.rb} +30 -12
  51. data/lib/sass/script/{operation.rb → tree/operation.rb} +33 -21
  52. data/lib/sass/script/{string_interpolation.rb → tree/string_interpolation.rb} +14 -4
  53. data/lib/sass/script/{unary_operation.rb → tree/unary_operation.rb} +21 -9
  54. data/lib/sass/script/tree/variable.rb +57 -0
  55. data/lib/sass/script/tree.rb +15 -0
  56. data/lib/sass/script/value/arg_list.rb +36 -0
  57. data/lib/sass/script/value/base.rb +238 -0
  58. data/lib/sass/script/value/bool.rb +40 -0
  59. data/lib/sass/script/{color.rb → value/color.rb} +256 -74
  60. data/lib/sass/script/value/deprecated_false.rb +55 -0
  61. data/lib/sass/script/value/helpers.rb +155 -0
  62. data/lib/sass/script/value/list.rb +128 -0
  63. data/lib/sass/script/value/map.rb +70 -0
  64. data/lib/sass/script/value/null.rb +49 -0
  65. data/lib/sass/script/{number.rb → value/number.rb} +115 -62
  66. data/lib/sass/script/{string.rb → value/string.rb} +9 -11
  67. data/lib/sass/script/value.rb +12 -0
  68. data/lib/sass/script.rb +35 -9
  69. data/lib/sass/scss/css_parser.rb +2 -12
  70. data/lib/sass/scss/parser.rb +657 -230
  71. data/lib/sass/scss/rx.rb +17 -12
  72. data/lib/sass/scss/static_parser.rb +37 -6
  73. data/lib/sass/scss.rb +0 -1
  74. data/lib/sass/selector/abstract_sequence.rb +35 -3
  75. data/lib/sass/selector/comma_sequence.rb +29 -14
  76. data/lib/sass/selector/sequence.rb +371 -74
  77. data/lib/sass/selector/simple.rb +28 -13
  78. data/lib/sass/selector/simple_sequence.rb +163 -36
  79. data/lib/sass/selector.rb +138 -36
  80. data/lib/sass/shared.rb +3 -5
  81. data/lib/sass/source/map.rb +196 -0
  82. data/lib/sass/source/position.rb +39 -0
  83. data/lib/sass/source/range.rb +41 -0
  84. data/lib/sass/stack.rb +126 -0
  85. data/lib/sass/supports.rb +228 -0
  86. data/lib/sass/tree/at_root_node.rb +82 -0
  87. data/lib/sass/tree/comment_node.rb +34 -29
  88. data/lib/sass/tree/content_node.rb +9 -0
  89. data/lib/sass/tree/css_import_node.rb +60 -0
  90. data/lib/sass/tree/debug_node.rb +3 -3
  91. data/lib/sass/tree/directive_node.rb +33 -3
  92. data/lib/sass/tree/each_node.rb +9 -9
  93. data/lib/sass/tree/extend_node.rb +20 -6
  94. data/lib/sass/tree/for_node.rb +6 -6
  95. data/lib/sass/tree/function_node.rb +12 -4
  96. data/lib/sass/tree/if_node.rb +2 -15
  97. data/lib/sass/tree/import_node.rb +11 -5
  98. data/lib/sass/tree/media_node.rb +27 -11
  99. data/lib/sass/tree/mixin_def_node.rb +15 -4
  100. data/lib/sass/tree/mixin_node.rb +27 -7
  101. data/lib/sass/tree/node.rb +69 -35
  102. data/lib/sass/tree/prop_node.rb +47 -31
  103. data/lib/sass/tree/return_node.rb +4 -3
  104. data/lib/sass/tree/root_node.rb +20 -4
  105. data/lib/sass/tree/rule_node.rb +37 -26
  106. data/lib/sass/tree/supports_node.rb +38 -0
  107. data/lib/sass/tree/trace_node.rb +33 -0
  108. data/lib/sass/tree/variable_node.rb +10 -4
  109. data/lib/sass/tree/visitors/base.rb +5 -8
  110. data/lib/sass/tree/visitors/check_nesting.rb +67 -52
  111. data/lib/sass/tree/visitors/convert.rb +134 -53
  112. data/lib/sass/tree/visitors/cssize.rb +245 -51
  113. data/lib/sass/tree/visitors/deep_copy.rb +102 -0
  114. data/lib/sass/tree/visitors/extend.rb +68 -0
  115. data/lib/sass/tree/visitors/perform.rb +331 -105
  116. data/lib/sass/tree/visitors/set_options.rb +125 -0
  117. data/lib/sass/tree/visitors/to_css.rb +259 -95
  118. data/lib/sass/tree/warn_node.rb +3 -3
  119. data/lib/sass/tree/while_node.rb +3 -3
  120. data/lib/sass/util/cross_platform_random.rb +19 -0
  121. data/lib/sass/util/multibyte_string_scanner.rb +157 -0
  122. data/lib/sass/util/normalized_map.rb +130 -0
  123. data/lib/sass/util/ordered_hash.rb +192 -0
  124. data/lib/sass/util/subset_map.rb +11 -2
  125. data/lib/sass/util/test.rb +9 -0
  126. data/lib/sass/util.rb +565 -39
  127. data/lib/sass/version.rb +27 -15
  128. data/lib/sass.rb +39 -4
  129. data/test/sass/cache_test.rb +15 -0
  130. data/test/sass/compiler_test.rb +223 -0
  131. data/test/sass/conversion_test.rb +901 -107
  132. data/test/sass/css2sass_test.rb +94 -0
  133. data/test/sass/engine_test.rb +1059 -164
  134. data/test/sass/exec_test.rb +86 -0
  135. data/test/sass/extend_test.rb +933 -837
  136. data/test/sass/fixtures/test_staleness_check_across_importers.css +1 -0
  137. data/test/sass/fixtures/test_staleness_check_across_importers.scss +1 -0
  138. data/test/sass/functions_test.rb +995 -136
  139. data/test/sass/importer_test.rb +338 -18
  140. data/test/sass/logger_test.rb +58 -0
  141. data/test/sass/more_results/more_import.css +2 -2
  142. data/test/sass/plugin_test.rb +114 -30
  143. data/test/sass/results/cached_import_option.css +3 -0
  144. data/test/sass/results/filename_fn.css +3 -0
  145. data/test/sass/results/import.css +2 -2
  146. data/test/sass/results/import_charset.css +1 -0
  147. data/test/sass/results/import_charset_1_8.css +1 -0
  148. data/test/sass/results/import_charset_ibm866.css +1 -0
  149. data/test/sass/results/import_content.css +1 -0
  150. data/test/sass/results/script.css +1 -1
  151. data/test/sass/results/scss_import.css +2 -2
  152. data/test/sass/results/units.css +2 -2
  153. data/test/sass/script_conversion_test.rb +43 -1
  154. data/test/sass/script_test.rb +380 -36
  155. data/test/sass/scss/css_test.rb +257 -75
  156. data/test/sass/scss/scss_test.rb +2322 -110
  157. data/test/sass/source_map_test.rb +887 -0
  158. data/test/sass/templates/_cached_import_option_partial.scss +1 -0
  159. data/test/sass/templates/_double_import_loop2.sass +1 -0
  160. data/test/sass/templates/_filename_fn_import.scss +11 -0
  161. data/test/sass/templates/_imported_content.sass +3 -0
  162. data/test/sass/templates/_same_name_different_partiality.scss +1 -0
  163. data/test/sass/templates/bork5.sass +3 -0
  164. data/test/sass/templates/cached_import_option.scss +3 -0
  165. data/test/sass/templates/double_import_loop1.sass +1 -0
  166. data/test/sass/templates/filename_fn.scss +18 -0
  167. data/test/sass/templates/import_charset.sass +2 -0
  168. data/test/sass/templates/import_charset_1_8.sass +2 -0
  169. data/test/sass/templates/import_charset_ibm866.sass +2 -0
  170. data/test/sass/templates/import_content.sass +4 -0
  171. data/test/sass/templates/same_name_different_ext.sass +2 -0
  172. data/test/sass/templates/same_name_different_ext.scss +1 -0
  173. data/test/sass/templates/same_name_different_partiality.scss +1 -0
  174. data/test/sass/templates/single_import_loop.sass +1 -0
  175. data/test/sass/templates/subdir/import_up1.scss +1 -0
  176. data/test/sass/templates/subdir/import_up2.scss +1 -0
  177. data/test/sass/test_helper.rb +1 -1
  178. data/test/sass/util/multibyte_string_scanner_test.rb +147 -0
  179. data/test/sass/util/normalized_map_test.rb +51 -0
  180. data/test/sass/util_test.rb +183 -0
  181. data/test/sass/value_helpers_test.rb +181 -0
  182. data/test/test_helper.rb +45 -5
  183. data/vendor/listen/CHANGELOG.md +228 -0
  184. data/vendor/listen/CONTRIBUTING.md +38 -0
  185. data/vendor/listen/Gemfile +30 -0
  186. data/vendor/listen/Guardfile +8 -0
  187. data/vendor/{fssm → listen}/LICENSE +1 -1
  188. data/vendor/listen/README.md +315 -0
  189. data/vendor/listen/Rakefile +47 -0
  190. data/vendor/listen/Vagrantfile +96 -0
  191. data/vendor/listen/lib/listen/adapter.rb +214 -0
  192. data/vendor/listen/lib/listen/adapters/bsd.rb +112 -0
  193. data/vendor/listen/lib/listen/adapters/darwin.rb +85 -0
  194. data/vendor/listen/lib/listen/adapters/linux.rb +113 -0
  195. data/vendor/listen/lib/listen/adapters/polling.rb +67 -0
  196. data/vendor/listen/lib/listen/adapters/windows.rb +87 -0
  197. data/vendor/listen/lib/listen/dependency_manager.rb +126 -0
  198. data/vendor/listen/lib/listen/directory_record.rb +371 -0
  199. data/vendor/listen/lib/listen/listener.rb +225 -0
  200. data/vendor/listen/lib/listen/multi_listener.rb +143 -0
  201. data/vendor/listen/lib/listen/turnstile.rb +28 -0
  202. data/vendor/listen/lib/listen/version.rb +3 -0
  203. data/vendor/listen/lib/listen.rb +40 -0
  204. data/vendor/listen/listen.gemspec +22 -0
  205. data/vendor/listen/spec/listen/adapter_spec.rb +183 -0
  206. data/vendor/listen/spec/listen/adapters/bsd_spec.rb +36 -0
  207. data/vendor/listen/spec/listen/adapters/darwin_spec.rb +37 -0
  208. data/vendor/listen/spec/listen/adapters/linux_spec.rb +47 -0
  209. data/vendor/listen/spec/listen/adapters/polling_spec.rb +68 -0
  210. data/vendor/listen/spec/listen/adapters/windows_spec.rb +30 -0
  211. data/vendor/listen/spec/listen/dependency_manager_spec.rb +107 -0
  212. data/vendor/listen/spec/listen/directory_record_spec.rb +1225 -0
  213. data/vendor/listen/spec/listen/listener_spec.rb +169 -0
  214. data/vendor/listen/spec/listen/multi_listener_spec.rb +174 -0
  215. data/vendor/listen/spec/listen/turnstile_spec.rb +56 -0
  216. data/vendor/listen/spec/listen_spec.rb +73 -0
  217. data/vendor/listen/spec/spec_helper.rb +21 -0
  218. data/vendor/listen/spec/support/adapter_helper.rb +629 -0
  219. data/vendor/listen/spec/support/directory_record_helper.rb +55 -0
  220. data/vendor/listen/spec/support/fixtures_helper.rb +29 -0
  221. data/vendor/listen/spec/support/listeners_helper.rb +156 -0
  222. data/vendor/listen/spec/support/platform_helper.rb +15 -0
  223. metadata +344 -271
  224. data/lib/sass/less.rb +0 -382
  225. data/lib/sass/script/bool.rb +0 -18
  226. data/lib/sass/script/funcall.rb +0 -162
  227. data/lib/sass/script/list.rb +0 -76
  228. data/lib/sass/script/literal.rb +0 -245
  229. data/lib/sass/script/variable.rb +0 -54
  230. data/lib/sass/scss/sass_parser.rb +0 -11
  231. data/test/sass/less_conversion_test.rb +0 -653
  232. data/vendor/fssm/README.markdown +0 -55
  233. data/vendor/fssm/Rakefile +0 -59
  234. data/vendor/fssm/VERSION.yml +0 -5
  235. data/vendor/fssm/example.rb +0 -9
  236. data/vendor/fssm/fssm.gemspec +0 -77
  237. data/vendor/fssm/lib/fssm/backends/fsevents.rb +0 -36
  238. data/vendor/fssm/lib/fssm/backends/inotify.rb +0 -26
  239. data/vendor/fssm/lib/fssm/backends/polling.rb +0 -25
  240. data/vendor/fssm/lib/fssm/backends/rubycocoa/fsevents.rb +0 -131
  241. data/vendor/fssm/lib/fssm/monitor.rb +0 -26
  242. data/vendor/fssm/lib/fssm/path.rb +0 -91
  243. data/vendor/fssm/lib/fssm/pathname.rb +0 -502
  244. data/vendor/fssm/lib/fssm/state/directory.rb +0 -57
  245. data/vendor/fssm/lib/fssm/state/file.rb +0 -24
  246. data/vendor/fssm/lib/fssm/support.rb +0 -63
  247. data/vendor/fssm/lib/fssm/tree.rb +0 -176
  248. data/vendor/fssm/lib/fssm.rb +0 -33
  249. data/vendor/fssm/profile/prof-cache.rb +0 -40
  250. data/vendor/fssm/profile/prof-fssm-pathname.html +0 -1231
  251. data/vendor/fssm/profile/prof-pathname.rb +0 -68
  252. data/vendor/fssm/profile/prof-plain-pathname.html +0 -988
  253. data/vendor/fssm/profile/prof.html +0 -2379
  254. data/vendor/fssm/spec/path_spec.rb +0 -75
  255. data/vendor/fssm/spec/root/duck/quack.txt +0 -0
  256. data/vendor/fssm/spec/root/file.css +0 -0
  257. data/vendor/fssm/spec/root/file.rb +0 -0
  258. data/vendor/fssm/spec/root/file.yml +0 -0
  259. data/vendor/fssm/spec/root/moo/cow.txt +0 -0
  260. data/vendor/fssm/spec/spec_helper.rb +0 -14
@@ -1,7 +1,5 @@
1
1
  require 'sass/scss/rx'
2
2
 
3
- require 'strscan'
4
-
5
3
  module Sass
6
4
  module Script
7
5
  # The lexical analyzer for SassScript.
@@ -18,26 +16,29 @@ module Sass
18
16
  # `value`: \[`Object`\]
19
17
  # : The Ruby object corresponding to the value of the token.
20
18
  #
21
- # `line`: \[`Fixnum`\]
22
- # : The line of the source file on which the token appears.
23
- #
24
- # `offset`: \[`Fixnum`\]
25
- # : The number of bytes into the line the SassScript token appeared.
19
+ # `source_range`: \[`Sass::Source::Range`\]
20
+ # : The range in the source file in which the token appeared.
26
21
  #
27
22
  # `pos`: \[`Fixnum`\]
28
23
  # : The scanner position at which the SassScript token appeared.
29
- Token = Struct.new(:type, :value, :line, :offset, :pos)
24
+ Token = Struct.new(:type, :value, :source_range, :pos)
30
25
 
31
26
  # The line number of the lexer's current position.
32
27
  #
33
28
  # @return [Fixnum]
34
- attr_reader :line
29
+ def line
30
+ return @line unless @tok
31
+ @tok.source_range.start_pos.line
32
+ end
35
33
 
36
34
  # The number of bytes into the current line
37
- # of the lexer's current position.
35
+ # of the lexer's current position (1-based).
38
36
  #
39
37
  # @return [Fixnum]
40
- attr_reader :offset
38
+ def offset
39
+ return @offset unless @tok
40
+ @tok.source_range.start_pos.offset
41
+ end
41
42
 
42
43
  # A hash from operator strings to the corresponding token types.
43
44
  OPERATORS = {
@@ -64,15 +65,14 @@ module Sass
64
65
  '}' => :end_interpolation,
65
66
  ';' => :semicolon,
66
67
  '{' => :lcurly,
68
+ '...' => :splat,
67
69
  }
68
70
 
69
71
  OPERATORS_REVERSE = Sass::Util.map_hash(OPERATORS) {|k, v| [v, k]}
70
72
 
71
- TOKEN_NAMES = Sass::Util.map_hash(OPERATORS_REVERSE) {|k, v| [k, v.inspect]}.merge({
73
+ TOKEN_NAMES = Sass::Util.map_hash(OPERATORS_REVERSE) {|k, v| [k, v.inspect]}.merge(
72
74
  :const => "variable (e.g. $foo)",
73
- :ident => "identifier (e.g. middle)",
74
- :bool => "boolean (e.g. true, false)",
75
- })
75
+ :ident => "identifier (e.g. middle)")
76
76
 
77
77
  # A list of operator strings ordered with longer names first
78
78
  # so that `>` and `<` don't clobber `>=` and `<=`.
@@ -89,15 +89,18 @@ module Sass
89
89
  :single_line_comment => SINGLE_LINE_COMMENT,
90
90
  :variable => /(\$)(#{IDENT})/,
91
91
  :ident => /(#{IDENT})(\()?/,
92
- :number => /(-)?(?:(\d*\.\d+)|(\d+))([a-zA-Z%]+)?/,
92
+ :number => /(?:(\d*\.\d+)|(\d+))([a-zA-Z%]+)?/,
93
+ :unary_minus_number => /-(?:(\d*\.\d+)|(\d+))([a-zA-Z%]+)?/,
93
94
  :color => HEXCOLOR,
94
- :bool => /(true|false)\b/,
95
- :ident_op => %r{(#{Regexp.union(*IDENT_OP_NAMES.map{|s| Regexp.new(Regexp.escape(s) + "(?!#{NMCHAR}|\Z)")})})},
96
- :op => %r{(#{Regexp.union(*OP_NAMES)})},
95
+ :ident_op => /(#{Regexp.union(*IDENT_OP_NAMES.map do |s|
96
+ Regexp.new(Regexp.escape(s) + "(?!#{NMCHAR}|\Z)")
97
+ end)})/,
98
+ :op => /(#{Regexp.union(*OP_NAMES)})/,
97
99
  }
98
100
 
99
101
  class << self
100
102
  private
103
+
101
104
  def string_re(open, close)
102
105
  /#{open}((?:\\.|\#(?!\{)|[^#{close}\\#])*)(#{close}|#\{)/
103
106
  end
@@ -110,23 +113,39 @@ module Sass
110
113
  # while the boolean represents whether or not the string
111
114
  # is following an interpolated segment.
112
115
  STRING_REGULAR_EXPRESSIONS = {
113
- [:double, false] => string_re('"', '"'),
114
- [:single, false] => string_re("'", "'"),
115
- [:double, true] => string_re('', '"'),
116
- [:single, true] => string_re('', "'"),
117
- [:uri, false] => /url\(#{W}(#{URLCHAR}*?)(#{W}\)|#\{)/,
118
- [:uri, true] => /(#{URLCHAR}*?)(#{W}\)|#\{)/,
116
+ :double => {
117
+ false => string_re('"', '"'),
118
+ true => string_re('', '"')
119
+ },
120
+ :single => {
121
+ false => string_re("'", "'"),
122
+ true => string_re('', "'")
123
+ },
124
+ :uri => {
125
+ false => /url\(#{W}(#{URLCHAR}*?)(#{W}\)|#\{)/,
126
+ true => /(#{URLCHAR}*?)(#{W}\)|#\{)/
127
+ },
128
+ # Defined in https://developer.mozilla.org/en/CSS/@-moz-document as a
129
+ # non-standard version of http://www.w3.org/TR/css3-conditional/
130
+ :url_prefix => {
131
+ false => /url-prefix\(#{W}(#{URLCHAR}*?)(#{W}\)|#\{)/,
132
+ true => /(#{URLCHAR}*?)(#{W}\)|#\{)/
133
+ },
134
+ :domain => {
135
+ false => /domain\(#{W}(#{URLCHAR}*?)(#{W}\)|#\{)/,
136
+ true => /(#{URLCHAR}*?)(#{W}\)|#\{)/
137
+ }
119
138
  }
120
139
 
121
140
  # @param str [String, StringScanner] The source text to lex
122
- # @param line [Fixnum] The line on which the SassScript appears.
123
- # Used for error reporting
124
- # @param offset [Fixnum] The number of characters in on which the SassScript appears.
125
- # Used for error reporting
141
+ # @param line [Fixnum] The 1-based line on which the SassScript appears.
142
+ # Used for error reporting and sourcemap building
143
+ # @param offset [Fixnum] The 1-based character (not byte) offset in the line in the source.
144
+ # Used for error reporting and sourcemap building
126
145
  # @param options [{Symbol => Object}] An options hash;
127
146
  # see {file:SASS_REFERENCE.md#sass_options the Sass options documentation}
128
147
  def initialize(str, line, offset, options)
129
- @scanner = str.is_a?(StringScanner) ? str : StringScanner.new(str)
148
+ @scanner = str.is_a?(StringScanner) ? str : Sass::Util::MultibyteStringScanner.new(str)
130
149
  @line = line
131
150
  @offset = offset
132
151
  @options = options
@@ -141,7 +160,7 @@ module Sass
141
160
  @tok ||= read_token
142
161
  @tok, tok = nil, @tok
143
162
  @prev = tok
144
- return tok
163
+ tok
145
164
  end
146
165
 
147
166
  # Returns whether or not there's whitespace before the next token.
@@ -166,7 +185,11 @@ module Sass
166
185
  # Rewinds the underlying StringScanner
167
186
  # to before the token returned by \{#peek}.
168
187
  def unpeek!
169
- @scanner.pos = @tok.pos if @tok
188
+ if @tok
189
+ @scanner.pos = @tok.pos
190
+ @line = @tok.source_range.start_pos.line
191
+ @offset = @tok.source_range.start_pos.offset
192
+ end
170
193
  end
171
194
 
172
195
  # @return [Boolean] Whether or not there's more source text to lex.
@@ -209,13 +232,11 @@ module Sass
209
232
 
210
233
  def read_token
211
234
  return if done?
212
- return unless value = token
213
- type, val, size = value
214
- size ||= @scanner.matched_size
215
-
216
- val.line = @line if val.is_a?(Script::Node)
217
- Token.new(type, val, @line,
218
- current_position - size, @scanner.pos - size)
235
+ start_pos = source_position
236
+ value = token
237
+ return unless value
238
+ type, val = value
239
+ Token.new(type, val, range(start_pos), @scanner.pos - @scanner.matched_size)
219
240
  end
220
241
 
221
242
  def whitespace
@@ -229,9 +250,9 @@ module Sass
229
250
  return string(interp_type, true)
230
251
  end
231
252
 
232
- variable || string(:double, false) || string(:single, false) || number ||
233
- color || bool || string(:uri, false) || raw(UNICODERANGE) ||
234
- special_fun || ident_op || ident || op
253
+ variable || string(:double, false) || string(:single, false) || number || color ||
254
+ string(:uri, false) || raw(UNICODERANGE) || special_fun || special_val || ident_op ||
255
+ ident || op
235
256
  end
236
257
 
237
258
  def variable
@@ -239,8 +260,6 @@ module Sass
239
260
  end
240
261
 
241
262
  def _variable(rx)
242
- line = @line
243
- offset = @offset
244
263
  return unless scan(rx)
245
264
 
246
265
  [:const, @scanner[2]]
@@ -252,82 +271,113 @@ module Sass
252
271
  end
253
272
 
254
273
  def string(re, open)
255
- return unless scan(STRING_REGULAR_EXPRESSIONS[[re, open]])
256
- if @scanner[2] == '#{' #'
274
+ return unless scan(STRING_REGULAR_EXPRESSIONS[re][open])
275
+ if @scanner[2] == '#{' # '
257
276
  @scanner.pos -= 2 # Don't actually consume the #{
277
+ @offset -= 2
258
278
  @interpolation_stack << re
259
279
  end
260
280
  str =
261
281
  if re == :uri
262
- Script::String.new("#{'url(' unless open}#{@scanner[1]}#{')' unless @scanner[2] == '#{'}")
282
+ url = "#{'url(' unless open}#{@scanner[1]}#{')' unless @scanner[2] == '#{'}"
283
+ Script::Value::String.new(url)
263
284
  else
264
- Script::String.new(@scanner[1].gsub(/\\(['"]|\#\{)/, '\1'), :string)
285
+ Script::Value::String.new(@scanner[1].gsub(/\\(['"]|\#\{)/, '\1'), :string)
265
286
  end
266
287
  [:string, str]
267
288
  end
268
289
 
269
290
  def number
270
- return unless scan(REGULAR_EXPRESSIONS[:number])
271
- value = @scanner[2] ? @scanner[2].to_f : @scanner[3].to_i
272
- value = -value if @scanner[1]
273
- [:number, Script::Number.new(value, Array(@scanner[4]))]
291
+ # Handling unary minus is complicated by the fact that whitespace is an
292
+ # operator in SassScript. We want "1-2" to be parsed as "1 - 2", but we
293
+ # want "1 -2" to be parsed as "1 (-2)". To accomplish this, we only
294
+ # parse a unary minus as part of a number literal if there's whitespace
295
+ # before and not after it. Cases like "(-2)" are handled by the unary
296
+ # minus logic in the parser instead.
297
+ if @scanner.peek(1) == '-'
298
+ return if @scanner.pos == 0
299
+ @scanner.pos -= 1
300
+ # Don't use @scanner.scan so we don't mess up the match data.
301
+ unary_minus_allowed = @scanner.peek(1) =~ /\s/
302
+ @scanner.pos += 1
303
+
304
+ return unless unary_minus_allowed
305
+ return unless scan(REGULAR_EXPRESSIONS[:unary_minus_number])
306
+ minus = true
307
+ else
308
+ return unless scan(REGULAR_EXPRESSIONS[:number])
309
+ minus = false
310
+ end
311
+
312
+ value = (@scanner[1] ? @scanner[1].to_f : @scanner[2].to_i) * (minus ? -1 : 1)
313
+ script_number = Script::Value::Number.new(value, Array(@scanner[3]))
314
+ [:number, script_number]
274
315
  end
275
316
 
276
317
  def color
277
- return unless s = scan(REGULAR_EXPRESSIONS[:color])
318
+ s = scan(REGULAR_EXPRESSIONS[:color])
319
+ return unless s
278
320
  raise Sass::SyntaxError.new(<<MESSAGE.rstrip) unless s.size == 4 || s.size == 7
279
321
  Colors must have either three or six digits: '#{s}'
280
322
  MESSAGE
281
- value = s.scan(/^#(..?)(..?)(..?)$/).first.
282
- map {|num| num.ljust(2, num).to_i(16)}
283
- [:color, Script::Color.new(value)]
284
- end
285
-
286
- def bool
287
- return unless s = scan(REGULAR_EXPRESSIONS[:bool])
288
- [:bool, Script::Bool.new(s == 'true')]
323
+ script_color = Script::Value::Color.from_hex(s)
324
+ [:color, script_color]
289
325
  end
290
326
 
291
327
  def special_fun
292
- return unless str1 = scan(/((-[\w-]+-)?calc|expression|progid:[a-z\.]*)\(/i)
328
+ str1 = scan(/((-[\w-]+-)?(calc|element)|expression|progid:[a-z\.]*)\(/i)
329
+ return unless str1
293
330
  str2, _ = Sass::Shared.balance(@scanner, ?(, ?), 1)
294
331
  c = str2.count("\n")
295
332
  old_line = @line
296
333
  old_offset = @offset
297
334
  @line += c
298
- @offset = (c == 0 ? @offset + str2.size : str2[/\n(.*)/, 1].size)
335
+ @offset = c == 0 ? @offset + str2.size : str2[/\n([^\n]*)/, 1].size + 1
299
336
  [:special_fun,
300
- Sass::Util.merge_adjacent_strings(
337
+ Sass::Util.merge_adjacent_strings(
301
338
  [str1] + Sass::Engine.parse_interp(str2, old_line, old_offset, @options)),
302
- str1.size + str2.size]
339
+ str1.size + str2.size]
340
+ end
341
+
342
+ def special_val
343
+ return unless scan(/!important/i)
344
+ [:string, Script::Value::String.new("!important")]
303
345
  end
304
346
 
305
347
  def ident_op
306
- return unless op = scan(REGULAR_EXPRESSIONS[:ident_op])
348
+ op = scan(REGULAR_EXPRESSIONS[:ident_op])
349
+ return unless op
307
350
  [OPERATORS[op]]
308
351
  end
309
352
 
310
353
  def op
311
- return unless op = scan(REGULAR_EXPRESSIONS[:op])
354
+ op = scan(REGULAR_EXPRESSIONS[:op])
355
+ return unless op
312
356
  @interpolation_stack << nil if op == :begin_interpolation
313
357
  [OPERATORS[op]]
314
358
  end
315
359
 
316
360
  def raw(rx)
317
- return unless val = scan(rx)
361
+ val = scan(rx)
362
+ return unless val
318
363
  [:raw, val]
319
364
  end
320
365
 
321
366
  def scan(re)
322
- return unless str = @scanner.scan(re)
367
+ str = @scanner.scan(re)
368
+ return unless str
323
369
  c = str.count("\n")
324
370
  @line += c
325
- @offset = (c == 0 ? @offset + str.size : str[/\n(.*)/, 1].size)
371
+ @offset = (c == 0 ? @offset + str.size : str.size - str.rindex("\n") + 1)
326
372
  str
327
373
  end
328
374
 
329
- def current_position
330
- @offset + 1
375
+ def range(start_pos, end_pos = source_position)
376
+ Sass::Source::Range.new(start_pos, end_pos, @options[:filename], @options[:importer])
377
+ end
378
+
379
+ def source_position
380
+ Sass::Source::Position.new(@line, @offset)
331
381
  end
332
382
  end
333
383
  end