Skip to content

Commit 9fb564e

Browse files
committed
Refactor prelexer and improve performance
Implements some functions we previously used from the standard implementation to be locale unaware. This also improved the performance by quite a bit. Also fixes word boundary to let `-` be part of words
1 parent 6ab00d9 commit 9fb564e

18 files changed

+882
-650
lines changed

Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ SOURCES = \
122122
file.cpp \
123123
functions.cpp \
124124
inspect.cpp \
125+
lexer.cpp \
125126
node.cpp \
126127
json.cpp \
127128
emitter.cpp \

Makefile.am

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ libsass_la_SOURCES = \
6565
file.cpp file.hpp \
6666
functions.cpp functions.hpp \
6767
inspect.cpp inspect.hpp \
68+
lexer.cpp lexer.hpp \
6869
node.cpp node.hpp \
6970
json.cpp json.hpp \
7071
emitter.cpp emitter.hpp \

ast.hpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -460,14 +460,14 @@ namespace Sass {
460460
class Assignment : public Statement {
461461
ADD_PROPERTY(string, variable);
462462
ADD_PROPERTY(Expression*, value);
463-
ADD_PROPERTY(bool, is_guarded);
463+
ADD_PROPERTY(bool, is_default);
464464
ADD_PROPERTY(bool, is_global);
465465
public:
466466
Assignment(ParserState pstate,
467467
string var, Expression* val,
468-
bool guarded = false,
469-
bool global = false)
470-
: Statement(pstate), variable_(var), value_(val), is_guarded_(guarded), is_global_(global)
468+
bool is_default = false,
469+
bool is_global = false)
470+
: Statement(pstate), variable_(var), value_(val), is_default_(is_default), is_global_(is_global)
471471
{ }
472472
ATTACH_OPERATIONS();
473473
};

bind.cpp

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ namespace Sass {
2020
Parameter* p = (*ps)[i];
2121
param_map[p->name()] = p;
2222
// if (p->default_value()) {
23-
// env->current_frame()[p->name()] = p->default_value()->perform(eval->with(env));
23+
// env->local_frame()[p->name()] = p->default_value()->perform(eval->with(env));
2424
// }
2525
}
2626

@@ -41,12 +41,12 @@ namespace Sass {
4141
if (p->is_rest_parameter()) {
4242
if (a->is_rest_argument()) {
4343
// rest param and rest arg -- just add one to the other
44-
if (env->current_frame_has(p->name())) {
45-
*static_cast<List*>(env->current_frame()[p->name()])
44+
if (env->has_local(p->name())) {
45+
*static_cast<List*>(env->local_frame()[p->name()])
4646
+= static_cast<List*>(a->value());
4747
}
4848
else {
49-
env->current_frame()[p->name()] = a->value();
49+
env->local_frame()[p->name()] = a->value();
5050
}
5151
} else {
5252

@@ -55,7 +55,7 @@ namespace Sass {
5555
0,
5656
List::COMMA,
5757
true);
58-
env->current_frame()[p->name()] = arglist;
58+
env->local_frame()[p->name()] = arglist;
5959
while (ia < LA) {
6060
a = (*as)[ia];
6161
(*arglist) << new (ctx.mem) Argument(a->pstate(),
@@ -99,7 +99,7 @@ namespace Sass {
9999
msg << callee << " has no parameter named " << name;
100100
error(msg.str(), a->pstate());
101101
}
102-
env->current_frame()[name] = argmap->at(key);
102+
env->local_frame()[name] = argmap->at(key);
103103
}
104104
++ia;
105105
continue;
@@ -108,14 +108,14 @@ namespace Sass {
108108
}
109109

110110
if (a->name().empty()) {
111-
if (env->current_frame_has(p->name())) {
111+
if (env->has_local(p->name())) {
112112
stringstream msg;
113113
msg << "parameter " << p->name()
114114
<< " provided more than once in call to " << callee;
115115
error(msg.str(), a->pstate());
116116
}
117117
// ordinal arg -- bind it to the next param
118-
env->current_frame()[p->name()] = a->value();
118+
env->local_frame()[p->name()] = a->value();
119119
++ip;
120120
}
121121
else {
@@ -131,13 +131,13 @@ namespace Sass {
131131
<< "cannot be used as named argument";
132132
error(msg.str(), a->pstate());
133133
}
134-
if (env->current_frame_has(a->name())) {
134+
if (env->has_local(a->name())) {
135135
stringstream msg;
136136
msg << "parameter " << p->name()
137137
<< "provided more than once in call to " << callee;
138138
error(msg.str(), a->pstate());
139139
}
140-
env->current_frame()[a->name()] = a->value();
140+
env->local_frame()[a->name()] = a->value();
141141
}
142142
}
143143

@@ -150,9 +150,9 @@ namespace Sass {
150150
// cerr << "env for default params:" << endl;
151151
// env->print();
152152
// cerr << "********" << endl;
153-
if (!env->current_frame_has(leftover->name())) {
153+
if (!env->has_local(leftover->name())) {
154154
if (leftover->is_rest_parameter()) {
155-
env->current_frame()[leftover->name()] = new (ctx.mem) List(leftover->pstate(),
155+
env->local_frame()[leftover->name()] = new (ctx.mem) List(leftover->pstate(),
156156
0,
157157
List::COMMA,
158158
true);
@@ -167,7 +167,7 @@ namespace Sass {
167167
eval->backtrace = old_bt;
168168
eval->contextualize = old_context;
169169
// dv->perform(&to_string);
170-
env->current_frame()[leftover->name()] = dv;
170+
env->local_frame()[leftover->name()] = dv;
171171
}
172172
else {
173173
// param is unbound and has no default value -- error

environment.hpp

Lines changed: 102 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -18,83 +18,148 @@ namespace Sass {
1818
template <typename T>
1919
class Environment {
2020
// TODO: test with unordered_map
21-
map<string, T> current_frame_;
21+
map<string, T> local_frame_;
2222
ADD_PROPERTY(Environment*, parent);
2323

2424
public:
2525
Memory_Manager<AST_Node> mem;
26-
Environment() : current_frame_(map<string, T>()), parent_(0) { }
27-
28-
map<string, T>& current_frame() { return current_frame_; }
26+
Environment() : local_frame_(map<string, T>()), parent_(0) { }
2927

28+
// link parent to create a stack
3029
void link(Environment& env) { parent_ = &env; }
3130
void link(Environment* env) { parent_ = env; }
3231

33-
bool has(const string key) const
32+
// this is used to find the global frame
33+
// which is the second last on the stack
34+
bool is_lexical() const
3435
{
35-
if (current_frame_.count(key)) return true;
36-
else if (parent_) return parent_->has(key);
37-
else return false;
36+
return !! parent_ && parent_->parent_;
3837
}
3938

40-
bool current_frame_has(const string key) const
41-
{ return !!current_frame_.count(key); }
42-
43-
void current_frame_set(const string key, T val)
44-
{ current_frame_[key] = val; }
39+
// only match the real root scope
40+
// there is still a parent around
41+
// not sure what it is actually use for
42+
// I guess we store functions etc. there
43+
bool is_root_scope() const
44+
{
45+
return parent_ && ! parent_->parent_;
46+
}
4547

46-
void global_frame_set(const string key, T val)
47-
{ global_frame()->current_frame_[key] = val; }
48+
// scope operates on the current frame
4849

49-
Environment* grandparent() const
50-
{
51-
if(parent_ && parent_->parent_) return parent_->parent_;
52-
else return 0;
50+
map<string, T>& local_frame() {
51+
return local_frame_;
5352
}
5453

55-
Environment* global_frame()
54+
bool has_local(const string& key) const
55+
{ return local_frame_.count(key); }
56+
57+
T& get_local(const string& key)
58+
{ return local_frame_[key]; }
59+
60+
void set_local(const string& key, T val)
61+
{ local_frame_[key] = val; }
62+
63+
void del_local(const string& key)
64+
{ local_frame_.erase(key); }
65+
66+
67+
// global operates on the global frame
68+
// which is the second last on the stack
69+
70+
Environment* global_env()
5671
{
5772
Environment* cur = this;
58-
// looks like global variables
59-
// are in the second last parent
60-
while (cur->grandparent()) {
73+
while (cur->is_lexical()) {
6174
cur = cur->parent_;
6275
}
6376
return cur;
6477
}
6578

66-
bool global_frame_has(const string key) const
79+
bool has_global(const string& key)
80+
{ return global_env()->has(key); }
81+
82+
T& get_global(const string& key)
83+
{ return (*global_env())[key]; }
84+
85+
void set_global(const string& key, T val)
86+
{ global_env()->local_frame_[key] = val; }
87+
88+
void del_global(const string& key)
89+
{ global_env()->local_frame_.erase(key); }
90+
91+
// see if we have a lexical variable
92+
// move down the stack but stop before we
93+
// reach the global frame (is not included)
94+
bool has_lexical(const string& key) const
95+
{
96+
auto cur = this;
97+
while (cur->is_lexical()) {
98+
if (cur->has_local(key)) return true;
99+
cur = cur->parent_;
100+
}
101+
return false;
102+
}
103+
104+
// see if we have a lexical we could update
105+
// either update already existing lexical value
106+
// or if flag is set, we create one if no lexical found
107+
void set_lexical(const string& key, T val, bool global = false)
67108
{
68-
if(parent_ && !grandparent()) {
69-
return has(key);
109+
auto cur = this;
110+
while (cur->is_lexical()) {
111+
if (cur->has_local(key)) {
112+
cur->set_local(key, val);
113+
return;
114+
}
115+
cur = cur->parent_;
70116
}
71-
else if(parent_) {
72-
return parent_->global_frame_has(key);
117+
if (global) {
118+
set_global(key, val);
119+
} else {
120+
set_local(key, val);
73121
}
74-
else {
75-
return false;
122+
}
123+
124+
// look on the full stack for key
125+
// include all scopes available
126+
bool has(const string& key) const
127+
{
128+
auto cur = this;
129+
while (cur) {
130+
if (cur->has_local(key)) {
131+
return true;
132+
}
133+
cur = cur->parent_;
76134
}
135+
return false;
77136
}
78137

79-
T& operator[](const string key)
138+
// use array access for getter and setter functions
139+
T& operator[](const string& key)
80140
{
81-
if (current_frame_.count(key)) return current_frame_[key];
82-
else if (parent_) return (*parent_)[key];
83-
else return current_frame_[key];
141+
auto cur = this;
142+
while (cur) {
143+
if (cur->has_local(key)) {
144+
return cur->get_local(key);
145+
}
146+
cur = cur->parent_;
147+
}
148+
return get_local(key);
84149
}
85150

86-
#ifdef DEBUG
151+
#ifdef DEBUG
87152
void print()
88153
{
89-
for (typename map<string, T>::iterator i = current_frame_.begin(); i != current_frame_.end(); ++i) {
154+
for (typename map<string, T>::iterator i = local_frame_.begin(); i != local_frame_.end(); ++i) {
90155
cerr << i->first << endl;
91156
}
92157
if (parent_) {
93158
cerr << "---" << endl;
94159
parent_->print();
95160
}
96161
}
97-
#endif
162+
#endif
98163

99164
};
100165
}

0 commit comments

Comments
 (0)