44#include " fn_maps.hpp"
55
66#include " compiler.hpp"
7+ #include " exceptions.hpp"
78#include " ast_values.hpp"
89
910namespace Sass {
@@ -74,11 +75,111 @@ namespace Sass {
7475 {
7576 MapObj map = arguments[0 ]->assertMap (compiler, Strings::map);
7677 Value* key = arguments[1 ]->assertValue (compiler, Strings::key);
78+
79+
7780 auto it = map->find (key);
78- if (it != map->end ()) return it->second ;
81+ if (it != map->end ()) {
82+ auto rv = it->second ;
83+
84+ auto inner = arguments[2 ]->iterator ();
85+ auto cur = inner.begin (), end = inner.end ();
86+ if (cur == end) {
87+ return rv;
88+ }
89+ while (cur != end) {
90+ if (auto deep = rv->isaMap ()) {
91+ auto dada = deep->find (*cur);
92+ if (dada != deep->end ()) {
93+ rv = dada.value ();
94+ }
95+ else {
96+ return SASS_MEMORY_NEW (Null, pstate);
97+ }
98+ }
99+ else {
100+ return SASS_MEMORY_NEW (Null, pstate);
101+ }
102+ ++cur;
103+ }
104+
105+ return rv;
106+ }
79107 return SASS_MEMORY_NEW (Null, pstate);
80108 }
81109
110+
111+ BUILT_IN_FN (fnMapSetThreeArgs)
112+ {
113+ auto map = arguments[0 ]->assertMap (compiler, Strings::map);
114+ auto copy = SASS_MEMORY_COPY (map);
115+ auto it = copy->find (arguments[1 ]);
116+ if (it == copy->end ()) {
117+ copy->insert ({ arguments[1 ], arguments[2 ] });
118+ }
119+ else {
120+ it.value () = arguments[2 ];
121+ }
122+ return copy;
123+ }
124+
125+ BUILT_IN_FN (fnMapSetTwoArgs)
126+ {
127+ auto map = arguments[0 ]->assertMap (compiler, Strings::map);
128+ MapObj copy = map = SASS_MEMORY_COPY (map);
129+ auto it = arguments[1 ]->iterator ();
130+ auto size = arguments[1 ]->lengthAsList ();
131+ auto cur = it.begin (), end = it.end ();
132+ if (size == 0 ) {
133+ throw Exception::RuntimeException (compiler,
134+ " Expected $args to contain a key." );
135+ }
136+ else if (size == 1 ) {
137+ throw Exception::RuntimeException (compiler,
138+ " Expected $args to contain a value." );
139+ }
140+
141+
142+ while (cur != end) {
143+ auto qwe = *cur;
144+ auto it = map->find (qwe);
145+ if (it != map->end ()) {
146+ ValueObj inner = it->second ;
147+ if (auto qwe = inner->isaMap ()) {
148+ map = qwe;
149+ }
150+ else {
151+ if (cur == end - 2 ) {
152+ ++cur;
153+ it.value () = *cur;
154+ break ;
155+ }
156+ else {
157+ auto newMap = SASS_MEMORY_NEW (Map,
158+ map->pstate (), {});
159+ it.value () = newMap;
160+ map = newMap;
161+ }
162+ }
163+ }
164+ else {
165+ if (cur == end - 2 ) {
166+ ++cur;
167+ map->insert ({ qwe, *cur });
168+ break ;
169+ }
170+ else {
171+ auto newMap = SASS_MEMORY_NEW (Map,
172+ map->pstate (), {});
173+ map->insert ({ qwe, newMap });
174+ map = newMap;
175+ }
176+ }
177+ ++cur;
178+ }
179+
180+ return copy.detach ();
181+ }
182+
82183 /* ******************************************************************/
83184
84185 BUILT_IN_FN (merge)
@@ -99,6 +200,65 @@ namespace Sass {
99200 return copy;
100201 }
101202
203+ BUILT_IN_FN (merge_many)
204+ {
205+ MapObj map1 = arguments[0 ]->assertMap (compiler, Strings::map1);
206+
207+ auto it = arguments[1 ]->iterator ();
208+ auto size = arguments[1 ]->lengthAsList ();
209+
210+ if (size == 0 ) {
211+ throw Exception::RuntimeException (compiler,
212+ " Expected $args to contain a key." );
213+ }
214+ else if (size == 1 ) {
215+ throw Exception::RuntimeException (compiler,
216+ " Expected $args to contain a map." );
217+ }
218+
219+ auto cur = it.begin (), end = it.end () - 1 ;
220+
221+ Map *last = (end)->assertMap (compiler, Strings::map2);
222+
223+ MapObj copy = map1 = SASS_MEMORY_COPY (map1);
224+
225+ while (cur != end) {
226+
227+ auto it = copy->find (*cur);
228+ if (it != copy->end ()) {
229+ if (auto inner = it->second ->isaMap ()) {
230+ copy = SASS_MEMORY_COPY (inner);
231+ it.value () = copy;
232+ }
233+ else {
234+ Map* empty = SASS_MEMORY_NEW (Map,
235+ it->second ->pstate ());
236+ it.value () = empty;
237+ copy = empty;
238+ }
239+ }
240+ else {
241+ Map* empty = SASS_MEMORY_NEW (Map,
242+ last->pstate ());
243+ copy->insert ({ *cur, empty });
244+ copy = empty;
245+ }
246+
247+ // if (!cur->isaMap()) {
248+ // *cur = SASS_MEMORY_NEW(Map, )
249+ // }
250+
251+
252+ ++cur;
253+ }
254+
255+ for (auto kv : last->elements ()) {
256+ copy->insertOrSet (kv); }
257+ return map1.detach ();
258+ }
259+
260+
261+
102262 /* ******************************************************************/
103263
104264 // Because the signature below has an explicit `$key` argument, it doesn't
@@ -157,7 +317,48 @@ namespace Sass {
157317 {
158318 MapObj map = arguments[0 ]->assertMap (compiler, Strings::map);
159319 Value* key = arguments[1 ]->assertValue (compiler, Strings::key);
160- return SASS_MEMORY_NEW (Boolean, pstate, map->has (key));
320+ if (arguments[2 ]->lengthAsList () == 0 ) {
321+ return SASS_MEMORY_NEW (Boolean, pstate, map->has (key));
322+ }
323+ else {
324+ Map* current = map;
325+ auto first = current->find (key);
326+ if (first != current->end ()) {
327+ current = first->second ->isaMap ();
328+ if (!current) {
329+ return SASS_MEMORY_NEW (Boolean, pstate, false );
330+ }
331+ auto it = arguments[2 ]->iterator ();
332+ auto cur = it.begin (), end = it.end () - 1 ;
333+ Value* last = *end;
334+ while (cur != end) {
335+ auto inner = current->find (*cur);
336+ if (inner != current->end ()) {
337+ if (auto imap = inner->second ->isaMap ()) {
338+ current = imap;
339+ }
340+ else {
341+ return SASS_MEMORY_NEW (Boolean, pstate, false );
342+ }
343+ }
344+ else {
345+ return SASS_MEMORY_NEW (Boolean, pstate, false );
346+ }
347+ ++cur;
348+ }
349+
350+ // Still here, check now
351+ auto rv = current->find (last);
352+ return SASS_MEMORY_NEW (Boolean, pstate,
353+ rv != current->end ());
354+
355+ }
356+ else {
357+ return SASS_MEMORY_NEW (Boolean, pstate, false );
358+ }
359+
360+ }
361+ return SASS_MEMORY_NEW (Boolean, pstate, false );
161362 }
162363
163364 BUILT_IN_FN (fnDeepMerge)
@@ -211,16 +412,27 @@ namespace Sass {
211412 void registerFunctions (Compiler& ctx)
212413 {
213414 Module& module (ctx.createModule (" map" ));
214- // module.addFunction("get", ctx.registerBuiltInFunction("map-get", "$map, $key", set));
215- module .addFunction (" get" , ctx.registerBuiltInFunction (" map-get" , " $map, $key" , get));
216- module .addFunction (" merge" , ctx.registerBuiltInFunction (" map-merge" , " $map1, $map2" , merge));
415+
416+ module .addFunction (" set" , ctx.createBuiltInOverloadFns (" map-set" , {
417+ std::make_pair (" $map, $key, $value" , fnMapSetThreeArgs),
418+ std::make_pair (" $map, $args..." , fnMapSetTwoArgs)
419+ }));
420+
421+ module .addFunction (" get" , ctx.registerBuiltInFunction (" map-get" , " $map, $key, $keys..." , get));
422+
423+ module .addFunction (" merge" , ctx.registerBuiltInOverloadFns (" map-merge" , {
424+ std::make_pair (" $map1, $map2" , merge),
425+ std::make_pair (" $map1, $args..." , merge_many)
426+ }));
427+
217428 module .addFunction (" remove" , ctx.registerBuiltInOverloadFns (" map-remove" , {
218429 std::make_pair (" $map" , remove_one),
219430 std::make_pair (" $map, $key, $keys..." , remove_many)
220431 }));
432+
221433 module .addFunction (" keys" , ctx.registerBuiltInFunction (" map-keys" , " $map" , keys));
222434 module .addFunction (" values" , ctx.registerBuiltInFunction (" map-values" , " $map" , values));
223- module .addFunction (" has-key" , ctx.registerBuiltInFunction (" map-has-key" , " $map, $key" , hasKey));
435+ module .addFunction (" has-key" , ctx.registerBuiltInFunction (" map-has-key" , " $map, $key, $keys... " , hasKey));
224436
225437 module .addFunction (" deep-merge" , ctx.createBuiltInFunction (" deep-merge" , " $map1, $map2" , fnDeepMerge));
226438 module .addFunction (" deep-remove" , ctx.createBuiltInFunction (" deep-remove" , " $map, $key, $keys..." , fnDeepRemove));
0 commit comments