class Sass::Script::Lexer

that are easier to parse.
It takes a raw string and converts it to individual tokens
The lexical analyzer for SassScript.

def _variable(rx)

def _variable(rx)
  line = @line
  offset = @offset
  return unless scan(rx)
  if @scanner[1] == '!' && @scanner[2] != 'important'
    Script.var_warning(@scanner[2], line, offset + 1, @options[:filename])
  end
  [:const, @scanner[2]]
end

def after_interpolation?

Returns:
  • (Boolean) - Whether or not the last token lexed was `:end_interpolation`.
def after_interpolation?
  @prev && @prev.type == :end_interpolation
end

def bool

def bool
  return unless s = scan(REGULAR_EXPRESSIONS[:bool])
  [:bool, Script::Bool.new(s == 'true')]
end

def color

def color
  return unless s = scan(REGULAR_EXPRESSIONS[:color])
  raise Sass::SyntaxError.new(<<MESSAGE) unless s.size == 4 || s.size == 7
 must have either three or six digits: '#{s}'
E
  value = s.scan(/^#(..?)(..?)(..?)$/).first.
    map {|num| num.ljust(2, num).to_i(16)}
  [:color, Script::Color.new(value)]
end

def current_position

def current_position
  @offset + 1
end

def done?

Returns:
  • (Boolean) - Whether or not there's more source text to lex.
def done?
  whitespace unless after_interpolation? && @interpolation_stack.last
  @scanner.eos? && @tok.nil?
end

def expected!(name)

Raises:
  • (Sass::SyntaxError) -

Parameters:
  • name (String) -- The name of the entity that was expected but not found
def expected!(name)
  unpeek!
  Sass::SCSS::Parser.expected(@scanner, name, @line)
end

def ident

def ident
  return unless scan(REGULAR_EXPRESSIONS[:ident])
  [@scanner[2] ? :funcall : :ident, @scanner[1]]
end

def ident_op

def ident_op
  return unless op = scan(REGULAR_EXPRESSIONS[:ident_op])
  [OPERATORS[op]]
end

def initialize(str, line, offset, options)

Parameters:
  • options ({Symbol => Object}) -- An options hash;
  • offset (Fixnum) -- The number of characters in on which the SassScript appears.
  • line (Fixnum) -- The line on which the SassScript appears.
  • str (String, StringScanner) -- The source text to lex
def initialize(str, line, offset, options)
  @scanner = str.is_a?(StringScanner) ? str : StringScanner.new(str)
  @line = line
  @offset = offset
  @options = options
  @interpolation_stack = []
  @prev = nil
end

def next

Returns:
  • (Token) - The token that was moved past
def next
  @tok ||= read_token
  @tok, tok = nil, @tok
  @prev = tok
  return tok
end

def number

def number
  return unless scan(REGULAR_EXPRESSIONS[:number])
  value = @scanner[2] ? @scanner[2].to_f : @scanner[3].to_i
  value = -value if @scanner[1]
  [:number, Script::Number.new(value, Array(@scanner[4]))]
end

def op

def op
  return unless op = scan(REGULAR_EXPRESSIONS[:op])
  @interpolation_stack << nil if op == :begin_interpolation
  [OPERATORS[op]]
end

def peek

Returns:
  • (Token) - The next token
def peek
  @tok ||= read_token
end

def raw(rx)

def raw(rx)
  return unless val = scan(rx)
  [:raw, val]
end

def read_token

def read_token
  return if done?
  return unless value = token
  type, val, size = value
  size ||= @scanner.matched_size
  val.line = @line if val.is_a?(Script::Node)
  Token.new(type, val, @line,
    current_position - size, @scanner.pos - size)
end

def scan(re)

def scan(re)
  return unless str = @scanner.scan(re)
  c = str.count("\n")
  @line += c
  @offset = (c == 0 ? @offset + str.size : str[/\n(.*)/, 1].size)
  str
end

def special_fun

def special_fun
  return unless str1 = scan(/(calc|expression|progid:[a-z\.]*)\(/i)
  str2, _ = Haml::Shared.balance(@scanner, ?(, ?), 1)
  c = str2.count("\n")
  old_line = @line
  old_offset = @offset
  @line += c
  @offset = (c == 0 ? @offset + str2.size : str2[/\n(.*)/, 1].size)
  [:special_fun,
    Haml::Util.merge_adjacent_strings(
      [str1] + Sass::Engine.parse_interp(str2, old_line, old_offset, @options)),
    str1.size + str2.size]
end

def str

Returns:
  • (String) -

Other tags:
    Yield: - A block in which text is recorded
def str
  old_pos = @tok ? @tok.pos : @scanner.pos
  yield
  new_pos = @tok ? @tok.pos : @scanner.pos
  @scanner.string[old_pos...new_pos]
end

def string(re, open)

def string(re, open)
  return unless scan(STRING_REGULAR_EXPRESSIONS[[re, open]])
  if @scanner[2] == '#{' #'
    @scanner.pos -= 2 # Don't actually consume the #{
    @interpolation_stack << re
  end
  str =
    if re == :uri
      Script::String.new("#{'url(' unless open}#{@scanner[1]}#{')' unless @scanner[2] == '#{'}")
    else
      Script::String.new(@scanner[1].gsub(/\\(['"]|\#\{)/, '\1'), :string)
    end
  [:string, str]
end

def string_re(open, close)

def string_re(open, close)
  /#{open}((?:\\.|\#(?!\{)|[^#{close}\\#])*)(#{close}|#\{)/
end

def token

def token
  if after_interpolation? && (interp_type = @interpolation_stack.pop)
    return string(interp_type, true)
  end
  variable || string(:double, false) || string(:single, false) || number ||
    color || bool || string(:uri, false) || raw(UNICODERANGE) ||
    special_fun || ident_op || ident || op
end

def unpeek!

to before the token returned by \{#peek}.
Rewinds the underlying StringScanner
def unpeek!
  @scanner.pos = @tok.pos if @tok
end

def variable

def variable
  _variable(REGULAR_EXPRESSIONS[:variable])
end

def whitespace

def whitespace
  nil while scan(REGULAR_EXPRESSIONS[:whitespace]) ||
    scan(REGULAR_EXPRESSIONS[:comment]) ||
    scan(REGULAR_EXPRESSIONS[:single_line_comment])
end

def whitespace?(tok = @tok)

Returns:
  • (Boolean) -
def whitespace?(tok = @tok)
  if tok
    @scanner.string[0...tok.pos] =~ /\s\Z/
  else
    @scanner.string[@scanner.pos, 1] =~ /^\s/ ||
      @scanner.string[@scanner.pos - 1, 1] =~ /\s\Z/
  end
end