001: /***** BEGIN LICENSE BLOCK *****
002: * Version: CPL 1.0/GPL 2.0/LGPL 2.1
003: *
004: * The contents of this file are subject to the Common Public
005: * License Version 1.0 (the "License"); you may not use this file
006: * except in compliance with the License. You may obtain a copy of
007: * the License at http://www.eclipse.org/legal/cpl-v10.html
008: *
009: * Software distributed under the License is distributed on an "AS
010: * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
011: * implied. See the License for the specific language governing
012: * rights and limitations under the License.
013: *
014: * Copyright (C) 2002-2004 Anders Bengtsson <ndrsbngtssn@yahoo.se>
015: * Copyright (C) 2001-2004 Jan Arne Petersen <jpetersen@uni-bonn.de>
016: * Copyright (C) 2002 Benoit Cerrina <b.cerrina@wanadoo.fr>
017: * Copyright (C) 2004-2007 Thomas E Enebo <enebo@acm.org>
018: * Copyright (C) 2004 Stefan Matthias Aust <sma@3plus4.de>
019: *
020: * Alternatively, the contents of this file may be used under the terms of
021: * either of the GNU General Public License Version 2 or later (the "GPL"),
022: * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
023: * in which case the provisions of the GPL or the LGPL are applicable instead
024: * of those above. If you wish to allow use of your version of this file only
025: * under the terms of either the GPL or the LGPL, and not to allow others to
026: * use your version of this file under the terms of the CPL, indicate your
027: * decision by deleting the provisions above and replace them with the notice
028: * and other provisions required by the GPL or the LGPL. If you do not delete
029: * the provisions above, a recipient may use your version of this file under
030: * the terms of any one of the CPL, the GPL or the LGPL.
031: ***** END LICENSE BLOCK *****/package org.jruby.runtime;
032:
033: import org.jruby.Ruby;
034: import org.jruby.RubyArray;
035: import org.jruby.RubyModule;
036: import org.jruby.RubyProc;
037: import org.jruby.ast.IterNode;
038: import org.jruby.ast.MultipleAsgnNode;
039: import org.jruby.ast.Node;
040: import org.jruby.ast.NodeTypes;
041: import org.jruby.ast.util.ArgsUtil;
042: import org.jruby.evaluator.AssignmentVisitor;
043: import org.jruby.evaluator.EvaluationState;
044: import org.jruby.exceptions.JumpException;
045: import org.jruby.parser.BlockStaticScope;
046: import org.jruby.runtime.builtin.IRubyObject;
047: import org.jruby.util.collections.SinglyLinkedList;
048:
049: /**
050: * Internal live representation of a block ({...} or do ... end).
051: */
052: public class Block {
053: /**
054: * All Block variables should either refer to a real block or this NULL_BLOCK.
055: */
056: public static final Block NULL_BLOCK = new Block() {
057: public boolean isGiven() {
058: return false;
059: }
060:
061: public IRubyObject yield(ThreadContext context,
062: IRubyObject value, IRubyObject self, RubyModule klass,
063: boolean aValue) {
064: throw context.getRuntime().newLocalJumpError("noreason",
065: (IRubyObject) value, "yield called out of block");
066: }
067:
068: public Block cloneBlock() {
069: return this ;
070: }
071: };
072:
073: /**
074: * 'self' at point when the block is defined
075: */
076: protected IRubyObject self;
077:
078: /**
079: * AST Node representing the parameter (VARiable) list to the block.
080: */
081: private IterNode iterNode;
082:
083: /**
084: * frame of method which defined this block
085: */
086: protected Frame frame;
087: protected SinglyLinkedList cref;
088: protected Visibility visibility;
089: protected RubyModule klass;
090:
091: /**
092: * A reference to all variable values (and names) that are in-scope for this block.
093: */
094: protected DynamicScope dynamicScope;
095:
096: /**
097: * The Proc that this block is associated with. When we reference blocks via variable
098: * reference they are converted to Proc objects. We store a reference of the associated
099: * Proc object for easy conversion.
100: */
101: private RubyProc proc = null;
102:
103: public boolean isLambda = false;
104:
105: protected Arity arity;
106:
107: public static Block createBlock(ThreadContext context,
108: IterNode iterNode, DynamicScope dynamicScope,
109: IRubyObject self) {
110: return new Block(iterNode, self, context.getCurrentFrame(),
111: context.peekCRef(), context.getCurrentFrame()
112: .getVisibility(), context.getRubyClass(),
113: dynamicScope);
114: }
115:
116: protected Block() {
117: this (null, null, null, null, null, null, null);
118: }
119:
120: public Block(IterNode iterNode, IRubyObject self, Frame frame,
121: SinglyLinkedList cref, Visibility visibility,
122: RubyModule klass, DynamicScope dynamicScope) {
123:
124: //assert method != null;
125:
126: this .iterNode = iterNode;
127: this .self = self;
128: this .frame = frame;
129: this .visibility = visibility;
130: this .klass = klass;
131: this .cref = cref;
132: this .dynamicScope = dynamicScope;
133: this .arity = iterNode == null ? null : Arity
134: .procArityOf(iterNode.getVarNode());
135: }
136:
137: public static Block createBinding(Frame frame,
138: DynamicScope dynamicScope) {
139: ThreadContext context = frame.getSelf().getRuntime()
140: .getCurrentContext();
141:
142: // We create one extra dynamicScope on a binding so that when we 'eval "b=1", binding' the
143: // 'b' will get put into this new dynamic scope. The original scope does not see the new
144: // 'b' and successive evals with this binding will. I take it having the ability to have
145: // succesive binding evals be able to share same scope makes sense from a programmers
146: // perspective. One crappy outcome of this design is it requires Dynamic and Static
147: // scopes to be mutable for this one case.
148:
149: // Note: In Ruby 1.9 all of this logic can go away since they will require explicit
150: // bindings for evals.
151:
152: // We only define one special dynamic scope per 'logical' binding. So all bindings for
153: // the same scope should share the same dynamic scope. This allows multiple evals with
154: // different different bindings in the same scope to see the same stuff.
155: DynamicScope extraScope = dynamicScope.getBindingScope();
156:
157: // No binding scope so we should create one
158: if (extraScope == null) {
159: // If the next scope out has the same binding scope as this scope it means
160: // we are evaling within an eval and in that case we should be sharing the same
161: // binding scope.
162: DynamicScope parent = dynamicScope.getNextCapturedScope();
163: if (parent != null
164: && parent.getBindingScope() == dynamicScope) {
165: extraScope = dynamicScope;
166: } else {
167: extraScope = new DynamicScope(new BlockStaticScope(
168: dynamicScope.getStaticScope()), dynamicScope);
169: dynamicScope.setBindingScope(extraScope);
170: }
171: }
172:
173: // FIXME: Ruby also saves wrapper, which we do not
174: return new Block(null, frame.getSelf(), frame, context
175: .peekCRef(), frame.getVisibility(), context
176: .getBindingRubyClass(), extraScope);
177: }
178:
179: public IRubyObject call(ThreadContext context, IRubyObject[] args) {
180: return yield(context,
181: context.getRuntime().newArrayNoCopy(args), null, null,
182: true);
183: }
184:
185: protected void pre(ThreadContext context, RubyModule klass) {
186: context.preYieldSpecificBlock(this , klass);
187: }
188:
189: protected void post(ThreadContext context) {
190: context.postYield();
191: }
192:
193: public IRubyObject yield(ThreadContext context, IRubyObject value) {
194: return yield(context, value, null, null, false);
195: }
196:
197: /**
198: * Yield to this block, usually passed to the current call.
199: *
200: * @param context represents the current thread-specific data
201: * @param value The value to yield, either a single value or an array of values
202: * @param self The current self
203: * @param klass
204: * @param aValue Should value be arrayified or not?
205: * @return
206: */
207: public IRubyObject yield(ThreadContext context, IRubyObject value,
208: IRubyObject self, RubyModule klass, boolean aValue) {
209: if (klass == null) {
210: self = this .self;
211: frame.setSelf(self);
212: }
213:
214: pre(context, klass);
215:
216: try {
217: if (iterNode.getVarNode() != null) {
218: if (aValue) {
219: setupBlockArgs(context, iterNode.getVarNode(),
220: value, self);
221: } else {
222: setupBlockArg(context, iterNode.getVarNode(),
223: value, self);
224: }
225: }
226:
227: // This while loop is for restarting the block call in case a 'redo' fires.
228: while (true) {
229: try {
230: return EvaluationState.eval(context.getRuntime(),
231: context, iterNode.getBodyNode(), self,
232: NULL_BLOCK);
233: } catch (JumpException je) {
234: if (je.getJumpType() == JumpException.JumpType.RedoJump) {
235: context.pollThreadEvents();
236: // do nothing, allow loop to redo
237: } else {
238: if (je.getJumpType() == JumpException.JumpType.BreakJump
239: && je.getTarget() == null) {
240: je.setTarget(this );
241: }
242: throw je;
243: }
244: }
245: }
246:
247: } catch (JumpException je) {
248: // A 'next' is like a local return from the block, ending this call or yield.
249: if (je.getJumpType() == JumpException.JumpType.NextJump)
250: return (IRubyObject) je.getValue();
251:
252: throw je;
253: } finally {
254: post(context);
255: }
256: }
257:
258: private void setupBlockArgs(ThreadContext context, Node varNode,
259: IRubyObject value, IRubyObject self) {
260: Ruby runtime = self.getRuntime();
261:
262: switch (varNode.nodeId) {
263: case NodeTypes.ZEROARGNODE:
264: break;
265: case NodeTypes.MULTIPLEASGNNODE:
266: value = AssignmentVisitor.multiAssign(runtime, context,
267: self, (MultipleAsgnNode) varNode,
268: (RubyArray) value, false);
269: break;
270: default:
271: int length = arrayLength(value);
272: switch (length) {
273: case 0:
274: value = runtime.getNil();
275: break;
276: case 1:
277: value = ((RubyArray) value).eltInternal(0);
278: break;
279: default:
280: runtime.getWarnings().warn(
281: "multiple values for a block parameter ("
282: + length + " for 1)");
283: }
284: AssignmentVisitor.assign(runtime, context, self, varNode,
285: value, Block.NULL_BLOCK, false);
286: }
287: }
288:
289: private void setupBlockArg(ThreadContext context, Node varNode,
290: IRubyObject value, IRubyObject self) {
291: Ruby runtime = self.getRuntime();
292:
293: switch (varNode.nodeId) {
294: case NodeTypes.ZEROARGNODE:
295: return;
296: case NodeTypes.MULTIPLEASGNNODE:
297: value = AssignmentVisitor.multiAssign(runtime, context,
298: self, (MultipleAsgnNode) varNode, ArgsUtil
299: .convertToRubyArray(runtime, value,
300: ((MultipleAsgnNode) varNode)
301: .getHeadNode() != null),
302: false);
303: break;
304: default:
305: if (value == null) {
306: runtime
307: .getWarnings()
308: .warn(
309: "multiple values for a block parameter (0 for 1)");
310: }
311: AssignmentVisitor.assign(runtime, context, self, varNode,
312: value, Block.NULL_BLOCK, false);
313: }
314: }
315:
316: private int arrayLength(IRubyObject node) {
317: return node instanceof RubyArray ? ((RubyArray) node)
318: .getLength() : 0;
319: }
320:
321: public Block cloneBlock() {
322: // We clone dynamic scope because this will be a new instance of a block. Any previously
323: // captured instances of this block may still be around and we do not want to start
324: // overwriting those values when we create a new one.
325: // ENEBO: Once we make self, lastClass, and lastMethod immutable we can remove duplicate
326: Block newBlock = new Block(iterNode, self, frame.duplicate(),
327: cref, visibility, klass, dynamicScope.cloneScope());
328:
329: newBlock.isLambda = isLambda;
330:
331: return newBlock;
332: }
333:
334: /**
335: * What is the arity of this block?
336: *
337: * @return the arity
338: */
339: public Arity arity() {
340: return arity;
341: }
342:
343: public Visibility getVisibility() {
344: return visibility;
345: }
346:
347: public void setVisibility(Visibility visibility) {
348: this .visibility = visibility;
349: }
350:
351: public void setSelf(IRubyObject self) {
352: this .self = self;
353: }
354:
355: public SinglyLinkedList getCRef() {
356: return cref;
357: }
358:
359: /**
360: * Retrieve the proc object associated with this block
361: *
362: * @return the proc or null if this has no proc associated with it
363: */
364: public RubyProc getProcObject() {
365: return proc;
366: }
367:
368: /**
369: * Set the proc object associated with this block
370: *
371: * @param procObject
372: */
373: public void setProcObject(RubyProc procObject) {
374: this .proc = procObject;
375: }
376:
377: /**
378: * Gets the dynamicVariables that are local to this block. Parent dynamic scopes are also
379: * accessible via the current dynamic scope.
380: *
381: * @return Returns all relevent variable scoping information
382: */
383: public DynamicScope getDynamicScope() {
384: return dynamicScope;
385: }
386:
387: /**
388: * Gets the frame.
389: *
390: * @return Returns a RubyFrame
391: */
392: public Frame getFrame() {
393: return frame;
394: }
395:
396: /**
397: * Gets the klass.
398: * @return Returns a RubyModule
399: */
400: public RubyModule getKlass() {
401: return klass;
402: }
403:
404: /**
405: * Is the current block a real yield'able block instead a null one
406: *
407: * @return true if this is a valid block or false otherwise
408: */
409: public boolean isGiven() {
410: return true;
411: }
412: }
|