1// Copyright 2012 the V8 project authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5"use strict"; 6 7// This file relies on the fact that the following declaration has been made 8// in runtime.js: 9// var $Array = global.Array; 10 11var $Set = global.Set; 12var $Map = global.Map; 13 14 15// ------------------------------------------------------------------- 16// Harmony Set 17 18function SetConstructor(iterable) { 19 if (!%_IsConstructCall()) { 20 throw MakeTypeError('constructor_not_function', ['Set']); 21 } 22 23 var iter, adder; 24 25 if (!IS_NULL_OR_UNDEFINED(iterable)) { 26 iter = GetIterator(ToObject(iterable)); 27 adder = this.add; 28 if (!IS_SPEC_FUNCTION(adder)) { 29 throw MakeTypeError('property_not_function', ['add', this]); 30 } 31 } 32 33 %SetInitialize(this); 34 35 if (IS_UNDEFINED(iter)) return; 36 37 var next, done; 38 while (!(next = iter.next()).done) { 39 if (!IS_SPEC_OBJECT(next)) { 40 throw MakeTypeError('iterator_result_not_an_object', [next]); 41 } 42 %_CallFunction(this, next.value, adder); 43 } 44} 45 46 47function SetAddJS(key) { 48 if (!IS_SET(this)) { 49 throw MakeTypeError('incompatible_method_receiver', 50 ['Set.prototype.add', this]); 51 } 52 // Normalize -0 to +0 as required by the spec. 53 // Even though we use SameValueZero as the comparison for the keys we don't 54 // want to ever store -0 as the key since the key is directly exposed when 55 // doing iteration. 56 if (key === 0) { 57 key = 0; 58 } 59 return %SetAdd(this, key); 60} 61 62 63function SetHasJS(key) { 64 if (!IS_SET(this)) { 65 throw MakeTypeError('incompatible_method_receiver', 66 ['Set.prototype.has', this]); 67 } 68 return %SetHas(this, key); 69} 70 71 72function SetDeleteJS(key) { 73 if (!IS_SET(this)) { 74 throw MakeTypeError('incompatible_method_receiver', 75 ['Set.prototype.delete', this]); 76 } 77 return %SetDelete(this, key); 78} 79 80 81function SetGetSizeJS() { 82 if (!IS_SET(this)) { 83 throw MakeTypeError('incompatible_method_receiver', 84 ['Set.prototype.size', this]); 85 } 86 return %SetGetSize(this); 87} 88 89 90function SetClearJS() { 91 if (!IS_SET(this)) { 92 throw MakeTypeError('incompatible_method_receiver', 93 ['Set.prototype.clear', this]); 94 } 95 %SetClear(this); 96} 97 98 99function SetForEach(f, receiver) { 100 if (!IS_SET(this)) { 101 throw MakeTypeError('incompatible_method_receiver', 102 ['Set.prototype.forEach', this]); 103 } 104 105 if (!IS_SPEC_FUNCTION(f)) { 106 throw MakeTypeError('called_non_callable', [f]); 107 } 108 109 var iterator = new SetIterator(this, ITERATOR_KIND_VALUES); 110 var key; 111 var stepping = DEBUG_IS_ACTIVE && %DebugCallbackSupportsStepping(f); 112 var value_array = [UNDEFINED]; 113 while (%SetIteratorNext(iterator, value_array)) { 114 if (stepping) %DebugPrepareStepInIfStepping(f); 115 key = value_array[0]; 116 %_CallFunction(receiver, key, key, this, f); 117 } 118} 119 120 121// ------------------------------------------------------------------- 122 123function SetUpSet() { 124 %CheckIsBootstrapping(); 125 126 %SetCode($Set, SetConstructor); 127 %FunctionSetPrototype($Set, new $Object()); 128 %AddNamedProperty($Set.prototype, "constructor", $Set, DONT_ENUM); 129 130 %FunctionSetLength(SetForEach, 1); 131 132 // Set up the non-enumerable functions on the Set prototype object. 133 InstallGetter($Set.prototype, "size", SetGetSizeJS); 134 InstallFunctions($Set.prototype, DONT_ENUM, $Array( 135 "add", SetAddJS, 136 "has", SetHasJS, 137 "delete", SetDeleteJS, 138 "clear", SetClearJS, 139 "forEach", SetForEach 140 )); 141} 142 143SetUpSet(); 144 145 146// ------------------------------------------------------------------- 147// Harmony Map 148 149function MapConstructor(iterable) { 150 if (!%_IsConstructCall()) { 151 throw MakeTypeError('constructor_not_function', ['Map']); 152 } 153 154 var iter, adder; 155 156 if (!IS_NULL_OR_UNDEFINED(iterable)) { 157 iter = GetIterator(ToObject(iterable)); 158 adder = this.set; 159 if (!IS_SPEC_FUNCTION(adder)) { 160 throw MakeTypeError('property_not_function', ['set', this]); 161 } 162 } 163 164 %MapInitialize(this); 165 166 if (IS_UNDEFINED(iter)) return; 167 168 var next, done, nextItem; 169 while (!(next = iter.next()).done) { 170 if (!IS_SPEC_OBJECT(next)) { 171 throw MakeTypeError('iterator_result_not_an_object', [next]); 172 } 173 nextItem = next.value; 174 if (!IS_SPEC_OBJECT(nextItem)) { 175 throw MakeTypeError('iterator_value_not_an_object', [nextItem]); 176 } 177 %_CallFunction(this, nextItem[0], nextItem[1], adder); 178 } 179} 180 181 182function MapGetJS(key) { 183 if (!IS_MAP(this)) { 184 throw MakeTypeError('incompatible_method_receiver', 185 ['Map.prototype.get', this]); 186 } 187 return %MapGet(this, key); 188} 189 190 191function MapSetJS(key, value) { 192 if (!IS_MAP(this)) { 193 throw MakeTypeError('incompatible_method_receiver', 194 ['Map.prototype.set', this]); 195 } 196 // Normalize -0 to +0 as required by the spec. 197 // Even though we use SameValueZero as the comparison for the keys we don't 198 // want to ever store -0 as the key since the key is directly exposed when 199 // doing iteration. 200 if (key === 0) { 201 key = 0; 202 } 203 return %MapSet(this, key, value); 204} 205 206 207function MapHasJS(key) { 208 if (!IS_MAP(this)) { 209 throw MakeTypeError('incompatible_method_receiver', 210 ['Map.prototype.has', this]); 211 } 212 return %MapHas(this, key); 213} 214 215 216function MapDeleteJS(key) { 217 if (!IS_MAP(this)) { 218 throw MakeTypeError('incompatible_method_receiver', 219 ['Map.prototype.delete', this]); 220 } 221 return %MapDelete(this, key); 222} 223 224 225function MapGetSizeJS() { 226 if (!IS_MAP(this)) { 227 throw MakeTypeError('incompatible_method_receiver', 228 ['Map.prototype.size', this]); 229 } 230 return %MapGetSize(this); 231} 232 233 234function MapClearJS() { 235 if (!IS_MAP(this)) { 236 throw MakeTypeError('incompatible_method_receiver', 237 ['Map.prototype.clear', this]); 238 } 239 %MapClear(this); 240} 241 242 243function MapForEach(f, receiver) { 244 if (!IS_MAP(this)) { 245 throw MakeTypeError('incompatible_method_receiver', 246 ['Map.prototype.forEach', this]); 247 } 248 249 if (!IS_SPEC_FUNCTION(f)) { 250 throw MakeTypeError('called_non_callable', [f]); 251 } 252 253 var iterator = new MapIterator(this, ITERATOR_KIND_ENTRIES); 254 var stepping = DEBUG_IS_ACTIVE && %DebugCallbackSupportsStepping(f); 255 var value_array = [UNDEFINED, UNDEFINED]; 256 while (%MapIteratorNext(iterator, value_array)) { 257 if (stepping) %DebugPrepareStepInIfStepping(f); 258 %_CallFunction(receiver, value_array[1], value_array[0], this, f); 259 } 260} 261 262 263// ------------------------------------------------------------------- 264 265function SetUpMap() { 266 %CheckIsBootstrapping(); 267 268 %SetCode($Map, MapConstructor); 269 %FunctionSetPrototype($Map, new $Object()); 270 %AddNamedProperty($Map.prototype, "constructor", $Map, DONT_ENUM); 271 272 %FunctionSetLength(MapForEach, 1); 273 274 // Set up the non-enumerable functions on the Map prototype object. 275 InstallGetter($Map.prototype, "size", MapGetSizeJS); 276 InstallFunctions($Map.prototype, DONT_ENUM, $Array( 277 "get", MapGetJS, 278 "set", MapSetJS, 279 "has", MapHasJS, 280 "delete", MapDeleteJS, 281 "clear", MapClearJS, 282 "forEach", MapForEach 283 )); 284} 285 286SetUpMap(); 287