Parent

Class Index [+]

Quicksearch

Sass::Script::Parser

The parser for SassScript. It parses a string of code into a tree of {Script::Node}s.

Constants

PRECEDENCE
EXPR_NAMES

It would be possible to have unified # and # methods, but detecting the method/token difference turns out to be quite expensive.

Public Class Methods

new(str, line, offset, options = {}) click to toggle source

@param str [String, StringScanner] The source text to parse @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

@param options [{Symbol => Object}] An options hash;

  see {file:SASS_REFERENCE.md#sass_options the Sass options documentation}
    # File lib/sass/script/parser.rb, line 22
22:       def initialize(str, line, offset, options = {})
23:         @options = options
24:         @lexer = lexer_class.new(str, line, offset, options)
25:       end
parse(*args) click to toggle source

Parses a SassScript expression.

@overload parse(str, line, offset, filename = nil) @return [Script::Node] The root node of the parse tree @see Parser#initialize @see Parser#parse

     # File lib/sass/script/parser.rb, line 119
119:       def self.parse(*args)
120:         new(*args).parse
121:       end
precedence_of(op) click to toggle source

Returns an integer representing the precedence of the given operator. A lower integer indicates a looser binding.

@private

     # File lib/sass/script/parser.rb, line 137
137:         def precedence_of(op)
138:           PRECEDENCE.each_with_index do |e, i|
139:             return i if Array(e).include?(op)
140:           end
141:           raise "[BUG] Unknown operator #{op}"
142:         end

Private Class Methods

production(name, sub, *ops) click to toggle source

Defines a simple left-associative production. name is the name of the production, sub is the name of the production beneath it, and ops is a list of operators for this precedence level

     # File lib/sass/script/parser.rb, line 150
150:         def production(name, sub, *ops)
151:           class_eval             def #{name}              interp = try_ops_after_interp(#{ops.inspect}, #{name.inspect}) and return interp              return unless e = #{sub}              while tok = try_tok(#{ops.map {|o| o.inspect}.join(', ')})                interp = try_op_before_interp(tok, e) and return interp                line = @lexer.line                e = Operation.new(e, assert_expr(#{sub.inspect}), tok.type)                e.line = line              end              e            end
152:         end
unary(op, sub) click to toggle source
     # File lib/sass/script/parser.rb, line 166
166:         def unary(op, sub)
167:           class_eval             def unary_#{op}              return #{sub} unless tok = try_tok(:#{op})              interp = try_op_before_interp(tok) and return interp              line = @lexer.line               op = UnaryOperation.new(assert_expr(:unary_#{op}), :#{op})              op.line = line              op            end
168:         end

Public Instance Methods

line() click to toggle source

The line number of the parser’s current position.

@return [Fixnum]

    # File lib/sass/script/parser.rb, line 11
11:       def line
12:         @lexer.line
13:       end
parse() click to toggle source

Parses a SassScript expression.

@return [Script::Node] The root node of the parse tree @raise [Sass::SyntaxError] if the expression isn’t valid SassScript

    # File lib/sass/script/parser.rb, line 48
48:       def parse
49:         expr = assert_expr :expr
50:         assert_done
51:         expr.options = @options
52:         expr
53:       rescue Sass::SyntaxError => e
54:         e.modify_backtrace :line => @lexer.line, :filename => @options[:filename]
55:         raise e
56:       end
parse_interpolated() click to toggle source

Parses a SassScript expression within an interpolated segment (`#{}`). This means that it stops when it comes across an unmatched `}`, which signals the end of an interpolated segment, it returns rather than throwing an error.

@return [Script::Node] The root node of the parse tree @raise [Sass::SyntaxError] if the expression isn’t valid SassScript

    # File lib/sass/script/parser.rb, line 34
34:       def parse_interpolated
35:         expr = assert_expr :expr
36:         assert_tok :end_interpolation
37:         expr.options = @options
38:         expr
39:       rescue Sass::SyntaxError => e
40:         e.modify_backtrace :line => @lexer.line, :filename => @options[:filename]
41:         raise e
42:       end
parse_mixin_definition_arglist() click to toggle source

Parses the argument list for a mixin definition.

@return [Array] The root nodes of the arguments. @raise [Sass::SyntaxError] if the argument list isn’t valid SassScript

     # File lib/sass/script/parser.rb, line 99
 99:       def parse_mixin_definition_arglist
100:         args = defn_arglist!(false)
101:         assert_done
102: 
103:         args.each do |k, v|
104:           k.options = @options
105:           v.options = @options if v
106:         end
107:         args
108:       rescue Sass::SyntaxError => e
109:         e.modify_backtrace :line => @lexer.line, :filename => @options[:filename]
110:         raise e
111:       end
parse_mixin_include_arglist() click to toggle source

Parses the argument list for a mixin include.

@return [Array] The root nodes of the arguments. @raise [Sass::SyntaxError] if the argument list isn’t valid SassScript

    # File lib/sass/script/parser.rb, line 79
79:       def parse_mixin_include_arglist
80:         args = []
81: 
82:         if try_tok(:lparen)
83:           args = arglist || args
84:           assert_tok(:rparen)
85:         end
86:         assert_done
87: 
88:         args.each {|a| a.options = @options}
89:         args
90:       rescue Sass::SyntaxError => e
91:         e.modify_backtrace :line => @lexer.line, :filename => @options[:filename]
92:         raise e
93:       end
parse_until(tokens) click to toggle source

Parses a SassScript expression, ending it when it encounters one of the given identifier tokens.

@param [#] A set of strings that delimit the expression. @return [Script::Node] The root node of the parse tree @raise [Sass::SyntaxError] if the expression isn’t valid SassScript

    # File lib/sass/script/parser.rb, line 64
64:       def parse_until(tokens)
65:         @stop_at = tokens
66:         expr = assert_expr :expr
67:         assert_done
68:         expr.options = @options
69:         expr
70:       rescue Sass::SyntaxError => e
71:         e.modify_backtrace :line => @lexer.line, :filename => @options[:filename]
72:         raise e
73:       end

Private Instance Methods

arglist() click to toggle source
     # File lib/sass/script/parser.rb, line 297
297:       def arglist
298:         return unless e = interpolation
299:         return [e] unless try_tok(:comma)
300:         [e, *assert_expr(:arglist)]
301:       end
assert_done() click to toggle source
     # File lib/sass/script/parser.rb, line 381
381:       def assert_done
382:         return if @lexer.done?
383:         @lexer.expected!(EXPR_NAMES[:default])
384:       end
assert_expr(name) click to toggle source
     # File lib/sass/script/parser.rb, line 366
366:       def assert_expr(name)
367:         (e = send(name)) && (return e)
368:         @lexer.expected!(EXPR_NAMES[name] || EXPR_NAMES[:default])
369:       end
assert_tok(*names) click to toggle source
     # File lib/sass/script/parser.rb, line 371
371:       def assert_tok(*names)
372:         (t = try_tok(*names)) && (return t)
373:         @lexer.expected!(names.map {|tok| Lexer::TOKEN_NAMES[tok] || tok}.join(" or "))
374:       end
concat() click to toggle source
     # File lib/sass/script/parser.rb, line 224
224:       def concat
225:         return unless e = or_expr
226:         while sub = or_expr
227:           e = node(Operation.new(e, sub, :concat))
228:         end
229:         e
230:       end
defn_arglist!(must_have_default) click to toggle source
     # File lib/sass/script/parser.rb, line 262
262:       def defn_arglist!(must_have_default)
263:         return [] unless try_tok(:lparen)
264:         return [] if try_tok(:rparen)
265:         res = []
266:         loop do
267:           line = @lexer.line
268:           offset = @lexer.offset + 1
269:           c = assert_tok(:const)
270:           var = Script::Variable.new(c.value)
271:           if tok = (try_tok(:colon) || try_tok(:single_eq))
272:             val = assert_expr(:concat)
273: 
274:             if tok.type == :single_eq
275:               val.context = :equals
276:               val.options = @options
277:               Script.equals_warning("mixin argument defaults", "$#{c.value}",
278:                 val.to_sass, false, line, offset, @options[:filename])
279:             end
280:             must_have_default = true
281:           elsif must_have_default
282:             raise SyntaxError.new("Required argument #{var.inspect} must come before any optional arguments.")
283:           end
284:           res << [var, val]
285:           break unless try_tok(:comma)
286:         end
287:         assert_tok(:rparen)
288:         res
289:       end
fn_arglist() click to toggle source
     # File lib/sass/script/parser.rb, line 291
291:       def fn_arglist
292:         return unless e = equals
293:         return [e] unless try_tok(:comma)
294:         [e, *assert_expr(:fn_arglist)]
295:       end
funcall() click to toggle source
     # File lib/sass/script/parser.rb, line 255
255:       def funcall
256:         return raw unless tok = try_tok(:funcall)
257:         args = fn_arglist || []
258:         assert_tok(:rparen)
259:         node(Script::Funcall.new(tok.value, args))
260:       end
ident() click to toggle source
     # File lib/sass/script/parser.rb, line 244
244:       def ident
245:         return funcall unless @lexer.peek && @lexer.peek.type == :ident
246:         return if @stop_at && @stop_at.include?(@lexer.peek.value)
247: 
248:         name = @lexer.next
249:         if color = Color::HTML4_COLORS[name.value]
250:           return node(Color.new(color))
251:         end
252:         node(Script::String.new(name.value, :identifier))
253:       end
interpolation(first = concat) click to toggle source
     # File lib/sass/script/parser.rb, line 211
211:       def interpolation(first = concat)
212:         e = first
213:         while interp = try_tok(:begin_interpolation)
214:           wb = @lexer.whitespace?(interp)
215:           line = @lexer.line
216:           mid = parse_interpolated
217:           wa = @lexer.whitespace?
218:           e = Script::Interpolation.new(e, mid, concat, wb, wa)
219:           e.line = line
220:         end
221:         e
222:       end
lexer_class() click to toggle source

@private

     # File lib/sass/script/parser.rb, line 183
183:       def lexer_class; Lexer; end
literal() click to toggle source
     # File lib/sass/script/parser.rb, line 352
352:       def literal
353:         (t = try_tok(:color, :bool)) && (return t.value)
354:       end
node(node) click to toggle source
     # File lib/sass/script/parser.rb, line 386
386:       def node(node)
387:         node.line = @lexer.line
388:         node
389:       end
number() click to toggle source
     # File lib/sass/script/parser.rb, line 345
345:       def number
346:         return literal unless tok = try_tok(:number)
347:         num = tok.value
348:         num.original = num.to_s unless @in_parens
349:         num
350:       end
paren() click to toggle source
     # File lib/sass/script/parser.rb, line 318
318:       def paren
319:         return variable unless try_tok(:lparen)
320:         was_in_parens = @in_parens
321:         @in_parens = true
322:         e = assert_expr(:expr)
323:         assert_tok(:rparen)
324:         return e
325:       ensure
326:         @in_parens = was_in_parens
327:       end
raw() click to toggle source
     # File lib/sass/script/parser.rb, line 303
303:       def raw
304:         return special_fun unless tok = try_tok(:raw)
305:         node(Script::String.new(tok.value))
306:       end
special_fun() click to toggle source
     # File lib/sass/script/parser.rb, line 308
308:       def special_fun
309:         return paren unless tok = try_tok(:special_fun)
310:         first = node(Script::String.new(tok.value.first))
311:         Haml::Util.enum_slice(tok.value[1..1], 2).inject(first) do |l, (i, r)|
312:           Script::Interpolation.new(
313:             l, i, r && node(Script::String.new(r)),
314:             false, false)
315:         end
316:       end
string() click to toggle source
     # File lib/sass/script/parser.rb, line 334
334:       def string
335:         return number unless first = try_tok(:string)
336:         return first.value unless try_tok(:begin_interpolation)
337:         line = @lexer.line
338:         mid = parse_interpolated
339:         last = assert_expr(:string)
340:         interp = StringInterpolation.new(first.value, mid, last)
341:         interp.line = line
342:         interp
343:       end
try_op_before_interp(op, prev = nil) click to toggle source
     # File lib/sass/script/parser.rb, line 188
188:       def try_op_before_interp(op, prev = nil)
189:         return unless @lexer.peek && @lexer.peek.type == :begin_interpolation
190:         wb = @lexer.whitespace?(op)
191:         str = Script::String.new(Lexer::OPERATORS_REVERSE[op.type])
192:         str.line = @lexer.line
193:         interp = Script::Interpolation.new(prev, str, nil, wb, !:wa, :originally_text)
194:         interp.line = @lexer.line
195:         interpolation(interp)
196:       end
try_ops_after_interp(ops, name) click to toggle source
     # File lib/sass/script/parser.rb, line 198
198:       def try_ops_after_interp(ops, name)
199:         return unless @lexer.after_interpolation?
200:         return unless op = try_tok(*ops)
201:         interp = try_op_before_interp(op) and return interp
202: 
203:         wa = @lexer.whitespace?
204:         str = Script::String.new(Lexer::OPERATORS_REVERSE[op.type])
205:         str.line = @lexer.line
206:         interp = Script::Interpolation.new(nil, str, assert_expr(name), !:wb, wa, :originally_text)
207:         interp.line = @lexer.line
208:         return interp
209:       end
try_tok(*names) click to toggle source
     # File lib/sass/script/parser.rb, line 376
376:       def try_tok(*names)
377:         peeked =  @lexer.peek
378:         peeked && names.include?(peeked.type) && @lexer.next
379:       end
variable() click to toggle source
     # File lib/sass/script/parser.rb, line 329
329:       def variable
330:         return string unless c = try_tok(:const)
331:         node(Variable.new(*c.value))
332:       end

Disabled; run with --debug to generate this.

[Validate]

Generated with the Darkfish Rdoc Generator 1.1.6.