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?
-
(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)
-
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
-
(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 2.4. add whitespace to separate it from the previous token. end [OPERATORS[op]] end
def peek
-
(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