class Sass::Script::Parser

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

Constants

ASSOCIATIVE
EXPR_NAMES

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

PRECEDENCE
VALID_CSS_OPS

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 and sourcemap building

@param offset [Fixnum] The character (not byte) offset where the script starts in the line.

Used for error reporting and sourcemap building

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

{file:SASS_REFERENCE.md#sass_options the Sass options documentation}.
This supports an additional `:allow_extra_text` option that controls
whether the parser throws an error when extra text is encountered
after the parsed construct.
# File lib/sass/script/parser.rb, line 33
def initialize(str, line, offset, options = {})
  @options = options
  @allow_extra_text = options.delete(:allow_extra_text)
  @lexer = lexer_class.new(str, line, offset, options)
  @stop_at = nil
  @css_variable_warning = nil
end
parse(value, line, offset, options = {}) click to toggle source

Parses a SassScript expression.

@return [Script::Tree::Node] The root node of the parse tree @see Parser#initialize @see #parse

# File lib/sass/script/parser.rb, line 238
def self.parse(value, line, offset, options = {})
  css_variable = options.delete :css_variable
  new(value, line, offset, options).parse(css_variable)
end

Public Instance Methods

associative?(op) click to toggle source

Returns whether or not the given operation is associative.

@private

# File lib/sass/script/parser.rb, line 271
def associative?(op)
  ASSOCIATIVE.include?(op)
end
line() click to toggle source

The line number of the parser's current position.

@return [Fixnum]

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

The column number of the parser's current position.

@return [Fixnum]

# File lib/sass/script/parser.rb, line 19
def offset
  @lexer.offset
end
parse(css_variable = false) click to toggle source

Parses a SassScript expression.

@param css_variable [Boolean] Whether this is the value of a CSS variable. @return [Script::Tree::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 70
def parse(css_variable = false)
  if css_variable
    @css_variable_warning = CssVariableWarning.new
  end

  expr = assert_expr :expr
  assert_done
  expr.options = @options
  check_for_interpolation expr

  if css_variable
    @css_variable_warning.value = expr
  end

  expr
rescue Sass::SyntaxError => e
  e.modify_backtrace :line => @lexer.line, :filename => @options[:filename]
  raise e
end
parse_function_definition_arglist() click to toggle source

Parses the argument list for a function definition.

@return [(Array<Script::Tree::Node>, Script::Tree::Node)]

The root nodes of the arguments, and the splat argument.

@raise [Sass::SyntaxError] if the argument list isn't valid SassScript

# File lib/sass/script/parser.rb, line 186
def parse_function_definition_arglist
  args, splat = defn_arglist!(true)
  assert_done

  args.each do |k, v|
    check_for_interpolation k
    k.options = @options

    if v
      check_for_interpolation v
      v.options = @options
    end
  end

  if splat
    check_for_interpolation splat
    splat.options = @options
  end

  return args, splat
rescue Sass::SyntaxError => e
  e.modify_backtrace :line => @lexer.line, :filename => @options[:filename]
  raise e
end
parse_interpolated(warn_for_color = false) 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.

@param warn_for_color [Boolean] Whether raw color values passed to

interoplation should cause a warning.

@return [Script::Tree::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 50
def parse_interpolated(warn_for_color = false)
  # Start two characters back to compensate for #{
  start_pos = Sass::Source::Position.new(line, offset - 2)
  expr = assert_expr :expr
  assert_tok :end_interpolation
  expr = Sass::Script::Tree::Interpolation.new(
    nil, expr, nil, false, false, :warn_for_color => warn_for_color)
  check_for_interpolation expr
  expr.options = @options
  node(expr, start_pos)
rescue Sass::SyntaxError => e
  e.modify_backtrace :line => @lexer.line, :filename => @options[:filename]
  raise e
end
parse_mixin_definition_arglist() click to toggle source

Parses the argument list for a mixin definition.

@return [(Array<Script::Tree::Node>, Script::Tree::Node)]

The root nodes of the arguments, and the splat argument.

@raise [Sass::SyntaxError] if the argument list isn't valid SassScript

# File lib/sass/script/parser.rb, line 156
def parse_mixin_definition_arglist
  args, splat = defn_arglist!(false)
  assert_done

  args.each do |k, v|
    check_for_interpolation k
    k.options = @options

    if v
      check_for_interpolation v
      v.options = @options
    end
  end

  if splat
    check_for_interpolation splat
    splat.options = @options
  end

  return args, splat
rescue Sass::SyntaxError => e
  e.modify_backtrace :line => @lexer.line, :filename => @options[:filename]
  raise e
end
parse_mixin_include_arglist() click to toggle source

Parses the argument list for a mixin include.

@return [(Array<Script::Tree::Node>,

       {String => Script::Tree::Node},
       Script::Tree::Node,
       Script::Tree::Node)]
The root nodes of the positional arguments, keyword arguments, and
splat argument(s). Keyword arguments are in a hash from names to values.

@raise [Sass::SyntaxError] if the argument list isn't valid SassScript

# File lib/sass/script/parser.rb, line 117
def parse_mixin_include_arglist
  args, keywords = [], {}
  if try_tok(:lparen)
    args, keywords, splat, kwarg_splat = mixin_arglist
    assert_tok(:rparen)
  end
  assert_done

  args.each do |a|
    check_for_interpolation a
    a.options = @options
  end

  keywords.each do |_k, v|
    check_for_interpolation v
    v.options = @options
  end

  if splat
    check_for_interpolation splat
    splat.options = @options
  end

  if kwarg_splat
    check_for_interpolation kwarg_splat
    kwarg_splat.options = @options
  end

  return args, keywords, splat, kwarg_splat
rescue Sass::SyntaxError => e
  e.modify_backtrace :line => @lexer.line, :filename => @options[:filename]
  raise e
end
parse_string() click to toggle source

Parse a single string value, possibly containing interpolation. Doesn't assert that the scanner is finished after parsing.

@return [Script::Tree::Node] The root node of the parse tree. @raise [Sass::SyntaxError] if the string isn't valid SassScript

# File lib/sass/script/parser.rb, line 216
def parse_string
  unless (peek = @lexer.peek) &&
      (peek.type == :string ||
      (peek.type == :funcall && peek.value.downcase == 'url'))
    lexer.expected!("string")
  end

  expr = assert_expr :funcall
  check_for_interpolation expr
  expr.options = @options
  @lexer.unpeek!
  expr
rescue Sass::SyntaxError => e
  e.modify_backtrace :line => @lexer.line, :filename => @options[:filename]
  raise e
end
parse_until(tokens) click to toggle source

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

@param tokens [#include?(String)] A set of strings that delimit the expression. @return [Script::Tree::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 96
def parse_until(tokens)
  @stop_at = tokens
  expr = assert_expr :expr
  assert_done
  expr.options = @options
  check_for_interpolation expr
  expr
rescue Sass::SyntaxError => e
  e.modify_backtrace :line => @lexer.line, :filename => @options[:filename]
  raise e
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 261
def precedence_of(op)
  PRECEDENCE.each_with_index do |e, i|
    return i if Array(e).include?(op)
  end
  raise "[BUG] Unknown operator #{op.inspect}"
end