Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

113 lines (97 sloc) 3.679 kb
require 'set'
require 'sass/script/string'
require 'sass/script/number'
require 'sass/script/color'
require 'sass/script/functions'
require 'sass/script/unary_operation'
require 'sass/script/interpolation'
require 'sass/script/string_interpolation'
module Sass::Script
# A SassScript parse node representing a binary operation,
# such as `$a + $b` or `"foo" + 1`.
class Operation < Node
attr_reader :operand1
attr_reader :operand2
attr_reader :operator
# @param operand1 [Script::Node] The parse-tree node
# for the right-hand side of the operator
# @param operand2 [Script::Node] The parse-tree node
# for the left-hand side of the operator
# @param operator [Symbol] The operator to perform.
# This should be one of the binary operator names in {Lexer::OPERATORS}
def initialize(operand1, operand2, operator)
@operand1 = operand1
@operand2 = operand2
@operator = operator
super()
end
# @return [String] A human-readable s-expression representation of the operation
def inspect
"(#{@operator.inspect} #{@operand1.inspect} #{@operand2.inspect})"
end
# @see Node#to_sass
def to_sass(opts = {})
pred = Sass::Script::Parser.precedence_of(@operator)
o1 = operand_to_sass @operand1, :left, opts
o2 = operand_to_sass @operand2, :right, opts
sep =
case @operator
when :comma; ", "
when :space; " "
else; " #{Lexer::OPERATORS_REVERSE[@operator]} "
end
"#{o1}#{sep}#{o2}"
end
# Returns the operands for this operation.
#
# @return [Array<Node>]
# @see Node#children
def children
[@operand1, @operand2]
end
# @see Node#deep_copy
def deep_copy
node = dup
node.instance_variable_set('@operand1', @operand1.deep_copy)
node.instance_variable_set('@operand2', @operand2.deep_copy)
node
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)
literal1 = @operand1.perform(environment)
# Special-case :and and :or to support short-circuiting.
if @operator == :and
return literal1.to_bool ? @operand2.perform(environment) : literal1
elsif @operator == :or
return literal1.to_bool ? literal1 : @operand2.perform(environment)
end
literal2 = @operand2.perform(environment)
literal_types = [literal1.class, literal2.class]
if !literal_types.include?(String) && literal_types.include?(Null)
raise Sass::SyntaxError.new("Invalid null operation: \"#{literal1.inspect} #{@operator} #{literal2.inspect}\".")
end
begin
opts(literal1.send(@operator, literal2))
rescue NoMethodError => e
raise e unless e.name.to_s == @operator.to_s
raise Sass::SyntaxError.new("Undefined operation: \"#{literal1} #{@operator} #{literal2}\".")
end
end
private
def operand_to_sass(op, side, opts)
return "(#{op.to_sass(opts)})" if op.is_a?(List)
return op.to_sass(opts) unless op.is_a?(Operation)
pred = Sass::Script::Parser.precedence_of(@operator)
sub_pred = Sass::Script::Parser.precedence_of(op.operator)
assoc = Sass::Script::Parser.associative?(@operator)
return "(#{op.to_sass(opts)})" if sub_pred < pred ||
(side == :right && sub_pred == pred && !assoc)
op.to_sass(opts)
end
end
end
Jump to Line
Something went wrong with that request. Please try again.