001: package org.jruby.javasupport.util;
002:
003: import jregex.Pattern;
004:
005: import org.jruby.MetaClass;
006: import org.jruby.Ruby;
007: import org.jruby.RubyArray;
008: import org.jruby.RubyClass;
009: import org.jruby.RubyModule;
010: import org.jruby.RubyObject;
011: import org.jruby.evaluator.EvaluationState;
012: import org.jruby.exceptions.JumpException;
013: import org.jruby.internal.runtime.methods.DynamicMethod;
014: import org.jruby.internal.runtime.methods.WrapperMethod;
015: import org.jruby.parser.BlockStaticScope;
016: import org.jruby.parser.LocalStaticScope;
017: import org.jruby.parser.ReOptions;
018: import org.jruby.parser.StaticScope;
019: import org.jruby.runtime.Arity;
020: import org.jruby.runtime.Block;
021: import org.jruby.runtime.CallType;
022: import org.jruby.runtime.CompiledBlock;
023: import org.jruby.runtime.CompiledBlockCallback;
024: import org.jruby.runtime.DynamicScope;
025: import org.jruby.runtime.MethodFactory;
026: import org.jruby.runtime.ThreadContext;
027: import org.jruby.runtime.Visibility;
028: import org.jruby.runtime.builtin.IRubyObject;
029: import org.jruby.util.collections.SinglyLinkedList;
030:
031: /**
032: * Helper methods which are called by the compiler. Note: These will show no consumers, but
033: * generated code does call these so don't remove them thinking they are dead code.
034: *
035: */
036: public class CompilerHelpers {
037: private final static org.jruby.RegexpTranslator TRANS = new org.jruby.RegexpTranslator();
038:
039: public static CompiledBlock createBlock(ThreadContext context,
040: IRubyObject self, int arity, String[] staticScopeNames,
041: CompiledBlockCallback callback) {
042: StaticScope staticScope = new BlockStaticScope(context
043: .getCurrentScope().getStaticScope(), staticScopeNames);
044:
045: return new CompiledBlock(context, self, Arity
046: .createArity(arity), new DynamicScope(staticScope,
047: context.getCurrentScope()), callback);
048: }
049:
050: public static IRubyObject def(ThreadContext context,
051: Visibility visibility, IRubyObject self,
052: Class compiledClass, String name, String javaName,
053: String[] scopeNames, int arity) {
054: Ruby runtime = context.getRuntime();
055:
056: // FIXME: This is what the old def did, but doesn't work in the compiler for top-level methods. Hmm.
057: RubyModule containingClass = context.getRubyClass();
058: //RubyModule containingClass = self.getMetaClass();
059:
060: if (containingClass == null) {
061: throw runtime.newTypeError("No class to add method.");
062: }
063:
064: if (containingClass == runtime.getObject()
065: && name == "initialize") {
066: runtime
067: .getWarnings()
068: .warn(
069: "redefining Object#initialize may cause infinite loop");
070: }
071:
072: SinglyLinkedList cref = context.peekCRef();
073: StaticScope scope = new LocalStaticScope(null, scopeNames);
074:
075: MethodFactory factory = MethodFactory
076: .createFactory(compiledClass.getClassLoader());
077: DynamicMethod method;
078:
079: if (name == "initialize" || visibility.isModuleFunction()
080: || context.isTopLevel()) {
081: method = factory.getCompiledMethod(containingClass,
082: compiledClass, javaName, Arity.createArity(arity),
083: Visibility.PRIVATE, cref, scope);
084: } else {
085: method = factory.getCompiledMethod(containingClass,
086: compiledClass, javaName, Arity.createArity(arity),
087: visibility, cref, scope);
088: }
089:
090: containingClass.addMethod(name, method);
091:
092: if (visibility.isModuleFunction()) {
093: containingClass.getSingletonClass().addMethod(
094: name,
095: new WrapperMethod(containingClass
096: .getSingletonClass(), method,
097: Visibility.PUBLIC));
098: containingClass.callMethod(context,
099: "singleton_method_added", runtime.newSymbol(name));
100: }
101:
102: // 'class << state.self' and 'class << obj' uses defn as opposed to defs
103: if (containingClass.isSingleton()) {
104: ((MetaClass) containingClass).getAttachedObject()
105: .callMethod(context, "singleton_method_added",
106: runtime.newSymbol(name));
107: } else {
108: containingClass.callMethod(context, "method_added", runtime
109: .newSymbol(name));
110: }
111:
112: return runtime.getNil();
113: }
114:
115: public static IRubyObject doAttrAssign(IRubyObject receiver,
116: IRubyObject[] args, ThreadContext context, String name,
117: IRubyObject caller, CallType callType, Block block) {
118: if (receiver == caller)
119: callType = CallType.VARIABLE;
120:
121: try {
122: return receiver.compilerCallMethod(context, name, args,
123: caller, callType, block);
124: } catch (StackOverflowError sfe) {
125: throw context.getRuntime().newSystemStackError(
126: "stack level too deep");
127: }
128: }
129:
130: public static IRubyObject doAttrAssignIndexed(IRubyObject receiver,
131: IRubyObject[] args, ThreadContext context,
132: byte methodIndex, String name, IRubyObject caller,
133: CallType callType, Block block) {
134: if (receiver == caller)
135: callType = CallType.VARIABLE;
136:
137: try {
138: return receiver.compilerCallMethodWithIndex(context,
139: methodIndex, name, args, caller, callType, block);
140: } catch (StackOverflowError sfe) {
141: throw context.getRuntime().newSystemStackError(
142: "stack level too deep");
143: }
144: }
145:
146: public static IRubyObject doInvokeDynamic(IRubyObject receiver,
147: IRubyObject[] args, ThreadContext context, String name,
148: IRubyObject caller, CallType callType, Block block) {
149: try {
150: return receiver.compilerCallMethod(context, name, args,
151: caller, callType, block);
152: } catch (StackOverflowError sfe) {
153: throw context.getRuntime().newSystemStackError(
154: "stack level too deep");
155: }
156: }
157:
158: public static IRubyObject doInvokeDynamicIndexed(
159: IRubyObject receiver, IRubyObject[] args,
160: ThreadContext context, byte methodIndex, String name,
161: IRubyObject caller, CallType callType, Block block) {
162: try {
163: return receiver.compilerCallMethodWithIndex(context,
164: methodIndex, name, args, caller, callType, block);
165: } catch (StackOverflowError sfe) {
166: throw context.getRuntime().newSystemStackError(
167: "stack level too deep");
168: }
169: }
170:
171: public static RubyArray ensureRubyArray(IRubyObject value) {
172: if (!(value instanceof RubyArray)) {
173: value = RubyArray.newArray(value.getRuntime(), value);
174: }
175: return (RubyArray) value;
176: }
177:
178: public static IRubyObject fetchClassVariable(ThreadContext context,
179: Ruby runtime, IRubyObject self, String name) {
180: RubyModule rubyClass = EvaluationState.getClassVariableBase(
181: context, runtime);
182:
183: if (rubyClass == null)
184: rubyClass = self.getMetaClass();
185:
186: return rubyClass.getClassVar(name);
187: }
188:
189: public static IRubyObject handleJumpException(JumpException je,
190: Block block) {
191: // JRUBY-530, Kernel#loop case:
192: if (je.isBreakInKernelLoop()) {
193: // consume and rethrow or just keep rethrowing?
194: if (block == je.getTarget())
195: je.setBreakInKernelLoop(false);
196:
197: throw je;
198: }
199:
200: return (IRubyObject) je.getValue();
201: }
202:
203: public static IRubyObject nullToNil(IRubyObject value, Ruby runtime) {
204: return value != null ? value : runtime.getNil();
205: }
206:
207: public static RubyClass prepareSuperClass(Ruby runtime,
208: IRubyObject rubyClass) {
209: if (rubyClass != null) {
210: if (!(rubyClass instanceof RubyClass)) {
211: throw runtime
212: .newTypeError("superclass must be a Class ("
213: + RubyObject.trueFalseNil(rubyClass)
214: + ") given");
215: }
216: return (RubyClass) rubyClass;
217: }
218: return (RubyClass) null;
219: }
220:
221: public static RubyModule prepareClassNamespace(
222: ThreadContext context, IRubyObject rubyModule) {
223: if (rubyModule == null || rubyModule.isNil()) {
224: rubyModule = (RubyModule) context.peekCRef().getValue();
225:
226: if (rubyModule == null) {
227: throw context.getRuntime().newTypeError(
228: "no outer class/module");
229: }
230: }
231:
232: return (RubyModule) rubyModule;
233: }
234:
235: public static int regexpLiteralFlags(int options) {
236: return TRANS.flagsFor(options, 0);
237: }
238:
239: public static Pattern regexpLiteral(Ruby runtime, String ptr,
240: int options) {
241: IRubyObject noCaseGlobal = runtime.getGlobalVariables().get(
242: "$=");
243:
244: int extraOptions = noCaseGlobal.isTrue() ? ReOptions.RE_OPTION_IGNORECASE
245: : 0;
246:
247: try {
248: return TRANS.translate(ptr, options | extraOptions, 0);
249: } catch (jregex.PatternSyntaxException e) {
250: throw runtime.newRegexpError(e.getMessage());
251: }
252: }
253:
254: public static IRubyObject setClassVariable(ThreadContext context,
255: Ruby runtime, IRubyObject self, String name,
256: IRubyObject value) {
257: RubyModule rubyClass = EvaluationState.getClassVariableBase(
258: context, runtime);
259:
260: if (rubyClass == null)
261: rubyClass = self.getMetaClass();
262:
263: rubyClass.setClassVar(name, value);
264:
265: return value;
266: }
267:
268: public static void raiseArgumentError(Ruby runtime, int given,
269: int maximum) {
270: if (given > maximum) {
271: throw runtime.newArgumentError("wrong # of arguments("
272: + given + " for " + maximum + ")");
273: }
274: }
275: }
|