Class Sass::Script::Lexer
In: lib/sass/script/lexer.rb
Parent: Object
Haml::Util Engine Color SyntaxError UnitConversionError StandardError Node Operation Literal UnaryOperation Funcall Variable Number String Bool EvaluationContext Node\n[lib/sass/css.rb\nlib/sass/tree/node.rb] DebugNode IfNode CommentNode ForNode MixinNode VariableNode ImportNode WhileNode MixinDefNode Repl CSS Environment Lexer Parser PropNode\n[lib/sass/css.rb\nlib/sass/tree/prop_node.rb] DirectiveNode\n[lib/sass/css.rb\nlib/sass/tree/directive_node.rb] RuleNode\n[lib/sass/css.rb\nlib/sass/tree/rule_node.rb] Rack lib/sass/repl.rb lib/sass/css.rb lib/sass/environment.rb lib/sass/error.rb lib/sass/engine.rb lib/sass/script/lexer.rb lib/sass/script/color.rb lib/sass/script/string.rb lib/sass/script/unary_operation.rb lib/sass/script/variable.rb lib/sass/script/funcall.rb lib/sass/script/operation.rb lib/sass/script/bool.rb lib/sass/script/parser.rb lib/sass/script/literal.rb lib/sass/script/node.rb lib/sass/script/number.rb lib/sass/script/functions.rb Functions Script Files lib/sass/tree/while_node.rb lib/sass/tree/if_node.rb lib/sass/tree/mixin_def_node.rb lib/sass/tree/debug_node.rb lib/sass/tree/for_node.rb lib/sass/tree/import_node.rb lib/sass/tree/prop_node.rb lib/sass/tree/node.rb lib/sass/tree/comment_node.rb lib/sass/tree/mixin_node.rb lib/sass/tree/directive_node.rb lib/sass/tree/rule_node.rb lib/sass/tree/variable_node.rb Tree lib/sass/plugin/rack.rb Plugin Sass dot/m_54_0.png

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

Methods

Constants

Token = Struct.new(:type, :value, :line, :offset)   A struct containing information about an individual token.

`type`: \[{Symbol}\] : The type of token.

`value`: \[{Object}\] : The Ruby object corresponding to the value of the token.

`line`: \[{Fixnum}\] : The line of the source file on which the token appears.

`offset`: \[{Fixnum}\] : The number of bytes into the line the SassScript token appeared.

OPERATORS = { '+' => :plus, '-' => :minus, '*' => :times, '/' => :div, '%' => :mod, '=' => :single_eq, '(' => :lparen, ')' => :rparen, ',' => :comma, 'and' => :and, 'or' => :or, 'not' => :not, '==' => :eq, '!=' => :neq, '>=' => :gte, '<=' => :lte, '>' => :gt, '<' => :lt, '#{' => :begin_interpolation, '}' => :end_interpolation, }   A hash from operator strings to the corresponding token types.
OP_NAMES = OPERATORS.keys.sort_by {|o| -o.size}   A list of operator strings ordered with longer names first so that `>` and `<` don‘t clobber `>=` and `<=`.
REGULAR_EXPRESSIONS = { :whitespace => /\s*/, :variable => /!(\w+)/, :ident => /(\\.|[^\s\\+\-*\/%(),=!])+/, :string_end => /((?:\\.|\#(?!\{)|[^"\\#])*)(?:"|(?=#\{))/, :number => /(-)?(?:(\d*\.\d+)|(\d+))([a-zA-Z%]+)?/, :color => /\##{"([0-9a-fA-F]{1,2})" * 3}|(#{Color::HTML4_COLORS.keys.join("|")})/, :bool => /(true|false)\b/, :op => %r{(#{Regexp.union(*OP_NAMES.map{|s| Regexp.new(Regexp.escape(s) + (s =~ /\w$/ ? '(?:\b|$)' : ''))})})}   A hash of regular expressions that are used for tokenizing.

Public Class methods

@param str [String, StringScanner] The source text to lex @param line [Fixnum] The line on which the SassScript appears.

  Used for error reporting

@param offset [Fixnum] The number of characters in on which the SassScript appears.

  Used for error reporting

[Source]

    # File lib/sass/script/lexer.rb, line 69
69:       def initialize(str, line, offset, filename)
70:         @scanner = str.is_a?(StringScanner) ? str : StringScanner.new(str)
71:         @line = line
72:         @offset = offset
73:         @filename = filename
74:         @prev = nil
75:       end

Public Instance methods

@return [Boolean] Whether or not there‘s more source text to lex.

[Source]

    # File lib/sass/script/lexer.rb, line 95
95:       def done?
96:         whitespace unless after_interpolation?
97:         @scanner.eos? && @tok.nil?
98:       end

Moves the lexer forward one token.

@return [Token] The token that was moved past

[Source]

    # File lib/sass/script/lexer.rb, line 80
80:       def next
81:         @tok ||= read_token
82:         @tok, tok = nil, @tok
83:         @prev = tok
84:         return tok
85:       end

Returns the next token without moving the lexer forward.

@return [Token] The next token

[Source]

    # File lib/sass/script/lexer.rb, line 90
90:       def peek
91:         @tok ||= read_token
92:       end

Private Instance methods

[Source]

     # File lib/sass/script/lexer.rb, line 187
187:       def after_interpolation?
188:         @prev && @prev.type == :end_interpolation
189:       end

[Source]

     # File lib/sass/script/lexer.rb, line 136
136:       def begin_interpolation
137:         @scanner.scan
138:       end

[Source]

     # File lib/sass/script/lexer.rb, line 157
157:       def bool
158:         return unless s = @scanner.scan(REGULAR_EXPRESSIONS[:bool])
159:         [:bool, Script::Bool.new(s == 'true')]
160:       end

[Source]

     # File lib/sass/script/lexer.rb, line 147
147:       def color
148:         return unless @scanner.scan(REGULAR_EXPRESSIONS[:color])
149:         value = if @scanner[4]
150:                   color = Color::HTML4_COLORS[@scanner[4].downcase]
151:                 else
152:                   (1..3).map {|i| @scanner[i]}.map {|num| num.ljust(2, num).to_i(16)}
153:                 end
154:         [:color, Script::Color.new(value)]
155:       end

[Source]

     # File lib/sass/script/lexer.rb, line 179
179:       def current_position
180:         @offset + @scanner.pos + 1
181:       end

[Source]

     # File lib/sass/script/lexer.rb, line 126
126:       def ident
127:         return unless s = @scanner.scan(REGULAR_EXPRESSIONS[:ident])
128:         [:ident, s.gsub(/\\(.)/, '\1')]
129:       end

[Source]

     # File lib/sass/script/lexer.rb, line 183
183:       def last_match_position
184:         current_position - @scanner.matched_size
185:       end

[Source]

     # File lib/sass/script/lexer.rb, line 140
140:       def number
141:         return unless @scanner.scan(REGULAR_EXPRESSIONS[:number])
142:         value = @scanner[2] ? @scanner[2].to_f : @scanner[3].to_i
143:         value = -value if @scanner[1]
144:         [:number, Script::Number.new(value, Array(@scanner[4]))]
145:       end

[Source]

     # File lib/sass/script/lexer.rb, line 162
162:       def op
163:         prev_chr = @scanner.string[@scanner.pos - 1].chr
164:         return unless op = @scanner.scan(REGULAR_EXPRESSIONS[:op])
165:         if @prev && op == '-' && prev_chr !~ /\s/ &&
166:             [:bool, :ident, :const].include?(@prev.type)
167:           warn("DEPRECATION WARNING:\nOn line \#{@line}, character \#{last_match_position}\#{\" of '\#{@filename}'\" if @filename}\n- will be allowed as part of variable names in version 2.4.\nPlease add whitespace to separate it from the previous token.\n")
168:         end
169: 
170:         [OPERATORS[op]]
171:       end

[Source]

     # File lib/sass/script/lexer.rb, line 102
102:       def read_token
103:         return if done?
104: 
105:         value = token
106:         unless value
107:           raise SyntaxError.new("Syntax error in '#{@scanner.string}' at character #{current_position}.")
108:         end
109:         Token.new(value.first, value.last, @line, last_match_position)
110:       end

[Source]

     # File lib/sass/script/lexer.rb, line 131
131:       def string(start_char = '"')
132:         return unless @scanner.scan(/#{start_char}#{REGULAR_EXPRESSIONS[:string_end]}/)
133:         [:string, Script::String.new(@scanner[1].gsub(/\\([^0-9a-f])/, '\1').gsub(/\\([0-9a-f]{1,4})/, "\\\\\\1"))]
134:       end

[Source]

     # File lib/sass/script/lexer.rb, line 116
116:       def token
117:         return string('') if after_interpolation?
118:         variable || string || number || color || bool || op || ident
119:       end

[Source]

     # File lib/sass/script/lexer.rb, line 121
121:       def variable
122:         return unless @scanner.scan(REGULAR_EXPRESSIONS[:variable])
123:         [:const, @scanner[1]]
124:       end

[Source]

     # File lib/sass/script/lexer.rb, line 112
112:       def whitespace
113:         @scanner.scan(REGULAR_EXPRESSIONS[:whitespace])
114:       end

[Validate]