-
Notifications
You must be signed in to change notification settings - Fork 3
add support for lambda expressions #8
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -21,11 +21,14 @@ | |
| import java.io.IOException; | ||
| import java.lang.reflect.Type; | ||
| import java.util.ArrayList; | ||
| import java.util.Collections; | ||
| import java.util.List; | ||
| import java.util.Map; | ||
| import java.util.regex.Matcher; | ||
| import java.util.regex.Pattern; | ||
| import java.util.stream.Collector; | ||
| import java.util.stream.Collectors; | ||
| import java.util.stream.Stream; | ||
| import java.util.stream.StreamSupport; | ||
|
|
||
| import static com.squareup.javapoet.Util.checkArgument; | ||
|
|
@@ -415,6 +418,156 @@ public Builder add(CodeBlock codeBlock) { | |
| return this; | ||
| } | ||
|
|
||
| /** | ||
| * Structures a lambda function based on some inputs and a CodeBlock body.<br> | ||
| * Should be used with {@link #add(String, Object...) addCode}, | ||
| * to provide specific behaviour such as | ||
| * <b>methodcall((int x, int y) -> x + y, 5)</b>. | ||
| * @param parameters the input parameters of the function. | ||
| * @param mode the format mode that should be used. | ||
| * @see com.squareup.javapoet.LambdaMode LambdaMode. | ||
| * @param body the body of the function. | ||
| */ | ||
| public Builder addLambda(Iterable<ParameterSpec> parameters, LambdaMode mode, CodeBlock body) { | ||
| // check for specification of input type visibility | ||
| boolean emitTypes = mode.equals(LambdaMode.VISIBLE_TYPES); | ||
|
|
||
| Stream<ParameterSpec> parameterStream = StreamSupport.stream( | ||
| parameters.spliterator(), | ||
| false | ||
| ); | ||
|
|
||
| // the inputs of the lambda (left side) | ||
| String inputSide = parameterStream | ||
| .peek(p -> checkArgument(!p.type.equals(TypeName.VOID), // validate the input types | ||
| "lambda input parameters cannot be of void type") | ||
| ) | ||
| .map(p -> emitTypes ? p.toString() : p.name) | ||
| .collect(Collectors.joining(", ")); | ||
|
|
||
| // the count of given inputs | ||
| int paramsLen = inputSide.split(",").length; | ||
|
|
||
| // on 0 or more than 1 inputs, or in case of type emission, | ||
| // parentheses are mandatory | ||
| if (paramsLen > 1 || emitTypes || inputSide.isEmpty()) { | ||
| inputSide = "(" + inputSide + ")"; | ||
| } | ||
|
|
||
| // the body of the lambda (right side) | ||
| String bodySide = body.toString().replaceAll("\n", ""); | ||
|
|
||
| // in case of multiple statements, braces are mandatory | ||
| if (bodySide.contains(";")) { | ||
| bodySide = "{" + bodySide + "}"; | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is forcing a coding style. Users need to be able to specify newlines, indents, etc. Many people will not like the output of this.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The emitted braces are for lambdas that contain a full method body such as x -> {int y=5; return x + 5;} in contrast with the more common lambdas x -> x + 5 that dont have mutlitple statements. I dont exaclty understand what you mean about forcing a code style, since that braces in the first example are mandatory to producing valid java syntax. Are you saying that the user should be responsible for placing the braces in its code blocks if he wishes to have mutliple statements, so just remove lines 460-462? About the new lines and indents, since the body is a CodeBlock, the user can definitely place indents and new lines in the body if he wishes to, when creating the CodeBlock. Some further insights are very welcome!
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Indenting, newlines, etc. must all be configurable by users. |
||
| } | ||
|
|
||
| // the full lambda structure | ||
| add(inputSide + " -> " + bodySide); | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Assuming spaces around
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. My idea was based on the rest of the codebase that seems to follow that kind of pattern. We have methods such as beginControlFlow() for example that does indeed emitt spaces before { to produce the output and doesnt allow user configuration. I take that this is coded that way because spaces before { on if statements and for loops, are a standard for java code. |
||
| return this; | ||
| } | ||
|
|
||
| /** | ||
| * Structures a lambda function based on some inputs and a CodeBlock body.<br> | ||
| * Will not emit the input types.<br> | ||
| * Should be used with {@link #add(String, Object...) addCode}, | ||
| * to provide specific behaviour such as | ||
| * <b>methodcall((x, y) -> x + y, 5)</b>. | ||
| * @param parameters the input parameters of the function. | ||
| * @param body the body of the function. | ||
| */ | ||
| public Builder addLambda(Iterable<ParameterSpec> parameters, CodeBlock body) { | ||
| return addLambda(parameters, LambdaMode.DEFAULT, body); | ||
| } | ||
|
|
||
| /** | ||
| * Structures a lambda function based on some inputs and an expression body.<br> | ||
| * Should be used with {@link #add(String, Object...) addCode}, | ||
| * to provide specific behaviour such as | ||
| * <b>methodcall((int x, int y) -> x + y, 5)</b>. | ||
| * @param parameters the input parameters of the function. | ||
| * @param mode the format mode that should be used. | ||
| * @see com.squareup.javapoet.LambdaMode LambdaMode. | ||
| * @param expressionFormat the format that should be used | ||
| * for the expression. | ||
| * @param args the values that should be placed in the holders | ||
| * of the format. | ||
| */ | ||
| public Builder addLambda(Iterable<ParameterSpec> parameters, LambdaMode mode, | ||
| String expressionFormat, Object... args) { | ||
| return addLambda(parameters, mode, CodeBlock.of(expressionFormat, args)); | ||
| } | ||
|
|
||
| /** | ||
| * Structures a lambda function based on some inputs and an expression body.<br> | ||
| * Will not emit the input types.<br> | ||
| * Should be used with {@link #add(String, Object...) addCode}, | ||
| * to provide specific behaviour such as | ||
| * <b>methodcall((x, y) -> x + y, 5)</b>. | ||
| * @param parameters the input parameters of the function. | ||
| * @param expressionFormat the format that should be used | ||
| * for the expression. | ||
| * @param args the values that should be placed in the holders | ||
| * of the format. | ||
| */ | ||
| public Builder addLambda(Iterable<ParameterSpec> parameters, String expressionFormat, Object... args) { | ||
| return addLambda(parameters, LambdaMode.DEFAULT, CodeBlock.of(expressionFormat, args)); | ||
| } | ||
|
|
||
| /** | ||
| * Structures a producer lambda function based on a CodeBlock body.<br> | ||
| * Should be used with {@link #addCode(String, Object...) addCode}, | ||
| * to provide specific behaviour such as | ||
| * <b>methodcall(() -> 3 + 2, 5)</b>. | ||
| * @param mode the format mode that should be used. | ||
| * @see com.squareup.javapoet.LambdaMode LambdaMode. | ||
| * @param body the body of the lambda. | ||
| */ | ||
| public Builder addLambda(LambdaMode mode, CodeBlock body) { | ||
| return addLambda(Collections.emptyList(), mode, body); | ||
| } | ||
|
|
||
| /** | ||
| * Structures a producer lambda function based on a CodeBlock body.<br> | ||
| * Should be used with {@link #add(String, Object...) addCode}, | ||
| * to provide specific behaviour such as | ||
| * <b>methodcall(() -> 3 + 2, 5)</b>. | ||
| * @param body the body of the lambda. | ||
| */ | ||
| public Builder addLambda(CodeBlock body) { | ||
| return addLambda(Collections.emptyList(), LambdaMode.DEFAULT, body); | ||
| } | ||
|
|
||
| /** | ||
| * Structures a producer lambda function based on an expression body.<br> | ||
| * Should be used with {@link #addCode(String, Object...) addCode}, | ||
| * to provide specific behaviour such as | ||
| * <b>methodcall(() -> 3 + 2, 5)</b>. | ||
| * @param mode the format mode that should be used. | ||
| * @see com.squareup.javapoet.LambdaMode LambdaMode. | ||
| * @param expressionFormat the format that should be used | ||
| * for the expression. | ||
| * @param args the values that should be placed in the holders | ||
| * of the format. | ||
| */ | ||
| public Builder addLambda(LambdaMode mode, String expressionFormat, Object... args) { | ||
| return addLambda(Collections.emptyList(), mode, expressionFormat, args); | ||
| } | ||
|
|
||
| /** | ||
| * Structures a producer lambda function based on an expression body.<br> | ||
| * Should be used with {@link #add(String, Object...) addCode}, | ||
| * to provide specific behaviour such as | ||
| * <b>methodcall(() -> 3 + 2, 5)</b>. | ||
| * @param expressionFormat the format that should be used | ||
| * for the expression. | ||
| * @param args the values that should be placed in the holders | ||
| * of the format. | ||
| */ | ||
| public Builder addLambda(String expressionFormat, Object... args) { | ||
| return addLambda(Collections.emptyList(), LambdaMode.DEFAULT, expressionFormat, args); | ||
| } | ||
|
|
||
| public Builder indent() { | ||
| this.formatParts.add("$>"); | ||
| return this; | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| package com.squareup.javapoet; | ||
|
|
||
| /** | ||
| * The available format modes a lambda function can have. | ||
| * {@code DEFAULT} example: (x, y) -> x + y; | ||
| * {@code VISIBLE_TYPES} example: (int x, int y) -> x + y; | ||
| */ | ||
| public enum LambdaMode { | ||
| DEFAULT, | ||
| VISIBLE_TYPES | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems wrong. Why are we doing this? We should not reformat code that has already been specified by users.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
wdyt about having a new line after the { so for body inputs like:
we get outputs like:
(or with proper indents if you think thats better).
By leaving the formatted user input as is, without removing new lines, we might fall into outputs like:
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The braces placement should be customizable. No one will agree on where to put it. This is why I've been suggesting we have a
LambdaSpecclass. I don't see any way around it. If we had aLambdaSpecbuilder class we wouldn't need so many method overloads. This would also pay benefits for theswitchPR. the body after the->arm of a switch is just like a lambda and a builder would help there.I'd like to see all these method overloads moved into a builder class, possibly with a bas class that can re-used for the switch PR. The placement of the lambda body braces should be configurable just as it is in
ClodeBlock