From 98e2821b38a775737e42a2479a6bc65107210859 Mon Sep 17 00:00:00 2001 From: Elliot Kroo Date: Thu, 11 Mar 2010 15:21:30 -0800 Subject: reorganizing the first level of folders (trunk/branch folders are not the git way :) --- .../org/mozilla/javascript/NativeGenerator.java | 281 +++++++++++++++++++++ 1 file changed, 281 insertions(+) create mode 100644 infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeGenerator.java (limited to 'infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeGenerator.java') diff --git a/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeGenerator.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeGenerator.java new file mode 100644 index 0000000..0a8da9f --- /dev/null +++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/NativeGenerator.java @@ -0,0 +1,281 @@ +/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * Contributor(s): + * Norris Boyd + * + * Alternatively, the contents of this file may be used under the terms of + * the GNU General Public License Version 2 or later (the "GPL"), in which + * case the provisions of the GPL are applicable instead of those above. If + * you wish to allow use of your version of this file only under the terms of + * the GPL and not to allow others to use your version of this file under the + * MPL, indicate your decision by deleting the provisions above and replacing + * them with the notice and other provisions required by the GPL. If you do + * not delete the provisions above, a recipient may use your version of this + * file under either the MPL or the GPL. + * + * ***** END LICENSE BLOCK ***** */ + +package org.mozilla.javascript; + +/** + * This class implements generator objects. See + * http://developer.mozilla.org/en/docs/New_in_JavaScript_1.7#Generators + * + * @author Norris Boyd + */ +public final class NativeGenerator extends IdScriptableObject { + private static final Object GENERATOR_TAG = new Object(); + + static NativeGenerator init(ScriptableObject scope, boolean sealed) { + // Generator + // Can't use "NativeGenerator().exportAsJSClass" since we don't want + // to define "Generator" as a constructor in the top-level scope. + + NativeGenerator prototype = new NativeGenerator(); + if (scope != null) { + prototype.setParentScope(scope); + prototype.setPrototype(getObjectPrototype(scope)); + } + prototype.activatePrototypeMap(MAX_PROTOTYPE_ID); + if (sealed) { + prototype.sealObject(); + } + + // Need to access Generator prototype when constructing + // Generator instances, but don't have a generator constructor + // to use to find the prototype. Use the "associateValue" + // approach instead. + if (scope != null) { + scope.associateValue(GENERATOR_TAG, prototype); + } + + return prototype; + } + + /** + * Only for constructing the prototype object. + */ + private NativeGenerator() { } + + public NativeGenerator(Scriptable scope, NativeFunction function, + Object savedState) + { + this.function = function; + this.savedState = savedState; + // Set parent and prototype properties. Since we don't have a + // "Generator" constructor in the top scope, we stash the + // prototype in the top scope's associated value. + Scriptable top = ScriptableObject.getTopLevelScope(scope); + this.setParentScope(top); + NativeGenerator prototype = (NativeGenerator) + ScriptableObject.getTopScopeValue(top, GENERATOR_TAG); + this.setPrototype(prototype); + } + + public static final int GENERATOR_SEND = 0, + GENERATOR_THROW = 1, + GENERATOR_CLOSE = 2; + + public String getClassName() { + return "Generator"; + } + + /** + * Close the generator if it is still open. + */ + public void finalize() throws Throwable { + if (savedState != null) { + // This is a little tricky since we are most likely running in + // a different thread. We need to get a Context to run this, and + // we must call "doTopCall" since this will likely be the outermost + // JavaScript frame on this thread. + Context cx = Context.getCurrentContext(); + ContextFactory factory = cx != null ? cx.getFactory() + : ContextFactory.getGlobal(); + Scriptable scope = ScriptableObject.getTopLevelScope(this); + factory.call(new CloseGeneratorAction(this)); + } + } + + private static class CloseGeneratorAction implements ContextAction { + private NativeGenerator generator; + + CloseGeneratorAction(NativeGenerator generator) { + this.generator = generator; + } + + public Object run(Context cx) { + Scriptable scope = ScriptableObject.getTopLevelScope(generator); + Callable closeGenerator = new Callable() { + public Object call(Context cx, Scriptable scope, + Scriptable thisObj, Object[] args) { + return ((NativeGenerator)thisObj).resume(cx, scope, + GENERATOR_CLOSE, new GeneratorClosedException()); + } + }; + return ScriptRuntime.doTopCall(closeGenerator, cx, scope, + generator, null); + } + } + + protected void initPrototypeId(int id) { + String s; + int arity; + switch (id) { + case Id_close: arity=1; s="close"; break; + case Id_next: arity=1; s="next"; break; + case Id_send: arity=0; s="send"; break; + case Id_throw: arity=0; s="throw"; break; + case Id___iterator__: arity=1; s="__iterator__"; break; + default: throw new IllegalArgumentException(String.valueOf(id)); + } + initPrototypeMethod(GENERATOR_TAG, id, s, arity); + } + + public Object execIdCall(IdFunctionObject f, Context cx, Scriptable scope, + Scriptable thisObj, Object[] args) + { + if (!f.hasTag(GENERATOR_TAG)) { + return super.execIdCall(f, cx, scope, thisObj, args); + } + int id = f.methodId(); + + if (!(thisObj instanceof NativeGenerator)) + throw incompatibleCallError(f); + + NativeGenerator generator = (NativeGenerator) thisObj; + + switch (id) { + + case Id_close: + // need to run any pending finally clauses + return generator.resume(cx, scope, GENERATOR_CLOSE, + new GeneratorClosedException()); + + case Id_next: + // arguments to next() are ignored + generator.firstTime = false; + return generator.resume(cx, scope, GENERATOR_SEND, + Undefined.instance); + + case Id_send: { + Object arg = args.length > 0 ? args[0] : Undefined.instance; + if (generator.firstTime && !arg.equals(Undefined.instance)) { + throw ScriptRuntime.typeError0("msg.send.newborn"); + } + return generator.resume(cx, scope, GENERATOR_SEND, arg); + } + + case Id_throw: + return generator.resume(cx, scope, GENERATOR_THROW, + args.length > 0 ? args[0] : Undefined.instance); + + case Id___iterator__: + return thisObj; + + default: + throw new IllegalArgumentException(String.valueOf(id)); + } + } + + private Object resume(Context cx, Scriptable scope, int operation, + Object value) + { + if (savedState == null) { + if (operation == GENERATOR_CLOSE) + return Undefined.instance; + Object thrown; + if (operation == GENERATOR_THROW) { + thrown = value; + } else { + thrown = NativeIterator.getStopIterationObject(scope); + } + throw new JavaScriptException(thrown, lineSource, lineNumber); + } + try { + synchronized (this) { + // generator execution is necessarily single-threaded and + // non-reentrant. + // See https://bugzilla.mozilla.org/show_bug.cgi?id=349263 + if (locked) + throw ScriptRuntime.typeError0("msg.already.exec.gen"); + locked = true; + } + return function.resumeGenerator(cx, scope, operation, savedState, + value); + } catch (GeneratorClosedException e) { + // On closing a generator in the compile path, the generator + // throws a special exception. This ensures execution of all pending + // finalizers and will not get caught by user code. + return Undefined.instance; + } catch (RhinoException e) { + lineNumber = e.lineNumber(); + lineSource = e.lineSource(); + savedState = null; + throw e; + } finally { + synchronized (this) { + locked = false; + } + if (operation == GENERATOR_CLOSE) + savedState = null; + } + } + +// #string_id_map# + + protected int findPrototypeId(String s) { + int id; +// #generated# Last update: 2007-06-14 13:13:03 EDT + L0: { id = 0; String X = null; int c; + int s_length = s.length(); + if (s_length==4) { + c=s.charAt(0); + if (c=='n') { X="next";id=Id_next; } + else if (c=='s') { X="send";id=Id_send; } + } + else if (s_length==5) { + c=s.charAt(0); + if (c=='c') { X="close";id=Id_close; } + else if (c=='t') { X="throw";id=Id_throw; } + } + else if (s_length==12) { X="__iterator__";id=Id___iterator__; } + if (X!=null && X!=s && !X.equals(s)) id = 0; + break L0; + } +// #/generated# + return id; + } + + private static final int + Id_close = 1, + Id_next = 2, + Id_send = 3, + Id_throw = 4, + Id___iterator__ = 5, + MAX_PROTOTYPE_ID = 5; + +// #/string_id_map# + private NativeFunction function; + private Object savedState; + private String lineSource; + private int lineNumber; + private boolean firstTime = true; + private boolean locked; + + public static class GeneratorClosedException extends RuntimeException { + } +} -- cgit v1.2.3