* return mc.methodBound(meth) ? buildGetArgumentDefn(..) : false
* ----------------------------------------------------------------- */
Label undefLabel = s.getNewLabel();
Variable tmpVar = s.getNewTemporaryVariable();
StringLiteral mName = new StringLiteral(((FCallNode)node).getName());
s.addInstr(new IsMethodBoundInstr(tmpVar, getSelf(s), mName));
s.addInstr(BEQInstr.create(tmpVar, manager.getFalse(), undefLabel));
Operand argsCheckDefn = buildGetArgumentDefinition(((FCallNode) node).getArgsNode(), s, "method");
return buildDefnCheckIfThenPaths(s, undefLabel, argsCheckDefn);
}
case VCALLNODE:
return buildDefinitionCheck(s, new IsMethodBoundInstr(s.getNewTemporaryVariable(), getSelf(s), new StringLiteral(((VCallNode) node).getName())), "method");
case CALLNODE: {
// SSS FIXME: Is there a reason to do this all with low-level IR?
// Can't this all be folded into a Java method that would be part
// of the runtime library?
Label undefLabel = s.getNewLabel();
CallNode iVisited = (CallNode) node;
Operand receiverDefn = buildGetDefinition(iVisited.getReceiverNode(), s);
s.addInstr(BEQInstr.create(receiverDefn, manager.getNil(), undefLabel));
// protected main block
CodeBlock protectedCode = new CodeBlock() {
public Operand run(Object[] args) {
IRScope s = (IRScope)args[0];
CallNode iVisited = (CallNode)args[1];
String methodName = iVisited.getName();
Variable tmpVar = s.getNewTemporaryVariable();
Operand receiver = build(iVisited.getReceiverNode(), s);
s.addInstr(new MethodDefinedInstr(tmpVar, receiver, new StringLiteral(methodName)));
return buildDefnCheckIfThenPaths(s, (Label)args[2], tmpVar);
}
};
// rescue block
CodeBlock rescueBlock = new CodeBlock() {
public Operand run(Object[] args) { return manager.getNil(); } // Nothing to do if we got an exception
};
// Try verifying definition, and if we get an exception, throw it out, and return nil
return protectCodeWithRescue(s, protectedCode, new Object[]{s, iVisited, undefLabel}, rescueBlock, null);
}
case CLASSVARNODE: {
// SSS FIXME: Is there a reason to do this all with low-level IR?
// Can't this all be folded into a Java method that would be part
// of the runtime library, which would be used both by the interpreter & the compiled code!
/* --------------------------------------------------------------------------
* Generate IR for this ruby pseudo-code:
* cm = tc.getCurrentScope.getStaticScope.getModule || self.metaclass
* cm.isClassVarDefined ? "class variable" : nil
* ------------------------------------------------------------------------------ */
ClassVarNode iVisited = (ClassVarNode) node;
Operand cm = classVarDefinitionContainer(s);
return buildDefinitionCheck(s, new ClassVarIsDefinedInstr(s.getNewTemporaryVariable(), cm, new StringLiteral(iVisited.getName())), "class variable");
}
case ATTRASSIGNNODE: {
Label undefLabel = s.getNewLabel();
AttrAssignNode iVisited = (AttrAssignNode) node;
Operand receiverDefn = buildGetDefinition(iVisited.getReceiverNode(), s);
s.addInstr(BEQInstr.create(receiverDefn, manager.getNil(), undefLabel));
// protected main block
CodeBlock protectedCode = new CodeBlock() {
public Operand run(Object[] args) {
/* --------------------------------------------------------------------------
* This basically combines checks from CALLNODE and FCALLNODE
*
* Generate IR for this sequence
*
* 1. r = receiver
* 2. mc = r.metaClass
* 3. v = mc.getVisibility(methodName)
* 4. f = !v || v.isPrivate? || (v.isProtected? && receiver/self?.kindof(mc.getRealClass))
* 5. return !f && mc.methodBound(attrmethod) ? buildGetArgumentDefn(..) : false
*
* Hide the complexity of instrs 2-4 into a verifyMethodIsPublicAccessible call
* which can executely entirely in Java-land. No reason to expose the guts in IR.
* ------------------------------------------------------------------------------ */
IRScope s = (IRScope)args[0];
AttrAssignNode iVisited = (AttrAssignNode)args[1];
Label undefLabel = (Label)args[2];
StringLiteral attrMethodName = new StringLiteral(iVisited.getName());
Variable tmpVar = s.getNewTemporaryVariable();
Operand receiver = build(iVisited.getReceiverNode(), s);
s.addInstr(new MethodIsPublicInstr(tmpVar, receiver, attrMethodName));
s.addInstr(BEQInstr.create(tmpVar, manager.getFalse(), undefLabel));
s.addInstr(new IsMethodBoundInstr(tmpVar, getSelf(s), attrMethodName));
s.addInstr(BEQInstr.create(tmpVar, manager.getFalse(), undefLabel));
Operand argsCheckDefn = buildGetArgumentDefinition(((AttrAssignNode) node).getArgsNode(), s, "assignment");
return buildDefnCheckIfThenPaths(s, undefLabel, argsCheckDefn);
}
};