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) 2001-2004 Jan Arne Petersen <jpetersen@uni-bonn.de>
015: * Copyright (C) 2002 Benoit Cerrina <b.cerrina@wanadoo.fr>
016: * Copyright (C) 2002-2004 Anders Bengtsson <ndrsbngtssn@yahoo.se>
017: * Copyright (C) 2004-2007 Thomas E Enebo <enebo@acm.org>
018: * Copyright (C) 2006 Charles O Nutter <headius@headius.com>
019: * Copyright (C) 2006 Miguel Covarrubias <mlcovarrubias@gmail.com>
020: *
021: * Alternatively, the contents of this file may be used under the terms of
022: * either of the GNU General Public License Version 2 or later (the "GPL"),
023: * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
024: * in which case the provisions of the GPL or the LGPL are applicable instead
025: * of those above. If you wish to allow use of your version of this file only
026: * under the terms of either the GPL or the LGPL, and not to allow others to
027: * use your version of this file under the terms of the CPL, indicate your
028: * decision by deleting the provisions above and replace them with the notice
029: * and other provisions required by the GPL or the LGPL. If you do not delete
030: * the provisions above, a recipient may use your version of this file under
031: * the terms of any one of the CPL, the GPL or the LGPL.
032: ***** END LICENSE BLOCK *****/package org.jruby.runtime;
033:
034: import org.jruby.RubyModule;
035: import org.jruby.lexer.yacc.ISourcePosition;
036: import org.jruby.runtime.builtin.IRubyObject;
037:
038: /**
039: * <p>Frame for a full (read: not 'fast') Ruby method invocation. Any Ruby method which calls
040: * another Ruby method (or yields to a block) will get a Frame. A fast method by contrast does
041: * not get a Frame because we know that we will not be calling/yielding.</p>
042: *
043: * A Frame is also needed for a few special cases:
044: * <ul>
045: * <li>Proc.new must check previous frame to get the block it is getting constructed for
046: * <li>block_given? must check the previous frame to see if a block is active
047: * </li>
048: *
049: */
050: public final class Frame {
051: /**
052: * The class for the method we are invoking for this frame. Note: This may not be the
053: * class where the implementation of the method lives.
054: */
055: private RubyModule klazz;
056:
057: /**
058: * The 'self' for this frame.
059: */
060: private IRubyObject self;
061:
062: /**
063: * The name of the method being invoked in this frame. Note: Blocks are backed by frames
064: * and do not have a name.
065: */
066: private String name;
067:
068: /**
069: * The arguments passed into the method of this frame. The frame captures arguments
070: * so that they can be reused for things like super/zsuper.
071: */
072: private IRubyObject[] args;
073:
074: private int requiredArgCount;
075:
076: /**
077: * The block that was passed in for this frame (as either a block or a &block argument).
078: * The frame captures the block for super/zsuper, but also for Proc.new (with no arguments)
079: * and also for block_given?. Both of those methods needs access to the block of the
080: * previous frame to work.
081: */
082: private final Block block;
083:
084: /**
085: * Does this delimit a frame where an eval with binding occurred. Used for stack traces.
086: */
087: private boolean isBindingFrame = false;
088:
089: /**
090: * The current visibility for anything defined under this frame
091: */
092: private Visibility visibility = Visibility.PUBLIC;
093:
094: private Object jumpTarget;
095:
096: public Object getJumpTarget() {
097: return jumpTarget;
098: }
099:
100: public void setJumpTarget(Object jumpTarget) {
101: this .jumpTarget = jumpTarget;
102: }
103:
104: /**
105: * The location in source where this block/method invocation is happening
106: */
107: private final ISourcePosition position;
108:
109: public Frame(ISourcePosition position) {
110: this (null, null, null, IRubyObject.NULL_ARRAY, 0,
111: Block.NULL_BLOCK, position, null);
112: }
113:
114: public Frame(RubyModule klazz, IRubyObject self, String name,
115: IRubyObject[] args, int requiredArgCount, Block block,
116: ISourcePosition position, Object jumpTarget) {
117: assert block != null : "Block uses null object pattern. It should NEVER be null";
118:
119: this .self = self;
120: this .args = args;
121: this .requiredArgCount = requiredArgCount;
122: this .name = name;
123: this .klazz = klazz;
124: this .position = position;
125: this .block = block;
126: this .jumpTarget = jumpTarget;
127: }
128:
129: /** Getter for property args.
130: * @return Value of property args.
131: */
132: IRubyObject[] getArgs() {
133: return args;
134: }
135:
136: /** Setter for property args.
137: * @param args New value of property args.
138: */
139: void setArgs(IRubyObject[] args) {
140: this .args = args;
141: }
142:
143: public int getRequiredArgCount() {
144: return requiredArgCount;
145: }
146:
147: /**
148: * @return the frames current position
149: */
150: ISourcePosition getPosition() {
151: return position;
152: }
153:
154: /**
155: * Return class that we are supposedly calling for this invocation
156: *
157: * @return the current class
158: */
159: public RubyModule getKlazz() {
160: return klazz;
161: }
162:
163: /**
164: * Set class that this method is supposedly calling on. Note: This is different than
165: * a native method's implementation class.
166: *
167: * @param klazz the new class
168: */
169: public void setKlazz(RubyModule klazz) {
170: this .klazz = klazz;
171: }
172:
173: /**
174: * Set the method name associated with this frame
175: *
176: * @param name the new name
177: */
178: public void setName(String name) {
179: this .name = name;
180: }
181:
182: /**
183: * Get the method name associated with this frame
184: *
185: * @return the method name
186: */
187: String getName() {
188: return name;
189: }
190:
191: /**
192: * Get the self associated with this frame
193: *
194: * @return the self
195: */
196: IRubyObject getSelf() {
197: return self;
198: }
199:
200: /**
201: * Set the self associated with this frame
202: *
203: * @param self is the new value of self
204: */
205: void setSelf(IRubyObject self) {
206: this .self = self;
207: }
208:
209: /**
210: * Get the visibility at the time of this frame
211: *
212: * @return the visibility
213: */
214: public Visibility getVisibility() {
215: return visibility;
216: }
217:
218: /**
219: * Change the visibility associated with this frame
220: *
221: * @param visibility the new visibility
222: */
223: public void setVisibility(Visibility visibility) {
224: this .visibility = visibility;
225: }
226:
227: /**
228: * Is this frame the frame which started a binding eval?
229: *
230: * @return true if it is a binding frame
231: */
232: public boolean isBindingFrame() {
233: return isBindingFrame;
234: }
235:
236: /**
237: * Set whether this is a binding frame or not
238: *
239: * @param isBindingFrame true if it is
240: */
241: public void setIsBindingFrame(boolean isBindingFrame) {
242: this .isBindingFrame = isBindingFrame;
243: }
244:
245: /**
246: * What block is associated with this frame?
247: *
248: * @return the block of this frame or NULL_BLOCK if no block given
249: */
250: public Block getBlock() {
251: return block;
252: }
253:
254: public Frame duplicate() {
255: IRubyObject[] newArgs;
256: if (args.length != 0) {
257: newArgs = new IRubyObject[args.length];
258: System.arraycopy(args, 0, newArgs, 0, args.length);
259: } else {
260: newArgs = args;
261: }
262:
263: return new Frame(klazz, self, name, newArgs, requiredArgCount,
264: block, position, jumpTarget);
265: }
266:
267: /* (non-Javadoc)
268: * @see java.lang.Object#toString()
269: */
270: public String toString() {
271: StringBuffer sb = new StringBuffer(50);
272: sb.append(position != null ? position.toString() : "-1");
273: sb.append(':');
274: sb.append(klazz + " " + name);
275: if (name != null) {
276: sb.append("in ");
277: sb.append(name);
278: }
279: return sb.toString();
280: }
281: }
|