Uh oh!
There was an error while loading. Please reload this page.
[SPARK-24361][SQL] Polish code block manipulation API - #21405
Conversation
…for constructing code block.
…ay not aware of necessary block inputs.
viirya
commented
May 23, 2018
SparkQA
commented
May 23, 2018
Test build #91014 has finished for PR 21405 at commit
|
viirya
commented
May 23, 2018
retest this please. |
SparkQA
commented
May 23, 2018
Test build #91021 has finished for PR 21405 at commit
|
viirya
commented
May 23, 2018
retest this please. |
| // We want to replace all occurrences of `expr` with the variable `aliasedParam`. | ||
| val aliasedCode = code.transformExprValues { | ||
| case SimpleExprValue("1 + 1", _) => aliasedParam |
There was a problem hiding this comment.
nit: I know the current code works correctly. How about replacing _ with CodeGenerator.javaClass(IntegerType)?
@viirya sorry do you already have some use-cases, goals in mind for this API? May you please explain me them? Thanks. |
@mgaido91 Yes, as @rednaxelafx said in previous RP, #19813 will be the first use case. I'd like to use this API to transform statement-based expressions in code blocks. For example, valcollectedStatements=HashMap[ExprValue, ExprValue]
valtransformed= code.transformExprValues {
case s @SimpleExprValue(_, javaType) =>if (collectedStatements.contains(s)) {
collectedStatements(s)
} else {
valaliasedVariable=JavaCode.variable(ctx.freshName("var"), javaType)
collectedStatements += s -> aliasedVariable
aliasedVariable
}
}
valcreateVariables= collectedStatements.foldLeft(EmptyBlock) { (block, (statement, variable)) =>
block +code"${statement.javaType.getName}$variable = $statement;"
}
ev.copy(code = createVariables + transformed) |
SparkQA
commented
May 23, 2018
Test build #91031 has finished for PR 21405 at commit
|
cloud-fan
commented
May 23, 2018
can we give a concrete use case in the PR description? I think splitting code into methods is a good one, but we need to make it completed, e.g. how the method is generated. |
@cloud-fan Thanks. I give a use case of splitting code into method in the PR description. I think it can show the basic idea and it is what I hope to make. |
| * Apply a map function to each java expression codes present in this java code, and return a new | ||
| * java code based on the mapped java expression codes. | ||
| */ | ||
| def transformExprValues(f: PartialFunction[ExprValue, ExprValue]): this.type = { |
There was a problem hiding this comment.
am I wrong or we are not updating the exprValues here?
There was a problem hiding this comment.
transformExprValues will create a new instance Block because a block is immutable. So once there are change, new block should take new exprValues.
There was a problem hiding this comment.
I see, can we add some tests for this?
There was a problem hiding this comment.
Ok. Will add them in next commit. Thanks.
viirya
commented
May 25, 2018
@cloud-fan I found that the way to collect method parameters in the use case can be simplified. Updated in the PR description. Please take a look when you have time. Thanks. |
viirya
commented
May 29, 2018
@cloud-fan@hvanhovell Do you have any comment/suggestion on this change? Thanks. |
SparkQA
commented
May 29, 2018
Test build #91251 has finished for PR 21405 at commit
|
viirya
commented
Jun 4, 2018
| * Trait representing an opaque fragments of java code. | ||
| */ | ||
| trait JavaCode { | ||
| trait JavaCode extends TreeNode[JavaCode] { |
There was a problem hiding this comment.
shall we only make Block extends TreeNode?
There was a problem hiding this comment.
Ok. Currently ExprValue doesn't have to be TreeNode.
| override def hashCode(): Int = value.hashCode() * 31 + javaType.hashCode() | ||
| } | ||
| case class LiteralExpr(override val value: String, override val javaType: Class[_]) |
There was a problem hiding this comment.
do we still need this change?
| // The expressions to be evaluated inside this block. | ||
| // All expressions to be evaluated inside this block and underlying blocks. | ||
| def exprValues: Set[ExprValue] |
There was a problem hiding this comment.
We can remove it, as discussed in other PR previously.
| test ("transform expr in nested blocks") { | ||
| val expr = JavaCode.expression("1 + 1", IntegerType) | ||
| val isNull = JavaCode.isNullVariable("expr1_isNull") |
There was a problem hiding this comment.
not related to this PR, shall we remove isNullVariable and always use expression(..., BooleanType)? Or we can add a bunch of intExpression(...), booleanExpression(...) etc.
There was a problem hiding this comment.
I think it is fine and maybe more clear. I was thinking the name of isNullVariable is a bit confusing at the first look actually.
| val block = code"${subBlocks(0)}\n${subBlocks(1)}\n${subBlocks(2)}" | ||
| val transformedBlock = block.transform { | ||
| case b: Block => b.transformExprValues { |
There was a problem hiding this comment.
hmmm, I'd image transformExprValues will also transform child blocks.
There was a problem hiding this comment.
so the this should be
block.transformExprValues {
case SimpleExprValue ...
}
There was a problem hiding this comment.
Then I may call it transformAllExprValues.
SparkQA
commented
Jul 5, 2018
Test build #92637 has finished for PR 21405 at commit
|
cloud-fan
commented
Jul 5, 2018
LGTM, can you update the demo in your PR description? thanks! |
SparkQA
commented
Jul 5, 2018
Test build #92640 has finished for PR 21405 at commit
|
SparkQA
commented
Jul 5, 2018
Test build #92642 has finished for PR 21405 at commit
|
viirya
commented
Jul 5, 2018
@cloud-fan Updated. Do you think I should address the comment #21405 (comment) to let |
cloud-fan
commented
Jul 5, 2018
we can do it later, when we do need |
cloud-fan
commented
Jul 5, 2018
thanks, merging to master! Looking forward to seeing how we can solve the method splitting problem with this infra :) |
What changes were proposed in this pull request?
Current code block manipulation API is immature and hacky. We need a formal API to manipulate code blocks.
The basic idea is making
JavaCodeasTreeNode. So we can use familiartransformAPI to manipulate code blocks and expressions in code blocks.For example, we can replace
SimpleExprValuein a code block like this:code.transformExprValues { caseSimpleExprValue("1 + 1", _) => aliasedParam }The example use case is splitting code to methods.
For example, we have an
ExprCodecontaining generated code. But it is too long and we need to split it as method. Because statement-based expressions can't be directly passed into. We need to transform them as variables first:How was this patch tested?
Added unite tests.