From 14da927d48cd71cf6e9ad642f9687951e1241c57 Mon Sep 17 00:00:00 2001 From: Marcel Greter Date: Tue, 3 May 2016 00:54:23 +0200 Subject: [PATCH] Implement indexed map access (incubating feature) --- src/ast.hpp | 16 +++++++++++--- src/functions.cpp | 55 ++++++++++++++++++++++++++++++++++++++--------- src/listize.cpp | 11 ++++++++++ src/listize.hpp | 1 + 4 files changed, 70 insertions(+), 13 deletions(-) diff --git a/src/ast.hpp b/src/ast.hpp index 02a25e12d8..de3bd0b5ce 100644 --- a/src/ast.hpp +++ b/src/ast.hpp @@ -303,6 +303,7 @@ namespace Sass { std::vector list_; protected: size_t hash_; + std::deque ordered; Expression* duplicate_key_; void reset_hash() { hash_ = 0; } void reset_duplicate_key() { duplicate_key_ = 0; } @@ -321,15 +322,24 @@ namespace Sass { Hashed& operator<<(std::pair p) { reset_hash(); - + ordered.push_back(p.first); + ordered.push_back(p.second); if (!has(p.first)) list_.push_back(p.first); else if (!duplicate_key_) duplicate_key_ = p.first; - elements_[p.first] = p.second; - adjust_after_pushing(p); return *this; } + Expression* key(size_t i) { + return ordered.at(i * 2); + } + Expression* value(size_t i) { + return ordered.at(i * 2 + 1); + } + Expression* value(size_t i, Expression* v) { + ordered[i * 2 + 1] = v; + return v; + } Hashed& operator+=(Hashed* h) { if (length() == 0) { diff --git a/src/functions.cpp b/src/functions.cpp index c83b1ad4dd..1772472d8f 100644 --- a/src/functions.cpp +++ b/src/functions.cpp @@ -1248,6 +1248,10 @@ namespace Sass { if (index < 0 || index > len - 1) error("index out of bounds for `" + std::string(sig) + "`", pstate); // return (*sl)[static_cast(index)]; Listize listize(ctx.mem); + if (m) { + List* l = SASS_MEMORY_NEW(ctx.mem, List, pstate, 2); + *l << m->key(index) << m->value(index); + } return (*sl)[static_cast(index)]->perform(&listize); } List* l = dynamic_cast(env["$list"]); @@ -1265,8 +1269,8 @@ namespace Sass { if (m) { l = SASS_MEMORY_NEW(ctx.mem, List, pstate, 1); - *l << m->keys()[static_cast(index)]; - *l << m->at(m->keys()[static_cast(index)]); + *l << m->key(index); + *l << m->value(index); return l; } else { @@ -1280,27 +1284,58 @@ namespace Sass { BUILT_IN(set_nth) { List* l = dynamic_cast(env["$list"]); + Map* m = dynamic_cast(env["$list"]); Number* n = ARG("$n", Number); Expression* v = ARG("$value", Expression); - if (!l) { + if (!m && !l) { l = SASS_MEMORY_NEW(ctx.mem, List, pstate, 1); *l << ARG("$list", Expression); } - if (l->empty()) error("argument `$list` of `" + std::string(sig) + "` must not be empty", pstate); - double index = std::floor(n->value() < 0 ? l->length() + n->value() : n->value() - 1); - if (index < 0 || index > l->length() - 1) error("index out of bounds for `" + std::string(sig) + "`", pstate); - List* result = SASS_MEMORY_NEW(ctx.mem, List, pstate, l->length(), l->separator()); - for (size_t i = 0, L = l->length(); i < L; ++i) { - *result << ((i == index) ? v : (*l)[i]); + size_t len = m ? m->length() : l->length(); + bool empty = m ? m->empty() : l->empty(); + if (empty) error("argument `$list` of `" + std::string(sig) + "` must not be empty", pstate); + double index = std::floor(n->value() < 0 ? len + n->value() : n->value() - 1); + if (index < 0 || index > len - 1) error("index out of bounds for `" + std::string(sig) + "`", pstate); + if (m) { + m->value(index, v); // update the value + Listize listize(ctx.mem); + return m->perform(&listize); + } + else { + List* result = SASS_MEMORY_NEW(ctx.mem, List, pstate, l->length(), l->separator()); + for (size_t i = 0, L = l->length(); i < L; ++i) { + *result << ((i == index) ? v : (*l)[i]); + } + return result; } - return result; } Signature index_sig = "index($list, $value)"; BUILT_IN(index) { + Map* m = dynamic_cast(env["$list"]); List* l = dynamic_cast(env["$list"]); Expression* v = ARG("$value", Expression); + + if (m) { + if (List* vl = dynamic_cast(v)) { + if (vl->size() == 2 && vl->separator() == SASS_SPACE) { + for (size_t i = 0, L = m->length(); i < L; i ++) { + if (Eval::eq(m->key(i), vl->at(0))) { + if (Eval::eq(m->value(i), vl->at(1))) { + // only return the index if the value matches too + return SASS_MEMORY_NEW(ctx.mem, Number, pstate, (double)(i+1)); + } else { + // found key, which is unique + // so nothing more to match + break; + } + } + } + } + } + } + if (!l) { l = SASS_MEMORY_NEW(ctx.mem, List, pstate, 1); *l << ARG("$list", Expression); diff --git a/src/listize.cpp b/src/listize.cpp index a9dfda9b1d..c5f64b505c 100644 --- a/src/listize.cpp +++ b/src/listize.cpp @@ -14,6 +14,17 @@ namespace Sass { : mem(mem) { } + Expression* Listize::operator()(Map* m) + { + List* l = SASS_MEMORY_NEW(mem, List, m->pstate(), m->length(), SASS_COMMA); + for (size_t i = 0, L = m->length(); i < L; i++) { + List* il = SASS_MEMORY_NEW(mem, List, m->pstate(), 2, SASS_SPACE); + *il << m->key(i) << m->value(i); + *l << il; + } + return l; + } + Expression* Listize::operator()(Selector_List* sel) { List* l = SASS_MEMORY_NEW(mem, List, sel->pstate(), sel->length(), SASS_COMMA); diff --git a/src/listize.hpp b/src/listize.hpp index cd6ef54207..e81c9134c1 100644 --- a/src/listize.hpp +++ b/src/listize.hpp @@ -24,6 +24,7 @@ namespace Sass { Listize(Memory_Manager&); ~Listize() { } + Expression* operator()(Map*); Expression* operator()(Selector_List*); Expression* operator()(Complex_Selector*); Expression* operator()(Compound_Selector*);