forked from sass/sass
-
Notifications
You must be signed in to change notification settings - Fork 0
/
environment.rb
143 lines (128 loc) · 4.13 KB
/
environment.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
require 'set'
module Sass
# 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
# so that they can be made available to {Sass::Script::Functions}.
class Environment
# The enclosing environment,
# or nil if this is the global environment.
#
# @return [Environment]
attr_reader :parent
attr_writer :options
# @param parent [Environment] See \{#parent}
def initialize(parent = nil)
@vars = {}
@mixins = {}
@parent = parent
@stack = [] unless parent
@mixins_in_use = Set.new unless parent
set_var("important", Script::String.new("!important")) unless @parent
end
# The options hash.
# See {file:SASS_REFERENCE.md#sass_options the Sass options documentation}.
#
# @return [{Symbol => Object}]
def options
@options || (parent && parent.options) || {}
end
# Push a new stack frame onto the mixin/include stack.
#
# @param frame_info [{Symbol => Object}]
# Frame information has the following keys:
#
# `:filename`
# : The name of the file in which the lexical scope changed.
#
# `:mixin`
# : The name of the mixin in which the lexical scope changed,
# or `nil` if it wasn't within in a mixin.
#
# `:line`
# : The line of the file on which the lexical scope changed. Never nil.
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
mixins_in_use << stack.last[:mixin] if stack.last[:mixin] && !stack.last[:prepared]
end
# Like \{#push\_frame}, but next time a stack frame is pushed,
# it will be merged with this frame.
#
# @param frame_info [{Symbol => Object}] Same as for \{#push\_frame}.
def prepare_frame(frame_info)
push_frame(frame_info.merge(:prepared => true))
end
# Pop a stack frame from the mixin/include stack.
def pop_frame
stack.pop if stack.last && stack.last[:prepared]
popped = stack.pop
mixins_in_use.delete(popped[:mixin]) if popped && popped[:mixin]
end
# A list of stack frames in the mixin/include stack.
# The last element in the list is the most deeply-nested frame.
#
# @return [Array<{Symbol => Object}>] The stack frames,
# of the form passed to \{#push\_frame}.
def stack
@stack ||= @parent.stack
end
# A set of names of mixins currently present in the stack.
#
# @return [Set<String>] The mixin names.
def mixins_in_use
@mixins_in_use ||= @parent.mixins_in_use
end
class << self
private
# 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)
_#{name}(name.gsub('_', '-'))
end
def _#{name}(name)
@#{name}s[name] || @parent && @parent._#{name}(name)
end
protected :_#{name}
def set_#{name}(name, value)
name = name.gsub('_', '-')
@#{name}s[name] = value unless try_set_#{name}(name, value)
end
def try_set_#{name}(name, value)
if @#{name}s.include?(name)
@#{name}s[name] = value
true
elsif @parent
@parent.try_set_#{name}(name, value)
else
false
end
end
protected :try_set_#{name}
def set_local_#{name}(name, value)
@#{name}s[name.gsub('_', '-')] = value
end
RUBY
end
end
# variable
# Script::Literal
inherited_hash :var
# mixin
# Engine::Mixin
inherited_hash :mixin
end
end