This repository was archived by the owner on Apr 10, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 13
Expand file tree
/
Copy pathIdEnumeration.cs
More file actions
144 lines (130 loc) · 4.56 KB
/
Copy pathIdEnumeration.cs
File metadata and controls
144 lines (130 loc) · 4.56 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
//------------------------------------------------------------------------------
// <license file="IdEnumeration.cs">
//
// The use and distribution terms for this software are contained in the file
// named 'LICENSE', which can be found in the resources directory of this
// distribution.
//
// By using this software in any fashion, you are agreeing to be bound by the
// terms of this license.
//
// </license>
//------------------------------------------------------------------------------
using System;
using EcmaScript.NET.Collections;
namespace EcmaScript.NET
{
/// <summary>
/// This is the enumeration needed by the for..in statement.
///
/// See ECMA 12.6.3.
///
/// IdEnumeration maintains a ObjToIntMap to make sure a given
/// id is enumerated only once across multiple objects in a
/// prototype chain.
///
/// ECMA delete doesn't hide properties in the prototype,
/// but js/ref does. This means that the js/ref for..in can
/// avoid maintaining a hash table and instead perform lookups
/// to see if a given property has already been enumerated.
///
/// </summary>
public class IdEnumeration
{
protected IdEnumeration ()
{
;
}
public IdEnumeration (object value, Context cx, bool enumValues)
{
obj = ScriptConvert.ToObjectOrNull (cx, value);
if (obj != null) {
// null or undefined do not cause errors but rather lead to empty
// "for in" loop
this.enumValues = enumValues;
// enumInit should read all initial ids before returning
// or "for (a.i in a)" would wrongly enumerate i in a as well
ChangeObject ();
}
}
private IScriptable obj;
private object [] ids;
private int index;
private ObjToIntMap used;
private string currentId;
private bool enumValues;
public virtual bool MoveNext ()
{
// OPT this could be more efficient
bool result;
for (; ; ) {
if (obj == null) {
result = false;
break;
}
if (index == ids.Length) {
obj = obj.GetPrototype ();
this.ChangeObject ();
continue;
}
object id = ids [index++];
if (used != null && used.has (id)) {
continue;
}
if (id is string) {
string strId = (string)id;
if (!obj.Has (strId, obj))
continue; // must have been deleted
currentId = strId;
}
else {
int intId = Convert.ToInt32 (id);
if (!obj.Has (intId, obj))
continue; // must have been deleted
currentId = Convert.ToString (intId);
}
result = true;
break;
}
return result;
}
public virtual object Current (Context cx)
{
if (!enumValues)
return currentId;
object result;
string s = ScriptRuntime.ToStringIdOrIndex (cx, currentId);
if (s == null) {
int index = ScriptRuntime.lastIndexResult (cx);
result = obj.Get (index, obj);
}
else {
result = obj.Get (s, obj);
}
return result;
}
private void ChangeObject ()
{
object [] ids = null;
while (obj != null) {
ids = obj.GetIds ();
if (ids.Length != 0) {
break;
}
obj = obj.GetPrototype ();
}
if (obj != null && this.ids != null) {
object [] previous = this.ids;
int L = previous.Length;
if (used == null) {
used = new ObjToIntMap (L);
}
for (int i = 0; i != L; ++i) {
used.intern (previous [i]);
}
}
this.ids = ids;
this.index = 0;
}
}
}