1
0
Fork 0
mirror of https://github.com/haml/haml.git synced 2022-11-09 12:33:31 -05:00

[Sass] Print the line numbers when printing the @extend loop error.

This commit is contained in:
Nathan Weizenbaum 2010-03-08 22:38:55 -08:00
parent 59c75df492
commit 03c2370405
4 changed files with 91 additions and 10 deletions

View file

@ -8,9 +8,14 @@ module Sass
class StaticParser < Parser
# Parses the text as a selector.
#
# @param line [Fixnum] The line on which the selector appears.
# Used for error reporting
# @param filename [String, nil] The file in which the selector appears,
# or nil if there is no such file.
# Used for error reporting
# @return [Selector::CommaSequence] The parsed selector
# @raise [Sass::SyntaxError] if there's a syntax error in the selector
def parse_selector
def parse_selector(line, filename)
init_scanner!
selectors = [expr!(:_selector)]
while tok(/,/)
@ -19,7 +24,10 @@ module Sass
selectors[-1] = Selector::Sequence.new(["\n"] + selectors.last.members) if ws.include?("\n")
end
expected("selector") unless @scanner.eos?
Selector::CommaSequence.new(selectors)
seq = Selector::CommaSequence.new(selectors)
seq.line = line
seq.filename = filename
seq
end
private

View file

@ -4,6 +4,17 @@ module Sass
# The abstract superclass for simple selectors
# (that is, those that don't compose multiple selectors).
class Node
# The line of the Sass template on which this selector was declared.
#
# @return [Fixnum]
attr_accessor :line
# The name of the file in which this selector was declared,
# or `nil` if it was not declared in a file (e.g. on stdin).
#
# @return [String, nil]
attr_accessor :filename
# Returns a representation of the node
# as an array of strings and potentially {Sass::Script::Node}s
# (if there's interpolation in the selector).
@ -90,8 +101,45 @@ module Sass
end
end
# The abstract parent class of the various selector sequence classes.
#
# All subclasses should implement a `members` method
# that returns an array of object that respond to `#line=` and `#filename=`.
class AbstractSequence
# The line of the Sass template on which this selector was declared.
#
# @return [Fixnum]
attr_reader :line
# The name of the file in which this selector was declared.
#
# @return [String, nil]
attr_reader :filename
# Sets the line of the Sass template on which this selector was declared.
# This also sets the line for all child selectors.
#
# @param line [Fixnum]
# @return [Fixnum]
def line=(line)
members.each {|m| m.line = line}
@line = line
end
# Sets the name of the file in which this selector was declared,
# or `nil` if it was not declared in a file (e.g. on stdin).
# This also sets the filename for all child selectors.
#
# @param filename [String, nil]
# @return [String, nil]
def filename=(filename)
members.each {|m| m.filename = filename}
@filename = filename
end
end
# A comma-separated sequence of selectors.
class CommaSequence
class CommaSequence < AbstractSequence
# The comma-separated selector sequences
# represented by this class.
#
@ -169,7 +217,28 @@ module Sass
# An operator-separated sequence of
# {SimpleSequence simple selector sequences}.
class Sequence
class Sequence < AbstractSequence
# Sets the line of the Sass template on which this selector was declared.
# This also sets the line for all child selectors.
#
# @param line [Fixnum]
# @return [Fixnum]
def line=(line)
members.each {|m| m.line = line if m.is_a?(SimpleSequence)}
line
end
# Sets the name of the file in which this selector was declared,
# or `nil` if it was not declared in a file (e.g. on stdin).
# This also sets the filename for all child selectors.
#
# @param filename [String, nil]
# @return [String, nil]
def filename=(filename)
members.each {|m| m.filename = filename if m.is_a?(SimpleSequence)}
filename
end
# The array of {SimpleSequence simple selector sequences}, operators, and newlines.
# The operators are strings such as `"+"` and `">"`
# representing the corresponding CSS operators.
@ -269,7 +338,7 @@ module Sass
# that all apply to a single element.
# For example, `.foo#bar[attr=baz]` is a simple sequence
# of the selectors `.foo`, `#bar`, and `[attr=baz]`.
class SimpleSequence
class SimpleSequence < AbstractSequence
# The array of individual selectors.
#
# @return [Array<Node>]
@ -363,7 +432,6 @@ module Sass
# Raise a {Sass::SyntaxError} describing a loop of `@extend` directives.
#
# @todo Print the @extend line numbers
# @todo Deterministically order the description based on line numbers
#
# @param supers [Array<Node>] The stack of selectors that contains the loop,
@ -374,8 +442,11 @@ module Sass
next sels.push(sel) unless sels.first.eql?(sel)
raise Sass::SyntaxError.new("An @extend loop was found:\n" +
Haml::Util.enum_cons(sels.push(sel), 2).
map {|sel1, sel2| " #{sel1.inspect} extends #{sel2.inspect}"}.
join(",\n"))
map do |sel1, sel2|
str = " #{sel1.inspect} extends #{sel2.inspect} on line #{sel1.line}"
str << " of " + sel1.filename if sel1.filename
str
end.join(",\n"))
end
# Should never get here
raise Sass::SyntaxError.new("An @extend loop exists, but the exact loop couldn't be found")

View file

@ -48,7 +48,8 @@ module Sass::Tree
protected
def perform!(environment)
@resolved_selector = Sass::SCSS::CssParser.new(run_interp(@selector, environment)).parse_selector
@resolved_selector = Sass::SCSS::CssParser.new(run_interp(@selector, environment)).
parse_selector(self.line, self.filename)
super
end
end

View file

@ -186,7 +186,8 @@ module Sass::Tree
# @param environment [Sass::Environment] The lexical environment containing
# variable and mixin values
def perform!(environment)
@parsed_rules = Sass::SCSS::StaticParser.new(run_interp(@rule, environment)).parse_selector
@parsed_rules = Sass::SCSS::StaticParser.new(run_interp(@rule, environment)).
parse_selector(self.line, self.filename)
super
end