org.mozilla.javascript.ES6Iterator Maven / Gradle / Ivy
The newest version!
/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mozilla.javascript;
public abstract class ES6Iterator extends IdScriptableObject {
static void init(ScriptableObject scope, boolean sealed, IdScriptableObject prototype, String tag) {
if (scope != null) {
prototype.setParentScope(scope);
prototype.setPrototype(getObjectPrototype(scope));
}
prototype.activatePrototypeMap(MAX_PROTOTYPE_ID);
if (sealed) {
prototype.sealObject();
}
// Need to access Iterator prototype when constructing
// Iterator instances, but don't have a iterator constructor
// to use to find the prototype. Use the "associateValue"
// approach instead.
if (scope != null) {
scope.associateValue(tag, prototype);
}
}
protected boolean exhausted = false;
ES6Iterator() {}
ES6Iterator(Scriptable scope) {
// Set parent and prototype properties. Since we don't have a
// "Iterator" constructor in the top scope, we stash the
// prototype in the top scope's associated value.
Scriptable top = ScriptableObject.getTopLevelScope(scope);
this.setParentScope(top);
IdScriptableObject prototype = (IdScriptableObject)
ScriptableObject.getTopScopeValue(top, getTag());
setPrototype(prototype);
}
@Override
protected void initPrototypeId(int id)
{
switch (id) {
case Id_next:
initPrototypeMethod(getTag(), id, NEXT_METHOD, 0);
return;
case Id_iterator:
initPrototypeMethod(getTag(), id, SymbolKey.ITERATOR, "[Symbol.iterator]", 0);
return;
case Id_toStringTag:
initPrototypeValue(Id_toStringTag, SymbolKey.TO_STRING_TAG, getClassName(), DONTENUM | READONLY);
return;
default: throw new IllegalArgumentException(String.valueOf(id));
}
}
@Override
public Object execIdCall(IdFunctionObject f, Context cx, Scriptable scope,
Scriptable thisObj, Object[] args)
{
if (!f.hasTag(getTag())) {
return super.execIdCall(f, cx, scope, thisObj, args);
}
int id = f.methodId();
if (!(thisObj instanceof ES6Iterator))
throw incompatibleCallError(f);
ES6Iterator iterator = (ES6Iterator) thisObj;
switch (id) {
case Id_next:
return iterator.next(cx, scope);
case Id_iterator:
return iterator;
default:
throw new IllegalArgumentException(String.valueOf(id));
}
}
@Override
protected int findPrototypeId(Symbol k) {
if (SymbolKey.ITERATOR.equals(k)) {
return Id_iterator;
} else if (SymbolKey.TO_STRING_TAG.equals(k)) {
return Id_toStringTag;
}
return 0;
}
@Override
protected int findPrototypeId(String s) {
if ("next".equals(s)) {
return Id_next;
}
return 0;
}
abstract protected boolean isDone(Context cx, Scriptable scope);
abstract protected Object nextValue(Context cx, Scriptable scope);
protected Object next(Context cx, Scriptable scope) {
Object value = Undefined.instance;
boolean done = isDone(cx, scope) || this.exhausted;
if (!done) {
value = nextValue(cx, scope);
} else {
this.exhausted = true;
}
return makeIteratorResult(cx, scope, done, value);
}
abstract protected String getTag();
// 25.1.1.3 The IteratorResult Interface
private Scriptable makeIteratorResult(Context cx, Scriptable scope, boolean done, Object value) {
Scriptable iteratorResult = cx.newObject(scope);
ScriptableObject.putProperty(iteratorResult, VALUE_PROPERTY, value);
ScriptableObject.putProperty(iteratorResult, DONE_PROPERTY, done);
return iteratorResult;
}
private static final int
Id_next = 1,
Id_iterator = 2,
Id_toStringTag = 3,
MAX_PROTOTYPE_ID = Id_toStringTag;
public static final String NEXT_METHOD = "next";
public static final String DONE_PROPERTY = "done";
public static final String VALUE_PROPERTY = "value";
}