Skip to content

Commit

Permalink
Merge pull request #41741 from poorna2152/worker_change_semantic
Browse files Browse the repository at this point in the history
Add semantic support for worker `on fail` clause
  • Loading branch information
lochana-chathura authored Dec 11, 2023
2 parents b1d64b3 + f2bfbf4 commit 176f977
Show file tree
Hide file tree
Showing 4 changed files with 187 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1743,7 +1743,18 @@ public BLangNode transform(NamedWorkerDeclarationNode namedWorkerDeclNode) {
// Set the function body
BLangBlockStmt blockStmt = (BLangBlockStmt) namedWorkerDeclNode.workerBody().apply(this);
BLangBlockFunctionBody bodyNode = (BLangBlockFunctionBody) TreeBuilder.createBlockFunctionBodyNode();
bodyNode.stmts = blockStmt.stmts;
if (namedWorkerDeclNode.onFailClause().isPresent()) {
BLangDo bLDo = (BLangDo) TreeBuilder.createDoNode();
bLDo.pos = workerBodyPos;
bLDo.setBody(blockStmt);
OnFailClauseNode onFailClauseNode = namedWorkerDeclNode.onFailClause().get();
bLDo.setOnFailClause(
(org.ballerinalang.model.clauses.OnFailClauseNode) (onFailClauseNode.apply(this)));
bodyNode.addStatement(bLDo);
} else {
bodyNode.stmts = blockStmt.stmts;
}

bodyNode.pos = workerBodyPos;
bLFunction.body = bodyNode;
bLFunction.internal = true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1510,12 +1510,15 @@ public void visit(BLangWhile whileNode, AnalyzerData data) {
public void visit(BLangDo doNode, AnalyzerData data) {
boolean onFailExists = doNode.onFailClause != null;
boolean failureHandled = data.failureHandled;
boolean previousWithinDoBlock = data.withinWorkerTopLevelDo;
data.withinWorkerTopLevelDo = isCommunicationAllowedLocation(data.env) && isInWorker(data.env);
if (onFailExists) {
data.failureHandled = true;
}
analyzeNode(doNode.body, data);
data.failureHandled = failureHandled;
analyseOnFailClause(onFailExists, doNode.onFailClause, data);
data.withinWorkerTopLevelDo = previousWithinDoBlock;
}


Expand Down Expand Up @@ -2002,7 +2005,8 @@ public void visit(BLangWorkerAsyncSendExpr asyncSendExpr, AnalyzerData data) {
}

String workerName = asyncSendExpr.workerIdentifier.getValue();
if (data.withinQuery || (!isCommunicationAllowedLocation(data.env) && !data.inInternallyDefinedBlockStmt)) {
if (!data.withinWorkerTopLevelDo && (data.withinQuery ||
(!isCommunicationAllowedLocation(data.env) && !data.inInternallyDefinedBlockStmt))) {
this.dlog.error(asyncSendExpr.pos, DiagnosticErrorCode.UNSUPPORTED_WORKER_SEND_POSITION);
was.hasErrors = true;
}
Expand Down Expand Up @@ -2061,7 +2065,8 @@ public void visit(BLangWorkerSyncSendExpr syncSendExpr, AnalyzerData data) {
was.hasErrors = true;
}

if (data.withinQuery || (!isCommunicationAllowedLocation(data.env) && !data.inInternallyDefinedBlockStmt)) {
if (!data.withinWorkerTopLevelDo && (data.withinQuery ||
(!isCommunicationAllowedLocation(data.env) && !data.inInternallyDefinedBlockStmt))) {
this.dlog.error(syncSendExpr.pos, DiagnosticErrorCode.UNSUPPORTED_WORKER_SEND_POSITION);
was.hasErrors = true;
}
Expand Down Expand Up @@ -4256,6 +4261,7 @@ public static class AnalyzerData {
boolean loopAlterNotAllowed;
// Fields related to worker system
boolean inInternallyDefinedBlockStmt;
boolean withinWorkerTopLevelDo;
int workerSystemMovementSequence;
Stack<WorkerActionSystem> workerActionSystemStack = new Stack<>();
Map<BSymbol, Set<BLangNode>> workerReferences = new HashMap<>();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/*
* Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com).
*
* WSO2 LLC. 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.test.worker;

import org.ballerinalang.test.BCompileUtil;
import org.ballerinalang.test.BRunUtil;
import org.ballerinalang.test.CompileResult;
import org.testng.Assert;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;

import java.util.Arrays;

/**
* Tests the worker on fail clause.
*/
public class WorkerOnFailTest {

private CompileResult result;

@BeforeClass
public void setup() {
this.result = BCompileUtil.compile("test-src/workers/worker-on-fail.bal");
Assert.assertEquals(result.getErrorCount(), 0, Arrays.asList(result.getDiagnostics()).toString());
}

@Test
public void simpleOnFailTest() {
Object returns = BRunUtil.invoke(result, "testOnFailInWorker");
long ret = (long) returns;
Assert.assertEquals(ret, -1);
}

@Test
public void doOnFailInsideWorker() {
Object returns = BRunUtil.invoke(result, "testDoOnFailInsideWorker");
long ret = (long) returns;
Assert.assertEquals(ret, 3);
}

@Test
public void returnWithinOnFail() {
Object returns = BRunUtil.invoke(result, "testReturnWithinOnFail");
long ret = (long) returns;
Assert.assertEquals(ret, -1);
}

@Test
public void onFailWorkerWithVariable() {
Object returns = BRunUtil.invoke(result, "testOnFailWorkerWithVariable");
long ret = (long) returns;
Assert.assertEquals(ret, 0);
}

@Test
public void workerOnFailWithSend() {
Object returns = BRunUtil.invoke(result, "testWorkerOnFailWithSend");
long ret = (long) returns;
Assert.assertEquals(ret, 1);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
function testOnFailInWorker() returns int {
int[] vals = returnIntArr();
int key = returnOne();
int val = 0;

worker A {
int? index = vals.indexOf(key);
if index != () {
val = vals[index];
} else {
check error("value not found");
}
} on fail {
val = -1;
}
wait A;
return val;
}

function testDoOnFailInsideWorker() returns int {
int val = 0;
worker A {
do {
val += 1;
fail error("error in do");
} on fail {
val += 1;
}
fail error("error for worker");
} on fail {
val += 1;
}
wait A;
return val;
}

function testReturnWithinOnFail() returns int {
int x = returnOne();
worker A returns string {
if (x == 1) {
check error("one");
}
return "not one";
} on fail error e {
return e.message();
}
string str = wait A;
return str == "one" ? -1 : 0;
}

function testOnFailWorkerWithVariable() returns int {
int x = 0;
worker A {
do {
x += 1;
fail error("error in do");
} on fail {
x += 1;
}
fail error("error in worker");
} on fail error e {
if e.message() == "error in worker" {
x -= 2;
} else {
x -= -1;
}
}
wait A;
return x;
}

function testWorkerOnFailWithSend() returns int {
worker A {
int x = 1;
x -> B;
check error("testWorkerOnFailWithSend");
} on fail var err {
_ = err.message();
}

worker B returns int {
return <- A;
}
return wait B;
}

function returnOne() returns int => 1;

function returnIntArr() returns int[] => [2, 3, 4, 5];

0 comments on commit 176f977

Please sign in to comment.