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

Merge branch 'scss' into conversions

Conflicts:
	lib/sass/script/funcall.rb
	lib/sass/script/literal.rb
	lib/sass/script/node.rb
	lib/sass/script/operation.rb
	lib/sass/script/unary_operation.rb
This commit is contained in:
Nathan Weizenbaum 2010-02-21 16:39:56 -08:00
commit de1a763fea
10 changed files with 158 additions and 61 deletions

View file

@ -34,12 +34,22 @@ module Sass
"#{name}(#{args.map {|a| a.to_sass}.join(', ')})"
end
# Returns the arguments to the function.
#
# @return [Array<Node>]
# @see Node#children
def children
@args
end
protected
# Evaluates the function call.
#
# @param environment [Sass::Environment] The environment in which to evaluate the SassScript
# @return [Literal] The SassScript object that is the value of the function call
# @raise [Sass::SyntaxError] if the function call raises an ArgumentError
def perform(environment)
def _perform(environment)
args = self.args.map {|a| a.perform(environment)}
ruby_name = name.gsub('-', '_')
unless Haml::Util.has?(:public_instance_method, Functions, ruby_name) && ruby_name !~ /^__/
@ -53,14 +63,6 @@ module Sass
raise e unless e.backtrace.any? {|t| t =~ /:in `(block in )?(#{name}|perform)'$/}
raise Sass::SyntaxError.new("#{e.message} for `#{name}'")
end
# Returns the arguments to the function.
#
# @return [Array<Node>]
# @see Node#children
def children
@args
end
end
end
end

View file

@ -157,6 +157,8 @@ module Sass
unless value
raise SyntaxError.new("Syntax error in '#{@scanner.string}' at character #{current_position}.")
end
value.last.line = @line if value.last.is_a?(Script::Node)
Token.new(value.first, value.last, @line, last_match_position)
end

View file

@ -23,14 +23,6 @@ module Sass::Script
@value = value
end
# Evaluates the literal.
#
# @param environment [Sass::Environment] The environment in which to evaluate the SassScript
# @return [Literal] This literal
def perform(environment)
self
end
# Returns an empty array.
#
# @return [Array<Node>] empty
@ -207,5 +199,15 @@ MSG
raise Sass::SyntaxError.new("[BUG] All subclasses of Sass::Literal must implement #to_s.")
end
alias_method :to_sass, :to_s
protected
# Evaluates the literal.
#
# @param environment [Sass::Environment] The environment in which to evaluate the SassScript
# @return [Literal] This literal
def _perform(environment)
self
end
end
end

View file

@ -8,6 +8,11 @@ module Sass::Script
# @return [{Symbol => Object}]
attr_reader :options
# The line of the document on which this node appeared.
#
# @return [Fixnum]
attr_accessor :line
# Sets the options hash for this node,
# as well as for all child nodes.
# See {file:SASS_REFERENCE.md#sass_options the Sass options documentation}.
@ -20,10 +25,16 @@ module Sass::Script
# Evaluates the node.
#
# \{#perform} shouldn't be overridden directly;
# instead, override \{#\_perform}.
#
# @param environment [Sass::Environment] The environment in which to evaluate the SassScript
# @return [Literal] The SassScript object that is the value of the SassScript
def perform(environment)
raise NotImplementedError.new("All subclasses of Sass::Script::Node must override #perform.")
_perform(environment)
rescue Sass::SyntaxError => e
e.modify_backtrace(:line => line)
raise e
end
# Returns all child nodes of this node.
@ -39,5 +50,16 @@ module Sass::Script
def to_sass
raise NotImplementedError.new("All subclasses of Sass::Script::Node must override #to_sass.")
end
protected
# Evaluates this node.
#
# @param environment [Sass::Environment] The environment in which to evaluate the SassScript
# @return [Literal] The SassScript object that is the value of the SassScript
# @see #perform
def _perform(environment)
raise NotImplementedError.new("All subclasses of Sass::Script::Node must override #_perform.")
end
end
end

View file

@ -42,12 +42,22 @@ module Sass::Script
"#{o1}#{sep}#{o2}"
end
# Returns the operands for this operation.
#
# @return [Array<Node>]
# @see Node#children
def children
[@operand1, @operand2]
end
protected
# Evaluates the operation.
#
# @param environment [Sass::Environment] The environment in which to evaluate the SassScript
# @return [Literal] The SassScript object that is the value of the operation
# @raise [Sass::SyntaxError] if the operation is undefined for the operands
def perform(environment)
def _perform(environment)
literal1 = @operand1.perform(environment)
literal2 = @operand2.perform(environment)
begin
@ -60,14 +70,6 @@ module Sass::Script
end
end
# Returns the operands for this operation.
#
# @return [Array<Node>]
# @see Node#children
def children
[@operand1, @operand2]
end
private
def operand_to_sass(pred, op)

View file

@ -5,6 +5,13 @@ module Sass
# The parser for SassScript.
# It parses a string of code into a tree of {Script::Node}s.
class Parser
# The line number of the parser's current position.
#
# @return [Fixnum]
def line
@lexer.line
end
# @param str [String, StringScanner] The source text to parse
# @param line [Fixnum] The line on which the SassScript appears.
# Used for error reporting
@ -151,7 +158,9 @@ module Sass
def #{name}
return unless e = #{sub}
while tok = try_tok(#{ops.map {|o| o.inspect}.join(', ')})
line = @lexer.line
e = Operation.new(e, assert_expr(#{sub.inspect}), tok.type)
e.line = line
end
e
end
@ -162,7 +171,10 @@ RUBY
class_eval <<RUBY
def unary_#{op}
return #{sub} unless try_tok(:#{op})
UnaryOperation.new(assert_expr(:unary_#{op}), :#{op})
line = @lexer.line
op = UnaryOperation.new(assert_expr(:unary_#{op}), :#{op})
op.line = line
op
end
RUBY
end
@ -175,7 +187,7 @@ RUBY
def concat
return unless e = or_expr
while sub = or_expr
e = Operation.new(e, sub, :concat)
e = node(Operation.new(e, sub, :concat))
end
e
end
@ -199,7 +211,7 @@ RUBY
# An identifier without arguments is just a string
unless try_tok(:lparen)
if color = Color::HTML4_COLORS[name.value]
return Color.new(color)
return node(Color.new(color))
end
filename = @options[:filename]
@ -209,11 +221,11 @@ On line #{name.line}, character #{name.offset}#{" of '#{filename}'" if filename}
Implicit strings have been deprecated and will be removed in version 3.0.
'#{name.value}' was not quoted. Please add double quotes (e.g. "#{name.value}").
END
Script::String.new(name.value)
node(Script::String.new(name.value))
else
args = arglist || []
assert_tok(:rparen)
Script::Funcall.new(name.value, args)
node(Script::Funcall.new(name.value, args))
end
end
@ -245,15 +257,18 @@ END
def variable
return string unless c = try_tok(:const)
Variable.new(c.value)
node(Variable.new(c.value))
end
def string
return literal unless first = try_tok(:string)
return first.value unless try_tok(:begin_interpolation)
line = @lexer.line
mid = parse_interpolated
last = assert_expr(:string)
Operation.new(first.value, Operation.new(mid, last, :plus), :plus)
op = Operation.new(first.value, node(Operation.new(mid, last, :plus)), :plus)
op.line = line
op
end
def literal
@ -282,6 +297,11 @@ END
return if @lexer.done?
raise Sass::SyntaxError.new("Unexpected #{@lexer.peek.type} token.")
end
def node(node)
node.line = @lexer.line
node
end
end
end
end

View file

@ -24,20 +24,6 @@ module Sass::Script
op + (op =~ /[a-z]/ ? " " : "") + operand
end
# Evaluates the operation.
#
# @param environment [Sass::Environment] The environment in which to evaluate the SassScript
# @return [Literal] The SassScript object that is the value of the operation
# @raise [Sass::SyntaxError] if the operation is undefined for the operand
def perform(environment)
operator = "unary_#{@operator}"
literal = @operand.perform(environment)
literal.send(operator)
rescue NoMethodError => e
raise e unless e.name.to_s == operator.to_s
raise Sass::SyntaxError.new("Undefined unary operation: \"#{@operator} #{literal}\".")
end
# Returns the operand of the operation.
#
# @return [Array<Node>]
@ -45,5 +31,21 @@ module Sass::Script
def children
[@operand]
end
protected
# Evaluates the operation.
#
# @param environment [Sass::Environment] The environment in which to evaluate the SassScript
# @return [Literal] The SassScript object that is the value of the operation
# @raise [Sass::SyntaxError] if the operation is undefined for the operand
def _perform(environment)
operator = "unary_#{@operator}"
literal = @operand.perform(environment)
literal.send(operator)
rescue NoMethodError => e
raise e unless e.name.to_s == operator.to_s
raise Sass::SyntaxError.new("Undefined unary operation: \"#{@operator} #{literal}\".")
end
end
end

View file

@ -18,16 +18,6 @@ module Sass
end
alias_method :to_sass, :inspect
# Evaluates the variable.
#
# @param environment [Sass::Environment] The environment in which to evaluate the SassScript
# @return [Literal] The SassScript object that is the value of the variable
# @raise [Sass::SyntaxError] if the variable is undefined
def perform(environment)
(val = environment.var(name)) && (return val)
raise SyntaxError.new("Undefined variable: \"!#{name}\".")
end
# Returns an empty array.
#
# @return [Array<Node>] empty
@ -35,6 +25,18 @@ module Sass
def children
[]
end
protected
# Evaluates the variable.
#
# @param environment [Sass::Environment] The environment in which to evaluate the SassScript
# @return [Literal] The SassScript object that is the value of the variable
# @raise [Sass::SyntaxError] if the variable is undefined
def _perform(environment)
(val = environment.var(name)) && (return val)
raise SyntaxError.new("Undefined variable: \"!#{name}\".")
end
end
end
end

View file

@ -584,8 +584,11 @@ MESSAGE
end
def sass_script(*args)
ScriptParser.new(@scanner, @line,
@scanner.pos - (@scanner.string.rindex("\n") || 0)).send(*args)
parser = ScriptParser.new(@scanner, @line,
@scanner.pos - (@scanner.string.rindex("\n") || 0))
result = parser.send(*args)
@line = parser.line
result
end
EXPR_NAMES = {

View file

@ -824,7 +824,7 @@ SCSS
assert_equal 2, e.sass_line
end
def test_multiline_script_error
def test_multiline_script_syntax_error
render <<SCSS
foo {
bar =
@ -835,4 +835,44 @@ SCSS
assert_equal "Expected expression, was plus token.", e.message
assert_equal 3, e.sass_line
end
def test_multiline_script_runtime_error
render <<SCSS
foo {
bar = "baz" +
"bar" +
!bang }
SCSS
assert(false, "Expected syntax error")
rescue Sass::SyntaxError => e
assert_equal "Undefined variable: \"!bang\".", e.message
assert_equal 4, e.sass_line
end
def test_post_multiline_script_runtime_error
render <<SCSS
foo {
bar = "baz" +
"bar" +
"baz";
bip = !bop; }
SCSS
assert(false, "Expected syntax error")
rescue Sass::SyntaxError => e
assert_equal "Undefined variable: \"!bop\".", e.message
assert_equal 5, e.sass_line
end
def test_multiline_property_runtime_error
render <<SCSS
foo {
bar: baz
bar
\#{!bang} }
SCSS
assert(false, "Expected syntax error")
rescue Sass::SyntaxError => e
assert_equal "Undefined variable: \"!bang\".", e.message
assert_equal 4, e.sass_line
end
end