Skip to content

Commit

Permalink
Fix detection of tap assignment (close #89)
Browse files Browse the repository at this point in the history
Signed-off-by: Ben Sherman <[email protected]>
  • Loading branch information
bentsherman committed Jan 17, 2025
1 parent 34e5fdc commit dff88b5
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 24 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -456,15 +456,6 @@ public void visitExpressionStatement(ExpressionStatement node) {
}
return;
}
if( exp instanceof MethodCallExpression mce ) {
var source = mce.getObjectExpression();
var target = checkSetAssignment(mce);
if( target != null ) {
visit(source);
declareAssignedVariable(target);
return;
}
}
super.visitExpressionStatement(node);
}

Expand Down Expand Up @@ -562,21 +553,6 @@ private void checkExternalWriteInAsyncClosure(VariableExpression target, Variabl
addFutureWarning("Mutating an external variable in an operator closure may lead to a race condition", target, "External variable declared here", (ASTNode) variable);
}

/**
* Treat `set` operator as an assignment.
*/
private VariableExpression checkSetAssignment(MethodCallExpression node) {
if( !(currentDefinition instanceof WorkflowNode) )
return null;
var name = node.getMethodAsString();
if( !"set".equals(name) )
return null;
var code = asDslBlock(node, 1);
if( code == null || code.getStatements().size() != 1 )
return null;
return asVarX(code.getStatements().get(0));
}

// expressions

private static final List<String> KEYWORDS = List.of(
Expand All @@ -588,6 +564,15 @@ private VariableExpression checkSetAssignment(MethodCallExpression node) {

@Override
public void visitMethodCallExpression(MethodCallExpression node) {
if( !node.isImplicitThis() ) {
var source = node.getObjectExpression();
var target = checkSetAssignment(node);
if( target != null ) {
visit(source);
declareAssignedVariable(target);
return;
}
}
if( node.isImplicitThis() && node.getMethod() instanceof ConstantExpression ) {
var name = node.getMethodAsString();
var variable = findVariableDeclaration(name, node);
Expand All @@ -599,6 +584,21 @@ public void visitMethodCallExpression(MethodCallExpression node) {
super.visitMethodCallExpression(node);
}

/**
* Treat `set` and `tap` operators as assignments.
*/
private VariableExpression checkSetAssignment(MethodCallExpression node) {
if( !(currentDefinition instanceof WorkflowNode) )
return null;
var name = node.getMethodAsString();
if( !"set".equals(name) && !"tap".equals(name) )
return null;
var code = asDslBlock(node, 1);
if( code == null || code.getStatements().size() != 1 )
return null;
return asVarX(code.getStatements().get(0));
}

@Override
public void visitDeclarationExpression(DeclarationExpression node) {
visit(node.getRightExpression());
Expand Down
8 changes: 8 additions & 0 deletions modules/compiler/src/main/java/script/types/Channel.java
Original file line number Diff line number Diff line change
Expand Up @@ -419,6 +419,14 @@ public static Channel<Path> watchPath(String filePattern, String events) {
""")
public abstract Channel take(int n);

@Operator
@Description("""
The `tap` operator assigns a source channel to a variable, whose name is specified in a closure.
[Read more](https://nextflow.io/docs/latest/reference/operator.html#tap)
""")
public abstract Channel tap(Closure holder);

@Operator
@Description("""
The `toList` operator collects all the values from a source channel into a list and emits the list as a single value.
Expand Down

0 comments on commit dff88b5

Please sign in to comment.