/** * Returns false if the argument expression is a lambda and the expected type * of the argument is not a function type or {@link Object}. * Returns true in all other cases. * * This serves as a shortcut to rule out decision path's where a method is overloaded * and one of the overloads accepts a function type but the other doesn't. In those cases * it is not necessary to compute the type of the lamdba expression twice. * * An example for this pattern is {@link IterableExtensions#filter(Iterable, Class)} vs * {@link IterableExtensions#filter(Iterable, org.eclipse.xtext.xbase.lib.Functions.Function1)}. */ protected boolean isPossibleFunctionType(int idx) { if (idx < arguments.getArgumentCount()) { XExpression argument = arguments.getArgument(idx); if (argument instanceof XClosure) { XClosure closure = (XClosure) argument; LightweightTypeReference declaredType = arguments.getDeclaredTypeForLambda(idx); if (declaredType != null && !declaredType.isType(Object.class)) { CommonTypeComputationServices services = getState().getReferenceOwner().getServices(); JvmOperation operation = services.getFunctionTypes().findImplementingOperation(declaredType); if (operation == null) { return false; } if (closure.isExplicitSyntax() && closure.getDeclaredFormalParameters().size() != operation.getParameters().size()) { return false; } } } } return true; }
protected boolean isXShortClosure(List<?> values, EReference reference, INodesForEObjectProvider nodes) { if (values.isEmpty() || values.size() > 2 || !(values.get(0) instanceof XClosure)) return false; XClosure closure = (XClosure) values.get(0); if (!closure.isExplicitSyntax()) return false; INode node = nodes.getNodeForMultiValue(reference, 0, 0, closure); if (node != null) { if (node.getGrammarElement() instanceof RuleCall) return ((RuleCall) node.getGrammarElement()).getRule() == grammarAccess.getXShortClosureRule(); if (node.getGrammarElement() instanceof Action) return node.getGrammarElement() == grammarAccess.getXShortClosureAccess().getXClosureAction_0_0_0(); return false; } return true; }
protected boolean isBuilderSyntax(List<?> values, EReference reference, INodesForEObjectProvider nodes) { if (values.isEmpty()) return false; int lastIndex = values.size() - 1; Object lastValue = values.get(lastIndex); if (!(lastValue instanceof XClosure)) return false; INode node = nodes.getNodeForMultiValue(reference, lastIndex, lastIndex, values.get(lastIndex)); if (node != null) { if (node.getGrammarElement() instanceof RuleCall) return ((RuleCall) node.getGrammarElement()).getRule() == grammarAccess.getXClosureRule(); if (node.getGrammarElement() instanceof Action) return node.getGrammarElement() == grammarAccess.getXClosureAccess().getXClosureAction_0_0_0(); return false; } return true; }
protected boolean bracesAreAddedByOuterStructure(XExpression expression) { EObject container = expression.eContainer(); if (container instanceof XTryCatchFinallyExpression || container instanceof XIfExpression || container instanceof XClosure || container instanceof XSynchronizedExpression) { return true; } if (container instanceof XBlockExpression) { XBlockExpression blockExpression = (XBlockExpression) container; EList<XExpression> expressions = blockExpression.getExpressions(); if (expressions.size() == 1 && expressions.get(0) == expression) { return bracesAreAddedByOuterStructure(blockExpression); } } if (!(container instanceof XExpression)) { return true; } return false; }
protected void _toJavaStatement(final XClosure closure, final ITreeAppendable b, boolean isReferenced) { if (!isReferenced) throw new IllegalArgumentException("a closure definition does not cause any side-effects"); LightweightTypeReference type = getLightweightType(closure); JvmOperation operation = findImplementingOperation(type); if (operation != null) { b.newLine().append("final "); b.append(type); b.append(" "); String variableName = b.declareSyntheticVariable(closure, "_function"); b.append(variableName).append(" = "); GeneratorConfig config = b.getGeneratorConfig(); if (config != null && config.getJavaSourceVersion().isAtLeast(JAVA8) && canCompileToJavaLambda(closure, type, operation)) { toLambda(closure, b, type, operation, false); } else { toAnonymousClass(closure, b, type, operation); } b.append(";"); } }
protected void _toJavaExpression(final XClosure closure, final ITreeAppendable b) { if (b.hasName(closure)) { b.trace(closure, false).append(getVarName(closure, b)); } else { LightweightTypeReference type = getLightweightType(closure); JvmOperation operation = findImplementingOperation(type); if (operation != null) { GeneratorConfig config = b.getGeneratorConfig(); if (config != null && config.getJavaSourceVersion().isAtLeast(JAVA8) && canCompileToJavaLambda(closure, type, operation)) { toLambda(closure, b.trace(closure, false), type, operation, true); } else { toAnonymousClass(closure, b.trace(closure, false), type, operation); } } } }
protected boolean canCompileToJavaLambda(XClosure closure, LightweightTypeReference typeRef, JvmOperation operation) { if (!typeRef.isInterfaceType()) return false; if (!operation.getTypeParameters().isEmpty()) return false; TreeIterator<EObject> iterator = closure.eAllContents(); JvmType jvmType = typeRef.getType(); while (iterator.hasNext()) { EObject obj = iterator.next(); if (obj instanceof XClosure) { iterator.prune(); } else if (obj instanceof XFeatureCall && isReferenceToSelf((XFeatureCall) obj, jvmType)) { return false; } } return true; }
protected XClosure builder(final List<XExpression> params) { XClosure _xifexpression = null; XExpression _last = IterableExtensions.<XExpression>last(params); boolean _tripleNotEquals = (_last != null); if (_tripleNotEquals) { XClosure _xblockexpression = null; { final EObject grammarElement = this.textRegionExtensions.grammarElement(IterableExtensions.<XExpression>last(params)); XClosure _xifexpression_1 = null; if (((Objects.equal(grammarElement, this.grammar.getXMemberFeatureCallAccess().getMemberCallArgumentsXClosureParserRuleCall_1_1_4_0()) || Objects.equal(grammarElement, this.grammar.getXFeatureCallAccess().getFeatureCallArgumentsXClosureParserRuleCall_4_0())) || Objects.equal(grammarElement, this.grammar.getXConstructorCallAccess().getArgumentsXClosureParserRuleCall_5_0()))) { XExpression _last_1 = IterableExtensions.<XExpression>last(params); _xifexpression_1 = ((XClosure) _last_1); } _xblockexpression = _xifexpression_1; } _xifexpression = _xblockexpression; } return _xifexpression; }
protected Iterable<XExpression> explicitParams(final List<XExpression> params) { Iterable<XExpression> _xblockexpression = null; { final XClosure builder = this.builder(params); Iterable<XExpression> _xifexpression = null; if ((builder != null)) { int _size = params.size(); int _minus = (_size - 1); _xifexpression = IterableExtensions.<XExpression>take(params, _minus); } else { _xifexpression = params; } _xblockexpression = _xifexpression; } return _xblockexpression; }
protected boolean prependNewLineIfMultiline(final EObject obj) { boolean _switchResult = false; boolean _matched = false; if (obj instanceof XMemberFeatureCall) { _matched=true; _switchResult = this.prependNewLineIfMultiline(this.builder(((XMemberFeatureCall)obj).getMemberCallArguments())); } if (!_matched) { if (obj instanceof XClosure) { _matched=true; _switchResult = false; } } if (!_matched) { if (obj instanceof XBlockExpression) { _matched=true; _switchResult = false; } } if (!_matched) { _switchResult = true; } return _switchResult; }
protected XClosure builder(final List<XExpression> params) { XClosure _xifexpression = null; XExpression _last = IterableExtensions.<XExpression>last(params); boolean _tripleNotEquals = (_last != null); if (_tripleNotEquals) { XClosure _xblockexpression = null; { INode _nodeForEObject = this._nodeModelAccess.nodeForEObject(IterableExtensions.<XExpression>last(params)); final EObject grammarElement = ((ICompositeNode) _nodeForEObject).getFirstChild().getGrammarElement(); XClosure _xifexpression_1 = null; if (((Objects.equal(grammarElement, this._xbaseGrammarAccess.getXMemberFeatureCallAccess().getMemberCallArgumentsXClosureParserRuleCall_1_1_4_0()) || Objects.equal(grammarElement, this._xbaseGrammarAccess.getXFeatureCallAccess().getFeatureCallArgumentsXClosureParserRuleCall_4_0())) || Objects.equal(grammarElement, this._xbaseGrammarAccess.getXConstructorCallAccess().getArgumentsXClosureParserRuleCall_5_0()))) { XExpression _last_1 = IterableExtensions.<XExpression>last(params); _xifexpression_1 = ((XClosure) _last_1); } _xblockexpression = _xifexpression_1; } _xifexpression = _xblockexpression; } return _xifexpression; }
/** * checks whether the given lambda should be formatted as a block. * That includes newlines after and before the brackets, and a fresh line for each expression. */ protected boolean isMultilineLambda(final XClosure closure) { final ILeafNode closingBracket = this._nodeModelAccess.nodeForKeyword(closure, "]"); HiddenLeafs _hiddenLeafsBefore = null; if (closingBracket!=null) { _hiddenLeafsBefore=this._hiddenLeafAccess.getHiddenLeafsBefore(closingBracket); } boolean _tripleNotEquals = (_hiddenLeafsBefore != null); if (_tripleNotEquals) { int _newLines = this._hiddenLeafAccess.getHiddenLeafsBefore(closingBracket).getNewLines(); return (_newLines > 0); } boolean _switchResult = false; XExpression _expression = closure.getExpression(); final XExpression block = _expression; boolean _matched = false; if (block instanceof XBlockExpression) { _matched=true; _switchResult = ((((XBlockExpression)block).getExpressions().size() > 1) && this.isEachExpressionInOwnLine(((XBlockExpression)block).getExpressions())); } if (!_matched) { _switchResult = false; } return _switchResult; }
@Test public void testClosureParameter() throws Exception { // List<? super String> list = Lists.newArrayList(); // ListExtensions.map(list, new Functions.Function1<CharSequence, String>() { // public String apply(CharSequence p) { // return null; // } // }); // ListExtensions.map(list, new Functions.Function1<Object, String>() { // public String apply(Object p) { // return null; // } // }); XBlockExpression block = (XBlockExpression) expression( "{\n" + " var java.util.List<? super String> list = null;\n" + " list.map(e|e)\n" + "}"); XMemberFeatureCall featureCall = (XMemberFeatureCall) block.getExpressions().get(1); XClosure closure = (XClosure) featureCall.getMemberCallArguments().get(0); JvmFormalParameter e = closure.getDeclaredFormalParameters().get(0); LightweightTypeReference typeRef = typeResolver.resolveTypes(closure).getActualType(e); assertEquals("java.lang.Object", typeRef.getIdentifier()); }
@Test public void testSerialize_01() throws Exception { Resource resource = newResource("'foo' as String"); XCastedExpression casted = (XCastedExpression) resource.getContents().get(0); XbaseFactory factory = XbaseFactory.eINSTANCE; XClosure closure = factory.createXClosure(); XStringLiteral stringLiteral = factory.createXStringLiteral(); stringLiteral.setValue("value"); XBlockExpression blockExpression = factory.createXBlockExpression(); blockExpression.getExpressions().add(stringLiteral); closure.setExpression(blockExpression); closure.setExplicitSyntax(true); XInstanceOfExpression instanceOfExpression = factory.createXInstanceOfExpression(); instanceOfExpression.setExpression(closure); instanceOfExpression.setType(EcoreUtil.copy(casted.getType())); resource.getContents().clear(); resource.getContents().add(instanceOfExpression); ISerializer serializer = get(ISerializer.class); String string = serializer.serialize(instanceOfExpression); assertEquals("[|\"value\"] instanceof String", string); XInstanceOfExpression parsedExpression = parseHelper.parse(string); assertTrue(EcoreUtil.equals(instanceOfExpression, parsedExpression)); }
@Check public void checkClosureParameterTypes(XClosure closure) { if (closure.getFormalParameters().isEmpty()) return; LightweightTypeReference closureType = getActualType(closure); if (closureType != null && closureType.isUnknown()) return; boolean checkedClosure = false; for (JvmFormalParameter p : closure.getFormalParameters()) { if (p.getParameterType() == null) { if (!checkedClosure) { LightweightTypeReference type = getExpectedType(closure); if (type == null) { error("There is no context to infer the closure's argument types from. Consider typing the arguments or put the closures into a typed context.", closure, null, INSIGNIFICANT_INDEX, TOO_LITTLE_TYPE_INFORMATION); return; } else { JvmOperation operation = getServices().getFunctionTypes().findImplementingOperation(type); if (operation == null) { error("There is no context to infer the closure's argument types from. Consider typing the arguments or use the closures in a more specific context.", closure, null, INSIGNIFICANT_INDEX, TOO_LITTLE_TYPE_INFORMATION); return; } } checkedClosure = true; } LightweightTypeReference parameterType = getActualType(closure, p); if (parameterType == null) { error("There is no context to infer the closure's argument types from. Consider typing the arguments or use the closures in a more specific context.", closure, null, INSIGNIFICANT_INDEX, TOO_LITTLE_TYPE_INFORMATION); return; } } } }
private boolean isTypeParameterOfClosureImpl(JvmTypeReference ref) { JvmFormalParameter parameter = EcoreUtil2.getContainerOfType(ref, JvmFormalParameter.class); if (parameter != null) { return parameter.eContainer() instanceof XClosure; } return false; }
@Check public void checkClosureParams(XClosure closure) { if (closure.getDeclaredFormalParameters().size() > 6) { error("The maximum number of parameters for a closure is six.", closure, Literals.XCLOSURE__DECLARED_FORMAL_PARAMETERS, 6, TOO_MANY_PARAMS_IN_CLOSURE); } }
@Override protected boolean doValidateContents(EObject eObject, DiagnosticChain diagnostics, Map<Object, Object> context) { checkCanceled(context); if (eObject instanceof XClosure) { return doValidateLambdaContents((XClosure) eObject, diagnostics, context); } return super.doValidateContents(eObject, diagnostics, context); }
protected void collectExits(EObject expr, List<XExpression> found) { if (expr instanceof XReturnExpression) { found.add((XExpression) expr); } else if (expr instanceof XThrowExpression) { found.add((XExpression) expr); } else if (expr instanceof XClosure) { return; } for (EObject child : expr.eContents()) { collectExits(child, found); } }
@Override public List<JvmFormalParameter> getParameters() { XClosure closure = getClosure(); if (closure.isExplicitSyntax()) { return closure.getDeclaredFormalParameters(); } if (implicitParameters != null) return implicitParameters; return closure.getImplicitFormalParameters(); }
public ClosureTypeComputer(XClosure closure, ITypeExpectation expectation, ITypeComputationState state) { this.closure = closure; this.expectation = expectation; this.state = state; this.services = state.getReferenceOwner().getServices(); this.functionTypes = services.getFunctionTypes(); }
protected ClosureWithExpectationHelper(XClosure closure, JvmOperation operation, ITypeExpectation expectation, ITypeComputationState state) { super(closure, expectation, state); this.operation = operation; if (operation == null || expectation.getExpectedType() == null) { throw new IllegalStateException("Cannot locate appropriate operation for " + getClosure()); } prepareComputation(); }
/** * Provide the error message for mutable variables that may not be captured in lambdas. * * @param variable the writable variable declaration * @param featureCall the reference to the variable * @param resolvedTypes type information */ protected String getInvalidWritableVariableAccessMessage(XVariableDeclaration variable, XAbstractFeatureCall featureCall, IResolvedTypes resolvedTypes) { // TODO this should be part of a separate validation service XClosure containingClosure = EcoreUtil2.getContainerOfType(featureCall, XClosure.class); if (containingClosure != null && !EcoreUtil.isAncestor(containingClosure, variable)) { return String.format("Cannot %srefer to the non-final variable %s inside a lambda expression", getImplicitlyMessagePart(featureCall), variable.getSimpleName()); } return null; }
protected void reorder(boolean varArgs, List<XExpression> copiedArgumentList, List<JvmFormalParameter> copiedParameterList, List<XExpression> shiftedArgumentList, List<JvmFormalParameter> shiftedParameterList) { int max = Math.min(copiedArgumentList.size(), copiedParameterList.size()); if (varArgs && copiedArgumentList.size() >= copiedParameterList.size()) max = max - 1; for(int i = 0; i < max; i++) { XExpression expression = copiedArgumentList.get(i); if (expression instanceof XClosure) { shiftedArgumentList.add(expression); shiftedParameterList.add(copiedParameterList.get(i)); } } copiedArgumentList.removeAll(shiftedArgumentList); copiedParameterList.removeAll(shiftedParameterList); }
protected boolean requiresReordering(List<XExpression> arguments, int parameterCount) { boolean lambdaSeen = false; for(int i = 0; i < arguments.size() && i < parameterCount; i++) { if (arguments.get(i) instanceof XClosure) { lambdaSeen = true; } else if (lambdaSeen) { return true; } } return false; }
@Override protected boolean isLambdaExpression(int argumentIdx) { if (isStatic() && argumentIdx == -1) { return false; } if (argumentIdx == 0) { if (getReceiver() != null) { return getReceiver() instanceof XClosure; } } return super.isLambdaExpression(argumentIdx); }
protected boolean isLambdaExpression(int argumentIdx) { if (argumentIdx >= arguments.getArgumentCount()) { return false; } XExpression argument = arguments.getArgument(argumentIdx); return argument != null && argument instanceof XClosure; }
/** * @return whether the expression itself (not its children) possibly causes a side-effect */ public boolean hasSideEffects(XExpression expr) { if (expr instanceof XClosure || expr instanceof XStringLiteral || expr instanceof XTypeLiteral || expr instanceof XBooleanLiteral || expr instanceof XNumberLiteral || expr instanceof XNullLiteral || expr instanceof XAnnotation ) return false; if(expr instanceof XCollectionLiteral) { for(XExpression element: ((XCollectionLiteral)expr).getElements()) { if(hasSideEffects(element)) return true; } return false; } if (expr instanceof XAbstractFeatureCall) { XAbstractFeatureCall featureCall = (XAbstractFeatureCall) expr; return hasSideEffects(featureCall, true); } if (expr instanceof XConstructorCall) { XConstructorCall constrCall = (XConstructorCall) expr; return findPureAnnotation(constrCall.getConstructor()) == null; } return true; }
@Override protected boolean isVariableDeclarationRequired(XExpression expr, ITreeAppendable b, boolean recursive) { if (expr instanceof XBooleanLiteral || expr instanceof XStringLiteral || expr instanceof XNumberLiteral || expr instanceof XTypeLiteral || expr instanceof XClosure || expr instanceof XNullLiteral) return false; return super.isVariableDeclarationRequired(expr,b, recursive); }
@Override protected void internalToConvertedExpression(XExpression obj, ITreeAppendable appendable) { if (obj instanceof XBlockExpression) { _toJavaExpression((XBlockExpression) obj, appendable); } else if (obj instanceof XCastedExpression) { _toJavaExpression((XCastedExpression) obj, appendable); } else if (obj instanceof XClosure) { _toJavaExpression((XClosure) obj, appendable); } else if (obj instanceof XAnnotation) { _toJavaExpression((XAnnotation) obj, appendable); } else if (obj instanceof XConstructorCall) { _toJavaExpression((XConstructorCall) obj, appendable); } else if (obj instanceof XIfExpression) { _toJavaExpression((XIfExpression) obj, appendable); } else if (obj instanceof XInstanceOfExpression) { _toJavaExpression((XInstanceOfExpression) obj, appendable); } else if (obj instanceof XSwitchExpression) { _toJavaExpression((XSwitchExpression) obj, appendable); } else if (obj instanceof XTryCatchFinallyExpression) { _toJavaExpression((XTryCatchFinallyExpression) obj, appendable); } else if (obj instanceof XListLiteral) { _toJavaExpression((XListLiteral) obj, appendable); } else if (obj instanceof XSetLiteral) { _toJavaExpression((XSetLiteral) obj, appendable); } else if (obj instanceof XSynchronizedExpression) { _toJavaExpression((XSynchronizedExpression) obj, appendable); } else if (obj instanceof XReturnExpression) { _toJavaExpression((XReturnExpression) obj, appendable); } else if (obj instanceof XThrowExpression) { _toJavaExpression((XThrowExpression) obj, appendable); } else { super.internalToConvertedExpression(obj, appendable); } }
private LightweightTypeReference findRealReturnType(XExpression expression) { if (expression == null) return null; JvmIdentifiableElement logicalContainer = getLogicalContainerProvider().getLogicalContainer(expression); if (logicalContainer instanceof JvmOperation) { return getLightweightType(logicalContainer); } if (expression instanceof XClosure) { IResolvedTypes resolvedTypes = batchTypeResolver.resolveTypes(expression); LightweightTypeReference type = resolvedTypes.getExpectedType(expression); if (type == null) { type = resolvedTypes.getActualType(expression); } if (type == null) { return null; } FunctionTypeReference functionType = type.tryConvertToFunctionTypeReference(false); if (functionType != null) { return functionType.getReturnType(); } return null; } XExpression containerExpression = EcoreUtil2.getContainerOfType(expression.eContainer(), XExpression.class); if (containerExpression == null) { LightweightTypeReference returnType = getLightweightReturnType(expression); return returnType; } return findRealReturnType(containerExpression); }
protected Object _doEvaluate(XClosure closure, IEvaluationContext context, CancelIndicator indicator) { Class<?> functionIntf = null; switch (closure.getFormalParameters().size()) { case 0: functionIntf = getClass(Functions.Function0.class); break; case 1: functionIntf = getClass(Functions.Function1.class); break; case 2: functionIntf = getClass(Functions.Function2.class); break; case 3: functionIntf = getClass(Functions.Function3.class); break; case 4: functionIntf = getClass(Functions.Function4.class); break; case 5: functionIntf = getClass(Functions.Function5.class); break; case 6: functionIntf = getClass(Functions.Function6.class); break; default: throw new IllegalStateException("Closures with more then 6 parameters are not supported."); } ClosureInvocationHandler invocationHandler = new ClosureInvocationHandler(closure, context, this, indicator); Object proxy = Proxy.newProxyInstance(classLoader, new Class<?>[] { functionIntf }, invocationHandler); return proxy; }
public boolean hasReturnExpression(final XExpression expression) { boolean _switchResult = false; boolean _matched = false; if (expression instanceof XReturnExpression) { _matched=true; _switchResult = true; } if (!_matched) { if (expression instanceof XThrowExpression) { _matched=true; _switchResult = true; } } if (!_matched) { if (expression instanceof XClosure) { _matched=true; _switchResult = false; } } if (!_matched) { final Function1<EObject, Boolean> _function = (EObject content) -> { boolean _switchResult_1 = false; boolean _matched_1 = false; if (content instanceof XExpression) { _matched_1=true; _switchResult_1 = this.hasReturnExpression(((XExpression)content)); } if (!_matched_1) { _switchResult_1 = false; } return Boolean.valueOf(_switchResult_1); }; _switchResult = IterableExtensions.<EObject>exists(expression.eContents(), _function); } return _switchResult; }
@Test public void testClosure_2() throws Exception { XClosure closure = (XClosure) expression("[bar|'foo']"); assertEquals("foo", ((XStringLiteral) ((XBlockExpression)closure.getExpression()).getExpressions().get(0)) .getValue()); assertEquals("bar", closure.getFormalParameters().get(0).getName()); assertNull(closure.getFormalParameters().get(0).getParameterType()); }
@Test public void testClosure_3() throws Exception { XClosure closure = (XClosure) expression("[String bar|'foo']"); assertEquals("foo", ((XStringLiteral) ((XBlockExpression)closure.getExpression()).getExpressions().get(0)) .getValue()); assertEquals("bar", closure.getFormalParameters().get(0).getName()); assertEquals(1, closure.getFormalParameters().size()); assertNotNull(closure.getFormalParameters().get(0).getParameterType()); }
@Test public void testClosure_4() throws Exception { XClosure closure = (XClosure) expression("[foo, String bar|'foo']"); assertEquals("foo", ((XStringLiteral) ((XBlockExpression)closure.getExpression()).getExpressions().get(0)) .getValue()); assertEquals("foo", closure.getFormalParameters().get(0).getName()); assertEquals("bar", closure.getFormalParameters().get(1).getName()); assertEquals(2, closure.getFormalParameters().size()); assertNull(closure.getFormalParameters().get(0).getParameterType()); assertNotNull(closure.getFormalParameters().get(1).getParameterType()); }
@Test public void testClosure_5() throws Exception { XClosure closure = (XClosure) expression("[(String) => String mapper|mapper('something')]"); assertTrue(((XBlockExpression)closure.getExpression()).getExpressions().get(0) instanceof XFeatureCall); JvmFormalParameter formalParameter = closure.getFormalParameters().get(0); assertEquals("mapper", formalParameter.getName()); assertTrue(formalParameter.getParameterType() instanceof XFunctionTypeRef); }