Browse Source

Unscopables

Dmitry Panov 5 years ago
parent
commit
f62cd66a92
3 changed files with 37 additions and 8 deletions
  1. 13 0
      builtin_arrray_test.go
  2. 1 0
      tc39_test.go
  3. 23 8
      vm.go

+ 13 - 0
builtin_arrray_test.go

@@ -206,3 +206,16 @@ func TestArrayOf(t *testing.T) {
 
 
 	testScript1(TESTLIB+SCRIPT, _undefined, t)
 	testScript1(TESTLIB+SCRIPT, _undefined, t)
 }
 }
+
+func TestUnscopables(t *testing.T) {
+	const SCRIPT = `
+	var keys = [];
+	var _length;
+	with (Array.prototype) {
+		_length = length;
+		keys.push('something');
+	}
+	_length === 0 && keys.length === 1 && keys[0] === "something";
+	`
+	testScript1(SCRIPT, valueTrue, t)
+}

+ 1 - 0
tc39_test.go

@@ -139,6 +139,7 @@ var (
 	es6WhiteList = map[string]bool{}
 	es6WhiteList = map[string]bool{}
 
 
 	es6IdWhiteList = []string{
 	es6IdWhiteList = []string{
+		"8.1.2.1",
 		"9.5",
 		"9.5",
 		"12.9.3",
 		"12.9.3",
 		"12.9.4",
 		"12.9.4",

+ 23 - 8
vm.go

@@ -200,9 +200,21 @@ func (s *valueStack) expand(idx int) {
 	}
 	}
 }
 }
 
 
+func stashObjHas(obj objectImpl, name string) bool {
+	if obj.hasPropertyStr(name) {
+		if unscopables, ok := obj.getSym(symUnscopables, nil).(*Object); ok {
+			if b := unscopables.self.getStr(name, nil); b != nil {
+				return !b.ToBoolean()
+			}
+		}
+		return true
+	}
+	return false
+}
+
 func (s *stash) put(name string, v Value) bool {
 func (s *stash) put(name string, v Value) bool {
 	if s.obj != nil {
 	if s.obj != nil {
-		if found := s.obj.getStr(name, nil); found != nil {
+		if stashObjHas(s.obj, name) {
 			s.obj.setOwnStr(name, v, false)
 			s.obj.setOwnStr(name, v, false)
 			return true
 			return true
 		}
 		}
@@ -234,7 +246,7 @@ func (s *stash) getByIdx(idx uint32) Value {
 
 
 func (s *stash) getByName(name string, _ *vm) (v Value, exists bool) {
 func (s *stash) getByName(name string, _ *vm) (v Value, exists bool) {
 	if s.obj != nil {
 	if s.obj != nil {
-		if s.obj.hasPropertyStr(name) {
+		if stashObjHas(s.obj, name) {
 			return nilSafe(s.obj.getStr(name, nil)), true
 			return nilSafe(s.obj.getStr(name, nil)), true
 		}
 		}
 		return nil, false
 		return nil, false
@@ -258,7 +270,10 @@ func (s *stash) createBinding(name string) {
 
 
 func (s *stash) deleteBinding(name string) bool {
 func (s *stash) deleteBinding(name string) bool {
 	if s.obj != nil {
 	if s.obj != nil {
-		return s.obj.deleteStr(name, false)
+		if stashObjHas(s.obj, name) {
+			return s.obj.deleteStr(name, false)
+		}
+		return false
 	}
 	}
 	if idx, found := s.names[name]; found {
 	if idx, found := s.names[name]; found {
 		s.values[idx] = nil
 		s.values[idx] = nil
@@ -1318,7 +1333,7 @@ func (s resolveVar1) exec(vm *vm) {
 	var ref ref
 	var ref ref
 	for stash := vm.stash; stash != nil; stash = stash.outer {
 	for stash := vm.stash; stash != nil; stash = stash.outer {
 		if stash.obj != nil {
 		if stash.obj != nil {
-			if stash.obj.hasPropertyStr(name) {
+			if stashObjHas(stash.obj, name) {
 				ref = &objRef{
 				ref = &objRef{
 					base: stash.obj,
 					base: stash.obj,
 					name: name,
 					name: name,
@@ -1352,7 +1367,7 @@ func (d deleteVar) exec(vm *vm) {
 	ret := true
 	ret := true
 	for stash := vm.stash; stash != nil; stash = stash.outer {
 	for stash := vm.stash; stash != nil; stash = stash.outer {
 		if stash.obj != nil {
 		if stash.obj != nil {
-			if stash.obj.hasPropertyStr(name) {
+			if stashObjHas(stash.obj, name) {
 				ret = stash.obj.deleteStr(name, false)
 				ret = stash.obj.deleteStr(name, false)
 				goto end
 				goto end
 			}
 			}
@@ -1402,7 +1417,7 @@ func (s resolveVar1Strict) exec(vm *vm) {
 	var ref ref
 	var ref ref
 	for stash := vm.stash; stash != nil; stash = stash.outer {
 	for stash := vm.stash; stash != nil; stash = stash.outer {
 		if stash.obj != nil {
 		if stash.obj != nil {
-			if stash.obj.hasPropertyStr(name) {
+			if stashObjHas(stash.obj, name) {
 				ref = &objRef{
 				ref = &objRef{
 					base:   stash.obj,
 					base:   stash.obj,
 					name:   name,
 					name:   name,
@@ -1524,8 +1539,8 @@ func (r resolveVar) exec(vm *vm) {
 	stash := vm.stash
 	stash := vm.stash
 	var ref ref
 	var ref ref
 	for i := 0; i < level; i++ {
 	for i := 0; i < level; i++ {
-		if stash.obj != nil {
-			if stash.obj.hasPropertyStr(r.name) {
+		if obj := stash.obj; obj != nil {
+			if stashObjHas(obj, r.name) {
 				ref = &objRef{
 				ref = &objRef{
 					base:   stash.obj,
 					base:   stash.obj,
 					name:   r.name,
 					name:   r.name,