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) 2002-2004 Jan Arne Petersen <jpetersen@uni-bonn.de>
016: * Copyright (C) 2003-2004 Thomas E Enebo <enebo@acm.org>
017: *
018: * Alternatively, the contents of this file may be used under the terms of
019: * either of the GNU General Public License Version 2 or later (the "GPL"),
020: * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
021: * in which case the provisions of the GPL or the LGPL are applicable instead
022: * of those above. If you wish to allow use of your version of this file only
023: * under the terms of either the GPL or the LGPL, and not to allow others to
024: * use your version of this file under the terms of the CPL, indicate your
025: * decision by deleting the provisions above and replace them with the notice
026: * and other provisions required by the GPL or the LGPL. If you do not delete
027: * the provisions above, a recipient may use your version of this file under
028: * the terms of any one of the CPL, the GPL or the LGPL.
029: ***** END LICENSE BLOCK *****/package org.jruby.evaluator;
030:
031: import org.jruby.Ruby;
032: import org.jruby.RubyArray;
033: import org.jruby.RubyModule;
034: import org.jruby.ast.AttrAssignNode;
035: import org.jruby.ast.CallNode;
036: import org.jruby.ast.ClassVarAsgnNode;
037: import org.jruby.ast.ClassVarDeclNode;
038: import org.jruby.ast.Colon2Node;
039: import org.jruby.ast.ConstDeclNode;
040: import org.jruby.ast.DAsgnNode;
041: import org.jruby.ast.GlobalAsgnNode;
042: import org.jruby.ast.InstAsgnNode;
043: import org.jruby.ast.LocalAsgnNode;
044: import org.jruby.ast.MultipleAsgnNode;
045: import org.jruby.ast.Node;
046: import org.jruby.ast.NodeTypes;
047: import org.jruby.ast.StarNode;
048: import org.jruby.runtime.Block;
049: import org.jruby.runtime.CallType;
050: import org.jruby.runtime.ThreadContext;
051: import org.jruby.runtime.builtin.IRubyObject;
052:
053: /**
054: *
055: * @author jpetersen
056: */
057: public class AssignmentVisitor {
058: public static IRubyObject assign(Ruby runtime,
059: ThreadContext context, IRubyObject self, Node node,
060: IRubyObject value, Block block, boolean check) {
061: IRubyObject result = null;
062:
063: switch (node.nodeId) {
064: case NodeTypes.ATTRASSIGNNODE:
065: attrAssignNode(runtime, context, self, node, value, block);
066: break;
067: case NodeTypes.CALLNODE:
068: callNode(runtime, context, self, node, value, block);
069: break;
070: case NodeTypes.CLASSVARASGNNODE:
071: classVarAsgnNode(context, node, value);
072: break;
073: case NodeTypes.CLASSVARDECLNODE:
074: classVarDeclNode(runtime, context, node, value);
075: break;
076: case NodeTypes.CONSTDECLNODE:
077: constDeclNode(runtime, context, self, node, value, block);
078: break;
079: case NodeTypes.DASGNNODE:
080: dasgnNode(context, node, value);
081: break;
082: case NodeTypes.GLOBALASGNNODE:
083: globalAsgnNode(runtime, node, value);
084: break;
085: case NodeTypes.INSTASGNNODE:
086: instAsgnNode(self, node, value);
087: break;
088: case NodeTypes.LOCALASGNNODE:
089: localAsgnNode(context, node, value);
090: break;
091: case NodeTypes.MULTIPLEASGNNODE:
092: result = multipleAsgnNode(runtime, context, self, node,
093: value, check);
094: break;
095: default:
096: throw new RuntimeException(
097: "Invalid node encountered in interpreter: \""
098: + node.getClass().getName()
099: + "\", please report this at www.jruby.org");
100: }
101:
102: return result;
103: }
104:
105: private static void attrAssignNode(Ruby runtime,
106: ThreadContext context, IRubyObject self, Node node,
107: IRubyObject value, Block block) {
108: AttrAssignNode iVisited = (AttrAssignNode) node;
109:
110: IRubyObject receiver = EvaluationState.eval(runtime, context,
111: iVisited.getReceiverNode(), self, block);
112:
113: // If reciever is self then we do the call the same way as vcall
114: CallType callType = (receiver == self ? CallType.VARIABLE
115: : CallType.NORMAL);
116:
117: if (iVisited.getArgsNode() == null) { // attribute set.
118: receiver.callMethod(context, iVisited.getName(),
119: new IRubyObject[] { value }, callType);
120: } else { // element set
121: RubyArray args = (RubyArray) EvaluationState.eval(runtime,
122: context, iVisited.getArgsNode(), self, block);
123: args.append(value);
124: receiver.callMethod(context, iVisited.getName(), args
125: .toJavaArray(), callType);
126: }
127: }
128:
129: private static void callNode(Ruby runtime, ThreadContext context,
130: IRubyObject self, Node node, IRubyObject value, Block block) {
131: CallNode iVisited = (CallNode) node;
132:
133: IRubyObject receiver = EvaluationState.eval(runtime, context,
134: iVisited.getReceiverNode(), self, block);
135:
136: if (iVisited.getArgsNode() == null) { // attribute set.
137: receiver.callMethod(context, iVisited.getName(),
138: new IRubyObject[] { value }, CallType.NORMAL);
139: } else { // element set
140: RubyArray args = (RubyArray) EvaluationState.eval(runtime,
141: context, iVisited.getArgsNode(), self, block);
142: args.append(value);
143: receiver.callMethod(context, iVisited.getName(), args
144: .toJavaArray(), CallType.NORMAL);
145: }
146: }
147:
148: private static void classVarAsgnNode(ThreadContext context,
149: Node node, IRubyObject value) {
150: ClassVarAsgnNode iVisited = (ClassVarAsgnNode) node;
151: context.getRubyClass().setClassVar(iVisited.getName(), value);
152: }
153:
154: private static void classVarDeclNode(Ruby runtime,
155: ThreadContext context, Node node, IRubyObject value) {
156: ClassVarDeclNode iVisited = (ClassVarDeclNode) node;
157: if (runtime.getVerbose().isTrue()
158: && context.getRubyClass().isSingleton()) {
159: runtime.getWarnings().warn(iVisited.getPosition(),
160: "Declaring singleton class variable.");
161: }
162: context.getRubyClass().setClassVar(iVisited.getName(), value);
163: }
164:
165: private static void constDeclNode(Ruby runtime,
166: ThreadContext context, IRubyObject self, Node node,
167: IRubyObject value, Block block) {
168: ConstDeclNode iVisited = (ConstDeclNode) node;
169: Node constNode = iVisited.getConstNode();
170:
171: IRubyObject module;
172:
173: if (constNode == null) {
174: // FIXME: why do we check RubyClass and then use CRef?
175: if (context.getRubyClass() == null) {
176: // TODO: wire into new exception handling mechanism
177: throw runtime
178: .newTypeError("no class/module to define constant");
179: }
180: module = (RubyModule) context.peekCRef().getValue();
181: } else if (constNode instanceof Colon2Node) {
182: module = EvaluationState.eval(runtime, context,
183: ((Colon2Node) iVisited.getConstNode())
184: .getLeftNode(), self, block);
185: } else { // Colon3
186: module = runtime.getObject();
187: }
188:
189: ((RubyModule) module).setConstant(iVisited.getName(), value);
190: }
191:
192: private static void dasgnNode(ThreadContext context, Node node,
193: IRubyObject value) {
194: DAsgnNode iVisited = (DAsgnNode) node;
195: context.getCurrentScope().setValue(iVisited.getIndex(), value,
196: iVisited.getDepth());
197: }
198:
199: private static void globalAsgnNode(Ruby runtime, Node node,
200: IRubyObject value) {
201: GlobalAsgnNode iVisited = (GlobalAsgnNode) node;
202: runtime.getGlobalVariables().set(iVisited.getName(), value);
203: }
204:
205: private static void instAsgnNode(IRubyObject self, Node node,
206: IRubyObject value) {
207: InstAsgnNode iVisited = (InstAsgnNode) node;
208: self.setInstanceVariable(iVisited.getName(), value);
209: }
210:
211: private static void localAsgnNode(ThreadContext context, Node node,
212: IRubyObject value) {
213: LocalAsgnNode iVisited = (LocalAsgnNode) node;
214:
215: context.getCurrentScope().setValue(iVisited.getIndex(), value,
216: iVisited.getDepth());
217: }
218:
219: public static IRubyObject multiAssign(Ruby runtime,
220: ThreadContext context, IRubyObject self,
221: MultipleAsgnNode node, RubyArray value, boolean callAsProc) {
222: // Assign the values.
223: int valueLen = value.getLength();
224: int varLen = node.getHeadNode() == null ? 0 : node
225: .getHeadNode().size();
226:
227: int j = 0;
228: for (; j < valueLen && j < varLen; j++) {
229: Node lNode = node.getHeadNode().get(j);
230: assign(runtime, context, self, lNode, value.eltInternal(j),
231: Block.NULL_BLOCK, callAsProc);
232: }
233:
234: if (callAsProc && j < varLen) {
235: throw runtime.newArgumentError("Wrong # of arguments ("
236: + valueLen + " for " + varLen + ")");
237: }
238:
239: Node argsNode = node.getArgsNode();
240: if (argsNode != null) {
241: if (argsNode instanceof StarNode) {
242: // no check for '*'
243: } else if (varLen < valueLen) {
244: assign(runtime, context, self, argsNode, value
245: .subseqLight(varLen, valueLen),
246: Block.NULL_BLOCK, callAsProc);
247: } else {
248: assign(runtime, context, self, argsNode, RubyArray
249: .newArrayLight(runtime, 0), Block.NULL_BLOCK,
250: callAsProc);
251: }
252: } else if (callAsProc && valueLen < varLen) {
253: throw runtime.newArgumentError("Wrong # of arguments ("
254: + valueLen + " for " + varLen + ")");
255: }
256:
257: while (j < varLen) {
258: assign(runtime, context, self, node.getHeadNode().get(j++),
259: runtime.getNil(), Block.NULL_BLOCK, callAsProc);
260: }
261:
262: return value;
263: }
264:
265: private static IRubyObject multipleAsgnNode(Ruby runtime,
266: ThreadContext context, IRubyObject self, Node node,
267: IRubyObject value, boolean check) {
268: IRubyObject result;
269: MultipleAsgnNode iVisited = (MultipleAsgnNode) node;
270: if (!(value instanceof RubyArray)) {
271: value = RubyArray.newArrayNoCopyLight(runtime,
272: new IRubyObject[] { value });
273: }
274: result = multiAssign(runtime, context, self, iVisited,
275: (RubyArray) value, check);
276: return result;
277: }
278: }
|