From 87e9ce58bb9b487dbb5badd122687d593a8cd234 Mon Sep 17 00:00:00 2001 From: poorna2152 Date: Tue, 21 Nov 2023 16:12:55 +0530 Subject: [PATCH 1/2] Add semantic for worker on fail --- .../compiler/parser/BLangNodeBuilder.java | 13 ++- .../semantics/analyzer/CodeAnalyzer.java | 10 ++- .../test/worker/WorkerOnFailTest.java | 78 ++++++++++++++++ .../test-src/workers/worker-on-fail.bal | 89 +++++++++++++++++++ 4 files changed, 187 insertions(+), 3 deletions(-) create mode 100644 tests/jballerina-unit-test/src/test/java/org/ballerinalang/test/worker/WorkerOnFailTest.java create mode 100644 tests/jballerina-unit-test/src/test/resources/test-src/workers/worker-on-fail.bal diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/parser/BLangNodeBuilder.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/parser/BLangNodeBuilder.java index 36d2041bbb0b..bc66a64213e5 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/parser/BLangNodeBuilder.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/parser/BLangNodeBuilder.java @@ -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; diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/CodeAnalyzer.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/CodeAnalyzer.java index fe7daa9c6550..42f1e46b58e0 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/CodeAnalyzer.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/CodeAnalyzer.java @@ -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.withinDoBlock; + data.withinDoBlock = true; if (onFailExists) { data.failureHandled = true; } analyzeNode(doNode.body, data); data.failureHandled = failureHandled; analyseOnFailClause(onFailExists, doNode.onFailClause, data); + data.withinDoBlock = previousWithinDoBlock; } @@ -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.withinDoBlock && (data.withinQuery || + (!isCommunicationAllowedLocation(data.env) && !data.inInternallyDefinedBlockStmt))) { this.dlog.error(asyncSendExpr.pos, DiagnosticErrorCode.UNSUPPORTED_WORKER_SEND_POSITION); was.hasErrors = true; } @@ -2061,7 +2065,8 @@ public void visit(BLangWorkerSyncSendExpr syncSendExpr, AnalyzerData data) { was.hasErrors = true; } - if (data.withinQuery || (!isCommunicationAllowedLocation(data.env) && !data.inInternallyDefinedBlockStmt)) { + if (!data.withinDoBlock && (data.withinQuery || + (!isCommunicationAllowedLocation(data.env) && !data.inInternallyDefinedBlockStmt))) { this.dlog.error(syncSendExpr.pos, DiagnosticErrorCode.UNSUPPORTED_WORKER_SEND_POSITION); was.hasErrors = true; } @@ -4256,6 +4261,7 @@ public static class AnalyzerData { boolean loopAlterNotAllowed; // Fields related to worker system boolean inInternallyDefinedBlockStmt; + boolean withinDoBlock; int workerSystemMovementSequence; Stack workerActionSystemStack = new Stack<>(); Map> workerReferences = new HashMap<>(); diff --git a/tests/jballerina-unit-test/src/test/java/org/ballerinalang/test/worker/WorkerOnFailTest.java b/tests/jballerina-unit-test/src/test/java/org/ballerinalang/test/worker/WorkerOnFailTest.java new file mode 100644 index 000000000000..883be193b203 --- /dev/null +++ b/tests/jballerina-unit-test/src/test/java/org/ballerinalang/test/worker/WorkerOnFailTest.java @@ -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); + } + +} diff --git a/tests/jballerina-unit-test/src/test/resources/test-src/workers/worker-on-fail.bal b/tests/jballerina-unit-test/src/test/resources/test-src/workers/worker-on-fail.bal new file mode 100644 index 000000000000..4fbf781f33fa --- /dev/null +++ b/tests/jballerina-unit-test/src/test/resources/test-src/workers/worker-on-fail.bal @@ -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]; From f2bfbf4ddc728f1266fce8fc93062bb543e05eb6 Mon Sep 17 00:00:00 2001 From: poorna2152 Date: Wed, 22 Nov 2023 11:04:53 +0530 Subject: [PATCH 2/2] Update the top level check --- .../compiler/semantics/analyzer/CodeAnalyzer.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/CodeAnalyzer.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/CodeAnalyzer.java index 42f1e46b58e0..d3237f101ad7 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/CodeAnalyzer.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/CodeAnalyzer.java @@ -1510,15 +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.withinDoBlock; - data.withinDoBlock = true; + 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.withinDoBlock = previousWithinDoBlock; + data.withinWorkerTopLevelDo = previousWithinDoBlock; } @@ -2005,7 +2005,7 @@ public void visit(BLangWorkerAsyncSendExpr asyncSendExpr, AnalyzerData data) { } String workerName = asyncSendExpr.workerIdentifier.getValue(); - if (!data.withinDoBlock && (data.withinQuery || + if (!data.withinWorkerTopLevelDo && (data.withinQuery || (!isCommunicationAllowedLocation(data.env) && !data.inInternallyDefinedBlockStmt))) { this.dlog.error(asyncSendExpr.pos, DiagnosticErrorCode.UNSUPPORTED_WORKER_SEND_POSITION); was.hasErrors = true; @@ -2065,7 +2065,7 @@ public void visit(BLangWorkerSyncSendExpr syncSendExpr, AnalyzerData data) { was.hasErrors = true; } - if (!data.withinDoBlock && (data.withinQuery || + if (!data.withinWorkerTopLevelDo && (data.withinQuery || (!isCommunicationAllowedLocation(data.env) && !data.inInternallyDefinedBlockStmt))) { this.dlog.error(syncSendExpr.pos, DiagnosticErrorCode.UNSUPPORTED_WORKER_SEND_POSITION); was.hasErrors = true; @@ -4261,7 +4261,7 @@ public static class AnalyzerData { boolean loopAlterNotAllowed; // Fields related to worker system boolean inInternallyDefinedBlockStmt; - boolean withinDoBlock; + boolean withinWorkerTopLevelDo; int workerSystemMovementSequence; Stack workerActionSystemStack = new Stack<>(); Map> workerReferences = new HashMap<>();