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 after_interpolation?

def after_interpolation?
  @prev && @prev.type == :end_interpolation
end

def begin_interpolation

def begin_interpolation
  @scanner.scan
end

def bool

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

def color

def color
  return unless @scanner.scan(REGULAR_EXPRESSIONS[:color])
  value = if @scanner[4]
            color = Color::HTML4_COLORS[@scanner[4].downcase]
          else
            (1..3).map {|i| @scanner[i]}.map {|num| num.ljust(2, num).to_i(16)}
          end
  [:color, Script::Color.new(value)]
end

def current_position

def current_position
  @offset + @scanner.pos + 1
end

def done?

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

def ident

def ident
  return unless s = @scanner.scan(REGULAR_EXPRESSIONS[:ident])
  [:ident, s.gsub(/\\(.)/, '\1')]
end

def initialize(str, line, offset, filename)

Parameters:
  • 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, filename)
  @scanner = str.is_a?(StringScanner) ? str : StringScanner.new(str)
  @line = line
  @offset = offset
  @filename = filename
  @prev = nil
end

def last_match_position

def last_match_position
  current_position - @scanner.matched_size
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 @scanner.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
  prev_chr = @scanner.string[@scanner.pos - 1].chr
  return unless op = @scanner.scan(REGULAR_EXPRESSIONS[:op])
  if @prev && op == '-' && prev_chr !~ /\s/ &&
      [:bool, :ident, :const].include?(@prev.type)
    warn(<<END)
ATION WARNING:
e #{@line}, character #{last_match_position}#{" of '#{@filename}'" if @filename}
 be allowed as part of variable names in version 3.0.
 add whitespace to separate it from the previous token.
  end
  [OPERATORS[op]]
end

def peek

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

def read_token

def read_token
  return if done?
  value = token
  unless value
    raise SyntaxError.new("Syntax error in '#{@scanner.string}' at character #{current_position}.")
  end
  Token.new(value.first, value.last, @line, last_match_position)
end

def string(start_char = '"')

def string(start_char = '"')
  return unless @scanner.scan(/#{start_char}#{REGULAR_EXPRESSIONS[:string_end]}/)
  [:string, Script::String.new(@scanner[1].gsub(/\\([^0-9a-f])/, '\1').gsub(/\\([0-9a-f]{1,4})/, "\\\\\\1"))]
end

def token

def token
  return string('') if after_interpolation?
  variable || string || number || color || bool || op || ident
end

def variable

def variable
  return unless @scanner.scan(REGULAR_EXPRESSIONS[:variable])
  [:const, @scanner[1]]
end

def whitespace

def whitespace
  @scanner.scan(REGULAR_EXPRESSIONS[:whitespace])
end