public boolean addGeneratedClosureConstructorCall(ConstructorCallExpression call) { ClassNode classNode = controller.getClassNode(); if (!classNode.declaresInterface(ClassHelper.GENERATED_CLOSURE_Type)) return false; AsmClassGenerator acg = controller.getAcg(); OperandStack operandStack = controller.getOperandStack(); MethodVisitor mv = controller.getMethodVisitor(); mv.visitVarInsn(ALOAD, 0); ClassNode callNode = classNode.getSuperClass(); TupleExpression arguments = (TupleExpression) call.getArguments(); if (arguments.getExpressions().size() != 2) throw new GroovyBugError( "expected 2 arguments for closure constructor super call, but got" + arguments.getExpressions().size()); arguments.getExpression(0).visit(acg); operandStack.box(); arguments.getExpression(1).visit(acg); operandStack.box(); // TODO: replace with normal String, p not needed Parameter p = new Parameter(ClassHelper.OBJECT_TYPE, "_p"); String descriptor = BytecodeHelper.getMethodDescriptor(ClassHelper.VOID_TYPE, new Parameter[] {p, p}); mv.visitMethodInsn( INVOKESPECIAL, BytecodeHelper.getClassInternalName(callNode), "<init>", descriptor, false); operandStack.remove(2); return true; }
public void visitMethodCallExpression(MethodCallExpression mce) { super.visitMethodCallExpression(mce); Expression aexp = mce.getArguments(); if (aexp instanceof TupleExpression) { TupleExpression arguments = (TupleExpression) aexp; for (Expression e : arguments.getExpressions()) { checkForInvalidDeclaration(e); } } else { checkForInvalidDeclaration(aexp); } }
private void checkFinalFieldAccess(Expression expression) { // currently not looking for PropertyExpression: dealt with at runtime using // ReadOnlyPropertyException if (!(expression instanceof VariableExpression) && !(expression instanceof TupleExpression)) return; if (expression instanceof TupleExpression) { TupleExpression list = (TupleExpression) expression; for (Expression e : list.getExpressions()) { checkForFinal(expression, (VariableExpression) e); } } else { checkForFinal(expression, (VariableExpression) expression); } }
public void visitDeclarationExpression(DeclarationExpression expression) { // visit right side first to avoid the usage of a // variable before its declaration expression.getRightExpression().visit(this); if (expression.isMultipleAssignmentDeclaration()) { TupleExpression list = expression.getTupleExpression(); for (Expression e : list.getExpressions()) { declare((VariableExpression) e); } } else { declare(expression.getVariableExpression()); } }
/** * If constructor does not define a call to super, then transform constructor to get String,int * parameters at beginning and add call super(String,int). */ private void transformConstructor(ConstructorNode ctor, boolean isAic) { boolean chainedThisConstructorCall = false; ConstructorCallExpression cce = null; if (ctor.firstStatementIsSpecialConstructorCall()) { Statement code = ctor.getFirstStatement(); cce = (ConstructorCallExpression) ((ExpressionStatement) code).getExpression(); if (cce.isSuperCall()) return; // must be call to this(...) chainedThisConstructorCall = true; } // we need to add parameters Parameter[] oldP = ctor.getParameters(); Parameter[] newP = new Parameter[oldP.length + 2]; String stringParameterName = getUniqueVariableName("__str", ctor.getCode()); newP[0] = new Parameter(ClassHelper.STRING_TYPE, stringParameterName); String intParameterName = getUniqueVariableName("__int", ctor.getCode()); newP[1] = new Parameter(ClassHelper.int_TYPE, intParameterName); System.arraycopy(oldP, 0, newP, 2, oldP.length); ctor.setParameters(newP); VariableExpression stringVariable = new VariableExpression(newP[0]); VariableExpression intVariable = new VariableExpression(newP[1]); if (chainedThisConstructorCall) { TupleExpression args = (TupleExpression) cce.getArguments(); List<Expression> argsExprs = args.getExpressions(); argsExprs.add(0, stringVariable); argsExprs.add(1, intVariable); } else { // add a super call List<Expression> args = new ArrayList<Expression>(); args.add(stringVariable); args.add(intVariable); if (isAic) { for (Parameter parameter : oldP) { args.add(new VariableExpression(parameter.getName())); } } cce = new ConstructorCallExpression(ClassNode.SUPER, new ArgumentListExpression(args)); BlockStatement code = new BlockStatement(); code.addStatement(new ExpressionStatement(cce)); Statement oldCode = ctor.getCode(); if (oldCode != null) code.addStatement(oldCode); ctor.setCode(code); } }
public MethodNode tryFindPossibleMethod(String name, Expression arguments) { int count = 0; if (arguments instanceof TupleExpression) { TupleExpression tuple = (TupleExpression) arguments; // TODO this won't strictly be true when using list expansion in argument calls count = tuple.getExpressions().size(); } else return null; MethodNode res = null; ClassNode node = this; TupleExpression args = (TupleExpression) arguments; do { for (MethodNode method : node.getMethods(name)) { if (method.getParameters().length == count) { boolean match = true; for (int i = 0; i != count; ++i) if (!args.getType().isDerivedFrom(method.getParameters()[i].getType())) { match = false; break; } if (match) { if (res == null) res = method; else { if (res.getParameters().length != count) return null; if (node.equals(this)) return null; match = true; for (int i = 0; i != count; ++i) if (!res.getParameters()[i].getType().equals(method.getParameters()[i].getType())) { match = false; break; } if (!match) return null; } } } } node = node.getSuperClass(); } while (node != null); return res; }
/** * Returns true if the given method has a possibly matching instance method with the given name * and arguments. * * @param name the name of the method of interest * @param arguments the arguments to match against * @return true if a matching method was found */ public boolean hasPossibleMethod(String name, Expression arguments) { int count = 0; if (arguments instanceof TupleExpression) { TupleExpression tuple = (TupleExpression) arguments; // TODO this won't strictly be true when using list expansion in argument calls count = tuple.getExpressions().size(); } ClassNode node = this; do { for (MethodNode method : getMethods(name)) { if (method.getParameters().length == count && !method.isStatic()) { return true; } } node = node.getSuperClass(); } while (node != null); return false; }
protected Expression transformConstructorCallExpression(ConstructorCallExpression cce) { inSpecialConstructorCall = cce.isSpecialCall(); Expression expression = cce.getArguments(); if (expression instanceof TupleExpression) { TupleExpression tuple = (TupleExpression) expression; if (tuple.getExpressions().size() == 1) { expression = tuple.getExpression(0); if (expression instanceof NamedArgumentListExpression) { NamedArgumentListExpression namedArgs = (NamedArgumentListExpression) expression; List<MapEntryExpression> entryExpressions = namedArgs.getMapEntryExpressions(); for (int i = 0; i < entryExpressions.size(); i++) { entryExpressions.set( i, (MapEntryExpression) transformMapEntryExpression(entryExpressions.get(i), cce.getType())); } } } } Expression ret = cce.transformExpression(this); inSpecialConstructorCall = false; return ret; }
/** * Returns true if the given method has a possibly matching static method with the given name and * arguments. * * @param name the name of the method of interest * @param arguments the arguments to match against * @return true if a matching method was found */ public boolean hasPossibleStaticMethod(String name, Expression arguments) { int count = 0; if (arguments instanceof TupleExpression) { TupleExpression tuple = (TupleExpression) arguments; // TODO this won't strictly be true when using list expansion in argument calls count = tuple.getExpressions().size(); } else if (arguments instanceof MapExpression) { count = 1; } for (MethodNode method : getMethods(name)) { if (method.isStatic()) { Parameter[] parameters = method.getParameters(); if (parameters.length == count) return true; // handle varargs case if (parameters.length > 0 && parameters[parameters.length - 1].getType().isArray()) { if (count >= parameters.length - 1) return true; } // handle parameters with default values int nonDefaultParameters = 0; for (Parameter parameter : parameters) { if (!parameter.hasInitialExpression()) { nonDefaultParameters++; } } if (count < parameters.length && nonDefaultParameters <= count) { return true; } } } return false; }
@Override public void visitTupleExpression(TupleExpression expression) { // LOG.debug "Transforming expression '${expression}':" if (expression.getLineNumber() >= 0 && expression.getLineNumber() < lineNumbers.length) { // LOG.debug " start from ${expression.lineNumber} to ${lineNumbers[expression.lineNumber // - 1]}" expression.setLineNumber(lineNumbers[expression.getLineNumber() - 1]); } if (expression.getLastLineNumber() > 0 && expression.getLastLineNumber() < lineNumbers.length) { // LOG.debug " end from ${expression.lastLineNumber} to // ${lineNumbers[expression.lastLineNumber - 1]}" expression.setLastLineNumber(lineNumbers[expression.getLastLineNumber() - 1]); } super.visitTupleExpression(expression); }
public void visitTupleExpression(TupleExpression expression) { visitListOfExpressions(expression.getExpressions()); }
public void evaluateEqual(BinaryExpression expression, boolean defineVariable) { AsmClassGenerator acg = controller.getAcg(); CompileStack compileStack = controller.getCompileStack(); OperandStack operandStack = controller.getOperandStack(); Expression rightExpression = expression.getRightExpression(); Expression leftExpression = expression.getLeftExpression(); ClassNode lhsType = controller.getTypeChooser().resolveType(leftExpression, controller.getClassNode()); if (defineVariable && rightExpression instanceof EmptyExpression && !(leftExpression instanceof TupleExpression)) { VariableExpression ve = (VariableExpression) leftExpression; BytecodeVariable var = compileStack.defineVariable( ve, controller.getTypeChooser().resolveType(ve, controller.getClassNode()), false); operandStack.loadOrStoreVariable(var, false); return; } // let's evaluate the RHS and store the result ClassNode rhsType; if (rightExpression instanceof ListExpression && lhsType.isArray()) { ListExpression list = (ListExpression) rightExpression; ArrayExpression array = new ArrayExpression(lhsType.getComponentType(), list.getExpressions()); array.setSourcePosition(list); array.visit(acg); } else if (rightExpression instanceof EmptyExpression) { rhsType = leftExpression.getType(); loadInitValue(rhsType); } else { rightExpression.visit(acg); } rhsType = operandStack.getTopOperand(); boolean directAssignment = defineVariable && !(leftExpression instanceof TupleExpression); int rhsValueId; if (directAssignment) { VariableExpression var = (VariableExpression) leftExpression; if (var.isClosureSharedVariable() && ClassHelper.isPrimitiveType(rhsType)) { // GROOVY-5570: if a closure shared variable is a primitive type, it must be boxed rhsType = ClassHelper.getWrapper(rhsType); operandStack.box(); } // ensure we try to unbox null to cause a runtime NPE in case we assign // null to a primitive typed variable, even if it is used only in boxed // form as it is closure shared if (var.isClosureSharedVariable() && ClassHelper.isPrimitiveType(var.getOriginType()) && isNull(rightExpression)) { operandStack.doGroovyCast(var.getOriginType()); // these two are never reached in bytecode and only there // to avoid verifyerrors and compiler infrastructure hazzle operandStack.box(); operandStack.doGroovyCast(lhsType); } // normal type transformation if (!ClassHelper.isPrimitiveType(lhsType) && isNull(rightExpression)) { operandStack.replace(lhsType); } else { operandStack.doGroovyCast(lhsType); } rhsType = lhsType; rhsValueId = compileStack.defineVariable(var, lhsType, true).getIndex(); } else { rhsValueId = compileStack.defineTemporaryVariable("$rhs", rhsType, true); } // TODO: if rhs is VariableSlotLoader already, then skip crating a new one BytecodeExpression rhsValueLoader = new VariableSlotLoader(rhsType, rhsValueId, operandStack); // assignment for subscript if (leftExpression instanceof BinaryExpression) { BinaryExpression leftBinExpr = (BinaryExpression) leftExpression; if (leftBinExpr.getOperation().getType() == Types.LEFT_SQUARE_BRACKET) { assignToArray( expression, leftBinExpr.getLeftExpression(), leftBinExpr.getRightExpression(), rhsValueLoader); } compileStack.removeVar(rhsValueId); return; } compileStack.pushLHS(true); // multiple declaration if (leftExpression instanceof TupleExpression) { TupleExpression tuple = (TupleExpression) leftExpression; int i = 0; for (Expression e : tuple.getExpressions()) { VariableExpression var = (VariableExpression) e; MethodCallExpression call = new MethodCallExpression( rhsValueLoader, "getAt", new ArgumentListExpression(new ConstantExpression(i))); call.visit(acg); i++; if (defineVariable) { operandStack.doGroovyCast(var); compileStack.defineVariable(var, true); operandStack.remove(1); } else { acg.visitVariableExpression(var); } } } // single declaration else if (defineVariable) { rhsValueLoader.visit(acg); operandStack.remove(1); compileStack.popLHS(); return; } // normal assignment else { int mark = operandStack.getStackLength(); // to leave a copy of the rightExpression value on the stack after the assignment. rhsValueLoader.visit(acg); TypeChooser typeChooser = controller.getTypeChooser(); ClassNode targetType = typeChooser.resolveType(leftExpression, controller.getClassNode()); operandStack.doGroovyCast(targetType); leftExpression.visit(acg); operandStack.remove(operandStack.getStackLength() - mark); } compileStack.popLHS(); // return value of assignment rhsValueLoader.visit(acg); compileStack.removeVar(rhsValueId); }