Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.jruby.compiler.ASTCompiler Maven / Gradle / Ivy
package org.jruby.compiler;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.jcodings.Encoding;
import org.jruby.RubyFixnum;
import org.jruby.RubyFloat;
import org.jruby.RubyInstanceConfig;
import org.jruby.RubyMatchData;
import org.jruby.RubyString;
import org.jruby.ast.*;
import org.jruby.exceptions.JumpException;
import org.jruby.lexer.yacc.ISourcePosition;
import org.jruby.runtime.Helpers;
import org.jruby.parser.StaticScope;
import org.jruby.runtime.Arity;
import org.jruby.runtime.BlockBody;
import org.jruby.runtime.CallType;
import org.jruby.runtime.MethodIndex;
import org.jruby.util.DefinedMessage;
import org.jruby.util.StringSupport;
import org.jruby.util.cli.Options;
public class ASTCompiler {
private boolean isAtRoot = true ;
protected boolean is1_9 () {
return false ;
}
public void compileBody (Node node, BodyCompiler context, boolean expr) {
Node oldBodyNode = currentBodyNode;
currentBodyNode = node;
compile(node, context, expr);
currentBodyNode = oldBodyNode;
}
public void compile (Node node, BodyCompiler context, boolean expr) {
if (node == null ) {
if (expr) context.loadNil();
return ;
}
switch (node.getNodeType()) {
case ALIASNODE:
compileAlias((AliasNode) node, context, expr);
break ;
case ANDNODE:
compileAnd(node, context, expr);
break ;
case ARGSCATNODE:
compileArgsCat(node, context, expr);
break ;
case ARGSPUSHNODE:
compileArgsPush(node, context, expr);
break ;
case ARRAYNODE:
compileArray(node, context, expr);
break ;
case ATTRASSIGNNODE:
compileAttrAssign(node, context, expr);
break ;
case BACKREFNODE:
compileBackref(node, context, expr);
break ;
case BEGINNODE:
compileBegin(node, context, expr);
break ;
case BIGNUMNODE:
compileBignum(node, context, expr);
break ;
case BLOCKNODE:
compileBlock(node, context, expr);
break ;
case BREAKNODE:
compileBreak(node, context, expr);
break ;
case CALLNODE:
compileCall(node, context, expr);
break ;
case CASENODE:
compileCase(node, context, expr);
break ;
case CLASSNODE:
compileClass(node, context, expr);
break ;
case CLASSVARNODE:
compileClassVar(node, context, expr);
break ;
case CLASSVARASGNNODE:
compileClassVarAsgn(node, context, expr);
break ;
case CLASSVARDECLNODE:
compileClassVarDecl(node, context, expr);
break ;
case COLON2NODE:
compileColon2(node, context, expr);
break ;
case COLON3NODE:
compileColon3(node, context, expr);
break ;
case CONSTDECLNODE:
compileConstDecl(node, context, expr);
break ;
case CONSTNODE:
compileConst(node, context, expr);
break ;
case DASGNNODE:
compileDAsgn(node, context, expr);
break ;
case DEFINEDNODE:
compileDefined(node, context, expr);
break ;
case DEFNNODE:
compileDefn(node, context, expr);
break ;
case DEFSNODE:
compileDefs(node, context, expr);
break ;
case DOTNODE:
compileDot(node, context, expr);
break ;
case DREGEXPNODE:
compileDRegexp(node, context, expr);
break ;
case DSTRNODE:
compileDStr(node, context, expr);
break ;
case DSYMBOLNODE:
compileDSymbol(node, context, expr);
break ;
case DVARNODE:
compileDVar(node, context, expr);
break ;
case DXSTRNODE:
compileDXStr(node, context, expr);
break ;
case ENSURENODE:
compileEnsureNode(node, context, expr);
break ;
case EVSTRNODE:
compileEvStr(node, context, expr);
break ;
case FALSENODE:
compileFalse(node, context, expr);
break ;
case FCALLNODE:
compileFCall(node, context, expr);
break ;
case FIXNUMNODE:
compileFixnum(node, context, expr);
break ;
case FLIPNODE:
compileFlip(node, context, expr);
break ;
case FLOATNODE:
compileFloat(node, context, expr);
break ;
case FORNODE:
compileFor(node, context, expr);
break ;
case GLOBALASGNNODE:
compileGlobalAsgn(node, context, expr);
break ;
case GLOBALVARNODE:
compileGlobalVar(node, context, expr);
break ;
case HASHNODE:
compileHash(node, context, expr);
break ;
case IFNODE:
compileIf(node, context, expr);
break ;
case INSTASGNNODE:
compileInstAsgn(node, context, expr);
break ;
case INSTVARNODE:
compileInstVar(node, context, expr);
break ;
case ITERNODE:
compileIter(node, context);
break ;
case LITERALNODE:
compileLiteral((LiteralNode) node, context);
break ;
case LOCALASGNNODE:
compileLocalAsgn(node, context, expr);
break ;
case LOCALVARNODE:
compileLocalVar(node, context, expr);
break ;
case MATCH2NODE:
compileMatch2(node, context, expr);
break ;
case MATCH3NODE:
compileMatch3(node, context, expr);
break ;
case MATCHNODE:
compileMatch(node, context, expr);
break ;
case MODULENODE:
compileModule(node, context, expr);
break ;
case MULTIPLEASGNNODE:
compileMultipleAsgn(node, context, expr);
break ;
case NEWLINENODE:
compileNewline(node, context, expr);
break ;
case NEXTNODE:
compileNext(node, context, expr);
break ;
case NTHREFNODE:
compileNthRef(node, context, expr);
break ;
case NILNODE:
compileNil(node, context, expr);
break ;
case NOTNODE:
compileNot(node, context, expr);
break ;
case OPASGNANDNODE:
compileOpAsgnAnd(node, context, expr);
break ;
case OPASGNNODE:
compileOpAsgn(node, context, expr);
break ;
case OPASGNORNODE:
compileOpAsgnOr(node, context, expr);
break ;
case OPELEMENTASGNNODE:
compileOpElementAsgn(node, context, expr);
break ;
case ORNODE:
compileOr(node, context, expr);
break ;
case POSTEXENODE:
compilePostExe(node, context, expr);
break ;
case PREEXENODE:
compilePreExe(node, context, expr);
break ;
case REDONODE:
compileRedo(node, context, expr);
break ;
case REGEXPNODE:
compileRegexp(node, context, expr);
break ;
case RESCUEBODYNODE:
throw new NotCompilableException("rescue body is handled by rescue compilation at: " + node.getPosition());
case RESCUENODE:
compileRescue(node, context, expr);
break ;
case RETRYNODE:
compileRetry(node, context, expr);
break ;
case RETURNNODE:
compileReturn(node, context, expr);
break ;
case ROOTNODE:
throw new NotCompilableException("Use compileRoot(); Root node at: " + node.getPosition());
case SCLASSNODE:
compileSClass(node, context, expr);
break ;
case SELFNODE:
compileSelf(node, context, expr);
break ;
case SPLATNODE:
compileSplat(node, context, expr);
break ;
case STRNODE:
compileStr(node, context, expr);
break ;
case SUPERNODE:
compileSuper(node, context, expr);
break ;
case SVALUENODE:
compileSValue(node, context, expr);
break ;
case SYMBOLNODE:
compileSymbol(node, context, expr);
break ;
case TOARYNODE:
compileToAry(node, context, expr);
break ;
case TRUENODE:
compileTrue(node, context, expr);
break ;
case UNDEFNODE:
compileUndef((UndefNode) node, context, expr);
break ;
case UNTILNODE:
compileUntil(node, context, expr);
break ;
case VALIASNODE:
compileVAlias(node, context, expr);
break ;
case VCALLNODE:
compileVCall(node, context, expr);
break ;
case WHILENODE:
compileWhile(node, context, expr);
break ;
case WHENNODE:
assert false : "When nodes are handled by case node compilation." ;
break ;
case XSTRNODE:
compileXStr(node, context, expr);
break ;
case YIELDNODE:
compileYield(node, context, expr);
break ;
case ZARRAYNODE:
compileZArray(node, context, expr);
break ;
case ZSUPERNODE:
compileZSuper(node, context, expr);
break ;
default :
throw new NotCompilableException("Unknown node encountered in compiler: " + node);
}
}
public void compileArguments (Node node, BodyCompiler context) {
switch (node.getNodeType()) {
case ARGSCATNODE:
compileArgsCatArguments(node, context, true );
break ;
case ARGSPUSHNODE:
compileArgsPushArguments(node, context, true );
break ;
case ARRAYNODE:
compileArrayArguments(node, context, true );
break ;
case SPLATNODE:
compileSplatArguments(node, context, true );
break ;
default :
compile(node, context, true );
context.convertToJavaArray();
}
}
public class VariableArityArguments implements ArgumentsCallback {
private Node node;
public VariableArityArguments (Node node) {
this .node = node;
}
public int getArity () {
return -1 ;
}
public void call (BodyCompiler context) {
compileArguments(node, context);
}
}
public class SpecificArityArguments implements ArgumentsCallback {
private int arity;
private Node node;
public SpecificArityArguments (Node node) {
if (node.getNodeType() == NodeType.ARRAYNODE && ((ArrayNode)node).isLightweight()) {
this .arity = ((ArrayNode)node).size();
} else {
this .arity = 1 ;
}
this .node = node;
}
public int getArity () {
return arity;
}
public void call (BodyCompiler context) {
if (node.getNodeType() == NodeType.ARRAYNODE) {
ArrayNode arrayNode = (ArrayNode)node;
if (arrayNode.isLightweight()) {
for (Node n : arrayNode.childNodes()) {
compile(n, context,true );
}
} else {
compile(arrayNode, context,true );
}
} else {
compile(node, context,true );
}
}
}
public ArgumentsCallback getArgsCallback (Node node) {
if (node == null ) {
return null ;
}
while (node.getNodeType() == NodeType.NEWLINENODE) {
node = ((NewlineNode)node).getNextNode();
}
switch (node.getNodeType()) {
case ARGSCATNODE:
case ARGSPUSHNODE:
case SPLATNODE:
return new VariableArityArguments(node);
case ARRAYNODE:
ArrayNode arrayNode = (ArrayNode)node;
if (arrayNode.size() == 0 ) {
return null ;
} else if (arrayNode.size() > 3 ) {
return new VariableArityArguments(node);
} else {
return new SpecificArityArguments(node);
}
default :
return new SpecificArityArguments(node);
}
}
public void compileAssignment (Node node, BodyCompiler context) {
switch (node.getNodeType()) {
case ATTRASSIGNNODE:
compileAttrAssignAssignment(node, context);
break ;
case DASGNNODE:
DAsgnNode dasgnNode = (DAsgnNode)node;
context.getVariableCompiler().assignLocalVariable(dasgnNode.getIndex(), dasgnNode.getDepth(), false );
break ;
case CLASSVARASGNNODE:
compileClassVarAsgnAssignment(node, context);
break ;
case CLASSVARDECLNODE:
compileClassVarDeclAssignment(node, context);
break ;
case CONSTDECLNODE:
compileConstDeclAssignment(node, context);
break ;
case GLOBALASGNNODE:
compileGlobalAsgnAssignment(node, context);
break ;
case INSTASGNNODE:
compileInstAsgnAssignment(node, context);
break ;
case LOCALASGNNODE:
LocalAsgnNode localAsgnNode = (LocalAsgnNode)node;
context.getVariableCompiler().assignLocalVariable(localAsgnNode.getIndex(), localAsgnNode.getDepth(), false );
break ;
case MULTIPLEASGNNODE:
compileMultipleAsgnAssignment(node, context, false );
break ;
case ZEROARGNODE:
context.consumeCurrentValue();
break ;
default :
throw new NotCompilableException("Can't compile assignment node: " + node);
}
}
public void compileAlias (final AliasNode alias, BodyCompiler context, boolean expr) {
CompilerCallback args = new CompilerCallback() {
public void call (BodyCompiler context) {
compile(alias.getNewName(), context, true );
compile(alias.getOldName(), context, true );
}
};
context.defineAlias(args);
if (!expr) context.consumeCurrentValue();
}
public void compileAnd (Node node, BodyCompiler context, final boolean expr) {
final AndNode andNode = (AndNode) node;
if (andNode.getFirstNode().getNodeType().alwaysTrue()) {
compile(andNode.getFirstNode(), context, false );
compile(andNode.getSecondNode(), context, expr);
} else if (andNode.getFirstNode().getNodeType().alwaysFalse()) {
compile(andNode.getFirstNode(), context, expr);
} else {
compile(andNode.getFirstNode(), context, true );
BranchCallback longCallback = new BranchCallback() {
public void branch (BodyCompiler context) {
compile(andNode.getSecondNode(), context, true );
}
};
context.performLogicalAnd(longCallback);
if (!expr) context.consumeCurrentValue();
}
}
public void compileArray (Node node, BodyCompiler context, boolean expr) {
ArrayNode arrayNode = (ArrayNode) node;
if (expr) {
ArrayCallback callback = new ArrayCallback() {
public void nextValue (BodyCompiler context, Object sourceArray, int index) {
Node node = (Node) ((Object[]) sourceArray)[index];
compile(node, context, true );
}
};
List childNodes = arrayNode.childNodes();
if (isListAllLiterals(arrayNode)) {
context.createNewLiteralArray(childNodes.toArray(), callback, arrayNode.isLightweight());
} else {
context.createNewArray(childNodes.toArray(), callback, arrayNode.isLightweight());
}
} else {
if (isListAllLiterals(arrayNode)) {
} else {
for (Iterator iter = arrayNode.childNodes().iterator(); iter.hasNext();) {
Node nextNode = iter.next();
compile(nextNode, context, false );
}
}
}
}
private boolean isListAllLiterals (ListNode listNode) {
for (int i = 0 ; i < listNode.size(); i++) {
switch (listNode.get(i).getNodeType()) {
case STRNODE:
case FLOATNODE:
case FIXNUMNODE:
case BIGNUMNODE:
case REGEXPNODE:
case ZARRAYNODE:
case SYMBOLNODE:
case NILNODE:
continue ;
case ARRAYNODE:
if (isListAllLiterals((ArrayNode)listNode.get(i))) {
continue ;
} else {
return false ;
}
case HASHNODE:
if (isListAllLiterals(((HashNode)listNode.get(i)).getListNode())) {
continue ;
} else {
return false ;
}
default :
return false ;
}
}
return true ;
}
public void compileArgsCat (Node node, BodyCompiler context, boolean expr) {
ArgsCatNode argsCatNode = (ArgsCatNode) node;
compile(argsCatNode.getFirstNode(), context,true );
compile(argsCatNode.getSecondNode(), context,true );
context.argsCat();
if (!expr) context.consumeCurrentValue();
}
public void compileArgsPush (Node node, BodyCompiler context, boolean expr) {
throw new NotCompilableException("ArgsPush should never be encountered bare in 1.8" );
}
private void compileAttrAssign (Node node, BodyCompiler context, boolean expr) {
final AttrAssignNode attrAssignNode = (AttrAssignNode) node;
CompilerCallback receiverCallback = new CompilerCallback() {
public void call (BodyCompiler context) {
compile(attrAssignNode.getReceiverNode(), context,true );
}
};
ArgumentsCallback argsCallback = getArgsCallback(attrAssignNode.getArgsNode());
boolean isSelf = attrAssignNode.getReceiverNode() instanceof SelfNode;
context.getInvocationCompiler().invokeAttrAssign(attrAssignNode.getName(), receiverCallback, argsCallback, isSelf, expr);
}
public void compileAttrAssignAssignment (Node node, BodyCompiler context) {
final AttrAssignNode attrAssignNode = (AttrAssignNode) node;
CompilerCallback receiverCallback = new CompilerCallback() {
public void call (BodyCompiler context) {
compile(attrAssignNode.getReceiverNode(), context,true );
}
};
ArgumentsCallback argsCallback = getArgsCallback(attrAssignNode.getArgsNode());
boolean isSelf = attrAssignNode.getReceiverNode() instanceof SelfNode;
context.getInvocationCompiler().invokeAttrAssignMasgn(attrAssignNode.getName(), receiverCallback, argsCallback, isSelf);
}
public void compileBackref (Node node, BodyCompiler context, boolean expr) {
BackRefNode iVisited = (BackRefNode) node;
context.performBackref(iVisited.getType());
if (!expr) context.consumeCurrentValue();
}
public void compileBegin (Node node, BodyCompiler context, boolean expr) {
BeginNode beginNode = (BeginNode) node;
compile(beginNode.getBodyNode(), context, expr);
}
public void compileBignum (Node node, BodyCompiler context, boolean expr) {
if (expr) context.createNewBignum(((BignumNode) node).getValue());
}
public void compileBlock (Node node, BodyCompiler context, boolean expr) {
BlockNode blockNode = (BlockNode) node;
for (Iterator iter = blockNode.childNodes().iterator(); iter.hasNext();) {
Node n = iter.next();
compile(n, context, iter.hasNext() ? false : expr);
}
}
public void compileBreak (Node node, BodyCompiler context, boolean expr) {
final BreakNode breakNode = (BreakNode) node;
CompilerCallback valueCallback = new CompilerCallback() {
public void call (BodyCompiler context) {
if (breakNode.getValueNode() != null ) {
compile(breakNode.getValueNode(), context, true );
} else {
context.loadNil();
}
}
};
context.issueBreakEvent(valueCallback);
if (!expr) context.consumeCurrentValue();
}
public void compileCall (Node node, BodyCompiler context, boolean expr) {
final CallNode callNode = (CallNode) node;
CompilerCallback receiverCallback = new CompilerCallback() {
public void call (BodyCompiler context) {
compile(callNode.getReceiverNode(), context, true );
}
};
ArgumentsCallback argsCallback = getArgsCallback(callNode.getArgsNode());
CompilerCallback closureArg = getBlock(callNode.getIterNode());
String name = callNode.getName();
CallType callType = CallType.NORMAL;
if (argsCallback != null && argsCallback.getArity() == 1 ) {
Node argument = callNode.getArgsNode().childNodes().get(0 );
if (argument instanceof FixnumNode) {
if (MethodIndex.hasFastFixnumOps(name)) {
context.getInvocationCompiler().invokeBinaryFixnumRHS(name, receiverCallback, ((FixnumNode)argument).getValue());
if (!expr) context.consumeCurrentValue();
return ;
}
} else if (argument instanceof FloatNode) {
if (MethodIndex.hasFastFloatOps(name)) {
context.getInvocationCompiler().invokeBinaryFloatRHS(name, receiverCallback, ((FloatNode)argument).getValue());
if (!expr) context.consumeCurrentValue();
return ;
}
}
}
if (RubyInstanceConfig.FASTSEND_COMPILE_ENABLED) {
String literalSend = getLiteralSend(callNode);
if (literalSend != null ) {
name = literalSend;
callType = CallType.FUNCTIONAL;
}
}
if (callNode instanceof SpecialArgs) {
context.getInvocationCompiler().invokeDynamicVarargs(
name, receiverCallback, argsCallback,
callType, closureArg, callNode.getIterNode() instanceof IterNode);
} else {
context.getInvocationCompiler().invokeDynamic(
name, receiverCallback, argsCallback,
callType, closureArg, callNode.getIterNode() instanceof IterNode);
}
if (!expr) context.consumeCurrentValue();
}
private static final Map>> Intrinsics;
static {
Intrinsics = new HashMap();
Map> fixnumIntrinsics = new HashMap();
Intrinsics.put(RubyFixnum.class, fixnumIntrinsics);
Map fixnumLongIntrinsics = new HashMap();
fixnumIntrinsics.put(FixnumNode.class, fixnumLongIntrinsics);
fixnumLongIntrinsics.put("+" , "op_plus" );
fixnumLongIntrinsics.put("-" , "op_minus" );
fixnumLongIntrinsics.put("/" , "op_div" );
fixnumLongIntrinsics.put("*" , "op_plus" );
fixnumLongIntrinsics.put("**" , "op_pow" );
fixnumLongIntrinsics.put("<" , "op_lt" );
fixnumLongIntrinsics.put("<=" , "op_le" );
fixnumLongIntrinsics.put(">" , "op_gt" );
fixnumLongIntrinsics.put(">=" , "op_ge" );
fixnumLongIntrinsics.put("==" , "op_equal" );
fixnumLongIntrinsics.put("<=>" , "op_cmp" );
Map> floatIntrinsics = new HashMap();
Intrinsics.put(RubyFloat.class, floatIntrinsics);
MapfloatDoubleIntrinsics = new HashMap();
floatIntrinsics.put(FloatNode.class, floatDoubleIntrinsics);
floatDoubleIntrinsics.put("+" , "op_plus" );
floatDoubleIntrinsics.put("-" , "op_minus" );
floatDoubleIntrinsics.put("/" , "op_fdiv" );
floatDoubleIntrinsics.put("*" , "op_plus" );
floatDoubleIntrinsics.put("**" , "op_pow" );
floatDoubleIntrinsics.put("<" , "op_lt" );
floatDoubleIntrinsics.put("<=" , "op_le" );
floatDoubleIntrinsics.put(">" , "op_gt" );
floatDoubleIntrinsics.put(">=" , "op_ge" );
floatDoubleIntrinsics.put("==" , "op_equal" );
floatDoubleIntrinsics.put("<=>" , "op_cmp" );
}
private String getLiteralSend (CallNode callNode) {
if (callNode.getName().equals("__send__" )) {
if (callNode.getArgsNode() instanceof ArrayNode) {
ArrayNode arrayNode = (ArrayNode)callNode.getArgsNode();
if (arrayNode.get(0 ) instanceof SymbolNode) {
return ((SymbolNode)arrayNode.get(0 )).getName();
} else if (arrayNode.get(0 ) instanceof StrNode) {
return ((StrNode)arrayNode.get(0 )).getValue().toString();
}
}
}
return null ;
}
public void compileCase (Node node, BodyCompiler context, boolean expr) {
CaseNode caseNode = (CaseNode) node;
List cases = caseNode.getCases().childNodes();
Node elseNode = caseNode.getElseNode();
boolean outline = caseNode.getCases().size() > Options.COMPILE_OUTLINE_CASECOUNT.load();
compileWhen(caseNode.getCaseNode(), cases, elseNode, context, expr, outline);
}
private FastSwitchType getHomogeneousSwitchType (List whenNodes) {
FastSwitchType foundType = null ;
Outer: for (Node node : whenNodes) {
WhenNode whenNode = (WhenNode)node;
if (whenNode.getExpressionNodes() instanceof ArrayNode) {
ArrayNode arrayNode = (ArrayNode)whenNode.getExpressionNodes();
for (Node maybeFixnum : arrayNode.childNodes()) {
if (maybeFixnum instanceof FixnumNode) {
FixnumNode fixnumNode = (FixnumNode)maybeFixnum;
long value = fixnumNode.getValue();
if (value <= Integer.MAX_VALUE && value >= Integer.MIN_VALUE) {
if (foundType != null && foundType != FastSwitchType.FIXNUM) return null ;
if (foundType == null ) foundType = FastSwitchType.FIXNUM;
continue ;
} else {
return null ;
}
} else {
return null ;
}
}
} else if (whenNode.getExpressionNodes() instanceof FixnumNode) {
FixnumNode fixnumNode = (FixnumNode)whenNode.getExpressionNodes();
long value = fixnumNode.getValue();
if (value <= Integer.MAX_VALUE && value >= Integer.MIN_VALUE) {
if (foundType != null && foundType != FastSwitchType.FIXNUM) return null ;
if (foundType == null ) foundType = FastSwitchType.FIXNUM;
continue ;
} else {
return null ;
}
} else if (whenNode.getExpressionNodes() instanceof StrNode) {
StrNode strNode = (StrNode)whenNode.getExpressionNodes();
if (strNode.getValue().length() == 1 ) {
if (foundType != null && foundType != FastSwitchType.SINGLE_CHAR_STRING) return null ;
if (foundType == null ) foundType = FastSwitchType.SINGLE_CHAR_STRING;
continue ;
}
} else if (whenNode.getExpressionNodes() instanceof SymbolNode) {
SymbolNode symbolNode = (SymbolNode)whenNode.getExpressionNodes();
if (symbolNode.getName().length() == 1 ) {
if (foundType != null && foundType != FastSwitchType.SINGLE_CHAR_SYMBOL) return null ;
if (foundType == null ) foundType = FastSwitchType.SINGLE_CHAR_SYMBOL;
continue ;
}
} else {
return null ;
}
}
return foundType;
}
public void compileWhen (final Node value, List whenNodes, final Node elseNode, BodyCompiler context, final boolean expr, boolean outline) {
CompilerCallback caseValue = null ;
if (value != null ) caseValue = new CompilerCallback() {
public void call (BodyCompiler context) {
compile(value, context, true );
context.pollThreadEvents();
}
};
List conditionals = new ArrayList();
List bodies = new ArrayList();
Map switchCases = null ;
FastSwitchType switchType = getHomogeneousSwitchType(whenNodes);
if (switchType != null && !RubyInstanceConfig.FULL_TRACE_ENABLED) {
switchCases = new HashMap();
}
for (Node node : whenNodes) {
final WhenNode whenNode = (WhenNode)node;
CompilerCallback body = new CompilerCallback() {
public void call (BodyCompiler context) {
if (RubyInstanceConfig.FULL_TRACE_ENABLED) context.traceLine(whenNode.getPosition());
compile(whenNode.getBodyNode(), context, expr);
}
};
addConditionalForWhen(whenNode, conditionals, bodies, body);
if (switchCases != null ) switchCases.put(body, getOptimizedCases(whenNode));
}
CompilerCallback fallback = new CompilerCallback() {
public void call (BodyCompiler context) {
compile(elseNode, context, expr);
}
};
context.compileSequencedConditional(caseValue, switchType, switchCases, conditionals, bodies, fallback, outline);
}
private int [] getOptimizedCases(WhenNode whenNode) {
if (whenNode.getExpressionNodes() instanceof ArrayNode) {
ArrayNode expression = (ArrayNode)whenNode.getExpressionNodes();
if (expression.get(expression.size() - 1 ) instanceof WhenNode) {
return null ;
}
int [] cases = new int [expression.size()];
for (int i = 0 ; i < cases.length; i++) {
switch (expression.get(i).getNodeType()) {
case FIXNUMNODE:
cases[i] = (int )((FixnumNode)expression.get(i)).getValue();
break ;
default :
return null ;
}
}
return cases;
} else if (whenNode.getExpressionNodes() instanceof FixnumNode) {
FixnumNode fixnumNode = (FixnumNode)whenNode.getExpressionNodes();
return new int [] {(int )fixnumNode.getValue()};
} else if (whenNode.getExpressionNodes() instanceof StrNode) {
StrNode strNode = (StrNode)whenNode.getExpressionNodes();
if (strNode.getValue().length() == 1 ) {
return new int [] {strNode.getValue().get(0 )};
} else {
return new int [] {strNode.getValue().hashCode()};
}
} else if (whenNode.getExpressionNodes() instanceof SymbolNode) {
SymbolNode symbolNode = (SymbolNode)whenNode.getExpressionNodes();
if (symbolNode.getName().length() == 1 ) {
return new int [] {symbolNode.getName().charAt(0 )};
} else {
return new int [] {symbolNode.getName().hashCode()};
}
}
return null ;
}
private void addConditionalForWhen (final WhenNode whenNode, List conditionals, List bodies, CompilerCallback body) {
bodies.add(body);
if (whenNode.getExpressionNodes() instanceof ArrayNode) {
if (whenNode instanceof WhenOneArgNode) {
conditionals.add(new ArgumentsCallback() {
public int getArity () {
return 1 ;
}
public void call (BodyCompiler context) {
compile(whenNode.getExpressionNodes(), context, true );
}
});
return ;
}
}
conditionals.add(getArgsCallback(whenNode.getExpressionNodes()));
}
public void compileClass (Node node, BodyCompiler context, boolean expr) {
final ClassNode classNode = (ClassNode) node;
final Node superNode = classNode.getSuperNode();
final Node cpathNode = classNode.getCPath();
CompilerCallback superCallback = new CompilerCallback() {
public void call (BodyCompiler context) {
compile(superNode, context, true );
}
};
if (superNode == null ) {
superCallback = null ;
}
ISourcePosition[] lastPosition = new ISourcePosition[1 ];
CompilerCallback bodyCallback = new CompilerCallback() {
public void call (BodyCompiler context) {
boolean oldIsAtRoot = isAtRoot;
isAtRoot = false ;
if (classNode.getBodyNode() != null ) {
compile(classNode.getBodyNode(), context, true );
} else {
context.loadNil();
}
isAtRoot = oldIsAtRoot;
}
};
CompilerCallback pathCallback = new CompilerCallback() {
public void call (BodyCompiler context) {
if (cpathNode instanceof Colon2Node) {
Node leftNode = ((Colon2Node) cpathNode).getLeftNode();
if (leftNode != null ) {
if (leftNode instanceof NilNode) {
context.raiseTypeError("No outer class" );
} else {
compile(leftNode, context, true );
}
} else {
context.loadNil();
}
} else if (cpathNode instanceof Colon3Node) {
context.loadObject();
} else {
context.loadNil();
}
}
};
ASTInspector inspector = new ASTInspector();
inspector.inspect(classNode.getBodyNode());
context.defineClass(classNode.getCPath().getName(), classNode.getScope(), superCallback, pathCallback, bodyCallback, null , inspector, classNode.getPosition());
if (!expr) context.consumeCurrentValue();
}
public void compileSClass (Node node, BodyCompiler context, boolean expr) {
final SClassNode sclassNode = (SClassNode) node;
CompilerCallback receiverCallback = new CompilerCallback() {
public void call (BodyCompiler context) {
compile(sclassNode.getReceiverNode(), context, true );
}
};
CompilerCallback bodyCallback = new CompilerCallback() {
public void call (BodyCompiler context) {
boolean oldIsAtRoot = isAtRoot;
isAtRoot = false ;
if (sclassNode.getBodyNode() != null ) {
compile(sclassNode.getBodyNode(), context, true );
} else {
context.loadNil();
}
isAtRoot = oldIsAtRoot;
}
};
ASTInspector inspector = new ASTInspector();
inspector.inspect(sclassNode.getBodyNode());
context.defineClass("SCLASS" , sclassNode.getScope(), null , null , bodyCallback, receiverCallback, inspector, sclassNode.getPosition());
if (!expr) context.consumeCurrentValue();
}
public void compileClassVar (Node node, BodyCompiler context, boolean expr) {
ClassVarNode classVarNode = (ClassVarNode) node;
context.retrieveClassVariable(classVarNode.getName());
if (!expr) context.consumeCurrentValue();
}
public void compileClassVarAsgn (Node node, BodyCompiler context, boolean expr) {
final ClassVarAsgnNode classVarAsgnNode = (ClassVarAsgnNode) node;
CompilerCallback value = new CompilerCallback() {
public void call (BodyCompiler context) {
compile(classVarAsgnNode.getValueNode(), context, true );
}
};
context.assignClassVariable(classVarAsgnNode.getName(), value);
if (!expr) context.consumeCurrentValue();
}
public void compileClassVarAsgnAssignment (Node node, BodyCompiler context) {
ClassVarAsgnNode classVarAsgnNode = (ClassVarAsgnNode) node;
context.assignClassVariable(classVarAsgnNode.getName());
context.consumeCurrentValue();
}
public void compileClassVarDecl (Node node, BodyCompiler context, boolean expr) {
final ClassVarDeclNode classVarDeclNode = (ClassVarDeclNode) node;
CompilerCallback value = new CompilerCallback() {
public void call (BodyCompiler context) {
compile(classVarDeclNode.getValueNode(), context, true );
}
};
context.declareClassVariable(classVarDeclNode.getName(), value);
if (!expr) context.consumeCurrentValue();
}
public void compileClassVarDeclAssignment (Node node, BodyCompiler context) {
ClassVarDeclNode classVarDeclNode = (ClassVarDeclNode) node;
context.declareClassVariable(classVarDeclNode.getName());
context.consumeCurrentValue();
}
public void compileConstDecl (Node node, BodyCompiler context, boolean expr) {
final ConstDeclNode constDeclNode = (ConstDeclNode) node;
final Node constNode = constDeclNode.getConstNode();
if (constNode == null ) {
context.assignConstantInCurrent(constDeclNode.getName(), new CompilerCallback() {
public void call (BodyCompiler context) {
compile(constDeclNode.getValueNode(), context, true );
}
});
} else if (constNode.getNodeType() == NodeType.COLON2NODE) {
context.assignConstantInModule(constDeclNode.getName(), new CompilerCallback() {
public void call (BodyCompiler context) {
compile(constDeclNode.getValueNode(), context, true );
compile(((Colon2Node) constNode).getLeftNode(), context, true );
}
});
} else {
context.assignConstantInObject(constDeclNode.getName(), new CompilerCallback() {
public void call (BodyCompiler context) {
compile(constDeclNode.getValueNode(), context, true );
}
});
}
if (!expr) context.consumeCurrentValue();
}
public void compileConstDeclAssignment (Node node, BodyCompiler context) {
ConstDeclNode constDeclNode = (ConstDeclNode) node;
Node constNode = constDeclNode.getConstNode();
if (constNode == null ) {
context.mAssignConstantInCurrent(constDeclNode.getName());
} else if (constNode.getNodeType() == NodeType.COLON2NODE) {
compile(((Colon2Node) constNode).getLeftNode(), context,true );
context.mAssignConstantInModule(constDeclNode.getName());
} else {
context.mAssignConstantInObject(constDeclNode.getName());
}
context.consumeCurrentValue();
}
public void compileConst (Node node, BodyCompiler context, boolean expr) {
ConstNode constNode = (ConstNode) node;
context.retrieveConstant(constNode.getName());
if (!expr) context.consumeCurrentValue();
}
public void compileColon2 (Node node, BodyCompiler context, boolean expr) {
final Colon2Node iVisited = (Colon2Node) node;
Node leftNode = iVisited.getLeftNode();
final String name = iVisited.getName();
if (leftNode == null ) {
context.loadObject();
context.retrieveConstantFromModule(name);
} else {
if (node instanceof Colon2ConstNode) {
compile(iVisited.getLeftNode(), context, true );
context.retrieveConstantFromModule(name);
} else if (node instanceof Colon2MethodNode) {
final CompilerCallback receiverCallback = new CompilerCallback() {
public void call (BodyCompiler context) {
compile(iVisited.getLeftNode(), context,true );
}
};
context.getInvocationCompiler().invokeDynamic(name, receiverCallback, null , CallType.FUNCTIONAL, null , false );
} else {
compile(iVisited.getLeftNode(), context, true );
}
}
if (!expr) context.consumeCurrentValue();
}
public void compileColon3 (Node node, BodyCompiler context, boolean expr) {
Colon3Node iVisited = (Colon3Node) node;
String name = iVisited.getName();
context.retrieveConstantFromObject(name);
if (!expr) context.consumeCurrentValue();
}
public void compileGetDefinitionBase (final Node node, BodyCompiler context) {
switch (node.getNodeType()) {
case CLASSVARASGNNODE:
case CLASSVARDECLNODE:
case CONSTDECLNODE:
case DASGNNODE:
case GLOBALASGNNODE:
case LOCALASGNNODE:
case MULTIPLEASGNNODE:
case OPASGNNODE:
case OPELEMENTASGNNODE:
case DVARNODE:
case FALSENODE:
case TRUENODE:
case LOCALVARNODE:
case INSTVARNODE:
case BACKREFNODE:
case SELFNODE:
case VCALLNODE:
case YIELDNODE:
case GLOBALVARNODE:
case CONSTNODE:
case FCALLNODE:
case CLASSVARNODE:
case COLON2NODE:
case COLON3NODE:
case CALLNODE:
compileGetDefinition(node, context);
break ;
case NEWLINENODE:
compileGetDefinitionBase(((NewlineNode)node).getNextNode(), context);
break ;
default :
compileGetDefinition(node, context);
}
}
public void compileDefined (final Node node, BodyCompiler context, boolean expr) {
if (expr) {
compileGetDefinitionBase(((DefinedNode) node).getExpressionNode(), context);
context.nullToNil();
}
}
public void compileGetArgumentDefinition (final Node node, BodyCompiler context, String type) {
if (node == null ) {
context.pushDefinedMessage(DefinedMessage.byText(type));
} else if (node instanceof ArrayNode) {
Object endToken = context.getNewEnding();
for (int i = 0 ; i < ((ArrayNode) node).size(); i++) {
Node iterNode = ((ArrayNode) node).get(i);
compileGetDefinition(iterNode, context);
context.ifNull(endToken);
}
context.pushDefinedMessage(DefinedMessage.byText(type));
Object realToken = context.getNewEnding();
context.go(realToken);
context.setEnding(endToken);
context.pushNull();
context.setEnding(realToken);
} else {
compileGetDefinition(node, context);
Object endToken = context.getNewEnding();
context.ifNull(endToken);
context.pushDefinedMessage(DefinedMessage.byText(type));
Object realToken = context.getNewEnding();
context.go(realToken);
context.setEnding(endToken);
context.pushNull();
context.setEnding(realToken);
}
}
public void compileGetDefinition (final Node node, BodyCompiler context) {
switch (node.getNodeType()) {
case CLASSVARASGNNODE:
case CLASSVARDECLNODE:
case CONSTDECLNODE:
case DASGNNODE:
case GLOBALASGNNODE:
case LOCALASGNNODE:
case MULTIPLEASGNNODE:
case MULTIPLEASGN19NODE:
case OPASGNNODE:
case OPASGNANDNODE:
case OPASGNORNODE:
case OPELEMENTASGNNODE:
case INSTASGNNODE:
context.pushDefinedMessage(DefinedMessage.ASSIGNMENT);
break ;
case ANDNODE:
case ORNODE:
case DSTRNODE:
case DREGEXPNODE:
compileDefinedAndOrDStrDRegexp(node, context);
break ;
case NOTNODE:
{
context.rescue(new BranchCallback() {
public void branch (BodyCompiler context) {
compile(node, context, false );
context.pushDefinedMessage(DefinedMessage.EXPRESSION);
}
}, JumpException.class,
new BranchCallback() {
public void branch (BodyCompiler context) {
context.pushNull();
}
}, RubyString.class);
context.definedNot();
break ;
}
case BACKREFNODE:
compileDefinedBackref(node, context);
break ;
case DVARNODE:
compileDefinedDVar(node, context);
break ;
case FALSENODE:
context.pushDefinedMessage(DefinedMessage.FALSE);
break ;
case TRUENODE:
context.pushDefinedMessage(DefinedMessage.TRUE);
break ;
case LOCALVARNODE:
context.pushDefinedMessage(DefinedMessage.LOCAL_VARIABLE);
break ;
case MATCH2NODE:
case MATCH3NODE:
context.pushDefinedMessage(DefinedMessage.METHOD);
break ;
case NILNODE:
context.pushDefinedMessage(DefinedMessage.NIL);
break ;
case NTHREFNODE:
compileDefinedNthref(node, context);
break ;
case SELFNODE:
context.pushDefinedMessage(DefinedMessage.SELF);
break ;
case VCALLNODE:
context.loadSelf();
context.isMethodBound(((VCallNode) node).getName(),
new BranchCallback() {
public void branch (BodyCompiler context) {
context.pushDefinedMessage(DefinedMessage.METHOD);
}
},
new BranchCallback() {
public void branch (BodyCompiler context) {
context.pushNull();
}
});
break ;
case YIELDNODE:
context.hasBlock(new BranchCallback() {
public void branch (BodyCompiler context) {
context.pushDefinedMessage(DefinedMessage.YIELD);
}
},
new BranchCallback() {
public void branch (BodyCompiler context) {
context.pushNull();
}
});
break ;
case GLOBALVARNODE:
context.isGlobalDefined(((GlobalVarNode) node).getName(),
new BranchCallback() {
public void branch (BodyCompiler context) {
context.pushDefinedMessage(DefinedMessage.GLOBAL_VARIABLE);
}
},
new BranchCallback() {
public void branch (BodyCompiler context) {
context.pushNull();
}
});
break ;
case INSTVARNODE:
context.isInstanceVariableDefined(((InstVarNode) node).getName());
break ;
case CONSTNODE:
context.isConstantDefined(((ConstNode) node).getName());
break ;
case FCALLNODE:
context.loadSelf();
context.isMethodBound(((FCallNode) node).getName(),
new BranchCallback() {
public void branch (BodyCompiler context) {
compileGetArgumentDefinition(((FCallNode) node).getArgsNode(), context, "method" );
}
},
new BranchCallback() {
public void branch (BodyCompiler context) {
context.pushNull();
}
});
break ;
case COLON3NODE:
case COLON2NODE:
{
final Colon3Node iVisited = (Colon3Node) node;
final String name = iVisited.getName();
BranchCallback setup = new BranchCallback() {
public void branch (BodyCompiler context) {
if (iVisited instanceof Colon2Node) {
final Node leftNode = ((Colon2Node) iVisited).getLeftNode();
compile(leftNode, context,true );
} else {
context.loadObject();
}
}
};
context.isConstantBranch(setup, name);
break ;
}
case CALLNODE:
compileDefinedCall(node, context);
break ;
case CLASSVARNODE:
{
ClassVarNode iVisited = (ClassVarNode) node;
final Object ending = context.getNewEnding();
final Object failure = context.getNewEnding();
final Object singleton = context.getNewEnding();
Object second = context.getNewEnding();
Object third = context.getNewEnding();
context.loadCurrentModule();
context.duplicateCurrentValue();
context.ifNotNull(second);
context.consumeCurrentValue();
context.loadSelf();
context.metaclass();
context.duplicateCurrentValue();
context.isClassVarDefined(iVisited.getName(),
new BranchCallback() {
public void branch (BodyCompiler context) {
context.consumeCurrentValue();
context.pushDefinedMessage(DefinedMessage.CLASS_VARIABLE);
context.go(ending);
}
},
new BranchCallback() {
public void branch (BodyCompiler context) {
}
});
context.setEnding(second);
context.duplicateCurrentValue();
context.isClassVarDefined(iVisited.getName(),
new BranchCallback() {
public void branch (BodyCompiler context) {
context.consumeCurrentValue();
context.pushDefinedMessage(DefinedMessage.CLASS_VARIABLE);
context.go(ending);
}
},
new BranchCallback() {
public void branch (BodyCompiler context) {
}
});
context.setEnding(third);
context.duplicateCurrentValue();
context.ifSingleton(singleton);
context.consumeCurrentValue();
context.go(failure);
context.setEnding(singleton);
context.attached();
context.notIsModuleAndClassVarDefined(iVisited.getName(), failure);
context.pushDefinedMessage(DefinedMessage.CLASS_VARIABLE);
context.go(ending);
context.setEnding(failure);
context.pushNull();
context.setEnding(ending);
}
break ;
case ZSUPERNODE:
{
Object fail = context.getNewEnding();
Object fail2 = context.getNewEnding();
Object fail_easy = context.getNewEnding();
Object ending = context.getNewEnding();
context.getFrameName();
context.duplicateCurrentValue();
context.ifNull(fail);
context.getFrameKlazz();
context.duplicateCurrentValue();
context.ifNull(fail2);
context.superClass();
context.ifNotSuperMethodBound(fail_easy);
context.pushDefinedMessage(DefinedMessage.SUPER);
context.go(ending);
context.setEnding(fail2);
context.consumeCurrentValue();
context.setEnding(fail);
context.consumeCurrentValue();
context.setEnding(fail_easy);
context.pushNull();
context.setEnding(ending);
}
break ;
case SUPERNODE:
{
Object fail = context.getNewEnding();
Object fail2 = context.getNewEnding();
Object fail_easy = context.getNewEnding();
Object ending = context.getNewEnding();
context.getFrameName();
context.duplicateCurrentValue();
context.ifNull(fail);
context.getFrameKlazz();
context.duplicateCurrentValue();
context.ifNull(fail2);
context.superClass();
context.ifNotSuperMethodBound(fail_easy);
compileGetArgumentDefinition(((SuperNode) node).getArgsNode(), context, "super" );
context.go(ending);
context.setEnding(fail2);
context.consumeCurrentValue();
context.setEnding(fail);
context.consumeCurrentValue();
context.setEnding(fail_easy);
context.pushNull();
context.setEnding(ending);
break ;
}
case ATTRASSIGNNODE:
{
final AttrAssignNode iVisited = (AttrAssignNode) node;
Object isnull = context.getNewEnding();
Object ending = context.getNewEnding();
compileGetDefinition(iVisited.getReceiverNode(), context);
context.ifNull(isnull);
context.rescue(new BranchCallback() {
public void branch (BodyCompiler context) {
compile(iVisited.getReceiverNode(), context,true );
context.duplicateCurrentValue();
context.metaclass();
context.duplicateCurrentValue();
context.getVisibilityFor(iVisited.getName());
context.duplicateCurrentValue();
final Object isfalse = context.getNewEnding();
Object isreal = context.getNewEnding();
Object ending = context.getNewEnding();
context.isPrivate(isfalse, 3 );
context.isNotProtected(isreal, 1 );
context.selfIsKindOf(isreal);
context.consumeCurrentValue();
context.go(isfalse);
context.setEnding(isreal);
context.isMethodBound(iVisited.getName(), new BranchCallback() {
public void branch (BodyCompiler context) {
compileGetArgumentDefinition(iVisited.getArgsNode(), context, "assignment" );
}
},
new BranchCallback() {
public void branch (BodyCompiler context) {
context.go(isfalse);
}
});
context.go(ending);
context.setEnding(isfalse);
context.pushNull();
context.setEnding(ending);
}
}, JumpException.class,
new BranchCallback() {
public void branch (BodyCompiler context) {
context.pushNull();
}
}, RubyString.class);
context.go(ending);
context.setEnding(isnull);
context.pushNull();
context.setEnding(ending);
break ;
}
default :
context.rescue(new BranchCallback() {
public void branch (BodyCompiler context) {
compile(node, context,true );
context.consumeCurrentValue();
context.pushNull();
}
}, JumpException.class,
new BranchCallback() {
public void branch (BodyCompiler context) {
context.pushNull();
}
}, RubyString.class);
context.consumeCurrentValue();
context.pushDefinedMessage(DefinedMessage.EXPRESSION);
}
}
protected void compileDefinedAndOrDStrDRegexp (final Node node, BodyCompiler context) {
context.rescue(new BranchCallback() {
public void branch (BodyCompiler context) {
compile(node, context, false );
context.pushDefinedMessage(DefinedMessage.EXPRESSION);
}
}, JumpException.class,
new BranchCallback() {
public void branch (BodyCompiler context) {
context.pushNull();
}
}, RubyString.class);
}
protected void compileDefinedCall (final Node node, BodyCompiler context) {
final CallNode iVisited = (CallNode) node;
Object isnull = context.getNewEnding();
Object ending = context.getNewEnding();
compileGetDefinition(iVisited.getReceiverNode(), context);
context.ifNull(isnull);
context.rescue(new BranchCallback() {
public void branch (BodyCompiler context) {
compile(iVisited.getReceiverNode(), context, true );
context.definedCall(iVisited.getName());
}
}, JumpException.class,
new BranchCallback() {
public void branch (BodyCompiler context) {
context.pushNull();
}
}, RubyString.class);
context.go(ending);
context.setEnding(isnull);
context.pushNull();
context.setEnding(ending);
}
protected void compileDefinedDVar (final Node node, BodyCompiler context) {
context.pushDefinedMessage(DefinedMessage.LOCAL_VARIABLE_IN_BLOCK);
}
protected void compileDefinedBackref (final Node node, BodyCompiler context) {
context.backref();
context.isInstanceOf(RubyMatchData.class,
new BranchCallback() {
public void branch (BodyCompiler context) {
context.pushDefinedMessage(DefinedMessage.byText("$" + ((BackRefNode) node).getType()));
}
},
new BranchCallback() {
public void branch (BodyCompiler context) {
context.pushNull();
}
});
}
protected void compileDefinedNthref (final Node node, BodyCompiler context) {
context.isCaptured(((NthRefNode) node).getMatchNumber(),
new BranchCallback() {
public void branch (BodyCompiler context) {
context.pushDefinedMessage(DefinedMessage.byText("$" + ((NthRefNode) node).getMatchNumber()));
}
},
new BranchCallback() {
public void branch (BodyCompiler context) {
context.pushNull();
}
});
}
public void compileDAsgn (Node node, BodyCompiler context, boolean expr) {
final DAsgnNode dasgnNode = (DAsgnNode) node;
CompilerCallback value = new CompilerCallback() {
public void call (BodyCompiler context) {
compile(dasgnNode.getValueNode(), context, true );
}
};
context.getVariableCompiler().assignLocalVariable(dasgnNode.getIndex(), dasgnNode.getDepth(), value, expr);
}
public void compileDAsgnAssignment (Node node, BodyCompiler context, boolean expr) {
DAsgnNode dasgnNode = (DAsgnNode) node;
context.getVariableCompiler().assignLocalVariable(dasgnNode.getIndex(), dasgnNode.getDepth(), expr);
}
private Node currentBodyNode;
public void compileDefn (Node node, BodyCompiler context, boolean expr) {
final DefnNode defnNode = (DefnNode) node;
final ArgsNode argsNode = defnNode.getArgsNode();
CompilerCallback body = new CompilerCallback() {
public void call (BodyCompiler context) {
if (defnNode.getBodyNode() != null ) {
Node oldBodyNode = currentBodyNode;
currentBodyNode = defnNode.getBodyNode();
if (defnNode.getBodyNode() instanceof RescueNode) {
compileRescueInternal(defnNode.getBodyNode(), context, true );
} else {
compile(defnNode.getBodyNode(), context, true );
}
currentBodyNode = oldBodyNode;
} else {
context.loadNil();
}
}
};
CompilerCallback args = new CompilerCallback() {
public void call (BodyCompiler context) {
compileArgs(argsNode, context, true );
}
};
ASTInspector inspector = new ASTInspector();
inspector.inspect(defnNode.getArgsNode());
if (defnNode.getBodyNode() instanceof RescueNode) {
RescueNode rescueNode = (RescueNode)defnNode.getBodyNode();
inspector.inspect(rescueNode.getBodyNode());
inspector.inspect(rescueNode.getElseNode());
inspector.inspect(rescueNode.getRescueNode());
} else {
inspector.inspect(defnNode.getBodyNode());
}
context.defineNewMethod(
defnNode.getName(), defnNode.getArgsNode().getArity().getValue(),
defnNode.getScope(), body, args, null , inspector, isAtRoot,
defnNode.getPosition().getFile(), defnNode.getPosition().getStartLine(),
Helpers.encodeParameterList(argsNode));
if (!expr) context.consumeCurrentValue();
}
public void compileDefs (Node node, BodyCompiler context, boolean expr) {
final DefsNode defsNode = (DefsNode) node;
final ArgsNode argsNode = defsNode.getArgsNode();
CompilerCallback receiver = new CompilerCallback() {
public void call (BodyCompiler context) {
compile(defsNode.getReceiverNode(), context, true );
}
};
CompilerCallback body = new CompilerCallback() {
public void call (BodyCompiler context) {
if (defsNode.getBodyNode() != null ) {
if (defsNode.getBodyNode() instanceof RescueNode) {
compileRescueInternal(defsNode.getBodyNode(), context, true );
} else {
compile(defsNode.getBodyNode(), context, true );
}
} else {
context.loadNil();
}
}
};
CompilerCallback args = new CompilerCallback() {
public void call (BodyCompiler context) {
compileArgs(argsNode, context, true );
}
};
ASTInspector inspector = new ASTInspector();
inspector.inspect(defsNode.getArgsNode());
if (defsNode.getBodyNode() instanceof RescueNode) {
RescueNode rescueNode = (RescueNode)defsNode.getBodyNode();
inspector.inspect(rescueNode.getBodyNode());
inspector.inspect(rescueNode.getElseNode());
inspector.inspect(rescueNode.getRescueNode());
} else {
inspector.inspect(defsNode.getBodyNode());
}
context.defineNewMethod(
defsNode.getName(), defsNode.getArgsNode().getArity().getValue(),
defsNode.getScope(), body, args, receiver, inspector, false ,
defsNode.getPosition().getFile(), defsNode.getPosition().getStartLine(),
Helpers.encodeParameterList(argsNode));
if (!expr) context.consumeCurrentValue();
}
public void compileArgs (Node node, BodyCompiler context, boolean expr) {
final ArgsNode argsNode = (ArgsNode) node;
final int required = argsNode.getRequiredArgsCount();
final int opt = argsNode.getOptionalArgsCount();
final int rest = argsNode.getRestArg();
ArrayCallback requiredAssignment = null ;
ArrayCallback optionalGiven = null ;
ArrayCallback optionalNotGiven = null ;
CompilerCallback restAssignment = null ;
CompilerCallback blockAssignment = null ;
if (required > 0 ) {
requiredAssignment = new ArrayCallback() {
public void nextValue (BodyCompiler context, Object object, int index) {
context.getVariableCompiler().assignLocalVariable(index, false );
}
};
}
if (opt > 0 ) {
optionalGiven = new ArrayCallback() {
public void nextValue (BodyCompiler context, Object object, int index) {
Node optArg = ((ListNode) object).get(index);
compileAssignment(optArg, context);
}
};
optionalNotGiven = new ArrayCallback() {
public void nextValue (BodyCompiler context, Object object, int index) {
Node optArg = ((ListNode) object).get(index);
compile(optArg, context, false );
}
};
}
if (rest > -1 ) {
restAssignment = new CompilerCallback() {
public void call (BodyCompiler context) {
context.getVariableCompiler().assignLocalVariable(argsNode.getRestArg(), false );
}
};
}
if (argsNode.getBlock() != null ) {
blockAssignment = new CompilerCallback() {
public void call (BodyCompiler context) {
context.getVariableCompiler().assignLocalVariable(argsNode.getBlock().getCount(), false );
}
};
}
context.getVariableCompiler().checkMethodArity(required, opt, rest);
context.getVariableCompiler().assignMethodArguments(argsNode.getPre(),
argsNode.getRequiredArgsCount(),
argsNode.getOptArgs(),
argsNode.getOptionalArgsCount(),
requiredAssignment,
optionalGiven,
optionalNotGiven,
restAssignment,
blockAssignment);
if (!expr) context.consumeCurrentValue();
}
public void compileDot (Node node, BodyCompiler context, boolean expr) {
final DotNode dotNode = (DotNode) node;
if (expr) {
CompilerCallback beginEndCallback = new CompilerCallback() {
public void call (BodyCompiler context) {
compile(dotNode.getBeginNode(), context, true );
compile(dotNode.getEndNode(), context, true );
}
};
context.createNewRange(beginEndCallback, dotNode.isExclusive());
}
}
public void compileDRegexp (Node node, BodyCompiler context, boolean expr) {
final DRegexpNode dregexpNode = (DRegexpNode) node;
CompilerCallback createStringCallback = new CompilerCallback() {
public void call (BodyCompiler context) {
ArrayCallback dstrCallback = new ArrayCallback() {
public void nextValue (BodyCompiler context, Object sourceArray,
int index) {
compile(dregexpNode.get(index), context, true );
}
};
Encoding enc = null ;
if (dregexpNode.is19()) {
enc = dregexpNode.getEncoding();
}
context.createNewString(dstrCallback, dregexpNode.size(), enc);
}
};
if (expr) {
context.createNewRegexp(createStringCallback, dregexpNode.getOptions().toEmbeddedOptions());
} else {
for (Node nextNode : dregexpNode.childNodes()) {
compile(nextNode, context, false );
}
}
}
public void compileDNode (Node node, BodyCompiler context, boolean expr) {
final DNode dNode = (DNode) node;
ArrayCallback dstrCallback = new ArrayCallback() {
public void nextValue (BodyCompiler context, Object sourceArray,
int index) {
Node nextNode = dNode.get(index);
switch (nextNode.getNodeType()) {
case STRNODE:
context.appendByteList(((StrNode) nextNode).getValue(), ((StrNode) nextNode).getCodeRange(), dNode.is19());
break ;
case EVSTRNODE:
compile(((EvStrNode)nextNode).getBody(), context, true );
context.shortcutAppend(dNode.is19());
break ;
default :
compile(nextNode, context, true );
context.appendObject(dNode.is19());
}
}
};
if (expr) {
Encoding enc = null ;
if (dNode.is19()) {
enc = dNode.getEncoding();
}
context.buildNewString(dstrCallback, dNode.size(), enc);
} else {
for (Node nextNode : dNode.childNodes()) {
compile(nextNode, context, false );
}
}
}
public void compileDStr (Node node, BodyCompiler context, boolean expr) {
compileDNode(node, context, expr);
}
public void compileDSymbol (Node node, BodyCompiler context, boolean expr) {
final DSymbolNode dsymbolNode = (DSymbolNode) node;
compileDNode(dsymbolNode, context, expr);
if (expr) {
context.stringToSymbol(dsymbolNode.is19());
}
}
public void compileDVar (Node node, BodyCompiler context, boolean expr) {
DVarNode dvarNode = (DVarNode) node;
if (expr) context.getVariableCompiler().retrieveLocalVariable(dvarNode.getIndex(), dvarNode.getDepth());
}
public void compileDXStr (Node node, BodyCompiler context, boolean expr) {
final DXStrNode dxstrNode = (DXStrNode) node;
ArgumentsCallback argsCallback = new ArgumentsCallback() {
public int getArity () {
return 1 ;
}
public void call (BodyCompiler context) {
compileDNode(dxstrNode, context, true );
}
};
context.getInvocationCompiler().invokeDynamic("`" , null , argsCallback, CallType.FUNCTIONAL, null , false );
if (!expr) context.consumeCurrentValue();
}
public void compileEnsureNode (Node node, BodyCompiler context, boolean expr) {
final EnsureNode ensureNode = (EnsureNode) node;
if (ensureNode.getEnsureNode() != null ) {
context.performEnsure(new BranchCallback() {
public void branch (BodyCompiler context) {
if (ensureNode.getBodyNode() != null ) {
compile(ensureNode.getBodyNode(), context, true );
} else {
context.loadNil();
}
}
},
new BranchCallback() {
public void branch (BodyCompiler context) {
compile(ensureNode.getEnsureNode(), context, false );
}
});
} else {
if (ensureNode.getBodyNode() != null ) {
compile(ensureNode.getBodyNode(), context,true );
} else {
context.loadNil();
}
}
if (!expr) context.consumeCurrentValue();
}
public void compileEvStr (Node node, BodyCompiler context, boolean expr) {
final EvStrNode evStrNode = (EvStrNode) node;
compile(evStrNode.getBody(), context,true );
context.asString();
if (!expr) context.consumeCurrentValue();
}
public void compileFalse (Node node, BodyCompiler context, boolean expr) {
if (expr) {
context.loadFalse();
context.pollThreadEvents();
}
}
public void compileFCall (Node node, BodyCompiler context, boolean expr) {
final FCallNode fcallNode = (FCallNode) node;
ArgumentsCallback argsCallback = getArgsCallback(fcallNode.getArgsNode());
CompilerCallback closureArg = getBlock(fcallNode.getIterNode());
if (fcallNode instanceof SpecialArgs) {
context.getInvocationCompiler().invokeDynamicVarargs(fcallNode.getName(), null , argsCallback, CallType.FUNCTIONAL, closureArg, fcallNode.getIterNode() instanceof IterNode);
} else {
context.getInvocationCompiler().invokeDynamic(fcallNode.getName(), null , argsCallback, CallType.FUNCTIONAL, closureArg, fcallNode.getIterNode() instanceof IterNode);
}
if (!expr) context.consumeCurrentValue();
}
private CompilerCallback getBlock (Node node) {
if (node == null ) {
return null ;
}
switch (node.getNodeType()) {
case ITERNODE:
final IterNode iterNode = (IterNode) node;
return new CompilerCallback() {
public void call (BodyCompiler context) {
compile(iterNode, context,true );
}
};
case BLOCKPASSNODE:
final BlockPassNode blockPassNode = (BlockPassNode) node;
return new CompilerCallback() {
public void call (BodyCompiler context) {
compile(blockPassNode.getBodyNode(), context,true );
context.unwrapPassedBlock();
}
};
default :
throw new NotCompilableException("ERROR: Encountered a method with a non-block, non-blockpass iter node at: " + node);
}
}
public void compileFixnum (Node node, BodyCompiler context, boolean expr) {
FixnumNode fixnumNode = (FixnumNode) node;
if (expr) context.createNewFixnum(fixnumNode.getValue());
}
public void compileFlip (Node node, BodyCompiler context, boolean expr) {
final FlipNode flipNode = (FlipNode) node;
context.getVariableCompiler().retrieveLocalVariable(flipNode.getIndex(), flipNode.getDepth());
if (flipNode.isExclusive()) {
context.performBooleanBranch(new BranchCallback() {
public void branch (BodyCompiler context) {
compile(flipNode.getEndNode(), context,true );
context.performBooleanBranch(new BranchCallback() {
public void branch (BodyCompiler context) {
context.loadFalse();
context.getVariableCompiler().assignLocalVariable(flipNode.getIndex(), flipNode.getDepth(), false );
}
}, new BranchCallback() {
public void branch (BodyCompiler context) {
}
});
context.loadTrue();
}
}, new BranchCallback() {
public void branch (BodyCompiler context) {
compile(flipNode.getBeginNode(), context,true );
becomeTrueOrFalse(context);
context.getVariableCompiler().assignLocalVariable(flipNode.getIndex(), flipNode.getDepth(), true );
}
});
} else {
context.performBooleanBranch(new BranchCallback() {
public void branch (BodyCompiler context) {
compile(flipNode.getEndNode(), context,true );
context.performBooleanBranch(new BranchCallback() {
public void branch (BodyCompiler context) {
context.loadFalse();
context.getVariableCompiler().assignLocalVariable(flipNode.getIndex(), flipNode.getDepth(), false );
}
}, new BranchCallback() {
public void branch (BodyCompiler context) {
}
});
context.loadTrue();
}
}, new BranchCallback() {
public void branch (BodyCompiler context) {
compile(flipNode.getBeginNode(), context,true );
context.performBooleanBranch(new BranchCallback() {
public void branch (BodyCompiler context) {
compile(flipNode.getEndNode(), context,true );
flipTrueOrFalse(context);
context.getVariableCompiler().assignLocalVariable(flipNode.getIndex(), flipNode.getDepth(), false );
context.loadTrue();
}
}, new BranchCallback() {
public void branch (BodyCompiler context) {
context.loadFalse();
}
});
}
});
}
if (!expr) context.consumeCurrentValue();
}
private void becomeTrueOrFalse (BodyCompiler context) {
context.performBooleanBranch(new BranchCallback() {
public void branch (BodyCompiler context) {
context.loadTrue();
}
}, new BranchCallback() {
public void branch (BodyCompiler context) {
context.loadFalse();
}
});
}
private void flipTrueOrFalse (BodyCompiler context) {
context.performBooleanBranch(new BranchCallback() {
public void branch (BodyCompiler context) {
context.loadFalse();
}
}, new BranchCallback() {
public void branch (BodyCompiler context) {
context.loadTrue();
}
});
}
public void compileFloat (Node node, BodyCompiler context, boolean expr) {
FloatNode floatNode = (FloatNode) node;
if (expr) context.createNewFloat(floatNode.getValue());
}
public void compileFor (Node node, BodyCompiler context, boolean expr) {
final ForNode forNode = (ForNode) node;
CompilerCallback receiverCallback = new CompilerCallback() {
public void call (BodyCompiler context) {
compile(forNode.getIterNode(), context, true );
}
};
final CompilerCallback closureArg = new CompilerCallback() {
public void call (BodyCompiler context) {
compileForIter(forNode, context);
}
};
context.getInvocationCompiler().invokeDynamic("each" , receiverCallback, null , CallType.NORMAL, closureArg, true );
if (!expr) context.consumeCurrentValue();
}
public void compileForIter (Node node, BodyCompiler context) {
final ForNode forNode = (ForNode) node;
final CompilerCallback closureBody = new CompilerCallback() {
public void call (BodyCompiler context) {
if (forNode.getBodyNode() != null ) {
compile(forNode.getBodyNode(), context,true );
} else {
context.loadNil();
}
}
};
final CompilerCallback closureArgs = new CompilerCallback() {
public void call (BodyCompiler context) {
if (forNode.getVarNode() != null ) {
compileAssignment(forNode.getVarNode(), context);
context.consumeCurrentValue();
}
}
};
boolean hasMultipleArgsHead = false ;
if (forNode.getVarNode() instanceof MultipleAsgnNode) {
hasMultipleArgsHead = ((MultipleAsgnNode) forNode.getVarNode()).getHeadNode() != null ;
}
NodeType argsNodeId = null ;
if (forNode.getVarNode() != null ) {
argsNodeId = forNode.getVarNode().getNodeType();
}
ASTInspector inspector = new ASTInspector();
inspector.inspect(forNode.getBodyNode());
inspector.inspect(forNode.getVarNode());
inspector.setFlag(forNode, ASTInspector.CLOSURE);
context.createNewForLoop(Arity.procArityOf(forNode.getVarNode()).getValue(),
closureBody, closureArgs, hasMultipleArgsHead, argsNodeId, inspector);
}
public void compileGlobalAsgn (Node node, BodyCompiler context, boolean expr) {
final GlobalAsgnNode globalAsgnNode = (GlobalAsgnNode) node;
CompilerCallback value = new CompilerCallback() {
public void call (BodyCompiler context) {
compile(globalAsgnNode.getValueNode(), context, true );
}
};
if (globalAsgnNode.getName().length() == 2 ) {
switch (globalAsgnNode.getName().charAt(1 )) {
case '_' :
context.getVariableCompiler().assignLastLine(value);
break ;
case '~' :
context.getVariableCompiler().assignBackRef(value);
break ;
default :
context.assignGlobalVariable(globalAsgnNode.getName(), value);
}
} else {
context.assignGlobalVariable(globalAsgnNode.getName(), value);
}
if (!expr) context.consumeCurrentValue();
}
public void compileGlobalAsgnAssignment (Node node, BodyCompiler context) {
GlobalAsgnNode globalAsgnNode = (GlobalAsgnNode) node;
if (globalAsgnNode.getName().length() == 2 ) {
switch (globalAsgnNode.getName().charAt(1 )) {
case '_' :
context.getVariableCompiler().assignLastLine();
break ;
case '~' :
context.getVariableCompiler().assignBackRef();
break ;
default :
context.assignGlobalVariable(globalAsgnNode.getName());
}
} else {
context.assignGlobalVariable(globalAsgnNode.getName());
}
context.consumeCurrentValue();
}
public void compileGlobalVar (Node node, BodyCompiler context, boolean expr) {
GlobalVarNode globalVarNode = (GlobalVarNode) node;
if (expr) {
if (globalVarNode.getName().length() == 2 ) {
switch (globalVarNode.getName().charAt(1 )) {
case '_' :
context.getVariableCompiler().retrieveLastLine();
break ;
case '~' :
context.getVariableCompiler().retrieveBackRef();
break ;
default :
context.retrieveGlobalVariable(globalVarNode.getName());
}
} else {
context.retrieveGlobalVariable(globalVarNode.getName());
}
}
}
public void compileHash (Node node, BodyCompiler context, boolean expr) {
compileHashCommon((HashNode) node, context, expr);
}
protected void compileHashCommon (HashNode hashNode, BodyCompiler context, boolean expr) {
if (expr) {
if (hashNode.getListNode() == null || hashNode.getListNode().size() == 0 ) {
context.createEmptyHash();
return ;
}
ArrayCallback hashCallback = new ArrayCallback() {
public void nextValue (BodyCompiler context, Object sourceArray,
int index) {
ListNode listNode = (ListNode) sourceArray;
int keyIndex = index * 2 ;
compile(listNode.get(keyIndex), context, true );
compile(listNode.get(keyIndex + 1 ), context, true );
}
};
if (isListAllLiterals(hashNode.getListNode())) {
context.createNewLiteralHash(hashNode.getListNode(), hashCallback, hashNode.getListNode().size() / 2 );
} else {
context.createNewHash(hashNode.getListNode(), hashCallback, hashNode.getListNode().size() / 2 );
}
} else {
for (Node nextNode : hashNode.getListNode().childNodes()) {
compile(nextNode, context, false );
}
}
}
protected void createNewHash (BodyCompiler context, HashNode hashNode, ArrayCallback hashCallback) {
context.createNewHash(hashNode.getListNode(), hashCallback, hashNode.getListNode().size() / 2 );
}
public void compileIf (Node node, BodyCompiler context, final boolean expr) {
final IfNode ifNode = (IfNode) node;
Node actualCondition = ifNode.getCondition();
while (actualCondition instanceof NewlineNode) {
actualCondition = ((NewlineNode)actualCondition).getNextNode();
}
if (actualCondition.getNodeType().alwaysTrue()) {
compile(actualCondition, context, false );
compile(ifNode.getThenBody(), context, expr);
} else if (actualCondition.getNodeType().alwaysFalse()) {
compile(ifNode.getElseBody(), context, expr);
} else {
BranchCallback trueCallback = new BranchCallback() {
public void branch (BodyCompiler context) {
if (ifNode.getThenBody() != null ) {
compile(ifNode.getThenBody(), context, expr);
} else {
if (expr) context.loadNil();
}
}
};
BranchCallback falseCallback = new BranchCallback() {
public void branch (BodyCompiler context) {
if (ifNode.getElseBody() != null ) {
compile(ifNode.getElseBody(), context, expr);
} else {
if (expr) context.loadNil();
}
}
};
if (actualCondition.getNodeType() == NodeType.GLOBALVARNODE) {
context.performBooleanGlobalBranch(((GlobalVarNode)actualCondition).getName(), trueCallback, falseCallback);
} else if (actualCondition.getNodeType() == NodeType.CONSTNODE) {
context.performBooleanConstantBranch(((ConstNode)actualCondition).getName(), trueCallback, falseCallback);
} else {
compileCondition(actualCondition, context, true );
context.performBooleanBranch2(trueCallback, falseCallback);
}
}
}
public void compileCondition (Node node, BodyCompiler context, boolean expr) {
switch (node.getNodeType()) {
case CALLNODE:
{
final CallNode callNode = (CallNode)node;
if (callNode.getArgsNode() != null ) {
List args = callNode.getArgsNode().childNodes();
if (args.size() == 1 && args.get(0 ) instanceof FixnumNode) {
final FixnumNode fixnumNode = (FixnumNode)args.get(0 );
if (callNode.getName().equals("<" ) ||
callNode.getName().equals(">" ) ||
callNode.getName().equals("<=" ) ||
callNode.getName().equals(">=" ) ||
callNode.getName().equals("==" )) {
context.getInvocationCompiler().invokeBinaryBooleanFixnumRHS(
callNode.getName(),
new CompilerCallback() {
public void call (BodyCompiler context) {
compile(callNode.getReceiverNode(), context, true );
}
},
fixnumNode.getValue());
return ;
}
}
}
}
}
compile(node, context, expr);
context.isTrue();
}
public void compileInstAsgn (Node node, BodyCompiler context, boolean expr) {
final InstAsgnNode instAsgnNode = (InstAsgnNode) node;
CompilerCallback value = new CompilerCallback() {
public void call (BodyCompiler context) {
compile(instAsgnNode.getValueNode(), context, true );
}
};
context.assignInstanceVariable(instAsgnNode.getName(), value);
if (!expr) context.consumeCurrentValue();
}
public void compileInstAsgnAssignment (Node node, BodyCompiler context) {
InstAsgnNode instAsgnNode = (InstAsgnNode) node;
context.assignInstanceVariable(instAsgnNode.getName());
context.consumeCurrentValue();
}
public void compileInstVar (Node node, BodyCompiler context, boolean expr) {
InstVarNode instVarNode = (InstVarNode) node;
if (expr) context.retrieveInstanceVariable(instVarNode.getName());
}
public void compileIter (Node node, BodyCompiler context) {
final IterNode iterNode = (IterNode) node;
final CompilerCallback closureBody = new CompilerCallback() {
public void call (BodyCompiler context) {
if (iterNode.getBodyNode() != null ) {
compile(iterNode.getBodyNode(), context, true );
} else {
context.loadNil();
}
}
};
final CompilerCallback closureArgs = new CompilerCallback() {
public void call (BodyCompiler context) {
if (iterNode.getVarNode() != null ) {
compileAssignment(iterNode.getVarNode(), context);
} else {
context.consumeCurrentValue();
}
if (iterNode.getBlockVarNode() != null ) {
compileAssignment(iterNode.getBlockVarNode(), context);
} else {
context.consumeCurrentValue();
}
}
};
boolean hasMultipleArgsHead = false ;
if (iterNode.getVarNode() instanceof MultipleAsgnNode) {
hasMultipleArgsHead = ((MultipleAsgnNode) iterNode.getVarNode()).getHeadNode() != null ;
}
NodeType argsNodeId = BlockBody.getArgumentTypeWackyHack(iterNode);
ASTInspector inspector = new ASTInspector();
inspector.inspect(iterNode.getBodyNode());
inspector.inspect(iterNode.getVarNode());
context.createNewClosure(iterNode.getPosition().getFile(), iterNode.getPosition().getStartLine(), iterNode.getScope(), Arity.procArityOf(iterNode.getVarNode()).getValue(),
closureBody, closureArgs, hasMultipleArgsHead, argsNodeId, inspector);
}
public void compileLiteral (LiteralNode literal, BodyCompiler context) {
context.literal(literal.getName());
}
public void compileLocalAsgn (Node node, BodyCompiler context, boolean expr) {
final LocalAsgnNode localAsgnNode = (LocalAsgnNode) node;
if (ASTInspector.PRAGMAS.contains(localAsgnNode.getName())) {
if (expr) context.loadNil();
} else {
CompilerCallback value = new CompilerCallback() {
public void call (BodyCompiler context) {
compile(localAsgnNode.getValueNode(), context,true );
}
};
context.getVariableCompiler().assignLocalVariable(localAsgnNode.getIndex(), localAsgnNode.getDepth(), value, expr);
}
}
public void compileLocalAsgnAssignment (Node node, BodyCompiler context, boolean expr) {
LocalAsgnNode localAsgnNode = (LocalAsgnNode) node;
context.getVariableCompiler().assignLocalVariable(localAsgnNode.getIndex(), localAsgnNode.getDepth(), expr);
}
public void compileLocalVar (Node node, BodyCompiler context, boolean expr) {
LocalVarNode localVarNode = (LocalVarNode) node;
if (expr) context.getVariableCompiler().retrieveLocalVariable(localVarNode.getIndex(), localVarNode.getDepth());
}
public void compileMatch (Node node, BodyCompiler context, boolean expr) {
MatchNode matchNode = (MatchNode) node;
compile(matchNode.getRegexpNode(), context,true );
context.match(is1_9());
if (!expr) context.consumeCurrentValue();
}
public void compileMatch2 (Node node, BodyCompiler context, boolean expr) {
final Match2Node matchNode = (Match2Node) node;
compile(matchNode.getReceiverNode(), context,true );
CompilerCallback value = new CompilerCallback() {
public void call (BodyCompiler context) {
compile(matchNode.getValueNode(), context,true );
}
};
context.match2(value, is1_9());
if (!expr) context.consumeCurrentValue();
}
public void compileMatch3 (Node node, BodyCompiler context, boolean expr) {
Match3Node matchNode = (Match3Node) node;
compile(matchNode.getReceiverNode(), context,true );
compile(matchNode.getValueNode(), context,true );
context.match3(is1_9());
if (!expr) context.consumeCurrentValue();
}
public void compileModule (Node node, BodyCompiler context, boolean expr) {
final ModuleNode moduleNode = (ModuleNode) node;
final Node cpathNode = moduleNode.getCPath();
CompilerCallback bodyCallback = new CompilerCallback() {
public void call (BodyCompiler context) {
if (moduleNode.getBodyNode() != null ) {
compile(moduleNode.getBodyNode(), context,true );
}
context.loadNil();
}
};
CompilerCallback pathCallback = new CompilerCallback() {
public void call (BodyCompiler context) {
if (cpathNode instanceof Colon2Node) {
Node leftNode = ((Colon2Node) cpathNode).getLeftNode();
if (leftNode != null ) {
compile(leftNode, context,true );
} else {
context.loadNil();
}
} else if (cpathNode instanceof Colon3Node) {
context.loadObject();
} else {
context.loadNil();
}
}
};
ASTInspector inspector = new ASTInspector();
inspector.inspect(moduleNode.getBodyNode());
context.defineModule(moduleNode.getCPath().getName(), moduleNode.getScope(), pathCallback, bodyCallback, inspector, moduleNode.getPosition());
if (!expr) context.consumeCurrentValue();
}
public void compileMultipleAsgn (Node node, BodyCompiler context, boolean expr) {
MultipleAsgnNode multipleAsgnNode = (MultipleAsgnNode) node;
if (expr) {
if (RubyInstanceConfig.FAST_MULTIPLE_ASSIGNMENT) {
compileOptimizedMultipleAsgn(multipleAsgnNode, context, false );
context.loadTrue();
} else {
compileUnoptimizedMultipleAsgn(multipleAsgnNode, context, expr);
}
} else {
compileOptimizedMultipleAsgn(multipleAsgnNode, context, expr);
}
}
private void compileOptimizedMultipleAsgn (MultipleAsgnNode multipleAsgnNode, BodyCompiler context, boolean expr) {
if (multipleAsgnNode.getValueNode() instanceof ArrayNode) {
if (multipleAsgnNode.getHeadNode() != null && multipleAsgnNode.getArgsNode() == null ) {
if (multipleAsgnNode.getHeadNode().size() == ((ArrayNode)multipleAsgnNode.getValueNode()).size()) {
boolean normalAssigns = true ;
for (Node asgn : multipleAsgnNode.getHeadNode().childNodes()) {
if (asgn instanceof ListNode) {
normalAssigns = false ;
break ;
}
}
if (normalAssigns) {
int size = multipleAsgnNode.getHeadNode().size();
if (size >= 2 && size <= 10 ) {
ArrayNode values = (ArrayNode)multipleAsgnNode.getValueNode();
for (Node value : values.childNodes()) {
compile(value, context, true );
}
context.reverseValues(size);
for (Node asgn : multipleAsgnNode.getHeadNode().childNodes()) {
compileAssignment(asgn, context);
}
return ;
}
}
}
}
} else {
if (multipleAsgnNode.getHeadNode() != null &&
multipleAsgnNode.getHeadNode().size() == 1 &&
multipleAsgnNode.getValueNode() instanceof ToAryNode &&
multipleAsgnNode.getArgsNode() != null ) {
compile(multipleAsgnNode.getValueNode().childNodes().get(0 ), context, true );
if (multipleAsgnNode.getArgsNode() instanceof StarNode) {
context.preMultiAssign(1 , false );
compileAssignment(multipleAsgnNode.getHeadNode().childNodes().get(0 ), context);
} else {
context.preMultiAssign(1 , true );
compileAssignment(multipleAsgnNode.getHeadNode().childNodes().get(0 ), context);
compileAssignment(multipleAsgnNode.getArgsNode(), context);
}
return ;
}
}
compileUnoptimizedMultipleAsgn(multipleAsgnNode, context, expr);
}
private void compileUnoptimizedMultipleAsgn (MultipleAsgnNode multipleAsgnNode, BodyCompiler context, boolean expr) {
compile(multipleAsgnNode.getValueNode(), context, true );
compileMultipleAsgnAssignment(multipleAsgnNode, context, expr);
}
public void compileMultipleAsgnAssignment (Node node, BodyCompiler context, boolean expr) {
final MultipleAsgnNode multipleAsgnNode = (MultipleAsgnNode) node;
ArrayCallback headAssignCallback = new ArrayCallback() {
public void nextValue (BodyCompiler context, Object sourceArray,
int index) {
ListNode headNode = (ListNode) sourceArray;
Node assignNode = headNode.get(index);
compileAssignment(assignNode, context);
}
};
CompilerCallback argsCallback = new CompilerCallback() {
public void call (BodyCompiler context) {
Node argsNode = multipleAsgnNode.getArgsNode();
if (argsNode instanceof StarNode) {
context.consumeCurrentValue();
} else {
compileAssignment(argsNode, context);
}
}
};
if (multipleAsgnNode.getHeadNode() == null ) {
if (multipleAsgnNode.getArgsNode() == null ) {
throw new NotCompilableException("Something's wrong, multiple assignment with no head or args at: " + multipleAsgnNode.getPosition());
} else {
if (multipleAsgnNode.getArgsNode() instanceof StarNode) {
} else {
context.ensureMultipleAssignableRubyArray(multipleAsgnNode.getHeadNode() != null );
context.forEachInValueArray(0 , 0 , null , null , argsCallback);
}
}
} else {
context.ensureMultipleAssignableRubyArray(multipleAsgnNode.getHeadNode() != null );
if (multipleAsgnNode.getArgsNode() == null ) {
context.forEachInValueArray(0 , multipleAsgnNode.getHeadNode().size(), multipleAsgnNode.getHeadNode(), headAssignCallback, null );
} else {
context.forEachInValueArray(0 , multipleAsgnNode.getHeadNode().size(), multipleAsgnNode.getHeadNode(), headAssignCallback, argsCallback);
}
}
if (!expr) context.consumeCurrentValue();
}
public void compileNewline (Node node, BodyCompiler context, boolean expr) {
context.lineNumber(node.getPosition());
context.setLinePosition(node.getPosition());
NewlineNode newlineNode = (NewlineNode) node;
if (RubyInstanceConfig.FULL_TRACE_ENABLED) context.traceLine(newlineNode.getPosition());
compile(newlineNode.getNextNode(), context, expr);
}
public void compileNext (Node node, BodyCompiler context, boolean expr) {
final NextNode nextNode = (NextNode) node;
CompilerCallback valueCallback = new CompilerCallback() {
public void call (BodyCompiler context) {
if (nextNode.getValueNode() != null ) {
compile(nextNode.getValueNode(), context,true );
} else {
context.loadNil();
}
}
};
context.pollThreadEvents();
context.issueNextEvent(valueCallback);
if (!expr) context.consumeCurrentValue();
}
public void compileNthRef (Node node, BodyCompiler context, boolean expr) {
NthRefNode nthRefNode = (NthRefNode) node;
if (expr) context.nthRef(nthRefNode.getMatchNumber());
}
public void compileNil (Node node, BodyCompiler context, boolean expr) {
if (expr) {
context.loadNil();
}
}
public void compileNot (Node node, BodyCompiler context, boolean expr) {
NotNode notNode = (NotNode) node;
compile(notNode.getConditionNode(), context, true );
context.negateCurrentValue();
if (!expr) context.consumeCurrentValue();
}
public void compileOpAsgnAnd (Node node, BodyCompiler context, boolean expr) {
final BinaryOperatorNode andNode = (BinaryOperatorNode) node;
compile(andNode.getFirstNode(), context,true );
BranchCallback longCallback = new BranchCallback() {
public void branch (BodyCompiler context) {
compile(andNode.getSecondNode(), context,true );
}
};
context.performLogicalAnd(longCallback);
context.pollThreadEvents();
if (!expr) context.consumeCurrentValue();
}
public void compileOpAsgnOr (Node node, BodyCompiler context, boolean expr) {
final OpAsgnOrNode orNode = (OpAsgnOrNode) node;
if (needsDefinitionCheck(orNode.getFirstNode())) {
compileGetDefinitionBase(orNode.getFirstNode(), context);
context.isNull(new BranchCallback() {
public void branch (BodyCompiler context) {
compile(orNode.getSecondNode(), context,true );
}
}, new BranchCallback() {
public void branch (BodyCompiler context) {
compile(orNode.getFirstNode(), context,true );
context.duplicateCurrentValue();
context.performBooleanBranch(new BranchCallback() {
public void branch (BodyCompiler context) {
}
},
new BranchCallback() {
public void branch (BodyCompiler context) {
context.consumeCurrentValue();
compile(orNode.getSecondNode(), context,true );
}
});
}
});
} else {
compile(orNode.getFirstNode(), context,true );
context.duplicateCurrentValue();
context.performBooleanBranch(new BranchCallback() {
public void branch (BodyCompiler context) {
}
},
new BranchCallback() {
public void branch (BodyCompiler context) {
context.consumeCurrentValue();
compile(orNode.getSecondNode(), context,true );
}
});
}
context.pollThreadEvents();
if (!expr) context.consumeCurrentValue();
}
private boolean needsDefinitionCheck (Node node) {
switch (node.getNodeType()) {
case CLASSVARASGNNODE:
case CLASSVARDECLNODE:
case CONSTDECLNODE:
case DASGNNODE:
case GLOBALASGNNODE:
case LOCALASGNNODE:
case MULTIPLEASGNNODE:
case OPASGNNODE:
case OPELEMENTASGNNODE:
case DVARNODE:
case FALSENODE:
case TRUENODE:
case LOCALVARNODE:
case MATCH2NODE:
case MATCH3NODE:
case NILNODE:
case SELFNODE:
return false ;
default :
return true ;
}
}
public void compileOpAsgn (Node node, BodyCompiler context, boolean expr) {
final OpAsgnNode opAsgnNode = (OpAsgnNode) node;
if (opAsgnNode.getOperatorName().equals("||" )) {
compileOpAsgnWithOr(opAsgnNode, context, true );
} else if (opAsgnNode.getOperatorName().equals("&&" )) {
compileOpAsgnWithAnd(opAsgnNode, context, true );
} else {
compileOpAsgnWithMethod(opAsgnNode, context, true );
}
context.pollThreadEvents();
if (!expr) context.consumeCurrentValue();
}
public void compileOpAsgnWithOr (Node node, BodyCompiler context, boolean expr) {
final OpAsgnNode opAsgnNode = (OpAsgnNode) node;
final CompilerCallback receiverCallback = new CompilerCallback() {
public void call (BodyCompiler context) {
compile(opAsgnNode.getReceiverNode(), context, true );
}
};
ArgumentsCallback argsCallback = getArgsCallback(opAsgnNode.getValueNode());
context.getInvocationCompiler().invokeOpAsgnWithOr(opAsgnNode.getVariableName(), opAsgnNode.getVariableNameAsgn(), receiverCallback, argsCallback);
if (!expr) context.consumeCurrentValue();
}
public void compileOpAsgnWithAnd (Node node, BodyCompiler context, boolean expr) {
final OpAsgnNode opAsgnNode = (OpAsgnNode) node;
final CompilerCallback receiverCallback = new CompilerCallback() {
public void call (BodyCompiler context) {
compile(opAsgnNode.getReceiverNode(), context, true );
}
};
ArgumentsCallback argsCallback = getArgsCallback(opAsgnNode.getValueNode());
context.getInvocationCompiler().invokeOpAsgnWithAnd(opAsgnNode.getVariableName(), opAsgnNode.getVariableNameAsgn(), receiverCallback, argsCallback);
if (!expr) context.consumeCurrentValue();
}
public void compileOpAsgnWithMethod (Node node, BodyCompiler context, boolean expr) {
final OpAsgnNode opAsgnNode = (OpAsgnNode) node;
final CompilerCallback receiverCallback = new CompilerCallback() {
public void call (BodyCompiler context) {
compile(opAsgnNode.getReceiverNode(), context, true );
}
};
ArgumentsCallback argsCallback = new ArgumentsCallback() {
public int getArity () {
return 1 ;
}
public void call (BodyCompiler context) {
compile(opAsgnNode.getValueNode(), context, true );
}
};
context.getInvocationCompiler().invokeOpAsgnWithMethod(opAsgnNode.getOperatorName(), opAsgnNode.getVariableName(), opAsgnNode.getVariableNameAsgn(), receiverCallback, argsCallback);
if (!expr) context.consumeCurrentValue();
}
public void compileOpElementAsgn (Node node, BodyCompiler context, boolean expr) {
final OpElementAsgnNode opElementAsgnNode = (OpElementAsgnNode) node;
if (opElementAsgnNode.getOperatorName() == "||" ) {
compileOpElementAsgnWithOr(node, context, expr);
} else if (opElementAsgnNode.getOperatorName() == "&&" ) {
compileOpElementAsgnWithAnd(node, context, expr);
} else {
compileOpElementAsgnWithMethod(node, context, expr);
}
}
private class OpElementAsgnArgumentsCallback implements ArgumentsCallback {
private Node node;
public OpElementAsgnArgumentsCallback (Node node) {
this .node = node;
}
public int getArity () {
switch (node.getNodeType()) {
case ARGSCATNODE:
case ARGSPUSHNODE:
case SPLATNODE:
return -1 ;
case ARRAYNODE:
ArrayNode arrayNode = (ArrayNode)node;
if (arrayNode.size() == 0 ) {
return 0 ;
} else if (arrayNode.size() > 3 ) {
return -1 ;
} else {
return ((ArrayNode)node).size();
}
default :
return 1 ;
}
}
public void call (BodyCompiler context) {
if (getArity() == 1 ) {
compile(((ArrayNode)node).get(0 ), context,true );
} else {
compileArguments(node, context);
}
}
};
public void compileOpElementAsgnWithOr (Node node, BodyCompiler context, boolean expr) {
final OpElementAsgnNode opElementAsgnNode = (OpElementAsgnNode) node;
CompilerCallback receiverCallback = new CompilerCallback() {
public void call (BodyCompiler context) {
compile(opElementAsgnNode.getReceiverNode(), context, true );
}
};
ArgumentsCallback argsCallback = new OpElementAsgnArgumentsCallback(opElementAsgnNode.getArgsNode());
CompilerCallback valueCallback = new CompilerCallback() {
public void call (BodyCompiler context) {
compile(opElementAsgnNode.getValueNode(), context, true );
}
};
context.getInvocationCompiler().opElementAsgnWithOr(receiverCallback, argsCallback, valueCallback);
if (!expr) context.consumeCurrentValue();
}
public void compileOpElementAsgnWithAnd (Node node, BodyCompiler context, boolean expr) {
final OpElementAsgnNode opElementAsgnNode = (OpElementAsgnNode) node;
CompilerCallback receiverCallback = new CompilerCallback() {
public void call (BodyCompiler context) {
compile(opElementAsgnNode.getReceiverNode(), context, true );
}
};
ArgumentsCallback argsCallback = new OpElementAsgnArgumentsCallback(opElementAsgnNode.getArgsNode());
CompilerCallback valueCallback = new CompilerCallback() {
public void call (BodyCompiler context) {
compile(opElementAsgnNode.getValueNode(), context, true );
}
};
context.getInvocationCompiler().opElementAsgnWithAnd(receiverCallback, argsCallback, valueCallback);
if (!expr) context.consumeCurrentValue();
}
public void compileOpElementAsgnWithMethod (Node node, BodyCompiler context, boolean expr) {
final OpElementAsgnNode opElementAsgnNode = (OpElementAsgnNode) node;
CompilerCallback receiverCallback = new CompilerCallback() {
public void call (BodyCompiler context) {
compile(opElementAsgnNode.getReceiverNode(), context,true );
}
};
ArgumentsCallback argsCallback = getArgsCallback(opElementAsgnNode.getArgsNode());
CompilerCallback valueCallback = new CompilerCallback() {
public void call (BodyCompiler context) {
compile(opElementAsgnNode.getValueNode(), context,true );
}
};
context.getInvocationCompiler().opElementAsgnWithMethod(receiverCallback, argsCallback, valueCallback, opElementAsgnNode.getOperatorName());
if (!expr) context.consumeCurrentValue();
}
public void compileOr (Node node, BodyCompiler context, boolean expr) {
final OrNode orNode = (OrNode) node;
if (orNode.getFirstNode().getNodeType().alwaysTrue()) {
compile(orNode.getFirstNode(), context, expr);
} else if (orNode.getFirstNode().getNodeType().alwaysFalse()) {
compile(orNode.getFirstNode(), context, false );
compile(orNode.getSecondNode(), context, expr);
} else {
compile(orNode.getFirstNode(), context, true );
BranchCallback longCallback = new BranchCallback() {
public void branch (BodyCompiler context) {
compile(orNode.getSecondNode(), context, true );
}
};
context.performLogicalOr(longCallback);
if (!expr) context.consumeCurrentValue();
}
}
public void compilePostExe (Node node, BodyCompiler context, boolean expr) {
final PostExeNode postExeNode = (PostExeNode) node;
final CompilerCallback closureBody = new CompilerCallback() {
public void call (BodyCompiler context) {
if (postExeNode.getBodyNode() != null ) {
compile(postExeNode.getBodyNode(), context, true );
} else {
context.loadNil();
}
}
};
context.createNewEndBlock(closureBody);
if (!expr) context.consumeCurrentValue();
}
public void compilePreExe (Node node, BodyCompiler context, boolean expr) {
final PreExeNode preExeNode = (PreExeNode) node;
final CompilerCallback closureBody = new CompilerCallback() {
public void call (BodyCompiler context) {
if (preExeNode.getBodyNode() != null ) {
compile(preExeNode.getBodyNode(), context,true );
} else {
context.loadNil();
}
}
};
context.runBeginBlock(preExeNode.getScope(), closureBody);
if (!expr) context.consumeCurrentValue();
}
public void compileRedo (Node node, BodyCompiler context, boolean expr) {
context.issueRedoEvent();
if (!expr) context.consumeCurrentValue();
}
public void compileRegexp (Node node, BodyCompiler context, boolean expr) {
RegexpNode reNode = (RegexpNode) node;
if (expr) context.createNewRegexp(reNode.getValue(), reNode.getOptions().toEmbeddedOptions());
}
public void compileRescue (Node node, BodyCompiler context, boolean expr) {
compileRescueInternal(node, context, false );
if (!expr) context.consumeCurrentValue();
}
private void compileRescueInternal (Node node, BodyCompiler context, final boolean light) {
final RescueNode rescueNode = (RescueNode) node;
BranchCallback body = new BranchCallback() {
public void branch (BodyCompiler context) {
if (rescueNode.getBodyNode() != null ) {
compile(rescueNode.getBodyNode(), context, true );
} else {
context.loadNil();
}
}
};
BranchCallback elseBody = null ;
if (rescueNode.getElseNode() != null ) {
elseBody = new BranchCallback() {
public void branch (BodyCompiler context) {
context.consumeCurrentValue();
compile(rescueNode.getElseNode(), context, true );
}
};
}
BranchCallback rubyHandler = new BranchCallback() {
public void branch (BodyCompiler context) {
compileRescueBodyInternal(rescueNode.getRescueNode(), context, light);
}
};
ASTInspector rescueInspector = new ASTInspector();
rescueInspector.inspect(rescueNode.getRescueNode());
if (light) {
context.performRescueLight(body, rubyHandler, elseBody, rescueInspector.getFlag(ASTInspector.RETRY));
} else {
context.performRescue(body, rubyHandler, elseBody, rescueInspector.getFlag(ASTInspector.RETRY));
}
}
private void compileRescueBodyInternal (Node node, BodyCompiler context, final boolean light) {
final RescueBodyNode rescueBodyNode = (RescueBodyNode) node;
context.loadException();
final Node exceptionList = rescueBodyNode.getExceptionNodes();
ArgumentsCallback rescueArgs = getArgsCallback(exceptionList);
if (rescueArgs == null ) rescueArgs = new ArgumentsCallback() {
public int getArity () {
return 1 ;
}
public void call (BodyCompiler context) {
context.loadStandardError();
}
};
context.checkIsExceptionHandled(rescueArgs);
BranchCallback trueBranch = new BranchCallback() {
public void branch (BodyCompiler context) {
Node realBody = rescueBodyNode.getBodyNode();
if (realBody instanceof NewlineNode) {
context.setLinePosition(realBody.getPosition());
while (realBody instanceof NewlineNode) {
realBody = ((NewlineNode)realBody).getNextNode();
}
}
if (realBody.getNodeType().isImmediate()) {
compile(realBody, context, true );
context.clearErrorInfo();
} else {
List exceptionNodes = null ;
if (exceptionList != null ) {
exceptionNodes = exceptionList.childNodes();
}
if (exceptionNodes != null &&
exceptionNodes.size() == 1 &&
exceptionNodes.get(0 ) instanceof ConstNode &&
((ConstNode) exceptionNodes.get(0 )).getName().equals("NativeException" )) {
context.storeNativeExceptionInErrorInfo();
} else {
context.storeExceptionInErrorInfo();
}
if (light) {
compile(rescueBodyNode.getBodyNode(), context, true );
} else {
BodyCompiler nestedBody = context.outline("rescue_line_" + rescueBodyNode.getPosition().getStartLine());
compile(rescueBodyNode.getBodyNode(), nestedBody, true );
nestedBody.endBody();
}
context.clearErrorInfo();
}
}
};
BranchCallback falseBranch = new BranchCallback() {
public void branch (BodyCompiler context) {
if (rescueBodyNode.getOptRescueNode() != null ) {
compileRescueBodyInternal(rescueBodyNode.getOptRescueNode(), context, light);
} else {
context.rethrowException();
}
}
};
context.performBooleanBranch(trueBranch, falseBranch);
}
public void compileRetry (Node node, BodyCompiler context, boolean expr) {
context.pollThreadEvents();
context.issueRetryEvent();
if (!expr) context.consumeCurrentValue();
}
public void compileReturn (Node node, BodyCompiler context, boolean expr) {
ReturnNode returnNode = (ReturnNode) node;
if (returnNode.getValueNode() != null ) {
compile(returnNode.getValueNode(), context,true );
} else {
context.loadNil();
}
context.performReturn();
if (!expr) context.consumeCurrentValue();
}
public void compileRoot (Node node, ScriptCompiler context, ASTInspector inspector) {
compileRoot(node, context, inspector, true , true );
}
public void compileRoot (Node node, ScriptCompiler context, ASTInspector inspector, boolean load, boolean main) {
RootNode rootNode = (RootNode) node;
StaticScope staticScope = rootNode.getStaticScope();
context.startScript(staticScope);
staticScope.setRestArg(-2 );
BodyCompiler methodCompiler = context.startFileMethod(null , staticScope, inspector);
Node nextNode = rootNode.getBodyNode();
if (nextNode != null ) {
if (nextNode.getNodeType() == NodeType.BLOCKNODE) {
BlockNode blockNode = (BlockNode) nextNode;
for (int i = 0 ; i < blockNode.size(); i++) {
if ((i + 1 ) % RubyInstanceConfig.CHAINED_COMPILE_LINE_COUNT == 0 ) {
methodCompiler = methodCompiler.chainToMethod("__file__from_line_" + (i + 1 ));
}
compile(blockNode.get(i), methodCompiler, i + 1 >= blockNode.size());
}
} else {
compile(nextNode, methodCompiler,true );
}
} else {
methodCompiler.loadNil();
}
methodCompiler.endBody();
context.endScript(load, main);
}
public void compileSelf (Node node, BodyCompiler context, boolean expr) {
if (expr) context.retrieveSelf();
}
public void compileSplat (Node node, BodyCompiler context, boolean expr) {
SplatNode splatNode = (SplatNode) node;
compile(splatNode.getValue(), context, true );
splatCurrentValue(context);
if (!expr) context.consumeCurrentValue();
}
protected void splatCurrentValue (BodyCompiler context) {
context.splatCurrentValue("splatValue" );
}
public void compileStr (Node node, BodyCompiler context, boolean expr) {
StrNode strNode = (StrNode) node;
if (expr) {
if (strNode instanceof FileNode) {
context.loadFilename();
} else {
context.createNewString(strNode.getValue(), strNode.getCodeRange());
}
}
}
public void compileSuper (Node node, BodyCompiler context, boolean expr) {
final SuperNode superNode = (SuperNode) node;
ArgumentsCallback argsCallback = getArgsCallback(superNode.getArgsNode());
CompilerCallback closureArg = getBlock(superNode.getIterNode());
if (superNode.getArgsNode() instanceof ArgsCatNode) {
context.getInvocationCompiler().invokeDynamicVarargs(null , null , argsCallback, CallType.SUPER, closureArg, superNode.getIterNode() instanceof IterNode);
} else {
context.getInvocationCompiler().invokeDynamic(null , null , argsCallback, CallType.SUPER, closureArg, superNode.getIterNode() instanceof IterNode);
}
if (!expr) context.consumeCurrentValue();
}
public void compileSValue (Node node, BodyCompiler context, boolean expr) {
SValueNode svalueNode = (SValueNode) node;
compile(svalueNode.getValue(), context,true );
context.singlifySplattedValue();
if (!expr) context.consumeCurrentValue();
}
public void compileSymbol (Node node, BodyCompiler context, boolean expr) {
SymbolNode symbol = (SymbolNode)node;
context.createNewSymbol(symbol.getName(), symbol.getEncoding());
if (!expr) context.consumeCurrentValue();
}
public void compileToAry (Node node, BodyCompiler context, boolean expr) {
ToAryNode toAryNode = (ToAryNode) node;
compile(toAryNode.getValue(), context,true );
context.aryToAry();
if (!expr) context.consumeCurrentValue();
}
public void compileTrue (Node node, BodyCompiler context, boolean expr) {
if (expr) {
context.loadTrue();
context.pollThreadEvents();
}
}
public void compileUndef (final UndefNode undef, BodyCompiler context, boolean expr) {
CompilerCallback nameArg = new CompilerCallback() {
public void call (BodyCompiler context) {
compile(undef.getName(), context, true );
}
};
context.undefMethod(nameArg);
if (!expr) context.consumeCurrentValue();
}
public void compileUntil (Node node, BodyCompiler context, boolean expr) {
final UntilNode untilNode = (UntilNode) node;
if (untilNode.getConditionNode().getNodeType().alwaysTrue() &&
untilNode.evaluateAtStart()) {
compile(untilNode.getConditionNode(), context, false );
if (expr) context.loadNil();
} else {
BranchCallback condition = new BranchCallback() {
public void branch (BodyCompiler context) {
compile(untilNode.getConditionNode(), context, true );
context.negateCurrentValue();
}
};
BranchCallback body = new BranchCallback() {
public void branch (BodyCompiler context) {
if (untilNode.getBodyNode() != null ) {
compile(untilNode.getBodyNode(), context, true );
}
}
};
if (untilNode.containsNonlocalFlow) {
context.performBooleanLoopSafe(condition, body, untilNode.evaluateAtStart());
} else {
context.performBooleanLoopLight(condition, body, untilNode.evaluateAtStart());
}
context.pollThreadEvents();
if (!expr) context.consumeCurrentValue();
}
}
public void compileVAlias (Node node, BodyCompiler context, boolean expr) {
VAliasNode valiasNode = (VAliasNode) node;
context.aliasGlobal(valiasNode.getNewName(), valiasNode.getOldName());
if (!expr) context.consumeCurrentValue();
}
public void compileVCall (Node node, BodyCompiler context, boolean expr) {
VCallNode vcallNode = (VCallNode) node;
context.getInvocationCompiler().invokeDynamic(vcallNode.getName(), null , null , CallType.VARIABLE, null , false );
if (!expr) context.consumeCurrentValue();
}
public void compileWhile (Node node, BodyCompiler context, boolean expr) {
final WhileNode whileNode = (WhileNode) node;
if (whileNode.getConditionNode().getNodeType().alwaysFalse() &&
whileNode.evaluateAtStart()) {
if (expr) context.loadNil();
} else {
BranchCallback condition = new BranchCallback() {
public void branch (BodyCompiler context) {
compile(whileNode.getConditionNode(), context, true );
}
};
BranchCallback body = new BranchCallback() {
public void branch (BodyCompiler context) {
if (whileNode.getBodyNode() != null ) {
compile(whileNode.getBodyNode(), context, true );
}
}
};
if (whileNode.containsNonlocalFlow) {
context.performBooleanLoopSafe(condition, body, whileNode.evaluateAtStart());
} else {
context.performBooleanLoopLight(condition, body, whileNode.evaluateAtStart());
}
context.pollThreadEvents();
if (!expr) context.consumeCurrentValue();
}
}
public void compileXStr (Node node, BodyCompiler context, boolean expr) {
final XStrNode xstrNode = (XStrNode) node;
ArgumentsCallback argsCallback = new ArgumentsCallback() {
public int getArity () {
return 1 ;
}
public void call (BodyCompiler context) {
context.createNewString(xstrNode.getValue(), StringSupport.CR_UNKNOWN);
}
};
context.getInvocationCompiler().invokeDynamic("`" , null , argsCallback, CallType.FUNCTIONAL, null , false );
if (!expr) context.consumeCurrentValue();
}
public void compileYield (Node node, BodyCompiler context, boolean expr) {
final YieldNode yieldNode = (YieldNode) node;
ArgumentsCallback argsCallback = getArgsCallback(yieldNode.getArgsNode());
if (argsCallback == null || argsCallback.getArity() == 0 ) {
context.getInvocationCompiler().yieldSpecific(argsCallback);
} else if ((argsCallback.getArity() == 1 || argsCallback.getArity() == 2 || argsCallback.getArity() == 3 ) && yieldNode.getExpandArguments()) {
context.getInvocationCompiler().yieldSpecific(argsCallback);
} else {
CompilerCallback argsCallback2 = null ;
if (yieldNode.getArgsNode() != null ) {
argsCallback2 = new CompilerCallback() {
public void call (BodyCompiler context) {
compile(yieldNode.getArgsNode(), context,true );
}
};
}
context.getInvocationCompiler().yield(argsCallback2, yieldNode.getExpandArguments());
}
if (!expr) context.consumeCurrentValue();
}
public void compileZArray (Node node, BodyCompiler context, boolean expr) {
if (expr) {
context.createEmptyArray();
}
}
public void compileZSuper (Node node, BodyCompiler context, boolean expr) {
ZSuperNode zsuperNode = (ZSuperNode) node;
CompilerCallback closure = getBlock(zsuperNode.getIterNode());
context.callZSuper(closure);
if (!expr) context.consumeCurrentValue();
}
public void compileArgsCatArguments (Node node, BodyCompiler context, boolean expr) {
ArgsCatNode argsCatNode = (ArgsCatNode) node;
compileArguments(argsCatNode.getFirstNode(), context);
compile(argsCatNode.getSecondNode(), context,true );
context.argsCatToArguments();
if (!expr) context.consumeCurrentValue();
}
public void compileArgsPushArguments (Node node, BodyCompiler context, boolean expr) {
ArgsPushNode argsPushNode = (ArgsPushNode) node;
compileArguments(argsPushNode.getFirstNode(), context);
compile(argsPushNode.getSecondNode(), context,true );
context.appendToObjectArray();
if (!expr) context.consumeCurrentValue();
}
public void compileArrayArguments (Node node, BodyCompiler context, boolean expr) {
ArrayNode arrayNode = (ArrayNode) node;
ArrayCallback callback = new ArrayCallback() {
public void nextValue (BodyCompiler context, Object sourceArray, int index) {
Node node = (Node) ((Object[]) sourceArray)[index];
compile(node, context,true );
}
};
context.setLinePosition(arrayNode.getPosition());
context.createObjectArray(arrayNode.childNodes().toArray(), callback);
if (!expr) context.consumeCurrentValue();
}
public void compileSplatArguments (Node node, BodyCompiler context, boolean expr) {
SplatNode splatNode = (SplatNode) node;
compile(splatNode.getValue(), context,true );
context.splatToArguments();
if (!expr) context.consumeCurrentValue();
}
}