diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/BaseVisitor.java b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/BaseVisitor.java index eaae28410150..9e18d30c0950 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/BaseVisitor.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/BaseVisitor.java @@ -143,6 +143,9 @@ import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLElementAccess; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLElementFilter; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLElementLiteral; +import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLFilterStepExtend; +import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLIndexedStepExtend; +import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLMethodCallStepExtend; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLNavigationAccess; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLProcInsLiteral; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLQName; @@ -1046,6 +1049,18 @@ public void visit(BLangXMLElementAccess xmlElementAccess) { public void visit(BLangXMLNavigationAccess xmlNavigation) { } + @Override + public void visit(BLangXMLIndexedStepExtend xmlIndexedStepExtend) { + } + + @Override + public void visit(BLangXMLFilterStepExtend xmlFilterStepExtend) { + } + + @Override + public void visit(BLangXMLMethodCallStepExtend xmlMethodCallStepExtend) { + } + @Override public void visit(BLangClassDefinition classDefinition) { } diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/NodeFinder.java b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/NodeFinder.java index e885d26aa376..00972ffff659 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/NodeFinder.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/NodeFinder.java @@ -87,6 +87,7 @@ import org.wso2.ballerinalang.compiler.tree.expressions.BLangElvisExpr; import org.wso2.ballerinalang.compiler.tree.expressions.BLangErrorConstructorExpr; import org.wso2.ballerinalang.compiler.tree.expressions.BLangErrorVarRef; +import org.wso2.ballerinalang.compiler.tree.expressions.BLangExtendedXMLNavigationAccess; import org.wso2.ballerinalang.compiler.tree.expressions.BLangFieldBasedAccess; import org.wso2.ballerinalang.compiler.tree.expressions.BLangGroupExpr; import org.wso2.ballerinalang.compiler.tree.expressions.BLangIndexBasedAccess; @@ -144,6 +145,9 @@ import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLElementAccess; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLElementFilter; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLElementLiteral; +import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLFilterStepExtend; +import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLIndexedStepExtend; +import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLMethodCallStepExtend; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLNavigationAccess; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLProcInsLiteral; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLQName; @@ -1283,10 +1287,31 @@ public void visit(BLangXMLElementAccess xmlElementAccess) { @Override public void visit(BLangXMLNavigationAccess xmlNavigation) { lookupNode(xmlNavigation.expr); - lookupNode(xmlNavigation.childIndex); lookupNodes(xmlNavigation.filters); } + @Override + public void visit(BLangExtendedXMLNavigationAccess extendedXmlNavigationAccess) { + lookupNode(extendedXmlNavigationAccess.stepExpr); + lookupNodes(extendedXmlNavigationAccess.extensions); + } + + @Override + public void visit(BLangXMLIndexedStepExtend xmlIndexedStepExtend) { + lookupNode(xmlIndexedStepExtend.indexExpr); + } + + @Override + public void visit(BLangXMLFilterStepExtend xmlFilterStepExtend) { + lookupNodes(xmlFilterStepExtend.filters); + setEnclosingNode(xmlFilterStepExtend, xmlFilterStepExtend.pos); + } + + @Override + public void visit(BLangXMLMethodCallStepExtend xmlMethodCallStepExtend) { + lookupNode(xmlMethodCallStepExtend.invocation); + } + @Override public void visit(BLangMatchStatement matchStatementNode) { lookupNode(matchStatementNode.expr); diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/ReferenceFinder.java b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/ReferenceFinder.java index 760d26ce9e14..f87708210ab6 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/ReferenceFinder.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/ReferenceFinder.java @@ -94,6 +94,7 @@ import org.wso2.ballerinalang.compiler.tree.expressions.BLangErrorConstructorExpr; import org.wso2.ballerinalang.compiler.tree.expressions.BLangErrorVarRef; import org.wso2.ballerinalang.compiler.tree.expressions.BLangExpression; +import org.wso2.ballerinalang.compiler.tree.expressions.BLangExtendedXMLNavigationAccess; import org.wso2.ballerinalang.compiler.tree.expressions.BLangFieldBasedAccess; import org.wso2.ballerinalang.compiler.tree.expressions.BLangFieldBasedAccess.BLangNSPrefixedFieldBasedAccess; import org.wso2.ballerinalang.compiler.tree.expressions.BLangGroupExpr; @@ -151,6 +152,9 @@ import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLElementAccess; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLElementFilter; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLElementLiteral; +import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLFilterStepExtend; +import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLIndexedStepExtend; +import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLMethodCallStepExtend; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLNavigationAccess; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLProcInsLiteral; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLQName; @@ -1323,11 +1327,36 @@ public void visit(BLangXMLElementAccess xmlElementAccess) { @Override public void visit(BLangXMLNavigationAccess xmlNavigation) { - find(xmlNavigation.childIndex); find(xmlNavigation.filters); find(xmlNavigation.expr); } + @Override + public void visit(BLangExtendedXMLNavigationAccess extendedXmlNavigationAccess) { + find(extendedXmlNavigationAccess.extensions); + find(extendedXmlNavigationAccess.stepExpr); + } + + @Override + public void visit(BLangXMLIndexedStepExtend xmlIndexedStepExtend) { + find(xmlIndexedStepExtend.indexExpr); + } + + @Override + public void visit(BLangXMLFilterStepExtend xmlFilterStepExtend) { + find(xmlFilterStepExtend.filters); + } + + @Override + public void visit(BLangXMLMethodCallStepExtend xmlMethodCallStepExtend) { + BLangInvocation invocation = xmlMethodCallStepExtend.invocation; + List argExprs = invocation.argExprs; + for (int i = 1; i < argExprs.size(); i++) { + find(argExprs.get(i)); + } + addIfSameSymbol(invocation.symbol, invocation.name.pos); + } + @Override public void visit(BLangClassDefinition classDefinition) { find(classDefinition.annAttachments); diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/SymbolFinder.java b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/SymbolFinder.java index dd857e2bbb63..87d19af25017 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/SymbolFinder.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/SymbolFinder.java @@ -98,6 +98,7 @@ import org.wso2.ballerinalang.compiler.tree.expressions.BLangErrorConstructorExpr; import org.wso2.ballerinalang.compiler.tree.expressions.BLangErrorVarRef; import org.wso2.ballerinalang.compiler.tree.expressions.BLangExpression; +import org.wso2.ballerinalang.compiler.tree.expressions.BLangExtendedXMLNavigationAccess; import org.wso2.ballerinalang.compiler.tree.expressions.BLangFieldBasedAccess; import org.wso2.ballerinalang.compiler.tree.expressions.BLangGroupExpr; import org.wso2.ballerinalang.compiler.tree.expressions.BLangIgnoreExpr; @@ -162,6 +163,9 @@ import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLElementAccess; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLElementFilter; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLElementLiteral; +import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLFilterStepExtend; +import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLIndexedStepExtend; +import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLMethodCallStepExtend; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLNavigationAccess; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLProcInsLiteral; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLQName; @@ -1670,10 +1674,30 @@ public void visit(BLangXMLElementAccess xmlElementAccess) { @Override public void visit(BLangXMLNavigationAccess xmlNavigation) { lookupNode(xmlNavigation.expr); - lookupNode(xmlNavigation.childIndex); lookupNodes(xmlNavigation.filters); } + @Override + public void visit(BLangExtendedXMLNavigationAccess extendedXmlNavigationAccess) { + lookupNode(extendedXmlNavigationAccess.stepExpr); + lookupNodes(extendedXmlNavigationAccess.extensions); + } + + @Override + public void visit(BLangXMLIndexedStepExtend xmlIndexedStepExtend) { + lookupNode(xmlIndexedStepExtend.indexExpr); + } + + @Override + public void visit(BLangXMLFilterStepExtend xmlFilterStepExtend) { + lookupNodes(xmlFilterStepExtend.filters); + } + + @Override + public void visit(BLangXMLMethodCallStepExtend xmlMethodCallStepExtend) { + lookupNode(xmlMethodCallStepExtend.invocation); + } + @Override public void visit(BLangInvocation.BLangResourceAccessInvocation resourceAccessInvocation) { lookupNodes(resourceAccessInvocation.annAttachments); diff --git a/compiler/ballerina-lang/src/main/java/org/ballerinalang/model/tree/NodeKind.java b/compiler/ballerina-lang/src/main/java/org/ballerinalang/model/tree/NodeKind.java index 989e0d1edc7c..1b6c3289d9fa 100644 --- a/compiler/ballerina-lang/src/main/java/org/ballerinalang/model/tree/NodeKind.java +++ b/compiler/ballerina-lang/src/main/java/org/ballerinalang/model/tree/NodeKind.java @@ -112,6 +112,10 @@ public enum NodeKind { XML_ELEMENT_FILTER_EXPR, XML_ELEMENT_ACCESS, XML_NAVIGATION, + XML_EXTENDED_NAVIGATION, + XML_STEP_INDEXED_EXTEND, + XML_STEP_FILTER_EXTEND, + XML_STEP_METHOD_CALL_EXTEND, STATEMENT_EXPRESSION, MATCH_EXPRESSION, MATCH_EXPRESSION_PATTERN_CLAUSE, diff --git a/compiler/ballerina-lang/src/main/java/org/ballerinalang/model/tree/expressions/XMLNavigationAccess.java b/compiler/ballerina-lang/src/main/java/org/ballerinalang/model/tree/expressions/XMLNavigationAccess.java index 9e1ac67d5b15..e7dba6911914 100644 --- a/compiler/ballerina-lang/src/main/java/org/ballerinalang/model/tree/expressions/XMLNavigationAccess.java +++ b/compiler/ballerina-lang/src/main/java/org/ballerinalang/model/tree/expressions/XMLNavigationAccess.java @@ -69,6 +69,4 @@ public static NavAccessType fromInt(int number) { List getFilters(); BLangExpression getExpression(); - - BLangExpression getChildIndex(); } diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/desugar/ClassClosureDesugar.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/desugar/ClassClosureDesugar.java index c57c896e92c3..8b5bcb4218ba 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/desugar/ClassClosureDesugar.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/desugar/ClassClosureDesugar.java @@ -61,6 +61,7 @@ import org.wso2.ballerinalang.compiler.tree.expressions.BLangErrorConstructorExpr; import org.wso2.ballerinalang.compiler.tree.expressions.BLangErrorVarRef; import org.wso2.ballerinalang.compiler.tree.expressions.BLangExpression; +import org.wso2.ballerinalang.compiler.tree.expressions.BLangExtendedXMLNavigationAccess; import org.wso2.ballerinalang.compiler.tree.expressions.BLangFieldBasedAccess; import org.wso2.ballerinalang.compiler.tree.expressions.BLangGroupExpr; import org.wso2.ballerinalang.compiler.tree.expressions.BLangIgnoreExpr; @@ -104,6 +105,9 @@ import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLCommentLiteral; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLElementAccess; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLElementLiteral; +import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLFilterStepExtend; +import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLIndexedStepExtend; +import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLMethodCallStepExtend; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLNavigationAccess; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLProcInsLiteral; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLQName; @@ -1092,11 +1096,33 @@ public void visit(BLangXMLElementAccess xmlElementAccess) { @Override public void visit(BLangXMLNavigationAccess xmlNavigation) { xmlNavigation.expr = rewriteExpr(xmlNavigation.expr); - xmlNavigation.childIndex = rewriteExpr(xmlNavigation.childIndex); result = xmlNavigation; } + @Override + public void visit(BLangExtendedXMLNavigationAccess extendedXMLNavigationAccess) { + extendedXMLNavigationAccess.stepExpr = rewriteExpr(extendedXMLNavigationAccess.stepExpr); + rewriteExprs(extendedXMLNavigationAccess.extensions); + result = extendedXMLNavigationAccess; + } + + @Override + public void visit(BLangXMLIndexedStepExtend xmlIndexedStepExtend) { + xmlIndexedStepExtend.indexExpr = rewriteExpr(xmlIndexedStepExtend.indexExpr); + result = xmlIndexedStepExtend; + } + @Override + public void visit(BLangXMLMethodCallStepExtend xmlMethodCallStepExtend) { + xmlMethodCallStepExtend.invocation = rewriteExpr(xmlMethodCallStepExtend.invocation); + result = xmlMethodCallStepExtend; + } + + @Override + public void visit(BLangXMLFilterStepExtend xmlFilterStepExtend) { + result = xmlFilterStepExtend; + } + @Override public void visit(BLangIndexBasedAccess.BLangJSONAccessExpr jsonAccessExpr) { jsonAccessExpr.indexExpr = rewriteExpr(jsonAccessExpr.indexExpr); diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/desugar/ClosureDesugar.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/desugar/ClosureDesugar.java index f3c4aa6328c0..2dc2e50fa1d8 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/desugar/ClosureDesugar.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/desugar/ClosureDesugar.java @@ -1900,7 +1900,6 @@ public void visit(BLangIndexBasedAccess.BLangXMLAccessExpr xmlIndexAccessExpr) { result = xmlIndexAccessExpr; } - @Override public void visit(BLangXMLElementAccess xmlElementAccess) { xmlElementAccess.expr = rewriteExpr(xmlElementAccess.expr); @@ -1910,11 +1909,9 @@ public void visit(BLangXMLElementAccess xmlElementAccess) { @Override public void visit(BLangXMLNavigationAccess xmlNavigation) { xmlNavigation.expr = rewriteExpr(xmlNavigation.expr); - xmlNavigation.childIndex = rewriteExpr(xmlNavigation.childIndex); result = xmlNavigation; } - @Override public void visit(BLangIndexBasedAccess.BLangJSONAccessExpr jsonAccessExpr) { jsonAccessExpr.indexExpr = rewriteExpr(jsonAccessExpr.indexExpr); diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/desugar/ClosureGenerator.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/desugar/ClosureGenerator.java index 8dddd9b2e014..7719b9d8c8b4 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/desugar/ClosureGenerator.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/desugar/ClosureGenerator.java @@ -92,6 +92,7 @@ import org.wso2.ballerinalang.compiler.tree.expressions.BLangErrorConstructorExpr; import org.wso2.ballerinalang.compiler.tree.expressions.BLangErrorVarRef; import org.wso2.ballerinalang.compiler.tree.expressions.BLangExpression; +import org.wso2.ballerinalang.compiler.tree.expressions.BLangExtendedXMLNavigationAccess; import org.wso2.ballerinalang.compiler.tree.expressions.BLangFieldBasedAccess; import org.wso2.ballerinalang.compiler.tree.expressions.BLangGroupExpr; import org.wso2.ballerinalang.compiler.tree.expressions.BLangIgnoreExpr; @@ -142,11 +143,15 @@ import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLCommentLiteral; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLElementAccess; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLElementLiteral; +import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLFilterStepExtend; +import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLIndexedStepExtend; +import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLMethodCallStepExtend; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLNavigationAccess; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLProcInsLiteral; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLQName; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLQuotedString; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLSequenceLiteral; +import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLStepExtend; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLTextLiteral; import org.wso2.ballerinalang.compiler.tree.statements.BLangAssignment; import org.wso2.ballerinalang.compiler.tree.statements.BLangBlockStmt; @@ -1392,10 +1397,36 @@ public void visit(BLangXMLElementAccess xmlElementAccess) { @Override public void visit(BLangXMLNavigationAccess xmlNavigation) { xmlNavigation.expr = rewriteExpr(xmlNavigation.expr); - xmlNavigation.childIndex = rewriteExpr(xmlNavigation.childIndex); result = xmlNavigation; } + @Override + public void visit(BLangExtendedXMLNavigationAccess extendedXmlNavigationAccess) { + extendedXmlNavigationAccess.stepExpr = rewriteExpr(extendedXmlNavigationAccess.stepExpr); + List extensions = extendedXmlNavigationAccess.extensions; + for (int i = 0; i < extensions.size(); i++) { + extensions.set(i, rewrite(extensions.get(i), env)); + } + result = extendedXmlNavigationAccess; + } + + @Override + public void visit(BLangXMLIndexedStepExtend xmlIndexedStepExtend) { + xmlIndexedStepExtend.indexExpr = rewriteExpr(xmlIndexedStepExtend.indexExpr); + result = xmlIndexedStepExtend; + } + + @Override + public void visit(BLangXMLFilterStepExtend xmlFilterStepExtend) { + result = xmlFilterStepExtend; + } + + @Override + public void visit(BLangXMLMethodCallStepExtend xmlMethodCallStepExtend) { + xmlMethodCallStepExtend.invocation = rewriteExpr(xmlMethodCallStepExtend.invocation); + result = xmlMethodCallStepExtend; + } + @Override public void visit(BLangIndexBasedAccess.BLangJSONAccessExpr jsonAccessExpr) { jsonAccessExpr.indexExpr = rewriteExpr(jsonAccessExpr.indexExpr); diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/desugar/ConstantPropagation.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/desugar/ConstantPropagation.java index 496d85290cdb..cda3e914e1f9 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/desugar/ConstantPropagation.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/desugar/ConstantPropagation.java @@ -75,6 +75,7 @@ import org.wso2.ballerinalang.compiler.tree.expressions.BLangElvisExpr; import org.wso2.ballerinalang.compiler.tree.expressions.BLangErrorConstructorExpr; import org.wso2.ballerinalang.compiler.tree.expressions.BLangErrorVarRef; +import org.wso2.ballerinalang.compiler.tree.expressions.BLangExtendedXMLNavigationAccess; import org.wso2.ballerinalang.compiler.tree.expressions.BLangFieldBasedAccess; import org.wso2.ballerinalang.compiler.tree.expressions.BLangGroupExpr; import org.wso2.ballerinalang.compiler.tree.expressions.BLangIndexBasedAccess; @@ -134,9 +135,13 @@ import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLElementAccess; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLElementFilter; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLElementLiteral; +import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLFilterStepExtend; +import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLIndexedStepExtend; +import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLMethodCallStepExtend; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLNavigationAccess; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLProcInsLiteral; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLSequenceLiteral; +import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLStepExtend; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLTextLiteral; import org.wso2.ballerinalang.compiler.tree.matchpatterns.BLangConstPattern; import org.wso2.ballerinalang.compiler.tree.matchpatterns.BLangErrorMatchPattern; @@ -874,10 +879,36 @@ public void visit(BLangXMLElementAccess xmlElementAccess) { @Override public void visit(BLangXMLNavigationAccess xmlNavigation) { - xmlNavigation.childIndex = rewrite(xmlNavigation.childIndex); result = xmlNavigation; } + @Override + public void visit(BLangExtendedXMLNavigationAccess extendedXmlNavigationAccess) { + List extensions = extendedXmlNavigationAccess.extensions; + for (int i = 0; i < extensions.size(); i++) { + BLangXMLStepExtend extension = extensions.get(i); + extensions.set(i, rewrite(extension)); + } + result = extendedXmlNavigationAccess; + } + + @Override + public void visit(BLangXMLIndexedStepExtend xmlIndexedStepExtend) { + xmlIndexedStepExtend.indexExpr = rewrite(xmlIndexedStepExtend.indexExpr); + result = xmlIndexedStepExtend; + } + + @Override + public void visit(BLangXMLFilterStepExtend xmlFilterStepExtend) { + result = xmlFilterStepExtend; + } + + @Override + public void visit(BLangXMLMethodCallStepExtend xmlMethodCallStepExtend) { + xmlMethodCallStepExtend.invocation = rewrite(xmlMethodCallStepExtend.invocation); + result = xmlMethodCallStepExtend; + } + @Override public void visit(BLangXMLNS xmlnsNode) { result = xmlnsNode; diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/desugar/Desugar.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/desugar/Desugar.java index 1e9308685081..438117ceeb51 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/desugar/Desugar.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/desugar/Desugar.java @@ -83,6 +83,7 @@ import org.wso2.ballerinalang.compiler.semantics.model.types.BType; import org.wso2.ballerinalang.compiler.semantics.model.types.BTypedescType; import org.wso2.ballerinalang.compiler.semantics.model.types.BUnionType; +import org.wso2.ballerinalang.compiler.semantics.model.types.BXMLSubType; import org.wso2.ballerinalang.compiler.tree.BLangAnnotation; import org.wso2.ballerinalang.compiler.tree.BLangAnnotationAttachment; import org.wso2.ballerinalang.compiler.tree.BLangBlockFunctionBody; @@ -142,6 +143,7 @@ import org.wso2.ballerinalang.compiler.tree.expressions.BLangErrorConstructorExpr; import org.wso2.ballerinalang.compiler.tree.expressions.BLangErrorVarRef; import org.wso2.ballerinalang.compiler.tree.expressions.BLangExpression; +import org.wso2.ballerinalang.compiler.tree.expressions.BLangExtendedXMLNavigationAccess; import org.wso2.ballerinalang.compiler.tree.expressions.BLangFieldBasedAccess; import org.wso2.ballerinalang.compiler.tree.expressions.BLangFieldBasedAccess.BLangStructFunctionVarRef; import org.wso2.ballerinalang.compiler.tree.expressions.BLangGroupExpr; @@ -227,11 +229,15 @@ import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLElementAccess; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLElementFilter; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLElementLiteral; +import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLFilterStepExtend; +import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLIndexedStepExtend; +import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLMethodCallStepExtend; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLNavigationAccess; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLProcInsLiteral; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLQName; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLQuotedString; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLSequenceLiteral; +import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLStepExtend; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLTextLiteral; import org.wso2.ballerinalang.compiler.tree.matchpatterns.BLangConstPattern; import org.wso2.ballerinalang.compiler.tree.matchpatterns.BLangErrorCauseMatchPattern; @@ -329,6 +335,7 @@ import javax.xml.XMLConstants; import static io.ballerina.runtime.api.constants.RuntimeConstants.UNDERSCORE; +import static org.ballerinalang.model.symbols.SymbolOrigin.SOURCE; import static org.ballerinalang.model.symbols.SymbolOrigin.VIRTUAL; import static org.ballerinalang.util.BLangCompilerConstants.RETRY_MANAGER_OBJECT_SHOULD_RETRY_FUNC; import static org.wso2.ballerinalang.compiler.desugar.ASTBuilderUtil.createBlockStmt; @@ -367,13 +374,13 @@ public class Desugar extends BLangNodeVisitor { private static final String CREATE_RECORD_VALUE = "createRecordFromMap"; private static final String CHANNEL_AUTO_CLOSE_FUNC_NAME = "autoClose"; - public static final String XML_INTERNAL_SELECT_DESCENDANTS = "selectDescendants"; public static final String XML_INTERNAL_CHILDREN = "children"; - public static final String XML_INTERNAL_GET_FILTERED_CHILDREN_FLAT = "getFilteredChildrenFlat"; + public static final String XML_MAP = "map"; + public static final String XML_GET_DESCENDANTS = "getDescendants"; public static final String XML_INTERNAL_GET_ELEMENT_NAME_NIL_LIFTING = "getElementNameNilLifting"; public static final String XML_INTERNAL_GET_ATTRIBUTE = "getAttribute"; public static final String XML_INTERNAL_GET_ELEMENTS = "getElements"; - public static final String XML_GET_CONTENT_OF_TEXT = "getContent"; + public static final String XML_ELEMENTS = "elements"; private SymbolTable symTable; private SymbolResolver symResolver; @@ -436,6 +443,7 @@ public class Desugar extends BLangNodeVisitor { private Map stmtsToBePropagatedToQuery = new HashMap<>(); // Reuse the strand annotation in isolated workers and start action private BLangAnnotationAttachment strandAnnotAttachement; + private BLangAnonymousModelHelper anonymousModelHelper; public static Desugar getInstance(CompilerContext context) { Desugar desugar = context.get(DESUGAR_KEY); @@ -473,6 +481,7 @@ private Desugar(CompilerContext context) { this.mockDesugar = MockDesugar.getInstance(context); this.classClosureDesugar = ClassClosureDesugar.getInstance(context); this.unifier = new Unifier(); + this.anonymousModelHelper = BLangAnonymousModelHelper.getInstance(context); } public BLangPackage perform(BLangPackage pkgNode) { @@ -6635,9 +6644,10 @@ private BLangInvocation rewriteXMLAttributeOrElemNameAccess(BLangFieldBasedAcces } // Handle element name access. + // Accessing field name using the "_" has been disallowed in the compile time. if (fieldName.equals("_")) { return createLanglibXMLInvocation(fieldAccessExpr.pos, XML_INTERNAL_GET_ELEMENT_NAME_NIL_LIFTING, - fieldAccessExpr.expr, new ArrayList<>(), new ArrayList<>()); + fieldAccessExpr.expr, Collections.emptyList(), Collections.emptyList()); } BLangLiteral attributeNameLiteral = createStringLiteral(fieldAccessExpr.field.pos, fieldName); @@ -6645,7 +6655,7 @@ private BLangInvocation rewriteXMLAttributeOrElemNameAccess(BLangFieldBasedAcces args.add(isOptionalAccessToLiteral(fieldAccessExpr)); return createLanglibXMLInvocation(fieldAccessExpr.pos, XML_INTERNAL_GET_ATTRIBUTE, fieldAccessExpr.expr, args, - new ArrayList<>()); + Collections.emptyList()); } private BLangExpression isOptionalAccessToLiteral(BLangFieldBasedAccess fieldAccessExpr) { @@ -8574,7 +8584,7 @@ public void visit(BLangXMLElementAccess xmlElementAccess) { ArrayList filters = expandFilters(xmlElementAccess.filters); BLangInvocation invocationNode = createLanglibXMLInvocation(xmlElementAccess.pos, XML_INTERNAL_GET_ELEMENTS, - xmlElementAccess.expr, new ArrayList<>(), filters); + xmlElementAccess.expr, Collections.emptyList(), filters); result = rewriteExpr(invocationNode); } @@ -8596,8 +8606,8 @@ private ArrayList expandFilters(List fil private BLangInvocation createLanglibXMLInvocation(Location pos, String functionName, BLangExpression invokeOnExpr, - ArrayList args, - ArrayList restArgs) { + List args, + List restArgs) { invokeOnExpr = rewriteExpr(invokeOnExpr); BLangInvocation invocationNode = (BLangInvocation) TreeBuilder.createInvocationNode(); @@ -8627,36 +8637,19 @@ private BLangInvocation createLanglibXMLInvocation(Location pos, String function @Override public void visit(BLangXMLNavigationAccess xmlNavigation) { xmlNavigation.expr = rewriteExpr(xmlNavigation.expr); - xmlNavigation.childIndex = rewriteExpr(xmlNavigation.childIndex); - - ArrayList filters = expandFilters(xmlNavigation.filters); - - // xml/**/ - if (xmlNavigation.navAccessType == XMLNavigationAccess.NavAccessType.DESCENDANTS) { - BLangInvocation invocationNode = createLanglibXMLInvocation(xmlNavigation.pos, - XML_INTERNAL_SELECT_DESCENDANTS, xmlNavigation.expr, new ArrayList<>(), filters); - result = rewriteExpr(invocationNode); - } else if (xmlNavigation.navAccessType == XMLNavigationAccess.NavAccessType.CHILDREN) { - // xml/* - BLangInvocation invocationNode = createLanglibXMLInvocation(xmlNavigation.pos, XML_INTERNAL_CHILDREN, - xmlNavigation.expr, new ArrayList<>(), new ArrayList<>()); - result = rewriteExpr(invocationNode); - } else { - BLangExpression childIndexExpr; - // xml/ - if (xmlNavigation.childIndex == null) { - childIndexExpr = new BLangLiteral(Long.valueOf(-1), symTable.intType); - } else { - // xml/[index] - childIndexExpr = xmlNavigation.childIndex; - } - ArrayList args = new ArrayList<>(); - args.add(rewriteExpr(childIndexExpr)); - - BLangInvocation invocationNode = createLanglibXMLInvocation(xmlNavigation.pos, - XML_INTERNAL_GET_FILTERED_CHILDREN_FLAT, xmlNavigation.expr, args, filters); - result = rewriteExpr(invocationNode); + if (xmlNavigation.parent.getKind() == NodeKind.XML_EXTENDED_NAVIGATION) { + result = xmlNavigation; + return; } + createMapFunctionForStepExpr(xmlNavigation, new ArrayList<>()); + } + + @Override + public void visit(BLangExtendedXMLNavigationAccess extendedXmlNavigationAccess) { + BLangXMLNavigationAccess stepExpr = extendedXmlNavigationAccess.stepExpr; + stepExpr.parent = extendedXmlNavigationAccess; + extendedXmlNavigationAccess.stepExpr = rewriteExpr(stepExpr); + createMapFunctionForStepExpr(extendedXmlNavigationAccess.stepExpr, extendedXmlNavigationAccess.extensions); } @Override @@ -10633,4 +10626,141 @@ protected void addTransactionInternalModuleImport() { env.enclPkg.symbol.imports.add(importDcl.symbol); } } + + private void createMapFunctionForStepExpr(BLangXMLNavigationAccess xmlNavigation, + List extensions) { + Location pos = xmlNavigation.pos; + List args; + List filters = expandFilters(xmlNavigation.filters); + + // xml/**/ + if (xmlNavigation.navAccessType == XMLNavigationAccess.NavAccessType.DESCENDANTS) { + args = List.of(createArrowFunctionForNavigation(pos, extensions, XML_GET_DESCENDANTS, filters)); + } else { + // xml/* + args = List.of(createArrowFunctionForNavigation(pos, extensions, XML_INTERNAL_CHILDREN, filters)); + } + + BLangInvocation elements = + createLanglibXMLInvocation(pos, XML_ELEMENTS, xmlNavigation.expr, Collections.emptyList(), + Collections.emptyList()); + BLangInvocation invocationNode = + createLanglibXMLInvocation(pos, XML_MAP, elements, args, Collections.emptyList()); + result = rewriteExpr(invocationNode); + } + + public BLangLambdaFunction createArrowFunctionForNavigation(Location pos, List extensions, + String func, List filters) { + BLangPackage enclPkg = env.enclPkg; + PackageID pkgID = enclPkg.packageID; + BType xmlType = symTable.xmlType; + BXMLSubType xmlElementType = symTable.xmlElementType; + + BLangArrowFunction arrowFunction = (BLangArrowFunction) TreeBuilder.createArrowFunctionNode(); + arrowFunction.pos = pos; + arrowFunction.functionName = createIdentifier(pos, anonymousModelHelper.getNextAnonymousFunctionKey(pkgID)); + + BInvokableTypeSymbol invokableTypeSymbol = Symbols.createInvokableTypeSymbol(SymTag.FUNCTION_TYPE, Flags.PUBLIC, + pkgID, xmlType, enclPkg.symbol.owner, pos, VIRTUAL); + arrowFunction.funcType = new BInvokableType(List.of(xmlElementType), xmlType, invokableTypeSymbol); + + BSymbol owner = env.scope.owner; + String parameterName = "$element$"; + BLangSimpleVariable param = (BLangSimpleVariable) TreeBuilder.createSimpleVariableNode(); + param.pos = pos; + param.setName(createIdentifier(pos, parameterName)); + BVarSymbol symbol = + new BVarSymbol(0, Names.fromString(parameterName), owner.pkgID, xmlElementType, owner, pos, SOURCE); + param.symbol = symbol; + param.typeNode = ASTBuilderUtil.createTypeNode(xmlElementType); + param.setBType(xmlElementType); + arrowFunction.params.add(param); + + BLangSimpleVarRef varRef = (BLangSimpleVarRef) TreeBuilder.createSimpleVariableReferenceNode(); + varRef.pos = pos; + varRef.variableName = createIdentifier(pos, parameterName); + varRef.symbol = symbol; + varRef.pkgAlias = (BLangIdentifier) TreeBuilder.createIdentifierNode(); + varRef.setBType(xmlElementType); + + BLangExpression expression = + createLanglibXMLInvocation(pos, func, varRef, Collections.emptyList(), Collections.emptyList()); + expression = rewriteExpr(expression); + + if (filters.size() > 0) { + expression = createLanglibXMLInvocation(pos, XML_INTERNAL_GET_ELEMENTS, expression, Collections.emptyList(), + filters); + expression = rewriteExpr(expression); + } + + expression = createExpressionForExtensions(extensions, arrowFunction, expression); + + arrowFunction.body = new BLangExprFunctionBody(); + arrowFunction.body.expr = expression; + arrowFunction.body.pos = arrowFunction.body.expr.pos; + result = rewrite(arrowFunction, env); + return (BLangLambdaFunction) result; + } + + private BLangExpression createExpressionForExtensions(List extensions, + BLangArrowFunction arrowFunction, + BLangExpression expression) { + for (BLangXMLStepExtend extension : extensions) { + switch (extension.getKind()) { + case XML_STEP_INDEXED_EXTEND -> expression = + createExpressionForIndexedStepExtend(arrowFunction, expression, + (BLangXMLIndexedStepExtend) extension); + case XML_STEP_FILTER_EXTEND -> expression = + createExpressionForFilterStepExtend(expression, (BLangXMLFilterStepExtend) extension); + case XML_STEP_METHOD_CALL_EXTEND -> + expression = createExpressionForMethodCallStepExtend(arrowFunction, expression, + (BLangXMLMethodCallStepExtend) extension); + default -> throw new IllegalStateException("Invalid xml step extension: " + extension.getKind()); + } + expression.setBType(symTable.xmlType); + } + return expression; + } + + private BLangExpression createExpressionForMethodCallStepExtend(BLangArrowFunction arrowFunction, + BLangExpression expression, + BLangXMLMethodCallStepExtend methodCallStepExtend) { + BLangInvocation invocation = methodCallStepExtend.invocation; + if (invocation.requiredArgs.size() > 0) { + invocation.requiredArgs.remove(0); + } + + for (BLangExpression arg : invocation.requiredArgs) { + markAndAddPossibleClosureVarsToArrowFunction(arrowFunction, arg); + } + expression = createLanglibXMLInvocation(methodCallStepExtend.pos, invocation.name.value, expression, + invocation.requiredArgs, invocation.restArgs); + expression = rewrite(expression, env); + return types.addConversionExprIfRequired(expression, symTable.xmlType); + } + + private BLangExpression createExpressionForFilterStepExtend(BLangExpression expression, + BLangXMLFilterStepExtend filterStepExtend) { + ArrayList filterExtensions = expandFilters(filterStepExtend.filters); + return createLanglibXMLInvocation(filterStepExtend.pos, XML_INTERNAL_GET_ELEMENTS, expression, + Collections.emptyList(), filterExtensions); + } + + private BLangExpression createExpressionForIndexedStepExtend(BLangArrowFunction arrowFunction, + BLangExpression expression, + BLangXMLIndexedStepExtend indexedStepExtend) { + BLangExpression indexExpr = indexedStepExtend.indexExpr; + markAndAddPossibleClosureVarsToArrowFunction(arrowFunction, indexExpr); + return ASTBuilderUtil.createIndexAccessExpr(expression, indexExpr); + } + + private static void markAndAddPossibleClosureVarsToArrowFunction(BLangArrowFunction arrFunction, + BLangExpression expression) { + if (expression.getKind() != NodeKind.SIMPLE_VARIABLE_REF) { + return; + } + BLangSimpleVarRef simpleVarRef = (BLangSimpleVarRef) expression; + simpleVarRef.symbol.closure = true; + arrFunction.closureVarSymbols.add(new ClosureVarSymbol(simpleVarRef.symbol, simpleVarRef.pos)); + } } diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/desugar/QueryDesugar.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/desugar/QueryDesugar.java index c292edb3a4c1..743c9d258b2f 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/desugar/QueryDesugar.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/desugar/QueryDesugar.java @@ -94,6 +94,7 @@ import org.wso2.ballerinalang.compiler.tree.expressions.BLangErrorConstructorExpr; import org.wso2.ballerinalang.compiler.tree.expressions.BLangErrorVarRef; import org.wso2.ballerinalang.compiler.tree.expressions.BLangExpression; +import org.wso2.ballerinalang.compiler.tree.expressions.BLangExtendedXMLNavigationAccess; import org.wso2.ballerinalang.compiler.tree.expressions.BLangFieldBasedAccess; import org.wso2.ballerinalang.compiler.tree.expressions.BLangGroupExpr; import org.wso2.ballerinalang.compiler.tree.expressions.BLangIgnoreExpr; @@ -2452,10 +2453,15 @@ public void visit(BLangXMLElementAccess xmlElementAccess) { @Override public void visit(BLangXMLNavigationAccess xmlNavigation) { xmlNavigation.expr = rewrite(xmlNavigation.expr); - xmlNavigation.childIndex = rewrite(xmlNavigation.childIndex); result = xmlNavigation; } + @Override + public void visit(BLangExtendedXMLNavigationAccess extendedXmlNavigationAccess) { + extendedXmlNavigationAccess.stepExpr = rewrite(extendedXmlNavigationAccess.stepExpr); + result = extendedXmlNavigationAccess; + } + //statements @Override public void visit(BLangBlockStmt blockNode) { 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 d5a798a6f385..abe9415231de 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 @@ -257,6 +257,7 @@ import io.ballerina.compiler.syntax.tree.XMLStartTagNode; import io.ballerina.compiler.syntax.tree.XMLStepExpressionNode; import io.ballerina.compiler.syntax.tree.XMLStepIndexedExtendNode; +import io.ballerina.compiler.syntax.tree.XMLStepMethodCallExtendNode; import io.ballerina.compiler.syntax.tree.XMLTextNode; import io.ballerina.identifier.Utils; import io.ballerina.runtime.internal.XmlFactory; @@ -358,6 +359,7 @@ import org.wso2.ballerinalang.compiler.tree.expressions.BLangErrorConstructorExpr; import org.wso2.ballerinalang.compiler.tree.expressions.BLangErrorVarRef; import org.wso2.ballerinalang.compiler.tree.expressions.BLangExpression; +import org.wso2.ballerinalang.compiler.tree.expressions.BLangExtendedXMLNavigationAccess; import org.wso2.ballerinalang.compiler.tree.expressions.BLangFieldBasedAccess; import org.wso2.ballerinalang.compiler.tree.expressions.BLangGroupExpr; import org.wso2.ballerinalang.compiler.tree.expressions.BLangIndexBasedAccess; @@ -427,11 +429,15 @@ import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLElementAccess; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLElementFilter; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLElementLiteral; +import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLFilterStepExtend; +import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLIndexedStepExtend; +import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLMethodCallStepExtend; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLNavigationAccess; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLProcInsLiteral; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLQName; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLQuotedString; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLSequenceLiteral; +import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLStepExtend; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLTextLiteral; import org.wso2.ballerinalang.compiler.tree.matchpatterns.BLangConstPattern; import org.wso2.ballerinalang.compiler.tree.matchpatterns.BLangErrorCauseMatchPattern; @@ -4444,17 +4450,15 @@ public BLangNode transform(XMLStepExpressionNode xmlStepExpressionNode) { } BLangExpression expr = createExpression(xmlStepExpressionNode.expression()); - BLangExpression childIndex = null; - for (Node extension : xmlStepExpressionNode.xmlStepExtend()) { - if (extension.kind() == SyntaxKind.XML_STEP_INDEXED_EXTEND) { - childIndex = createExpression(((XMLStepIndexedExtendNode) extension).expression()); - break; - } + BLangXMLNavigationAccess xmlNavigationAccess = new BLangXMLNavigationAccess( + getPosition(xmlStepExpressionNode.expression(), xmlStepExpressionNode.xmlStepStart()), expr, filters, + XMLNavigationAccess.NavAccessType.fromInt(starCount)); + if (xmlStepExpressionNode.xmlStepExtend().size() > 0) { + List extensions = + createBLangXMLStepExtends(xmlStepExpressionNode.xmlStepExtend(), xmlNavigationAccess); + return new BLangExtendedXMLNavigationAccess(getPosition(xmlStepExpressionNode), xmlNavigationAccess, + extensions); } - // TODO : implement the value for childIndex - BLangXMLNavigationAccess xmlNavigationAccess = - new BLangXMLNavigationAccess(getPosition(xmlStepExpressionNode), expr, filters, - XMLNavigationAccess.NavAccessType.fromInt(starCount), childIndex); return xmlNavigationAccess; } @@ -7080,4 +7084,36 @@ private void setClassQualifiers(NodeList qualifiers, BLangClassDefinition } } } + + private List createBLangXMLStepExtends(NodeList nodes, BLangExpression expr) { + List extensions = new ArrayList<>(nodes.size()); + BLangXMLStepExtend curExpr = null; + for (Node node : nodes) { + Location pos = getPosition(node); + switch (node.kind()) { + case XML_STEP_INDEXED_EXTEND -> curExpr = new BLangXMLIndexedStepExtend(pos, + createExpression(((XMLStepIndexedExtendNode) node).expression())); + case XML_STEP_METHOD_CALL_EXTEND -> { + XMLStepMethodCallExtendNode xmlStepMethodCallExtendNode = (XMLStepMethodCallExtendNode) node; + SimpleNameReferenceNode methodName = xmlStepMethodCallExtendNode.methodName(); + BLangInvocation bLangInvocation = createBLangInvocation(methodName, + xmlStepMethodCallExtendNode.parenthesizedArgList().arguments(), pos, + false); + bLangInvocation.expr = curExpr == null ? expr : curExpr; + curExpr = new BLangXMLMethodCallStepExtend(pos, bLangInvocation); + } + case XML_NAME_PATTERN_CHAIN -> { + XMLNamePatternChainingNode xmlNamePatternChainingNode = (XMLNamePatternChainingNode) node; + List filters = new ArrayList<>(); + for (Node namePattern : xmlNamePatternChainingNode.xmlNamePattern()) { + filters.add(createXMLElementFilter(namePattern)); + } + curExpr = new BLangXMLFilterStepExtend(pos, filters); + } + default -> throw new IllegalStateException("Invalid xml step extension kind: " + node.kind()); + } + extensions.add(curExpr); + } + return extensions; + } } diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/parser/NodeCloner.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/parser/NodeCloner.java index 3af5789cb94c..e1c8447007f6 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/parser/NodeCloner.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/parser/NodeCloner.java @@ -98,6 +98,7 @@ import org.wso2.ballerinalang.compiler.tree.expressions.BLangElvisExpr; import org.wso2.ballerinalang.compiler.tree.expressions.BLangErrorConstructorExpr; import org.wso2.ballerinalang.compiler.tree.expressions.BLangErrorVarRef; +import org.wso2.ballerinalang.compiler.tree.expressions.BLangExtendedXMLNavigationAccess; import org.wso2.ballerinalang.compiler.tree.expressions.BLangFieldBasedAccess; import org.wso2.ballerinalang.compiler.tree.expressions.BLangGroupExpr; import org.wso2.ballerinalang.compiler.tree.expressions.BLangIgnoreExpr; @@ -171,6 +172,9 @@ import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLElementAccess; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLElementFilter; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLElementLiteral; +import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLFilterStepExtend; +import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLIndexedStepExtend; +import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLMethodCallStepExtend; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLNavigationAccess; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLProcInsLiteral; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLQName; @@ -2310,6 +2314,21 @@ public void visit(BLangXMLElementFilter source) { source.cloneRef = clone; } + @Override + public void visit(BLangXMLIndexedStepExtend source) { + source.cloneRef = new BLangXMLIndexedStepExtend(source.pos, clone(source.indexExpr)); + } + + @Override + public void visit(BLangXMLFilterStepExtend source) { + source.cloneRef = new BLangXMLFilterStepExtend(source.pos, cloneList(source.filters)); + } + + @Override + public void visit(BLangXMLMethodCallStepExtend source) { + source.cloneRef = new BLangXMLMethodCallStepExtend(source.pos, clone(source.invocation)); + } + @Override public void visit(BLangXMLElementAccess source) { BLangXMLElementAccess clone = new BLangXMLElementAccess( @@ -2325,8 +2344,16 @@ public void visit(BLangXMLNavigationAccess source) { source.pos, clone(source.expr), cloneList(source.filters), - source.navAccessType, - clone(source.childIndex)); + source.navAccessType); + source.cloneRef = clone; + } + + @Override + public void visit(BLangExtendedXMLNavigationAccess source) { + BLangExtendedXMLNavigationAccess clone = new BLangExtendedXMLNavigationAccess( + source.pos, + clone(source.stepExpr), + cloneList(source.extensions)); source.cloneRef = clone; } 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 38ea11405b35..a5849d95d172 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 @@ -28,7 +28,6 @@ import org.ballerinalang.model.tree.OperatorKind; import org.ballerinalang.model.tree.TopLevelNode; import org.ballerinalang.model.tree.expressions.RecordLiteralNode; -import org.ballerinalang.model.tree.expressions.XMLNavigationAccess; import org.ballerinalang.model.tree.statements.StatementNode; import org.ballerinalang.model.tree.statements.VariableDefinitionNode; import org.ballerinalang.util.diagnostic.DiagnosticErrorCode; @@ -130,6 +129,7 @@ import org.wso2.ballerinalang.compiler.tree.expressions.BLangErrorConstructorExpr; import org.wso2.ballerinalang.compiler.tree.expressions.BLangErrorVarRef; import org.wso2.ballerinalang.compiler.tree.expressions.BLangExpression; +import org.wso2.ballerinalang.compiler.tree.expressions.BLangExtendedXMLNavigationAccess; import org.wso2.ballerinalang.compiler.tree.expressions.BLangFieldBasedAccess; import org.wso2.ballerinalang.compiler.tree.expressions.BLangGroupExpr; import org.wso2.ballerinalang.compiler.tree.expressions.BLangIndexBasedAccess; @@ -179,6 +179,9 @@ import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLCommentLiteral; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLElementAccess; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLElementLiteral; +import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLFilterStepExtend; +import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLIndexedStepExtend; +import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLMethodCallStepExtend; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLNavigationAccess; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLProcInsLiteral; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLQName; @@ -2879,28 +2882,27 @@ public void visit(BLangXMLElementAccess xmlElementAccess, AnalyzerData data) { @Override public void visit(BLangXMLNavigationAccess xmlNavigation, AnalyzerData data) { analyzeExpr(xmlNavigation.expr, data); - if (xmlNavigation.childIndex != null) { - if (xmlNavigation.navAccessType == XMLNavigationAccess.NavAccessType.DESCENDANTS - || xmlNavigation.navAccessType == XMLNavigationAccess.NavAccessType.CHILDREN) { - dlog.error(xmlNavigation.pos, DiagnosticErrorCode.UNSUPPORTED_MEMBER_ACCESS_IN_XML_NAVIGATION); - } - analyzeExpr(xmlNavigation.childIndex, data); - } - validateMethodInvocationsInXMLNavigationExpression(xmlNavigation); } - private void validateMethodInvocationsInXMLNavigationExpression(BLangXMLNavigationAccess expression) { - if (!expression.methodInvocationAnalyzed && expression.parent.getKind() == NodeKind.INVOCATION) { - BLangInvocation invocation = (BLangInvocation) expression.parent; - // avoid langlib invocations re-written to have the receiver as first argument. - if (invocation.argExprs.contains(expression) - && ((invocation.symbol.flags & Flags.LANG_LIB) != Flags.LANG_LIB)) { - return; - } + @Override + public void visit(BLangExtendedXMLNavigationAccess extendedXmlNavigationAccess, AnalyzerData data) { + analyzeExpr(extendedXmlNavigationAccess.stepExpr, data); + extendedXmlNavigationAccess.extensions.forEach(extension -> analyzeNode(extension, data)); + } - dlog.error(invocation.pos, DiagnosticErrorCode.UNSUPPORTED_METHOD_INVOCATION_XML_NAV); - } - expression.methodInvocationAnalyzed = true; + @Override + public void visit(BLangXMLIndexedStepExtend xmlIndexedStepExtend, AnalyzerData data) { + analyzeExpr(xmlIndexedStepExtend.indexExpr, data); + } + + @Override + public void visit(BLangXMLFilterStepExtend xmlFilterStepExtend, AnalyzerData data) { + /* ignore */ + } + + @Override + public void visit(BLangXMLMethodCallStepExtend xmlMethodCallStepExtend, AnalyzerData data) { + analyzeExpr(xmlMethodCallStepExtend.invocation, data); } @Override diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/DataflowAnalyzer.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/DataflowAnalyzer.java index cc99e2f6e7ec..586306c2fe69 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/DataflowAnalyzer.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/DataflowAnalyzer.java @@ -108,6 +108,7 @@ import org.wso2.ballerinalang.compiler.tree.expressions.BLangErrorConstructorExpr; import org.wso2.ballerinalang.compiler.tree.expressions.BLangErrorVarRef; import org.wso2.ballerinalang.compiler.tree.expressions.BLangExpression; +import org.wso2.ballerinalang.compiler.tree.expressions.BLangExtendedXMLNavigationAccess; import org.wso2.ballerinalang.compiler.tree.expressions.BLangFieldBasedAccess; import org.wso2.ballerinalang.compiler.tree.expressions.BLangGroupExpr; import org.wso2.ballerinalang.compiler.tree.expressions.BLangIndexBasedAccess; @@ -169,6 +170,9 @@ import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLCommentLiteral; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLElementAccess; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLElementLiteral; +import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLFilterStepExtend; +import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLIndexedStepExtend; +import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLMethodCallStepExtend; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLNavigationAccess; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLProcInsLiteral; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLQName; @@ -1639,9 +1643,27 @@ public void visit(BLangXMLElementAccess xmlElementAccess) { @Override public void visit(BLangXMLNavigationAccess xmlNavigation) { analyzeNode(xmlNavigation.expr, env); - if (xmlNavigation.childIndex == null) { - analyzeNode(xmlNavigation.childIndex, env); - } + } + + @Override + public void visit(BLangExtendedXMLNavigationAccess extendedXmlNavigationAccess) { + analyzeNode(extendedXmlNavigationAccess.stepExpr, env); + extendedXmlNavigationAccess.extensions.forEach(extension -> analyzeNode(extension, env)); + } + + @Override + public void visit(BLangXMLIndexedStepExtend xmlIndexedStepExtend) { + analyzeNode(xmlIndexedStepExtend.indexExpr, env); + } + + @Override + public void visit(BLangXMLFilterStepExtend xmlFilterStepExtend) { + /* ignore */ + } + + @Override + public void visit(BLangXMLMethodCallStepExtend xmlMethodCallStepExtend) { + analyzeNode(xmlMethodCallStepExtend.invocation, env); } @Override diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/IsolationAnalyzer.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/IsolationAnalyzer.java index 9b63f21d67f0..6d3806035ee5 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/IsolationAnalyzer.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/IsolationAnalyzer.java @@ -146,6 +146,7 @@ import org.wso2.ballerinalang.compiler.tree.expressions.BLangErrorConstructorExpr; import org.wso2.ballerinalang.compiler.tree.expressions.BLangErrorVarRef; import org.wso2.ballerinalang.compiler.tree.expressions.BLangExpression; +import org.wso2.ballerinalang.compiler.tree.expressions.BLangExtendedXMLNavigationAccess; import org.wso2.ballerinalang.compiler.tree.expressions.BLangFieldBasedAccess; import org.wso2.ballerinalang.compiler.tree.expressions.BLangGroupExpr; import org.wso2.ballerinalang.compiler.tree.expressions.BLangIgnoreExpr; @@ -192,6 +193,9 @@ import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLCommentLiteral; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLElementAccess; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLElementLiteral; +import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLFilterStepExtend; +import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLIndexedStepExtend; +import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLMethodCallStepExtend; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLNavigationAccess; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLProcInsLiteral; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLQName; @@ -2060,10 +2064,26 @@ public void visit(BLangXMLElementAccess xmlElementAccess) { @Override public void visit(BLangXMLNavigationAccess xmlNavigation) { - BLangExpression childIndex = xmlNavigation.childIndex; - if (childIndex != null) { - analyzeNode(childIndex, env); - } + } + + @Override + public void visit(BLangExtendedXMLNavigationAccess extendedXmlNavigationAccess) { + extendedXmlNavigationAccess.extensions.forEach(extension -> analyzeNode(extension, env)); + } + + @Override + public void visit(BLangXMLIndexedStepExtend xmlIndexedStepExtend) { + analyzeNode(xmlIndexedStepExtend.indexExpr, env); + } + + @Override + public void visit(BLangXMLFilterStepExtend xmlFilterStepExtend) { + /* ignore */ + } + + @Override + public void visit(BLangXMLMethodCallStepExtend xmlMethodCallStepExtend) { + analyzeNode(xmlMethodCallStepExtend.invocation, env); } @Override diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/TypeChecker.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/TypeChecker.java index 78f9d04fde2e..ab664d33f353 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/TypeChecker.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/TypeChecker.java @@ -111,6 +111,7 @@ import org.wso2.ballerinalang.compiler.tree.expressions.BLangErrorConstructorExpr; import org.wso2.ballerinalang.compiler.tree.expressions.BLangErrorVarRef; import org.wso2.ballerinalang.compiler.tree.expressions.BLangExpression; +import org.wso2.ballerinalang.compiler.tree.expressions.BLangExtendedXMLNavigationAccess; import org.wso2.ballerinalang.compiler.tree.expressions.BLangFieldBasedAccess; import org.wso2.ballerinalang.compiler.tree.expressions.BLangGroupExpr; import org.wso2.ballerinalang.compiler.tree.expressions.BLangIndexBasedAccess; @@ -161,6 +162,9 @@ import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLElementAccess; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLElementFilter; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLElementLiteral; +import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLFilterStepExtend; +import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLIndexedStepExtend; +import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLMethodCallStepExtend; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLNavigationAccess; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLProcInsLiteral; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLQName; @@ -471,20 +475,38 @@ public void visit(BLangXMLElementAccess xmlElementAccess, AnalyzerData data) { @Override public void visit(BLangXMLNavigationAccess xmlNavigation, AnalyzerData data) { checkXMLNamespacePrefixes(xmlNavigation.filters, data); - if (xmlNavigation.childIndex != null) { - checkExpr(xmlNavigation.childIndex, symTable.intType, data); - } checkExpr(xmlNavigation.expr, symTable.xmlType, data); - BType actualType = xmlNavigation.navAccessType == XMLNavigationAccess.NavAccessType.CHILDREN ? symTable.xmlType : symTable.xmlElementSeqType; - types.checkType(xmlNavigation, actualType, data.expType); - if (xmlNavigation.navAccessType == XMLNavigationAccess.NavAccessType.CHILDREN) { - data.resultType = symTable.xmlType; - } else { - data.resultType = symTable.xmlElementSeqType; - } + data.resultType = actualType; + } + + @Override + public void visit(BLangExtendedXMLNavigationAccess extendedXmlNavigationAccess, AnalyzerData data) { + BType expType = data.expType; + checkExpr(extendedXmlNavigationAccess.stepExpr, data); + data.expType = symTable.xmlType; + extendedXmlNavigationAccess.extensions.forEach(extension -> extension.accept(this, data)); + data.resultType = types.checkType(extendedXmlNavigationAccess, data.resultType, expType); + } + + @Override + public void visit(BLangXMLIndexedStepExtend xmlIndexedStepExtend, AnalyzerData data) { + BType prevResultType = data.resultType; + checkExpr(xmlIndexedStepExtend.indexExpr, symTable.intType, data); + data.resultType = prevResultType; + } + + @Override + public void visit(BLangXMLFilterStepExtend xmlFilterStepExtend, AnalyzerData data) { + checkXMLNamespacePrefixes(xmlFilterStepExtend.filters, data); + data.resultType = symTable.xmlElementSeqType; + } + + @Override + public void visit(BLangXMLMethodCallStepExtend xmlMethodCallStepExtend, AnalyzerData data) { + checkExpr(xmlMethodCallStepExtend.invocation, data.expType, data); } private void checkXMLNamespacePrefixes(List filters, AnalyzerData data) { diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/tree/BLangNodeAnalyzer.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/tree/BLangNodeAnalyzer.java index 1dcfec2e70f6..128ccb32b1ea 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/tree/BLangNodeAnalyzer.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/tree/BLangNodeAnalyzer.java @@ -59,6 +59,7 @@ import org.wso2.ballerinalang.compiler.tree.expressions.BLangElvisExpr; import org.wso2.ballerinalang.compiler.tree.expressions.BLangErrorConstructorExpr; import org.wso2.ballerinalang.compiler.tree.expressions.BLangErrorVarRef; +import org.wso2.ballerinalang.compiler.tree.expressions.BLangExtendedXMLNavigationAccess; import org.wso2.ballerinalang.compiler.tree.expressions.BLangFieldBasedAccess; import org.wso2.ballerinalang.compiler.tree.expressions.BLangGroupExpr; import org.wso2.ballerinalang.compiler.tree.expressions.BLangIgnoreExpr; @@ -124,6 +125,9 @@ import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLElementAccess; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLElementFilter; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLElementLiteral; +import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLFilterStepExtend; +import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLIndexedStepExtend; +import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLMethodCallStepExtend; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLNavigationAccess; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLProcInsLiteral; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLQName; @@ -671,4 +675,12 @@ public abstract class BLangNodeAnalyzer { public abstract void visit(BLangUserDefinedType node, T data); public abstract void visit(BLangValueType node, T data); + + public abstract void visit(BLangXMLIndexedStepExtend node, T props); + + public abstract void visit(BLangXMLFilterStepExtend node, T props); + + public abstract void visit(BLangXMLMethodCallStepExtend node, T props); + + public abstract void visit(BLangExtendedXMLNavigationAccess node, T props); } diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/tree/BLangNodeTransformer.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/tree/BLangNodeTransformer.java index 94d243341572..7f161b8221f9 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/tree/BLangNodeTransformer.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/tree/BLangNodeTransformer.java @@ -58,6 +58,7 @@ import org.wso2.ballerinalang.compiler.tree.expressions.BLangElvisExpr; import org.wso2.ballerinalang.compiler.tree.expressions.BLangErrorConstructorExpr; import org.wso2.ballerinalang.compiler.tree.expressions.BLangErrorVarRef; +import org.wso2.ballerinalang.compiler.tree.expressions.BLangExtendedXMLNavigationAccess; import org.wso2.ballerinalang.compiler.tree.expressions.BLangFieldBasedAccess; import org.wso2.ballerinalang.compiler.tree.expressions.BLangGroupExpr; import org.wso2.ballerinalang.compiler.tree.expressions.BLangIgnoreExpr; @@ -123,6 +124,9 @@ import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLElementAccess; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLElementFilter; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLElementLiteral; +import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLFilterStepExtend; +import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLIndexedStepExtend; +import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLMethodCallStepExtend; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLNavigationAccess; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLProcInsLiteral; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLQName; @@ -1124,4 +1128,20 @@ public R transform(BLangUserDefinedType node, T data) { public R transform(BLangValueType node, T data) { return transformNode(node, data); } + + public R transform(BLangXMLIndexedStepExtend node, T data) { + return transformNode(node, data); + } + + public R transform(BLangXMLFilterStepExtend node, T data) { + return transformNode(node, data); + } + + public R transform(BLangXMLMethodCallStepExtend node, T data) { + return transformNode(node, data); + } + + public R transform(BLangExtendedXMLNavigationAccess node, T data) { + return transformNode(node, data); + } } diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/tree/BLangNodeVisitor.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/tree/BLangNodeVisitor.java index 2a16231e6622..f878c382e473 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/tree/BLangNodeVisitor.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/tree/BLangNodeVisitor.java @@ -61,6 +61,7 @@ import org.wso2.ballerinalang.compiler.tree.expressions.BLangElvisExpr; import org.wso2.ballerinalang.compiler.tree.expressions.BLangErrorConstructorExpr; import org.wso2.ballerinalang.compiler.tree.expressions.BLangErrorVarRef; +import org.wso2.ballerinalang.compiler.tree.expressions.BLangExtendedXMLNavigationAccess; import org.wso2.ballerinalang.compiler.tree.expressions.BLangFieldBasedAccess; import org.wso2.ballerinalang.compiler.tree.expressions.BLangFieldBasedAccess.BLangStructFunctionVarRef; import org.wso2.ballerinalang.compiler.tree.expressions.BLangGroupExpr; @@ -148,6 +149,9 @@ import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLElementAccess; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLElementFilter; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLElementLiteral; +import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLFilterStepExtend; +import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLIndexedStepExtend; +import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLMethodCallStepExtend; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLNavigationAccess; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLProcInsLiteral; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLQName; @@ -1150,4 +1154,20 @@ public void visit(BLangReFlagsOnOff reFlagsOnOff) { public void visit(BLangReFlagExpression reFlagsOnOff) { throw new AssertionError(); } + + public void visit(BLangXMLIndexedStepExtend xmlIndexedStepExtend) { + throw new AssertionError(); + } + + public void visit(BLangXMLFilterStepExtend xmlFilterStepExtend) { + throw new AssertionError(); + } + + public void visit(BLangXMLMethodCallStepExtend xmlMethodCallStepExtend) { + throw new AssertionError(); + } + + public void visit(BLangExtendedXMLNavigationAccess extendedXMLNavigationAccess) { + throw new AssertionError(); + } } diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/tree/SimpleBLangNodeAnalyzer.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/tree/SimpleBLangNodeAnalyzer.java index e46255e5227f..442feb764d30 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/tree/SimpleBLangNodeAnalyzer.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/tree/SimpleBLangNodeAnalyzer.java @@ -62,6 +62,7 @@ import org.wso2.ballerinalang.compiler.tree.expressions.BLangElvisExpr; import org.wso2.ballerinalang.compiler.tree.expressions.BLangErrorConstructorExpr; import org.wso2.ballerinalang.compiler.tree.expressions.BLangErrorVarRef; +import org.wso2.ballerinalang.compiler.tree.expressions.BLangExtendedXMLNavigationAccess; import org.wso2.ballerinalang.compiler.tree.expressions.BLangFieldBasedAccess; import org.wso2.ballerinalang.compiler.tree.expressions.BLangGroupExpr; import org.wso2.ballerinalang.compiler.tree.expressions.BLangIgnoreExpr; @@ -128,6 +129,9 @@ import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLElementAccess; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLElementFilter; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLElementLiteral; +import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLFilterStepExtend; +import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLIndexedStepExtend; +import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLMethodCallStepExtend; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLNavigationAccess; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLProcInsLiteral; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLQName; @@ -885,6 +889,24 @@ public void visit(BLangLetExpression node, T data) { } @Override + public void visit(BLangXMLIndexedStepExtend node, T data) { + analyzeNode(node, data); + visitNode(node.indexExpr, data); + } + + public void visit(BLangXMLFilterStepExtend node, T data) { + analyzeNode(node, data); + visitNode(node.filters, data); + } + + public void visit(BLangXMLMethodCallStepExtend node, T data) { + analyzeNode(node, data); + visitNode(node.invocation.name, data); + visitNode(node.invocation.argExprs, data); + visitNode(node.invocation.requiredArgs, data); + visitNode(node.invocation.restArgs, data); + } + public void visit(BLangListConstructorExpr node, T data) { analyzeNode(node, data); visitNode(node.exprs, data); @@ -1254,11 +1276,16 @@ public void visit(BLangXMLElementLiteral node, T data) { public void visit(BLangXMLNavigationAccess node, T data) { analyzeNode(node, data); visitNode(node.expr, data); - visitNode(node.childIndex, data); visitNode(node.filters, data); } @Override + public void visit(BLangExtendedXMLNavigationAccess node, T data) { + analyzeNode(node, data); + visitNode(node.stepExpr, data); + visitNode(node.extensions, data); + } + public void visit(BLangXMLProcInsLiteral node, T data) { analyzeNode(node, data); visitNode(node.target, data); diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/tree/expressions/BLangExtendedXMLNavigationAccess.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/tree/expressions/BLangExtendedXMLNavigationAccess.java new file mode 100644 index 000000000000..7793cbc3d42f --- /dev/null +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/tree/expressions/BLangExtendedXMLNavigationAccess.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2024, 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.wso2.ballerinalang.compiler.tree.expressions; + +import io.ballerina.tools.diagnostics.Location; +import org.ballerinalang.model.tree.NodeKind; +import org.ballerinalang.model.tree.expressions.XMLNavigationAccess; +import org.wso2.ballerinalang.compiler.tree.BLangNodeAnalyzer; +import org.wso2.ballerinalang.compiler.tree.BLangNodeTransformer; +import org.wso2.ballerinalang.compiler.tree.BLangNodeVisitor; + +import java.util.List; +import java.util.StringJoiner; + +/** + * Represents xml step expression with extensions. + * Example: {@code x/*.[index], x/.get(0)} + * + * @since 2201.10.0 + */ +public class BLangExtendedXMLNavigationAccess extends BLangExpression implements XMLNavigationAccess { + + public BLangXMLNavigationAccess stepExpr; + public final List extensions; + + public BLangExtendedXMLNavigationAccess(Location pos, BLangXMLNavigationAccess stepExpr, + List extensions) { + this.pos = pos; + this.stepExpr = stepExpr; + this.extensions = extensions; + } + + @Override + public void accept(BLangNodeVisitor visitor) { + visitor.visit(this); + } + + @Override + public void accept(BLangNodeAnalyzer analyzer, T props) { + analyzer.visit(this, props); + } + + @Override + public R apply(BLangNodeTransformer modifier, T props) { + return modifier.transform(this, props); + } + + @Override + public NodeKind getKind() { + return NodeKind.XML_EXTENDED_NAVIGATION; + } + + @Override + public NavAccessType getNavAccessType() { + return this.stepExpr.navAccessType; + } + + @Override + public List getFilters() { + return null; + } + + @Override + public BLangExpression getExpression() { + return stepExpr; + } + + @Override + public String toString() { + StringJoiner extensionString = new StringJoiner(""); + this.extensions.forEach(extension -> extensionString.add(extension.toString())); + return stepExpr.toString() + extensionString.toString(); + } +} diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/tree/expressions/BLangXMLFilterStepExtend.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/tree/expressions/BLangXMLFilterStepExtend.java new file mode 100644 index 000000000000..cb9ab03da512 --- /dev/null +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/tree/expressions/BLangXMLFilterStepExtend.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2024, 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.wso2.ballerinalang.compiler.tree.expressions; + +import io.ballerina.tools.diagnostics.Location; +import org.ballerinalang.model.tree.NodeKind; +import org.wso2.ballerinalang.compiler.tree.BLangNodeAnalyzer; +import org.wso2.ballerinalang.compiler.tree.BLangNodeTransformer; +import org.wso2.ballerinalang.compiler.tree.BLangNodeVisitor; + +import java.util.List; +import java.util.StringJoiner; + +/** + * Represents xml step extension consisting of filters. + * Example: {@code x/*., x/.} + * + * @since 2201.10.0 + */ +public class BLangXMLFilterStepExtend extends BLangXMLStepExtend { + + public final List filters; + + public BLangXMLFilterStepExtend(Location pos, List filters) { + this.pos = pos; + this.filters = filters; + } + + public void accept(BLangNodeVisitor visitor) { + visitor.visit(this); + } + + @Override + public void accept(BLangNodeAnalyzer analyzer, T props) { + analyzer.visit(this, props); + } + + @Override + public R apply(BLangNodeTransformer modifier, T props) { + return modifier.transform(this, props); + } + + @Override + public NodeKind getKind() { + return NodeKind.XML_STEP_FILTER_EXTEND; + } + + @Override + public String toString() { + StringJoiner filters = new StringJoiner(" |"); + this.filters.forEach(f -> filters.add(f.toString())); + return "." + "/<" + filters.toString() + ">"; + } +} diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/tree/expressions/BLangXMLIndexedStepExtend.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/tree/expressions/BLangXMLIndexedStepExtend.java new file mode 100644 index 000000000000..208ea354862c --- /dev/null +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/tree/expressions/BLangXMLIndexedStepExtend.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2024, 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.wso2.ballerinalang.compiler.tree.expressions; + +import io.ballerina.tools.diagnostics.Location; +import org.ballerinalang.model.tree.NodeKind; +import org.wso2.ballerinalang.compiler.tree.BLangNodeAnalyzer; +import org.wso2.ballerinalang.compiler.tree.BLangNodeTransformer; +import org.wso2.ballerinalang.compiler.tree.BLangNodeVisitor; + +/** + * Represents indexed access on xml step expression extension. + * Example: {@code x/*.[index], x/[index]} + * + * @since 2201.10.0 + */ +public class BLangXMLIndexedStepExtend extends BLangXMLStepExtend { + public BLangExpression indexExpr; + + public BLangXMLIndexedStepExtend(Location pos, BLangExpression indexExpr) { + this.pos = pos; + this.indexExpr = indexExpr; + } + + @Override + public NodeKind getKind() { + return NodeKind.XML_STEP_INDEXED_EXTEND; + } + + @Override + public void accept(BLangNodeVisitor visitor) { + visitor.visit(this); + } + + @Override + public void accept(BLangNodeAnalyzer analyzer, T props) { + analyzer.visit(this, props); + } + + @Override + public R apply(BLangNodeTransformer modifier, T props) { + return modifier.transform(this, props); + } + + @Override + public String toString() { + return "[" + String.valueOf(indexExpr) + "]"; + } + +} diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/tree/expressions/BLangXMLMethodCallStepExtend.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/tree/expressions/BLangXMLMethodCallStepExtend.java new file mode 100644 index 000000000000..27a522cbc479 --- /dev/null +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/tree/expressions/BLangXMLMethodCallStepExtend.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2024, 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.wso2.ballerinalang.compiler.tree.expressions; + +import io.ballerina.tools.diagnostics.Location; +import org.ballerinalang.model.tree.NodeKind; +import org.wso2.ballerinalang.compiler.tree.BLangNodeAnalyzer; +import org.wso2.ballerinalang.compiler.tree.BLangNodeTransformer; +import org.wso2.ballerinalang.compiler.tree.BLangNodeVisitor; + +/** + * Represents method calls on xml step expression extension. + * Example: {@code x/.get(0), x/*.get(0)} + * + * @since 2201.10.0 + */ +public class BLangXMLMethodCallStepExtend extends BLangXMLStepExtend { + + public BLangInvocation invocation; + + public BLangXMLMethodCallStepExtend(Location pos, BLangInvocation invocation) { + this.pos = pos; + this.invocation = invocation; + this.invocation.parent = this; + } + + @Override + public NodeKind getKind() { + return NodeKind.XML_STEP_METHOD_CALL_EXTEND; + } + + @Override + public String toString() { + return "." + invocation.toString(); + } + + @Override + public void accept(BLangNodeVisitor visitor) { + visitor.visit(this); + } + + @Override + public void accept(BLangNodeAnalyzer analyzer, T props) { + analyzer.visit(this, props); + } + + @Override + public R apply(BLangNodeTransformer modifier, T props) { + return modifier.transform(this, props); + } + +} diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/tree/expressions/BLangXMLNavigationAccess.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/tree/expressions/BLangXMLNavigationAccess.java index bc19910a1217..3973bde961b3 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/tree/expressions/BLangXMLNavigationAccess.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/tree/expressions/BLangXMLNavigationAccess.java @@ -34,27 +34,18 @@ public class BLangXMLNavigationAccess extends BLangExpression implements XMLNavi // BLangNodes public BLangExpression expr; - public BLangExpression childIndex; public final List filters; // Parser Flags and Data public final NavAccessType navAccessType; - // Semantic Data - // Hack to avoid duplicate error messages in CodeAnalyzer, the reason for this flag is since we are adding - // the 'receiver' of a method invocation as the first parameter to langlib invocations, XMLNavigationAccess - // could be checked multiple times when used with langlib functions producing multiple error messages. - public boolean methodInvocationAnalyzed; - public BLangXMLNavigationAccess(Location pos, BLangExpression expr, List filters, - NavAccessType navAccessType, - BLangExpression childIndex) { + NavAccessType navAccessType) { this.pos = pos; this.expr = expr; this.filters = filters; this.navAccessType = navAccessType; - this.childIndex = childIndex; } @Override @@ -92,21 +83,17 @@ public BLangExpression getExpression() { return this.expr; } - @Override - public BLangExpression getChildIndex() { - return this.childIndex; - } - @Override public String toString() { + StringJoiner filters = new StringJoiner(" |"); + this.filters.forEach(f -> filters.add(f.toString())); switch (navAccessType) { case CHILDREN: return String.valueOf(expr) + "/*"; case CHILD_ELEMS: - StringJoiner filters = new StringJoiner(" |"); - this.filters.forEach(f -> filters.toString()); - return String.valueOf(expr) + "/<" + filters.toString() + ">" + - (childIndex != null ? "[" + String.valueOf(childIndex) + "]" : ""); + return String.valueOf(expr) + "/<" + filters.toString() + ">"; + case DESCENDANTS: + return String.valueOf(expr) + "/**/<" + filters.toString() + ">"; } return null; } diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/tree/expressions/BLangXMLStepExtend.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/tree/expressions/BLangXMLStepExtend.java new file mode 100644 index 000000000000..3be30ddf02cb --- /dev/null +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/tree/expressions/BLangXMLStepExtend.java @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2024, 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.wso2.ballerinalang.compiler.tree.expressions; + +/** + * Represents step extensions in xml step expression. + * + * @since 2201.10.0 + */ +public abstract class BLangXMLStepExtend extends BLangExpression { +} diff --git a/tests/ballerina-compiler-api-test/src/test/java/io/ballerina/semantic/api/test/ExpressionTypeTestNew.java b/tests/ballerina-compiler-api-test/src/test/java/io/ballerina/semantic/api/test/ExpressionTypeTestNew.java index f109e468f6bb..11d8b7d6b187 100644 --- a/tests/ballerina-compiler-api-test/src/test/java/io/ballerina/semantic/api/test/ExpressionTypeTestNew.java +++ b/tests/ballerina-compiler-api-test/src/test/java/io/ballerina/semantic/api/test/ExpressionTypeTestNew.java @@ -603,7 +603,12 @@ public Object[][] getLogicalExprPos() { // Group expr {282, 12, 282, 34, INT}, {282, 14, 282, 28, INT}, - + // XML step expression with extension + {376, 17, 376, 18, INT}, + {377, 13, 377, 19, UNION}, + {377, 17, 377, 18, INT}, + {378, 9, 378, 31, XML}, + {378, 16, 378, 23, XML}, }; } diff --git a/tests/ballerina-compiler-api-test/src/test/java/io/ballerina/semantic/api/test/allreferences/XMLRefsTest.java b/tests/ballerina-compiler-api-test/src/test/java/io/ballerina/semantic/api/test/allreferences/XMLRefsTest.java index b935d1791e48..de07a0bd9b3b 100644 --- a/tests/ballerina-compiler-api-test/src/test/java/io/ballerina/semantic/api/test/allreferences/XMLRefsTest.java +++ b/tests/ballerina-compiler-api-test/src/test/java/io/ballerina/semantic/api/test/allreferences/XMLRefsTest.java @@ -39,13 +39,15 @@ public Object[][] getLookupPositions() { location(21, 24, 27), location(26, 17, 20), location(27, 17, 20), - location(29, 16, 19)) + location(29, 16, 19), + location(34, 23, 26)) }, {23, 25, location(19, 37, 40), List.of(location(19, 37, 40), location(23, 25, 28), location(27, 23, 26), - location(28, 17, 20)) + location(28, 17, 20), + location(32, 20, 23)) }, }; } diff --git a/tests/ballerina-compiler-api-test/src/test/java/io/ballerina/semantic/api/test/symbols/SymbolsInXMLNavigationExprsTest.java b/tests/ballerina-compiler-api-test/src/test/java/io/ballerina/semantic/api/test/symbols/SymbolsInXMLNavigationExprsTest.java index 10ac8ccd284c..039543ee64c1 100644 --- a/tests/ballerina-compiler-api-test/src/test/java/io/ballerina/semantic/api/test/symbols/SymbolsInXMLNavigationExprsTest.java +++ b/tests/ballerina-compiler-api-test/src/test/java/io/ballerina/semantic/api/test/symbols/SymbolsInXMLNavigationExprsTest.java @@ -102,6 +102,23 @@ public Object[][] getStepExprPos() { }; } + @Test(dataProvider = "StepExprWithExtensionPosProvider") + public void testXmlStepExprWithExtension(int line, int col, SymbolKind kind, String name) { + assertSymbol(line, col, kind, name); + } + + @DataProvider(name = "StepExprWithExtensionPosProvider") + public Object[][] getStepExprWithExtensionPos() { + return new Object[][]{ + {49, 13, VARIABLE, "x1"}, + {49, 18, FUNCTION, "get"}, + {49, 22, VARIABLE, "indx"}, + {50, 23, XMLNS, "ns"}, + {51, 31, null, null}, + {51, 37, VARIABLE, "indx"} + }; + } + // utils private void assertSymbol(int line, int col, SymbolKind kind, String name) { diff --git a/tests/ballerina-compiler-api-test/src/test/resources/test-src/expressions_test.bal b/tests/ballerina-compiler-api-test/src/test/resources/test-src/expressions_test.bal index f95b4f4e5484..b6ee03566287 100644 --- a/tests/ballerina-compiler-api-test/src/test/resources/test-src/expressions_test.bal +++ b/tests/ballerina-compiler-api-test/src/test/resources/test-src/expressions_test.bal @@ -371,3 +371,10 @@ function testRegexp() { function name() { _ = xml ``; } + +function testXMLStepExprWithExtension() { + xml x = xml `10`; + xml x2 = x/*[0]; + x2 = x/*.get(0); + x2 = x/*[1].first().; +} diff --git a/tests/ballerina-compiler-api-test/src/test/resources/test-src/find-all-ref/find_ref_xml_context.bal b/tests/ballerina-compiler-api-test/src/test/resources/test-src/find-all-ref/find_ref_xml_context.bal index e40c32b18ac3..3b4a6225662f 100644 --- a/tests/ballerina-compiler-api-test/src/test/resources/test-src/find-all-ref/find_ref_xml_context.bal +++ b/tests/ballerina-compiler-api-test/src/test/resources/test-src/find-all-ref/find_ref_xml_context.bal @@ -28,4 +28,9 @@ function test() { xml x3 = x1.; xml x4 = x1/; var v1 = x1.ns0:id; + + int i = 1; + xml x6 = x1/**/; + xml x7 = x1/*[i]; + xml x8 = x1/..get(i); } diff --git a/tests/ballerina-compiler-api-test/src/test/resources/test-src/symbols/symbols_in_xml_navigation_test.bal b/tests/ballerina-compiler-api-test/src/test/resources/test-src/symbols/symbols_in_xml_navigation_test.bal index 18cf5a4813c2..5207dba40b5a 100644 --- a/tests/ballerina-compiler-api-test/src/test/resources/test-src/symbols/symbols_in_xml_navigation_test.bal +++ b/tests/ballerina-compiler-api-test/src/test/resources/test-src/symbols/symbols_in_xml_navigation_test.bal @@ -44,3 +44,10 @@ function testXMLStepExpr() { int indx = 0; function getXML() returns xml => xml `Hello World!`; + +function testXmlStepExprWithExtension() { + xml x1 = xml `T-shirttextWatch`; + xml x2 = x1/*.get(indx); + x2 = x1/.; + x2 = x1/**/.[indx]; +} diff --git a/tests/jballerina-unit-test/src/test/java/org/ballerinalang/test/types/xml/XMLAccessTest.java b/tests/jballerina-unit-test/src/test/java/org/ballerinalang/test/types/xml/XMLAccessTest.java index e5476c949922..957655fcf47d 100644 --- a/tests/jballerina-unit-test/src/test/java/org/ballerinalang/test/types/xml/XMLAccessTest.java +++ b/tests/jballerina-unit-test/src/test/java/org/ballerinalang/test/types/xml/XMLAccessTest.java @@ -25,6 +25,7 @@ import org.testng.Assert; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; +import org.testng.annotations.DataProvider; import org.testng.annotations.Test; /** @@ -189,7 +190,7 @@ public void testXMLNavigationOnSequenceWithNamespacesAndMultipleFilters() { "D"); } - @Test(enabled = false) // disabling until providing semantic support for step extension + @Test public void testXMLElementAccessNavigationAccessComposition() { BArray returns = (BArray) BRunUtil.invoke(navigation, "testXMLElementAccessNavigationAccessComposition"); Assert.assertEquals(returns.get(0).toString(), @@ -223,7 +224,7 @@ public void testXMLNavigationDescendantsStepWithXMLSubtypeOnLHS() { BRunUtil.invoke(navigation, "testXMLNavigationDescendantsStepWithXMLSubtypeOnLHS"); } - @Test(enabled = false) // disabling until providing semantic support for step extension + @Test public void testXMLNavigationWithEscapeCharacter() { BRunUtil.invoke(navigation, "testXMLNavigationWithEscapeCharacter"); } @@ -288,27 +289,59 @@ public void testXmlNavigationWithDefaultNamespaceDefinedAfter() { BRunUtil.invoke(navigation, "testXmlNavigationWithDefaultNamespaceDefinedAfter"); } - @Test(enabled = false) // disabling until providing semantic support for step extension - public void testXMLNavExpressionNegative() { - String methodInvocMessage = "method invocations are not yet supported within XML navigation expressions, " + - "use a grouping expression (parenthesis) " + - "if you intend to invoke the method on the result of the navigation expression."; + @Test(dataProvider = "xmlStepExtension") + public void testXmlStepExtension(String function) { + BRunUtil.invoke(navigation, function); + } - String navIndexingMessage = "member access operations are not yet supported within XML navigation " + - "expressions, use a grouping expression (parenthesis) " + - "if you intend to member-access the result of the navigation expression."; + @DataProvider + private Object[] xmlStepExtension() { + return new Object[]{ + "testXmlIndexedStepExtend", + "testXmlFilterStepExtend", + "testXmlIndexedAndFilterStepExtend", + "testXmlMethodCallStepExtend", + "testXmlMethodCallIndexedAndFilterStepExtend" + }; + } + + @Test + public void testXMLNavExpressionNegative() { int i = 0; - BAssertUtil.validateError(navigationNegative, i++, methodInvocMessage, 3, 13); - BAssertUtil.validateError(navigationNegative, i++, methodInvocMessage, 4, 13); - BAssertUtil.validateError(navigationNegative, i++, methodInvocMessage, 5, 13); - BAssertUtil.validateError(navigationNegative, i++, methodInvocMessage, 6, 13); - BAssertUtil.validateError(navigationNegative, i++, methodInvocMessage, 7, 13); - BAssertUtil.validateError(navigationNegative, i++, navIndexingMessage, 8, 13); - BAssertUtil.validateError(navigationNegative, i++, navIndexingMessage, 9, 13); + BAssertUtil.validateError(navigationNegative, i++, "undefined symbol 'j'", 4, 14); + BAssertUtil.validateError(navigationNegative, i++, "incompatible types: expected 'int', found 'string'", 5, 14); + BAssertUtil.validateError(navigationNegative, i++, "cannot find xml namespace prefix 'ns'", 6, 15); + BAssertUtil.validateError(navigationNegative, i++, "undefined symbol 'x2'", 7, 9); + BAssertUtil.validateError(navigationNegative, i++, "undefined symbol 'x2'", 8, 9); + BAssertUtil.validateError(navigationNegative, i++, "undefined symbol 'j'", 8, 18); + BAssertUtil.validateError(navigationNegative, i++, "incompatible types: expected 'int', found 'string'", 17, + 18); + BAssertUtil.validateError(navigationNegative, i++, "too many arguments in call to 'get()'", 18, 13); + BAssertUtil.validateError(navigationNegative, i++, "incompatible types: expected 'int', found 'string'", 19, + 18); + BAssertUtil.validateError(navigationNegative, i++, "undefined function 'foo' in type 'xml'", 21, 14); + BAssertUtil.validateError(navigationNegative, i++, "incompatible types: expected 'xml', found 'int'", 22, 13); + BAssertUtil.validateError(navigationNegative, i++, "incompatible types: expected 'int', found 'string'", 23, + 23); + BAssertUtil.validateError(navigationNegative, i++, "incompatible types: expected 'xml', found 'int'", 25, 22); + BAssertUtil.validateError(navigationNegative, i++, "undefined symbol 'r'", 29, 23); + BAssertUtil.validateError(navigationNegative, i++, + "incompatible types: expected 'boolean', found 'xml:Element'", 31, 31); + BAssertUtil.validateError(navigationNegative, i++, + "incompatible types: expected 'xml:ProcessingInstruction', found 'xml:Element'", 33, 60); + BAssertUtil.validateError(navigationNegative, i++, "incompatible types: expected 'xml', found '()'", 34, 18); + BAssertUtil.validateError(navigationNegative, i++, "undefined symbol 'r'", 36, 26); + BAssertUtil.validateError(navigationNegative, i++, + "incompatible types: expected 'boolean', found 'xml:Element'", 38, 34); + BAssertUtil.validateError(navigationNegative, i++, + "incompatible types: expected 'function (ballerina/lang.xml:0.0.0:ItemType) returns (boolean)', found" + + " 'function (xml) returns ()'", + 39, 29); + Assert.assertEquals(navigationNegative.getErrorCount(), i); } - @Test(enabled = false) // disabling until providing semantic support for step extension + @Test public void testXMLNavExpressionTypeCheckNegative() { CompileResult compile = BCompileUtil.compile("test-src/types/xml/xml-nav-access-type-check-negative.bal"); int i = 0; diff --git a/tests/jballerina-unit-test/src/test/java/org/ballerinalang/test/types/xml/XMLAttributeAccessTest.java b/tests/jballerina-unit-test/src/test/java/org/ballerinalang/test/types/xml/XMLAttributeAccessTest.java index 44b23d299f8d..029dd4bd2896 100644 --- a/tests/jballerina-unit-test/src/test/java/org/ballerinalang/test/types/xml/XMLAttributeAccessTest.java +++ b/tests/jballerina-unit-test/src/test/java/org/ballerinalang/test/types/xml/XMLAttributeAccessTest.java @@ -41,33 +41,33 @@ public void setup() { lexCompileRes = BCompileUtil.compile("test-src/types/xml/xml-attribute-access-lax-behavior.bal"); } - @Test(enabled = false) // disabling until providing semantic support for step extension + @Test public void testBasicAttributeAccessSyntax() { BRunUtil.invoke(compileResult, "getElementAttrBasic"); } - @Test(enabled = false) // disabling until providing semantic support for step extension + @Test public void testBasicOptionalAttributeAccessSyntax() { BRunUtil.invoke(compileResult, "getOptionalElementAttrBasic"); } - @Test(enabled = false) // disabling until providing semantic support for step extension + @Test public void testUserDefinedAttributeAccessSyntax() { BRunUtil.invoke(compileResult, "getUserDefinedTypeElementAttrBasic"); } - @Test(enabled = false) // disabling until providing semantic support for step extension + @Test public void testUserDefinedOptionalAttributeAccessSyntax() { BRunUtil.invoke(compileResult, "getUserDefinedTypeOptionalElementAttrBasic"); } - @Test(enabled = false) // disabling until providing semantic support for step extension + @Test public void testAttributeAccessSyntaxWithNS() { Object result = BRunUtil.invoke(compileResult, "getElementAttrWithNSPrefix"); Assert.assertEquals(result.toString(), "attr-with-ns-val"); } - @Test(enabled = false) // disabling until providing semantic support for step extension + @Test public void testGetAttrOfASequence() { Object result = BRunUtil.invoke(compileResult, "getAttrOfASequence"); Assert.assertEquals(result.toString(), @@ -159,21 +159,26 @@ public void testXMLDirectAttributeAccess() { Assert.assertTrue((Boolean) result.get(3)); } - @Test(enabled = false) // disabling until providing semantic support for step extension + @Test public void testXMLAfterRemoveAttribute() { BRunUtil.invoke(compileResult, "testXMLAfterRemoveAttribute"); } - @Test(enabled = false) // disabling until providing semantic support for step extension + @Test public void testXMLIndexedOptionalAttributeAccess() { BRunUtil.invoke(compileResult, "testXMLIndexedOptionalAttributeAccess"); } - @Test(enabled = false) // disabling until providing semantic support for step extension + @Test public void testErrorsOnXMLIndexedOptionalAttributeAccess() { BRunUtil.invoke(compileResult, "testErrorsOnXMLIndexedOptionalAttributeAccess"); } + @Test + public void testXMLIndexedOptionalAttributeAccessWithNS() { + BRunUtil.invoke(compileResult, "testXMLIndexedOptionalAttributeAccessWithNS"); + } + @Test public void testXmlAttributeAccessOnXmlUnionTypes() { BRunUtil.invoke(compileResult, "testXmlAttributeAccessOnXmlUnionTypes"); diff --git a/tests/jballerina-unit-test/src/test/resources/test-src/types/xml/xml-attribute-access-syntax.bal b/tests/jballerina-unit-test/src/test/resources/test-src/types/xml/xml-attribute-access-syntax.bal index c2fffbbab3df..7a6bde124daa 100644 --- a/tests/jballerina-unit-test/src/test/resources/test-src/types/xml/xml-attribute-access-syntax.bal +++ b/tests/jballerina-unit-test/src/test/resources/test-src/types/xml/xml-attribute-access-syntax.bal @@ -96,68 +96,70 @@ function testXMLIndexedOptionalAttributeAccess() { assertNonErrorValue(x1.[0][0]?.id, "0"); assertNonErrorValue(x1.[0][2]?.id, ()); + xml x2 = xml `book1010`; + assertNonErrorValue((x2/*)[0]?.n, "3"); + assertNonErrorValue(x2/*.[0]?.p, "4"); + assertNonErrorValue(x2/*.[1]?.p, "5"); + assertNonErrorValue(x2/*.[0]?.p, ()); + assertNonErrorValue((x2/)[0]?.p, "4"); + assertNonErrorValue((x2/<*>)[0]?.n, "3"); + assertNonErrorValue((x2/<*>)[2]?.p, "5"); + assertNonErrorValue((x2/<*>)[0]?.e, ()); + assertNonErrorValue(x2/*.[2]?.p, ()); + assertNonErrorValue((x2/*)[0][0]?.n, "3"); + assertNonErrorValue((x2/*)[1][0]?.p, "4"); + + xml x3 = xml `book1011`; + assertNonErrorValue((x3/**/)[0]?.g, "5"); + assertNonErrorValue((x3/**/)[1]?.g, "6"); + assertNonErrorValue((x3/**/)[0]?.n, "3"); + assertNonErrorValue((x3/**/)[0]?.n, "3"); + assertNonErrorValue((x3/**/)[0]?.n, ()); + assertNonErrorValue((x3/**/)[0]?.f, ()); + assertNonErrorValue((x3/**/)[3]?.g, ()); + assertNonErrorValue((x3/**/)[0][0]?.g, "5"); + assertNonErrorValue((x3/**/)[0][1]?.p, ()); +} + +function testXMLIndexedOptionalAttributeAccessWithNS() { xmlns "ns" as ns2; xmlns "ps" as ns3; - xml x2 = xml `ns2ans2a2ns3a`; - assertNonErrorValue(x2.[0]?.id, "1"); - assertNonErrorValue(x2.[1]?.id, "2"); - assertNonErrorValue(x2.[0]?.id, "3"); - assertNonErrorValue(x2.[0]?.id, "1"); - assertNonErrorValue(x2.[1]?.id, "2"); - assertNonErrorValue(x2.[2]?.id, "3"); - assertNonErrorValue(x2.[0]?.id, ()); - assertNonErrorValue(x2.[0]?.j, ()); - assertNonErrorValue(x2.[0]?.k, ()); - assertNonErrorValue(x2.[3]?.id, ()); - assertNonErrorValue(x2.[0][0]?.id, "1"); - assertNonErrorValue(x2.[0][0]?.id, ()); - assertNonErrorValue(x2.[1][0]?.id, "2"); - - xml x3 = xml `book1010`; - assertNonErrorValue((x3/*)[0]?.n, "3"); - assertNonErrorValue(x3/*.[0]?.p, "4"); - assertNonErrorValue(x3/*.[1]?.p, "5"); - assertNonErrorValue(x3/*.[0]?.p, ()); - assertNonErrorValue((x3/)[0]?.p, "4"); - assertNonErrorValue((x3/<*>)[0]?.n, "3"); - assertNonErrorValue((x3/<*>)[2]?.p, "5"); - assertNonErrorValue((x3/<*>)[0]?.e, ()); - assertNonErrorValue(x3/*.[2]?.p, ()); - assertNonErrorValue((x3/*)[0][0]?.n, "3"); - assertNonErrorValue((x3/*)[1][0]?.p, "4"); - - xml x4 = xml `book10`; - assertNonErrorValue(x4/*.[0]?.n, "3"); - assertNonErrorValue(x4/*.[0]?.p, "4"); - assertNonErrorValue((x4/)[0]?.n, "3"); - assertNonErrorValue((x4/)[0]?.p, "4"); - assertNonErrorValue((x4/)[1]?.p, "4"); - assertNonErrorValue((x4/)[0]?.k, ()); - assertNonErrorValue((x4/)[0]?.l, ()); - assertNonErrorValue((x4/)[0]?.l, ()); - assertNonErrorValue((x4/)[4]?.p, ()); - assertNonErrorValue(x4/*.[0][0]?.n, "3"); - assertNonErrorValue(x4/*.[2][0]?.p, ()); - - xml x5 = xml `book1011`; - assertNonErrorValue((x5/**/)[0]?.g, "5"); - assertNonErrorValue((x5/**/)[1]?.g, "6"); - assertNonErrorValue((x5/**/)[0]?.n, "3"); - assertNonErrorValue((x5/**/)[0]?.n, "3"); - assertNonErrorValue((x5/**/)[0]?.n, ()); - assertNonErrorValue((x5/**/)[0]?.f, ()); - assertNonErrorValue((x5/**/)[3]?.g, ()); - assertNonErrorValue((x5/**/)[0][0]?.g, "5"); - assertNonErrorValue((x5/**/)[0][1]?.p, ()); - - xml x6 = xml `book101`; - assertNonErrorValue((x6/**/)[0]?.g, "5"); - assertNonErrorValue((x6/**/)[1]?.g, "6"); - assertNonErrorValue((x6/**/)[0]?.g, ()); - assertNonErrorValue((x6/**/)[0]?.j, ()); - assertNonErrorValue((x6/**/)[5]?.g, ()); - assertNonErrorValue((x6/**/)[1][0]?.g, "6"); - assertNonErrorValue((x6/**/)[1][0]?.g, ()); + xml x1 = xml `ns2ans2a2ns3a`; + assertNonErrorValue(x1.[0]?.id, "1"); + assertNonErrorValue(x1.[1]?.id, "2"); + assertNonErrorValue(x1.[0]?.id, "3"); + assertNonErrorValue(x1.[0]?.id, "1"); + assertNonErrorValue(x1.[1]?.id, "2"); + assertNonErrorValue(x1.[2]?.id, "3"); + assertNonErrorValue(x1.[0]?.id, ()); + assertNonErrorValue(x1.[0]?.j, ()); + assertNonErrorValue(x1.[0]?.k, ()); + assertNonErrorValue(x1.[3]?.id, ()); + assertNonErrorValue(x1.[0][0]?.id, "1"); + assertNonErrorValue(x1.[0][0]?.id, ()); + assertNonErrorValue(x1.[1][0]?.id, "2"); + + xml x2 = xml `book10`; + assertNonErrorValue(x2/*.[0]?.n, "3"); + assertNonErrorValue(x2/*.[0]?.p, "4"); + assertNonErrorValue((x2/)[0]?.n, "3"); + assertNonErrorValue((x2/)[0]?.p, "4"); + assertNonErrorValue((x2/)[1]?.p, "4"); + assertNonErrorValue((x2/)[0]?.k, ()); + assertNonErrorValue((x2/)[0]?.l, ()); + assertNonErrorValue((x2/)[0]?.l, ()); + assertNonErrorValue((x2/)[4]?.p, ()); + assertNonErrorValue(x2/*.[0][0]?.n, "3"); + assertNonErrorValue(x2/*.[2][0]?.p, ()); + + xml x3 = xml `book101`; + assertNonErrorValue((x3/**/)[0]?.g, "5"); + assertNonErrorValue((x3/**/)[1]?.g, "6"); + assertNonErrorValue((x3/**/)[0]?.g, ()); + assertNonErrorValue((x3/**/)[0]?.j, ()); + assertNonErrorValue((x3/**/)[5]?.g, ()); + assertNonErrorValue((x3/**/)[1][0]?.g, "6"); + assertNonErrorValue((x3/**/)[1][0]?.g, ()); } function testErrorsOnXMLIndexedOptionalAttributeAccess() { diff --git a/tests/jballerina-unit-test/src/test/resources/test-src/types/xml/xml-nav-access-negative.bal b/tests/jballerina-unit-test/src/test/resources/test-src/types/xml/xml-nav-access-negative.bal index eeae1731df6d..32d15241a2d6 100644 --- a/tests/jballerina-unit-test/src/test/resources/test-src/types/xml/xml-nav-access-negative.bal +++ b/tests/jballerina-unit-test/src/test/resources/test-src/types/xml/xml-nav-access-negative.bal @@ -1,10 +1,40 @@ -function testXMLNavigationOnSingleElement() { - xml x1 = xml ``; - xml _ = x1/.clone(); - xml _ = x1/*.clone(); - xml _ = x1/<*>.clone(); - xml _ = x1/**/.clone(); - xml _ = x1/[0].clone(); - xml _ = x1/*[0]; - xml _ = x1/**/[0]; +function testXmlNegativeIndexedAndFilterStepExtend() { + string s = "a"; + xml x1 = xml `T-shirt19.99`; + _ = x1/*[j].; + _ = x1/*[s].; + _ = x1/*.; + _ = x2/*.; + _ = x2/*.[j]; +} + +function testXmlMethodCallNegativeStepExtend() returns error? { + int k = 0; + string s = "s"; + + xml x1 = xml `T-shirt19.99`; + + _ = x1/*.get("0"); + _ = x1/*.get(0, 2); + _ = x1/*.get(s); + + _ = x1/*.foo(); + _ = x1/*.length(); + _ = x1/*.slice(1, "5"); + + _ = x1/*.slice(0).length(); + _ = x1/*.elementChildren().get(0).getChildren(); + + + _ = x1/.get(r); + _ = x1/.get(0).getChildren(); + _ = x1/.filter(x => x); + + _ = x1/.map(y => xml:createProcessingInstruction(y.getTarget(), "sort")); + _ = x1/.forEach(function (xml y) {k = k + 1;}); + + _ = x1/**/.get(r); + _ = x1/**/.get(0).getChildren(); // error at the wrong place + invalid error + _ = x1/**/.filter(x => x); + _ = x1/**/.filter(function (xml y) {k = k + 1;}); } diff --git a/tests/jballerina-unit-test/src/test/resources/test-src/types/xml/xml-navigation-access.bal b/tests/jballerina-unit-test/src/test/resources/test-src/types/xml/xml-navigation-access.bal index 2cab7db17072..6f0e5aaa9488 100644 --- a/tests/jballerina-unit-test/src/test/resources/test-src/types/xml/xml-navigation-access.bal +++ b/tests/jballerina-unit-test/src/test/resources/test-src/types/xml/xml-navigation-access.bal @@ -24,7 +24,6 @@ function testXMLNavigationOnSingleElementWithNamespaces() returns [xml, xml, xml return [x2, x3, x4, x5, x6]; } - function testXMLNavigationOnSingleElementReferToDefaultNS() returns [xml, xml, xml, xml, xml, xml, int, xml] { xmlns "foo"; @@ -42,7 +41,6 @@ function testXMLNavigationOnSingleElementReferToDefaultNS() return [x2, x3, x4, x5, x6, x7, x8.length(), x9]; } - function testXMLNavigationOnSingleElementReferToDefaultNSViaPrefix() returns [xml, xml, xml, xml, xml] { xmlns "foo"; xmlns "bar" as k; @@ -161,13 +159,13 @@ function testXMLNavigationWithEscapeCharacter() { assert(x4, xml ``); xml x5 = x1/**//; - assert(x5, xml `some address`); + assert(x5, xml ``); xml x6 = x1/**//; - assert(x6, xml `Johnsome address`); + assert(x6, xml ``); xml x7 = x1/**//.; - assert(x7, xml `some address`); + assert(x7, xml ``); } type XC xml:Comment; @@ -278,6 +276,448 @@ function assertXmlNavigationWithDefaultNamespaceDefinedAfter(xml[] results) { assert(results[17], xml ``); } +const i = 0; + +function testXmlIndexedStepExtend() { + int k = 1; + xml x1 = xml + `T-shirt19.99 + Backpack34.99 + textWatch49.99`; + + assert(x1/*[0], xml `text`); + assert(x1/*[k], xml `T-shirtBackpackWatch`); + assert(x1/*[3], xml ``); + assertError(trap x1/*[-1], "xml sequence index out of range. Length: '3' requested: '-1'"); + + assert(x1/*[0][0], xml `text`); + assert(x1/*[k][i], xml `T-shirtBackpackWatch`); + assert(x1/*[1][1], xml ``); + assert(x1/*[3][3], xml ``); + assertError(trap x1/*[0][-1], "xml sequence index out of range. Length: '1' requested: '-1'"); + assertError(trap x1/*[-1], "xml sequence index out of range. Length: '3' requested: '-1'"); + + assert(x1/[i], xml `19.9934.9949.99`); + assert(x1/[5], xml ``); + assertError(trap x1/[-1], "xml sequence index out of range. Length: '1' requested: '-1'"); + + assert(x1/[i][0], xml `19.9934.9949.99`); + assert(x1/[0][1], xml ``); + assert(x1/[5][4], xml ``); + assertError(trap x1/[0][-1], "xml sequence index out of range. Length: '1' requested: '-1'"); + + assert(x1/**/[0], xml `T-shirtBackpackWatch`); + assert(x1/**/[5], xml ``); + assertError(trap x1/**/[-1], "xml sequence index out of range. Length: '1' requested: '-1'"); + + assert(x1/**/[0][0], xml `T-shirtBackpackWatch`); + assert(x1/**/[0][1], xml ``); + assert(x1/**/[5][4], xml ``); + assertError(trap x1/**/[0][-1], "xml sequence index out of range. Length: '1' requested: '-1'"); + + xml x2 = xml + `T-shirt19.99T-shirt2 + Backpack34.99Backpack2 + textWatch49.99Watch2`; + + assert(x2/**/[0], xml `T-shirtBackpackWatch`); + assert(x2/**/[1], xml `T-shirt2Backpack2Watch2`); + assert(x2/**/[2], xml ``); + assertError(trap x1/**/[-1], "xml sequence index out of range. Length: '1' requested: '-1'"); + + assert(x2/[0], xml `T-shirtBackpackWatch`); + assert(x2/[1], xml `T-shirt2Backpack2Watch2`); + assert(x2/[2], xml ``); + assertError(trap x1/[-1], "xml sequence index out of range. Length: '1' requested: '-1'"); + + xml:Element x3 = xml `xml textcdd`; + assert(x3/*[0], xml `xml text`); + assert(x3/*[1], xml `cd`); + assert(x3/*[2], xml `d`); + assert(x3/*[3], xml ``); + assert(x3/*[4], xml ``); + assertError(trap x3/*[-1], "xml sequence index out of range. Length: '4' requested: '-1'"); + + assert(x3/[0], xml `cd`); + assert(x3/[1], xml `d`); + assert(x3/[2], xml ``); + assertError(trap x3/[-1], "xml sequence index out of range. Length: '2' requested: '-1'"); + + assert(x3/**/[0], xml `c`); + assert(x3/**/[1], xml `d`); + assert(x3/**/[2], xml ``); + assertError(trap x3/**/[-1], "xml sequence index out of range. Length: '2' requested: '-1'"); + + xml:Comment x4 = xml ``; + assert(x4/*[0], xml ``); + assert(x4/*[-1], xml ``); + assert(x4/[0], xml ``); + assert(x4/[-1], xml ``); + assert(x4/**/[0], xml ``); + assert(x4/**/[-1], xml ``); + + xml:ProcessingInstruction x5 = xml ``; + assert(x5/*[0], xml ``); + assert(x5/*[-1], xml ``); + assert(x5/[i], xml ``); + assert(x5/[-1], xml ``); + assert(x5/**/[0], xml ``); + assert(x5/**/[-1], xml ``); + + xml:Text x6 = xml `xml text`; + assert(x6/*[0], xml ``); + assert(x6/*[-1], xml ``); + assert(x6/[0], xml ``); + assert(x6/[-1], xml ``); + assert(x6/**/[0], xml ``); + assert(x6/**/[-1], xml ``); +} + +function testXmlFilterStepExtend() { + xml x1 = xml + `T-shirt19.991nikeno + Backpack34.993adidasyes + textWatch49.992samsungno`; + + assert(x1/*., xml `T-shirtBackpackWatch`); + assert(x1/*., xml `19.9934.9949.99`); + assert(x1/*., xml ``); + assert(x1/*.., xml `T-shirtBackpackWatch`); + assert(x1/*.., xml ``); + assert(x1/*., + xml `T-shirt19.99Backpack34.99Watch49.99`); + assert(x1/*.., xml `19.9934.9949.99`); + assert(x1/*.<*>., xml `19.9934.9949.99`); + + assert(x1/., xml `T-shirtBackpackWatch`); + assert(x1/., xml `19.9934.9949.99`); + assert(x1/., xml `19.9934.9949.99`); + assert(x1/., + xml `T-shirt1Backpack3Watch2`); + assert(x1/.., xml `132`); + assert(x1/., xml ``); + assert(x1/., xml ``); + assert(x1/., xml ``); + + assert(x1/**/., xml `T-shirtnikeBackpackadidasWatchsamsung`); + assert(x1/**/., xml `19.9934.9949.99`); + assert(x1/**/., xml `noyesno`); + assert(x1/**/., xml `nikenoadidasyessamsungno`); + assert(x1/**/.., xml `T-shirtnikeBackpackadidasWatchsamsung`); + assert(x1/**/..<*>, xml `T-shirt19.99nikeBackpack34.99adidasWatch49.99samsung`); + assert(x1/**/., xml ``); + assert(x1/**/., xml ``); + + xml:Element x2 = xml ` + xml text + 10 + 15 + 30 + 4 + 40 + + `; + assert(x2/*., xml `1015`); + assert(x2/*., xml `30`); + assert(x2/*., xml `101530`); + assert(x2/*.., xml `30`); + assert(x2/*., xml ``); + assert(x2/*.., xml ``); + + assert(x2/., xml `1015`); + assert(x2/., xml `30`); + assert(x2/., xml `10154`); + assert(x2/.., xml `4`); + assert(x2/., xml ``); + assert(x2/., xml ``); + assert(x1/*.., xml ``); + + assert(x2/**/., xml `101530440`); + assert(x2/**/., xml `1015`); + assert(x2/**/., xml `30`); + assert(x2/**/., xml `30`); + assert(x2/**/., xml `1010151530440`); + assert(x2/**/.., xml `101530440`); + assert(x2/**/., xml ``); + assert(x2/**/., xml ``); + + xml:Comment x3 = xml ``; + assert(x3/*., xml ``); + assert(x3/*., xml ``); + assert(x3/*.., xml ``); + assert(x3/., xml ``); + assert(x3/., xml ``); + assert(x3/**/., xml ``); + assert(x3/**/., xml ``); + + xml:ProcessingInstruction x4 = xml ``; + assert(x4/*., xml ``); + assert(x4/*., xml ``); + assert(x4/*.., xml ``); + assert(x4/., xml ``); + assert(x4/., xml ``); + assert(x4/**/., xml ``); + assert(x4/**/., xml ``); + + xml:Text x5 = xml `xml text`; + assert(x5/*., xml ``); + assert(x5/*., xml ``); + assert(x5/*.., xml ``); + assert(x5/., xml ``); + assert(x5/., xml ``); + assert(x5/**/., xml ``); + assert(x5/**/., xml ``); +} + +function testXmlIndexedAndFilterStepExtend() { + int k = 1; + xml x1 = xml + `T-shirt19.99nikeno + BackpackIBackpack34.99adidasyes + textWatch49.99samsungno`; + + assert(x1/*[1]., xml `T-shirtWatch`); + assert(x1/*[k]., xml `T-shirtBackpackWatch`); + assert(x1/*[0]., xml ``); + assert(x1/*.[0][0], xml `T-shirtWatch`); + assert(x1/*.[1][0], xml ``); + assert(x1/*.[0]., xml `Backpack`); + assert(x1/*.[k]., xml `IBackpack`); + assertError(trap x1/*.[-1], "xml sequence index out of range. Length: '1' requested: '-1'"); + assertError(trap x1/*.[k].[-1], "xml sequence index out of range. Length: '0' requested: '-1'"); + + assert(x1/[0]., xml `adidasyes`); + assert(x1/.[0], xml `T-shirtWatch`); + assert(x1/.[5], xml ``); + assert(x1/[0]..[0], xml `nikenosamsungno`); + + assert(x1/**/[i]., xml `T-shirtWatch`); + assert(x1/**/[k]., xml `nikesamsung`); + assert(x1/**/[0].[0], xml `T-shirtWatch`); + assertError(trap x1/[-1]., "xml sequence index out of range. Length: '1' requested: '-1'"); + + xml:Element x2 = xml `xml textcdd`; + assert(x2/*.[i], xml `cd`); + assert(x2/*[2]., xml `d`); + assert(x2/*[2].[0]., xml `d`); + assertError(trap x2/*.[-1]., "xml sequence index out of range. Length: '2' requested: '-1'"); + + assert(x2/[0]., xml `cd`); + assert(x2/[1]., xml `d`); + assert(x2/[1].[k], xml ``); + assertError(trap x2/.[-1], "xml sequence index out of range. Length: '0' requested: '-1'"); + + assert(x2/**/.[0], xml `c`); + assert(x2/**/.[k], xml `d`); + assert(x2/**/<*>.[0], xml `c`); + assertError(trap x2/**/[-1]., "xml sequence index out of range. Length: '2' requested: '-1'"); + + xml:Comment x3 = xml ``; + assert(x3/*.[0], xml ``); + assert(x3/*[-1]., xml ``); + assert(x3/[i]., xml ``); + assert(x3/**/.[0]., xml ``); + assert(x3/**/[-1]., xml ``); + + xml:ProcessingInstruction x4 = xml ``; + assert(x4/*.[0], xml ``); + assert(x4/*[-1]., xml ``); + assert(x4/[0]..[i], xml ``); + assert(x4/.[-1], xml ``); + assert(x4/**/.[0], xml ``); + assert(x4/**/[-1].., xml ``); + + xml:Text x5 = xml `xml text`; + assert(x5/*.[0], xml ``); + assert(x5/*.[-1], xml ``); + assert(x5/[0]., xml ``); + assert(x5/[-1]., xml ``); + assert(x5/**/.[0], xml ``); + assert(x5/**/[-1]., xml ``); +} + +function testXmlMethodCallStepExtend() returns error? { + int k = 0; + string local = "local"; + xml x1 = xml + `T-shirt19.991nikeno + Backpack34.993adidasyes + textWatch49.992samsungno`; + + assert(x1/*.cloneReadOnly(), xml `T-shirt19.991nikenoBackpack34.993adidasyestextWatch49.992samsungno`); + assert(x1/*.get(0), xml `text`); + assert(x1/*.map(y => y), xml `T-shirt19.991nikenoBackpack34.993adidasyestextWatch49.992samsungno`); + assert(x1/*.filter(y => y is xml:Element), xml `T-shirt19.991nikenoBackpack34.993adidasyesWatch49.992samsungno`); + assert(x1/*.children().strip(), xml `T-shirt19.991nikenoBackpack34.993adidasyesWatch49.992samsungno`); + assert(x1/*.clone(), xml `T-shirt19.991nikenoBackpack34.993adidasyestextWatch49.992samsungno`); + assert(x1/*.first(), xml `T-shirt19.991nikenoBackpack34.993adidasyestextWatch49.992samsungno`); + assert(x1/*.last(), xml `T-shirt19.991nikenoBackpack34.993adidasyestextWatch49.992samsungno`); + // assert(x1/*.text(), xml `text`); + + assert(x1/.get(k), xml `T-shirtBackpackWatch`); + assert(x1/.map(y => y), xml `19.9934.9949.99`); + + assert(x1/.children(), xml `nikenoadidasyessamsungno`); + assert(x1/.children().filter(y => (y).getName() == "local"), xml `noyesno`); + + var xmlObj1 = object { + xml j = x1/[0]; + xml k = x1/**/.map(y => y.elementChildren().get(0)); + xml l = x1/.; + function init() { + } + }; + assert(xmlObj1.j, xml `T-shirtBackpackWatch`); + assert(xmlObj1.k, xml `nikeadidassamsung`); + assert(xmlObj1.l, xml `132`); + + assert(x1/**/.map(y => y), xml `noyesno`); + assert(x1/**/.filter(y => (y).data() == "yes"), xml `yes`); + assert(x1/**/<*>.children().filter(y => y is xml:Element), xml `nikenoadidasyessamsungno`); + assert(x1/**/.children().filter(y => y is xml:Element && y.getName() == local), xml `noyesno`); + assert(x1/**/.first().slice(0, 1), xml `T-shirtBackpackWatch`); + + function () returns [xml, xml, xml] xmlFunc = function() returns [xml, xml, xml] { + xml jf = x1/**/.get(1); + xml kf = x1/**/.; + xml lf = x1/[0]; + return [jf, kf, lf]; + }; + + [xml, xml, xml] [funcResult1, funcResult2, funcResult3] = xmlFunc(); + assert(funcResult1, xml `nikeadidassamsung`); + assert(funcResult2, xml `nikenoadidasyessamsungno`); + assert(funcResult3, xml `132`); + + xml:Element x2 = xml ` + xml text + 10 + 15 + 30 + 4 + 40 + 50 + nikeno + + `; + + assert(x2/*.filter(y => y is xml:Element), xml `10153044050nikeno`); + assert(x2/*.map(y => y is xml:Text ? xml `` : y), + xml `10153044050nikeno`); + assert(x2/*.filter(y => y is xml:Element), xml `10153044050nikeno`); + assert(x2/*.children().strip(), xml `10153044050nikeno`); + + assert(x2/.get(0), xml `10`); + assert(x2/.map(y => xml:createElement("price", {}, xml `${y.data()}.0`)), xml `40.050.0`); + assert(x2/.children(), xml `4`); + assert(x2/.children().filter(y => (y).getName() == "local"), xml `no`); + + assert(x2/**/.get(0), xml `nike`); + assert(x2/**/.map(y => y), xml `no`); + + assert(x2/**/<*>.children().filter(y => y is xml:Element), xml `1015304nikeno`); + assert(x2/**/.children().filter(y => y is xml:Element && y.getName() == "local"), xml `no`); + assert(x2/**/.first().slice(0, 1), xml `10`); + + xml:Comment x3 = xml ``; + assert(x3/*.map(y => y), xml ``); + assert(x3/*.strip(), xml ``); + assert(x3/.children().clone(), xml ``); + assert(x3/**/.get(k), xml ``); + + xml:ProcessingInstruction x4 = xml ``; + assert(x4/*.map(y => y), xml ``); + assert(x4/*.strip(), xml ``); + assert(x4/.children().clone(), xml ``); + assert(x4/**/.get(k), xml ``); + + xml:Text x5 = xml `xml text`; + assert(x5/*.first(), xml ``); + assert(x5/.last().clone(), xml ``); + assert(x5/**/.get(k), xml ``); +} + +function testXmlMethodCallIndexedAndFilterStepExtend() { + int k = 1; + boolean b = false; + string local = "local"; + xml x1 = xml + `T-shirt19.991nikeno + 34.99Backpack3adidasyes + textWatch49.992text 2samsungno`; + + assert(x1/*[0].filter(x => x is xml:Comment || x is xml:ProcessingInstruction), xml ``); + assert(x1/*.get(k)., xml `34.99`); + assert(x1/*..children(), xml `nikenoadidasyestext 2samsungno`); + assert(x1/*.children()., xml `nikeadidassamsung`); + assert(x1/*.elementChildren().<*>, xml `nikenoadidasyessamsungno`); + assert(x1/*.first().[0], xml `T-shirt34.99Watch`); + + assert(x1/.children()., xml `nikeadidassamsung`); + assert(x1/.children()[0], xml `adidastext 2`); + assert(x1/.children()[0]., xml `adidas`); + + assert(x1/**/.map(y => y).children()., xml `noyesno`); + assert(x1/**/.filter(y => (y).data() == "yes"), xml `yes`); + assert(x1/**/<*>.elementChildren()[0], xml `nikeadidassamsung`); + assert(x1/**/.slice(0, 1)., xml `34.99`); + var xmlObj1 = object { + xml x2 = x1/*.; + }; + + xml:Element x2 = xml ` + xml text + 10 + 15 + 30 + 4 + 40 + + `; + + assert(x2/*.filter(y => y is xml:Element)., xml `1015`); + assert(x2/*[1].clone()., xml `10`); + assert(x2/*.[1].clone(), xml `15`); + + assert(x2/[0].children()., xml `10`); + assert(x2/.map(y => y).children()., xml `4`); + assert(x2/.filter(function(xml y) returns boolean { + int|error val = int:fromString((y).data()); + if val is int { + return val > 5; + } + return false; + })[0], + xml `40`); + + assert(x2/**/.get(1).children()[0], xml `15`); + assert(x2/**/.map(y => y)[0], xml `10`); + assert(x2/**/.children()..filter(function(xml y) returns boolean { + int|error val = int:fromString((y).data()); + if val is int { + return val > 5; + } + return false; + }), xml `30`); + + xml:Comment x3 = xml ``; + assert(x3/*.map(y => y)[0]., xml ``); + assert(x3/*.strip().[1], xml ``); + assert(x3/.children().clone(), xml ``); + assert(x3/**/.get(k)., xml ``); + + xml:ProcessingInstruction x4 = xml ``; + assert(x4/*[0].map(y => y), xml ``); + assert(x4/*.strip()[1]., xml ``); + assert(x4/.children().clone()[1], xml ``); + assert(x4/**/[2].get(k)., xml ``); + + xml:Text x5 = xml `xml text`; + assert(x5/*[k].first()., xml ``); + assert(x5/.last().clone()[1], xml ``); + assert(x5/**/.get(k)[0].clone(), xml ``); +} + function assert(anydata actual, anydata expected) { if (expected != actual) { string reason = "expected `" + expected.toString() + "`, but found `" + actual.toString() + "`"; @@ -285,3 +725,13 @@ function assert(anydata actual, anydata expected) { panic e; } } + +function assertError(any|error value, string errorMessage) { + if value is error { + if (value.message() != errorMessage) { + panic error("Expected error message: " + errorMessage + " found: " + value.message()); + } + return; + } + panic error("Expected: Error, found: " + (typeof value).toString()); +}