2008-10-15 20:00:28 -07:00
|
|
|
module Sass
|
2009-04-26 01:32:57 -07:00
|
|
|
# The lexical environment for SassScript.
|
|
|
|
# This keeps track of variable and mixin definitions.
|
|
|
|
#
|
|
|
|
# A new environment is created for each level of Sass nesting.
|
|
|
|
# This allows variables to be lexically scoped.
|
|
|
|
# The new environment refers to the environment in the upper scope,
|
|
|
|
# so it has access to variables defined in enclosing scopes,
|
|
|
|
# but new variables are defined locally.
|
|
|
|
#
|
|
|
|
# Environment also keeps track of the {Engine} options
|
2009-05-10 20:59:48 -07:00
|
|
|
# so that they can be made available to {Sass::Script::Functions}.
|
2008-10-15 20:00:28 -07:00
|
|
|
class Environment
|
2009-04-26 01:32:57 -07:00
|
|
|
# The enclosing environment,
|
|
|
|
# or nil if this is the global environment.
|
|
|
|
#
|
|
|
|
# @return [Environment]
|
2008-10-15 20:00:28 -07:00
|
|
|
attr_reader :parent
|
2009-04-21 20:52:33 -07:00
|
|
|
attr_writer :options
|
2008-10-15 20:00:28 -07:00
|
|
|
|
2009-04-26 01:32:57 -07:00
|
|
|
# @param parent [Environment] See \{#parent}
|
2009-04-21 20:52:33 -07:00
|
|
|
def initialize(parent = nil)
|
2008-10-15 20:00:28 -07:00
|
|
|
@vars = {}
|
|
|
|
@mixins = {}
|
|
|
|
@parent = parent
|
2010-04-11 15:24:05 -07:00
|
|
|
@stack = [] unless parent
|
2009-04-21 23:51:37 -07:00
|
|
|
set_var("important", Script::String.new("!important")) unless @parent
|
2009-04-05 00:13:08 -07:00
|
|
|
end
|
|
|
|
|
2009-04-26 01:32:57 -07:00
|
|
|
# The options hash.
|
2009-06-18 13:40:57 -07:00
|
|
|
# See {file:SASS_REFERENCE.md#sass_options the Sass options documentation}.
|
2009-04-26 01:32:57 -07:00
|
|
|
#
|
2009-12-01 18:25:49 -08:00
|
|
|
# @return [{Symbol => Object}]
|
2009-04-05 00:13:08 -07:00
|
|
|
def options
|
|
|
|
@options || (parent && parent.options) || {}
|
2008-10-15 20:00:28 -07:00
|
|
|
end
|
|
|
|
|
2010-04-11 15:24:05 -07:00
|
|
|
# Push a new stack frame onto the mixin/include stack.
|
|
|
|
#
|
2010-04-10 11:51:43 -07:00
|
|
|
# @param frame_info [{Symbol => Object}]
|
2010-04-11 14:32:02 -07:00
|
|
|
# Frame information has the following keys:
|
2010-04-10 11:51:43 -07:00
|
|
|
#
|
2010-04-11 14:32:02 -07:00
|
|
|
# `:filename`
|
|
|
|
# : The name of the file in which the lexical scope changed.
|
2010-04-10 11:51:43 -07:00
|
|
|
#
|
2010-04-11 14:32:02 -07:00
|
|
|
# `:mixin`
|
|
|
|
# : The name of the mixin in which the lexical scope changed,
|
|
|
|
# or `nil` if it wasn't within in a mixin.
|
2010-04-10 11:51:43 -07:00
|
|
|
#
|
2010-04-11 14:32:02 -07:00
|
|
|
# `:line`
|
|
|
|
# : The line of the file on which the lexical scope changed. Never nil.
|
2010-04-11 15:24:05 -07:00
|
|
|
def push_frame(frame_info)
|
|
|
|
if stack.last && stack.last[:prepared]
|
|
|
|
stack.last.delete(:prepared)
|
|
|
|
stack.last.merge!(frame_info)
|
|
|
|
else
|
|
|
|
stack.push(frame_info)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
# Like \{#push\_frame}, but next time a stack frame is pushed,
|
|
|
|
# it will be merged with this frame.
|
2010-04-10 11:51:43 -07:00
|
|
|
#
|
2010-04-11 15:24:05 -07:00
|
|
|
# @param frame_info [{Symbol => Object}] Same as for \{#push\_frame}.
|
|
|
|
def prepare_frame(frame_info)
|
|
|
|
push_frame(frame_info.merge(:prepared => true))
|
2010-04-10 11:51:43 -07:00
|
|
|
end
|
|
|
|
|
2010-04-11 15:24:05 -07:00
|
|
|
# Pop a stack frame from the mixin/include stack.
|
|
|
|
def pop_frame
|
|
|
|
stack.pop if stack.last[:prepared]
|
|
|
|
stack.pop
|
2010-04-10 11:51:43 -07:00
|
|
|
end
|
|
|
|
|
2010-04-11 15:24:05 -07:00
|
|
|
# A list of stack frames in the mixin/include stack.
|
|
|
|
# The last element in the list is the most deeply-nested frame.
|
2010-04-11 14:32:02 -07:00
|
|
|
#
|
|
|
|
# @return [Array<{Symbol => Object}>] The stack frames,
|
|
|
|
# of the form passed to \{#push}.
|
2010-04-10 11:51:43 -07:00
|
|
|
def stack
|
2010-04-11 15:24:05 -07:00
|
|
|
@stack ||= @parent.stack
|
2010-04-10 11:51:43 -07:00
|
|
|
end
|
|
|
|
|
2009-04-26 01:32:57 -07:00
|
|
|
class << self
|
|
|
|
private
|
2008-10-15 20:00:28 -07:00
|
|
|
|
2009-04-26 01:32:57 -07:00
|
|
|
# Note: when updating this,
|
|
|
|
# update haml/yard/inherited_hash.rb as well.
|
|
|
|
def inherited_hash(name)
|
|
|
|
class_eval <<RUBY, __FILE__, __LINE__ + 1
|
|
|
|
def #{name}(name)
|
2010-02-20 23:36:44 -08:00
|
|
|
_#{name}(name.gsub('_', '-'))
|
2009-04-26 01:32:57 -07:00
|
|
|
end
|
2009-04-27 13:27:55 -07:00
|
|
|
|
2010-02-20 23:36:44 -08:00
|
|
|
def _#{name}(name)
|
|
|
|
@#{name}s[name] || @parent && @parent._#{name}(name)
|
|
|
|
end
|
|
|
|
protected :_#{name}
|
|
|
|
|
2009-04-26 01:32:57 -07:00
|
|
|
def set_#{name}(name, value)
|
2010-02-20 23:36:44 -08:00
|
|
|
name = name.gsub('_', '-')
|
2009-04-27 13:33:52 -07:00
|
|
|
@#{name}s[name] = value unless try_set_#{name}(name, value)
|
|
|
|
end
|
|
|
|
|
|
|
|
def try_set_#{name}(name, value)
|
|
|
|
if @#{name}s.include?(name)
|
2009-04-26 01:32:57 -07:00
|
|
|
@#{name}s[name] = value
|
2009-04-27 13:33:52 -07:00
|
|
|
true
|
|
|
|
elsif @parent
|
|
|
|
@parent.try_set_#{name}(name, value)
|
2009-04-26 01:32:57 -07:00
|
|
|
else
|
2009-04-27 13:33:52 -07:00
|
|
|
false
|
2009-04-26 01:32:57 -07:00
|
|
|
end
|
2008-10-15 20:00:28 -07:00
|
|
|
end
|
2009-04-27 13:33:52 -07:00
|
|
|
protected :try_set_#{name}
|
2008-10-15 20:00:28 -07:00
|
|
|
|
2009-04-26 01:32:57 -07:00
|
|
|
def set_local_#{name}(name, value)
|
2010-02-20 23:36:44 -08:00
|
|
|
@#{name}s[name.gsub('_', '-')] = value
|
2009-04-26 01:32:57 -07:00
|
|
|
end
|
2008-10-15 20:00:28 -07:00
|
|
|
RUBY
|
2009-04-26 01:32:57 -07:00
|
|
|
end
|
2008-10-15 20:00:28 -07:00
|
|
|
end
|
2009-04-26 01:32:57 -07:00
|
|
|
|
|
|
|
# variable
|
|
|
|
# Script::Literal
|
2008-10-15 20:00:28 -07:00
|
|
|
inherited_hash :var
|
2009-04-26 01:32:57 -07:00
|
|
|
# mixin
|
|
|
|
# Engine::Mixin
|
2008-10-15 20:00:28 -07:00
|
|
|
inherited_hash :mixin
|
|
|
|
end
|
|
|
|
end
|