Skip to content
This repository was archived by the owner on Oct 24, 2025. It is now read-only.

Commit ded586f

Browse files
committed
Move environment implementation into own source file
Makes it easier to switch debug statements on and of to track memory allocation. Also improved the API a bit.
1 parent 222d8c0 commit ded586f

File tree

6 files changed

+223
-101
lines changed

6 files changed

+223
-101
lines changed

Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,7 @@ SOURCES = \
160160
context.cpp \
161161
cssize.cpp \
162162
emitter.cpp \
163+
environment.cpp \
163164
error_handling.cpp \
164165
eval.cpp \
165166
expand.cpp \

Makefile.am

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ libsass_la_SOURCES = \
3737
subset_map.hpp mapping.hpp \
3838
color_names.hpp backtrace.hpp \
3939
cencode.c b64/cencode.h b64/encode.h \
40-
token.hpp environment.hpp \
40+
token.hpp \
4141
paths.hpp debug.hpp \
4242
utf8.h utf8/core.h \
4343
utf8/checked.h utf8/unchecked.h \
@@ -46,6 +46,7 @@ libsass_la_SOURCES = \
4646
bind.cpp bind.hpp \
4747
constants.cpp constants.hpp \
4848
context.cpp context.hpp \
49+
environment.cpp environment.hpp \
4950
error_handling.cpp error_handling.hpp \
5051
eval.cpp eval.hpp \
5152
expand.cpp expand.hpp \

environment.cpp

Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
#include "ast.hpp"
2+
#include "environment.hpp"
3+
4+
namespace Sass {
5+
6+
template <typename T>
7+
Environment<T>::Environment() : local_frame_(map<string, T>()), parent_(0) { }
8+
template <typename T>
9+
Environment<T>::Environment(Environment<T>* env) : local_frame_(map<string, T>()), parent_(env) { }
10+
template <typename T>
11+
Environment<T>::Environment(Environment<T>& env) : local_frame_(map<string, T>()), parent_(&env) { }
12+
13+
// link parent to create a stack
14+
template <typename T>
15+
void Environment<T>::link(Environment& env) { parent_ = &env; }
16+
template <typename T>
17+
void Environment<T>::link(Environment* env) { parent_ = env; }
18+
19+
// this is used to find the global frame
20+
// which is the second last on the stack
21+
template <typename T>
22+
bool Environment<T>::is_lexical() const
23+
{
24+
return !! parent_ && parent_->parent_;
25+
}
26+
27+
// only match the real root scope
28+
// there is still a parent around
29+
// not sure what it is actually use for
30+
// I guess we store functions etc. there
31+
template <typename T>
32+
bool Environment<T>::is_global() const
33+
{
34+
return parent_ && ! parent_->parent_;
35+
}
36+
37+
template <typename T>
38+
map<string, T>& Environment<T>::local_frame() {
39+
return local_frame_;
40+
}
41+
42+
template <typename T>
43+
bool Environment<T>::has_local(const string& key) const
44+
{ return local_frame_.find(key) != local_frame_.end(); }
45+
46+
template <typename T>
47+
T& Environment<T>::get_local(const string& key)
48+
{ return local_frame_[key]; }
49+
50+
template <typename T>
51+
void Environment<T>::set_local(const string& key, T val)
52+
{
53+
local_frame_[key] = val;
54+
}
55+
56+
template <typename T>
57+
void Environment<T>::del_local(const string& key)
58+
{ local_frame_.erase(key); }
59+
60+
template <typename T>
61+
Environment<T>* Environment<T>::global_env()
62+
{
63+
Environment* cur = this;
64+
while (cur->is_lexical()) {
65+
cur = cur->parent_;
66+
}
67+
return cur;
68+
}
69+
70+
template <typename T>
71+
bool Environment<T>::has_global(const string& key)
72+
{ return global_env()->has(key); }
73+
74+
template <typename T>
75+
T& Environment<T>::get_global(const string& key)
76+
{ return (*global_env())[key]; }
77+
78+
template <typename T>
79+
void Environment<T>::set_global(const string& key, T val)
80+
{
81+
global_env()->local_frame_[key] = val;
82+
}
83+
84+
template <typename T>
85+
void Environment<T>::del_global(const string& key)
86+
{ global_env()->local_frame_.erase(key); }
87+
88+
template <typename T>
89+
Environment<T>* Environment<T>::lexical_env(const string& key)
90+
{
91+
Environment* cur = this;
92+
while (cur) {
93+
if (cur->has_local(key)) {
94+
return cur;
95+
}
96+
cur = cur->parent_;
97+
}
98+
return this;
99+
}
100+
101+
// see if we have a lexical variable
102+
// move down the stack but stop before we
103+
// reach the global frame (is not included)
104+
template <typename T>
105+
bool Environment<T>::has_lexical(const string& key) const
106+
{
107+
auto cur = this;
108+
while (cur->is_lexical()) {
109+
if (cur->has_local(key)) return true;
110+
cur = cur->parent_;
111+
}
112+
return false;
113+
}
114+
115+
// see if we have a lexical we could update
116+
// either update already existing lexical value
117+
// or if flag is set, we create one if no lexical found
118+
template <typename T>
119+
void Environment<T>::set_lexical(const string& key, T val)
120+
{
121+
auto cur = this;
122+
while (cur->is_lexical()) {
123+
if (cur->has_local(key)) {
124+
cur->set_local(key, val);
125+
return;
126+
}
127+
cur = cur->parent_;
128+
}
129+
set_local(key, val);
130+
}
131+
132+
// look on the full stack for key
133+
// include all scopes available
134+
template <typename T>
135+
bool Environment<T>::has(const string& key) const
136+
{
137+
auto cur = this;
138+
while (cur) {
139+
if (cur->has_local(key)) {
140+
return true;
141+
}
142+
cur = cur->parent_;
143+
}
144+
return false;
145+
}
146+
147+
// use array access for getter and setter functions
148+
template <typename T>
149+
T& Environment<T>::operator[](const string& key)
150+
{
151+
auto cur = this;
152+
while (cur) {
153+
if (cur->has_local(key)) {
154+
return cur->get_local(key);
155+
}
156+
cur = cur->parent_;
157+
}
158+
return get_local(key);
159+
}
160+
161+
#ifdef DEBUG
162+
template <typename T>
163+
size_t Environment<T>::print(string prefix)
164+
{
165+
size_t indent = 0;
166+
if (parent_) indent = parent_->print(prefix) + 1;
167+
cerr << prefix << string(indent, ' ') << "== " << this << endl;
168+
for (typename map<string, T>::iterator i = local_frame_.begin(); i != local_frame_.end(); ++i) {
169+
if (!ends_with(i->first, "[f]") && !ends_with(i->first, "[f]4") && !ends_with(i->first, "[f]2")) {
170+
cerr << prefix << string(indent, ' ') << i->first << " " << i->second;
171+
// if (Value* val = dynamic_cast<Value*>(i->second))
172+
// { cerr << " : " << val->to_string(true, 5); }
173+
cerr << endl;
174+
}
175+
}
176+
return indent ;
177+
}
178+
#endif
179+
180+
// compile implementation for AST_Node
181+
template class Environment<AST_Node*>;
182+
183+
}
184+

0 commit comments

Comments
 (0)