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
@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
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
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
The line number of the parser's current position.
@return [Fixnum]
# File lib/sass/script/parser.rb, line 12 def line @lexer.line end
The column number of the parser's current position.
@return [Fixnum]
# File lib/sass/script/parser.rb, line 19 def offset @lexer.offset end
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
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
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
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
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 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
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
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