Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Query Action implementation & related refactoring #20975

Merged
merged 11 commits into from
Feb 13, 2020
3 changes: 3 additions & 0 deletions compiler/ballerina-lang/spotbugs-exclude.xml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@
<Match>
<Package name="org.wso2.ballerinalang.compiler.tree.expressions" />
</Match>
<Match>
<Package name="org.wso2.ballerinalang.compiler.tree.clauses" />
</Match>
<Match>
<Package name="org.wso2.ballerinalang.compiler.tree.statements" />
</Match>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
*/
package org.ballerinalang.model;

import org.ballerinalang.model.clauses.DoClauseNode;
import org.ballerinalang.model.clauses.FromClauseNode;
import org.ballerinalang.model.clauses.SelectClauseNode;
import org.ballerinalang.model.clauses.WhereClauseNode;
Expand Down Expand Up @@ -103,6 +104,7 @@
import org.ballerinalang.model.tree.statements.MatchNode.MatchStructuredBindingPatternNode;
import org.ballerinalang.model.tree.statements.MatchNode.MatchTypedBindingPatternNode;
import org.ballerinalang.model.tree.statements.PanicNode;
import org.ballerinalang.model.tree.statements.QueryActionNode;
import org.ballerinalang.model.tree.statements.RecordDestructureNode;
import org.ballerinalang.model.tree.statements.RetryNode;
import org.ballerinalang.model.tree.statements.ReturnNode;
Expand Down Expand Up @@ -146,6 +148,7 @@
import org.wso2.ballerinalang.compiler.tree.BLangTupleVariable;
import org.wso2.ballerinalang.compiler.tree.BLangTypeDefinition;
import org.wso2.ballerinalang.compiler.tree.BLangXMLNS;
import org.wso2.ballerinalang.compiler.tree.clauses.BLangDoClause;
import org.wso2.ballerinalang.compiler.tree.clauses.BLangFromClause;
import org.wso2.ballerinalang.compiler.tree.clauses.BLangSelectClause;
import org.wso2.ballerinalang.compiler.tree.clauses.BLangWhereClause;
Expand Down Expand Up @@ -222,6 +225,7 @@
import org.wso2.ballerinalang.compiler.tree.statements.BLangMatch.BLangMatchStructuredBindingPatternClause;
import org.wso2.ballerinalang.compiler.tree.statements.BLangMatch.BLangMatchTypedBindingPatternClause;
import org.wso2.ballerinalang.compiler.tree.statements.BLangPanic;
import org.wso2.ballerinalang.compiler.tree.statements.BLangQueryAction;
import org.wso2.ballerinalang.compiler.tree.statements.BLangRecordDestructure;
import org.wso2.ballerinalang.compiler.tree.statements.BLangRecordVariableDef;
import org.wso2.ballerinalang.compiler.tree.statements.BLangRetry;
Expand Down Expand Up @@ -647,6 +651,14 @@ public static SelectClauseNode createSelectClauseNode() {
return new BLangSelectClause();
}

public static DoClauseNode createDoClauseNode() {
return new BLangDoClause();
}

public static QueryActionNode createQueryActionStatementNode() {
return new BLangQueryAction();
}

public static WhereClauseNode createWhereClauseNode() {
return new BLangWhereClause();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* Copyright (c) 2020, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.ballerinalang.model.clauses;

import org.ballerinalang.model.tree.Node;
import org.ballerinalang.model.tree.statements.BlockNode;

/**
* The interface with the APIs to implement the "do" clause.
*
* @since 1.2.0
*/
public interface DoClauseNode extends Node {

BlockNode getBody();

void setBody(BlockNode body);
}
Original file line number Diff line number Diff line change
Expand Up @@ -150,11 +150,13 @@ public enum NodeKind {
COMPENSATE,
CHANNEL_RECEIVE,
CHANNEL_SEND,
DO_ACTION,

/* Clauses */
SELECT,
FROM,
WHERE,
DO,

/* Types */
ARRAY_TYPE,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* Copyright (c) 2020, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.ballerinalang.model.tree.statements;

import org.ballerinalang.model.clauses.DoClauseNode;
import org.ballerinalang.model.clauses.FromClauseNode;
import org.ballerinalang.model.clauses.WhereClauseNode;

import java.util.List;

/**
* Represents the DoAction statement node.
*
* @since 1.2.0
*/
public interface QueryActionNode extends StatementNode {

List<? extends FromClauseNode> getFromClauseNodes();

void addFromClauseNode(FromClauseNode fromClauseNode);

List<? extends WhereClauseNode> getWhereClauseNode();

void addWhereClauseNode(WhereClauseNode whereClauseNode);

DoClauseNode getDoClauseNode();

void setDoClauseNode(DoClauseNode doClauseNode);
}
Original file line number Diff line number Diff line change
Expand Up @@ -84,9 +84,6 @@
import org.wso2.ballerinalang.compiler.tree.BLangXMLNS;
import org.wso2.ballerinalang.compiler.tree.BLangXMLNS.BLangLocalXMLNS;
import org.wso2.ballerinalang.compiler.tree.BLangXMLNS.BLangPackageXMLNS;
import org.wso2.ballerinalang.compiler.tree.clauses.BLangFromClause;
import org.wso2.ballerinalang.compiler.tree.clauses.BLangSelectClause;
import org.wso2.ballerinalang.compiler.tree.clauses.BLangWhereClause;
import org.wso2.ballerinalang.compiler.tree.expressions.BLangAccessExpression;
import org.wso2.ballerinalang.compiler.tree.expressions.BLangAnnotAccessExpr;
import org.wso2.ballerinalang.compiler.tree.expressions.BLangArrowFunction;
Expand Down Expand Up @@ -186,6 +183,7 @@
import org.wso2.ballerinalang.compiler.tree.statements.BLangMatch.BLangMatchStructuredBindingPatternClause;
import org.wso2.ballerinalang.compiler.tree.statements.BLangMatch.BLangMatchTypedBindingPatternClause;
import org.wso2.ballerinalang.compiler.tree.statements.BLangPanic;
import org.wso2.ballerinalang.compiler.tree.statements.BLangQueryAction;
import org.wso2.ballerinalang.compiler.tree.statements.BLangRecordDestructure;
import org.wso2.ballerinalang.compiler.tree.statements.BLangRecordVariableDef;
import org.wso2.ballerinalang.compiler.tree.statements.BLangRetry;
Expand Down Expand Up @@ -260,6 +258,7 @@ public class Desugar extends BLangNodeVisitor {
private SymbolResolver symResolver;
private final SymbolEnter symbolEnter;
private ClosureDesugar closureDesugar;
private QueryDesugar queryDesugar;
private AnnotationDesugar annotationDesugar;
private Types types;
private Names names;
Expand Down Expand Up @@ -304,6 +303,7 @@ private Desugar(CompilerContext context) {
this.symResolver = SymbolResolver.getInstance(context);
this.symbolEnter = SymbolEnter.getInstance(context);
this.closureDesugar = ClosureDesugar.getInstance(context);
this.queryDesugar = QueryDesugar.getInstance(context);
this.annotationDesugar = AnnotationDesugar.getInstance(context);
this.types = Types.getInstance(context);
this.names = Names.getInstance(context);
Expand Down Expand Up @@ -4317,135 +4317,15 @@ public void visit(BLangStatementExpression bLangStatementExpression) {

@Override
public void visit(BLangQueryExpr queryExpr) {
List<BLangFromClause> fromClauseList = queryExpr.fromClauseList;
BLangFromClause fromClause = fromClauseList.get(0);
BLangSelectClause selectClause = queryExpr.selectClause;
List<BLangWhereClause> whereClauseList = queryExpr.whereClauseList;
DiagnosticPos pos = fromClause.pos;

// Create Foreach statement
//
// Below query expression :
// from var person in personList
//
// changes as,
// foreach var person in personList {
// ....
// }

BLangForeach leafForEach = null;
BLangForeach parentForEach = null;

for (BLangFromClause bLangFromClause : fromClauseList) {
BLangForeach foreach = (BLangForeach) TreeBuilder.createForeachNode();
foreach.pos = queryExpr.pos;
foreach.collection = bLangFromClause.collection;
types.setForeachTypedBindingPatternType(foreach);

foreach.variableDefinitionNode = bLangFromClause.variableDefinitionNode;
foreach.isDeclaredWithVar = fromClause.isDeclaredWithVar;

if (leafForEach != null) {
BLangBlockStmt foreachBody = ASTBuilderUtil.createBlockStmt(pos);
foreachBody.addStatement(foreach);
leafForEach.setBody(foreachBody);
} else {
parentForEach = foreach;
}

leafForEach = foreach;
}

BLangBlockStmt foreachBody = ASTBuilderUtil.createBlockStmt(pos);

BType outputArrayType;
if (selectClause.expression != null && selectClause.expression.type != null) {
outputArrayType = new BArrayType(selectClause.expression.type);
} else {
outputArrayType = fromClause.varType;
}

BLangListConstructorExpr emptyArrayExpr = ASTBuilderUtil.createEmptyArrayLiteral(pos,
(BArrayType) outputArrayType);
BVarSymbol emptyArrayVarSymbol = new BVarSymbol(0, new Name("$outputDataArray$"),
this.env.scope.owner.pkgID, outputArrayType, env.scope.owner);
BLangSimpleVariable outputArrayVariable =
ASTBuilderUtil.createVariable(pos, "$outputDataArray$", outputArrayType,
emptyArrayExpr, emptyArrayVarSymbol);

// Create temp array variable
// Person[] x = [];

BLangSimpleVariableDef outputVariableDef =
ASTBuilderUtil.createVariableDef(pos, outputArrayVariable);
BLangSimpleVarRef outputVarRef = ASTBuilderUtil.createVariableRef(pos, outputArrayVariable.symbol);

// Create indexed based access expression statement
// x[x.length()] = {
// firstName: person.firstName,
// lastName: person.lastName
// };

if (selectClause.expression.type == null) {
selectClause.expression.type = fromClause.varType;
}

BLangInvocation lengthInvocation = createLengthInvocation(pos, outputArrayVariable.symbol);
lengthInvocation.expr = outputVarRef;
BLangIndexBasedAccess indexAccessExpr = ASTBuilderUtil.createIndexAccessExpr(outputVarRef, lengthInvocation);
indexAccessExpr.type = selectClause.expression.type;

BLangAssignment outputVarAssignment = ASTBuilderUtil.createAssignmentStmt(pos, indexAccessExpr,
selectClause.expression);
// Set the indexed based access expression statement as foreach body
foreachBody.addStatement(outputVarAssignment);

if (whereClauseList.size() > 0) {
// Create If Statement with Where expression and foreach body
BLangIf outerIf = null;
BLangIf innerIf = null;
for (BLangWhereClause whereClause : whereClauseList) {
BLangIf bLangIf = (BLangIf) TreeBuilder.createIfElseStatementNode();
bLangIf.pos = queryExpr.pos;
bLangIf.expr = whereClause.expression;
if (innerIf != null) {
BLangBlockStmt bLangBlockStmt = ASTBuilderUtil.createBlockStmt(pos);
bLangBlockStmt.addStatement(bLangIf);
innerIf.setBody(bLangBlockStmt);
} else {
outerIf = bLangIf;
}
innerIf = bLangIf;
}
innerIf.setBody(foreachBody);
BLangBlockStmt bLangBlockStmt = ASTBuilderUtil.createBlockStmt(pos);
bLangBlockStmt.addStatement(outerIf);
leafForEach.setBody(bLangBlockStmt);
} else {
leafForEach.setBody(foreachBody);
}

// Create block statement with temp variable definition statement & foreach statement
BLangBlockStmt blockStmt = ASTBuilderUtil.createBlockStmt(pos);
blockStmt.addStatement(outputVariableDef);
blockStmt.addStatement(parentForEach);
BLangStatementExpression stmtExpr = ASTBuilderUtil.createStatementExpression(blockStmt, outputVarRef);

stmtExpr.type = outputArrayType;
BLangStatementExpression stmtExpr = queryDesugar.desugarQueryExpr(queryExpr, env);
result = rewrite(stmtExpr, env);
}


private BLangInvocation createLengthInvocation(DiagnosticPos pos, BVarSymbol collectionSymbol) {
BInvokableSymbol lengthInvokableSymbol =
(BInvokableSymbol) symResolver.lookupLangLibMethod(collectionSymbol.type,
names.fromString("length"));
BLangSimpleVarRef collection = ASTBuilderUtil.createVariableRef(pos, collectionSymbol);
BLangInvocation lengthInvocation = ASTBuilderUtil.createInvocationExprForMethod(pos, lengthInvokableSymbol,
Lists.of(collection), symResolver);
lengthInvocation.type = lengthInvokableSymbol.type.getReturnType();
// Note: No need to set lengthInvocation.expr for langLib functions as they are in requiredArgs
return lengthInvocation;
@Override
public void visit(BLangQueryAction queryAction) {
BLangBlockStmt blockStmt = queryDesugar.desugarQueryAction(queryAction, env);
rewrite(blockStmt, this.env);
result = blockStmt;
}

@Override
Expand Down
Loading