From 2f7747a1080abf11b16cb9edc8faf2b490aa426f Mon Sep 17 00:00:00 2001 From: Martin Middel Date: Mon, 20 Nov 2023 21:54:59 +0100 Subject: [PATCH] Implement switch expression --- src/expressions/dataTypes/Value.ts | 9 +- src/expressions/xquery/SwitchExpression.ts | 131 ++++++++++++++++++ src/parsing/astHelper.ts | 2 +- src/parsing/compileAstToExpression.ts | 45 +++++- src/parsing/prscParser.ts | 32 +++-- test/assets/failingXQueryXTestNames.csv | 12 +- test/assets/runnableTestSets.csv | 2 +- test/assets/unrunnableTestCases.csv | 16 ++- .../parsing/xquery/SwitchExpression.tests.ts | 102 ++++++++++++++ 9 files changed, 324 insertions(+), 27 deletions(-) create mode 100644 src/expressions/xquery/SwitchExpression.ts create mode 100644 test/specs/parsing/xquery/SwitchExpression.tests.ts diff --git a/src/expressions/dataTypes/Value.ts b/src/expressions/dataTypes/Value.ts index 857fb6a63..311b94c31 100644 --- a/src/expressions/dataTypes/Value.ts +++ b/src/expressions/dataTypes/Value.ts @@ -81,10 +81,11 @@ export const enum ValueType { } /** - * Handles the occurances in the XPath specs. - * Zero or one matches to '?'; - * One or more matches to '+'; - * Zero or more matches to '*' + * Handles the occurences in the XPath specs. + * + * * Zero or one matches to '?'; + * * One or more matches to '+'; + * * Zero or more matches to '*'; * * @private */ diff --git a/src/expressions/xquery/SwitchExpression.ts b/src/expressions/xquery/SwitchExpression.ts new file mode 100644 index 000000000..375cef6a5 --- /dev/null +++ b/src/expressions/xquery/SwitchExpression.ts @@ -0,0 +1,131 @@ +import ISequence from '../dataTypes/ISequence'; +import sequenceFactory from '../dataTypes/sequenceFactory'; +import { SequenceType } from '../dataTypes/Value'; +import DynamicContext from '../DynamicContext'; +import ExecutionParameters from '../ExecutionParameters'; +import Expression, { RESULT_ORDERINGS } from '../Expression'; +import sequenceDeepEqual, { + itemDeepEqual, +} from '../functions/builtInFunctions_sequences_deepEqual'; +import PossiblyUpdatingExpression, { SequenceCallbacks } from '../PossiblyUpdatingExpression'; +import Specificity from '../Specificity'; +import StaticContext from '../StaticContext'; +import atomizeSequence from '../util/atomizeSequence'; +import { IterationHint } from '../util/iterators'; +import { errXUST0001 } from '../xquery-update/XQueryUpdateFacilityErrors'; +import { errXPTY0004 } from './XQueryErrors'; + +export type SwitchExpressionClause = { + caseClauseExpression: PossiblyUpdatingExpression; + tests: Expression[]; +}; + +class SwitchExpression extends PossiblyUpdatingExpression { + private _amountOfCases: number; + private _argExpression: Expression; + private _testsByCase: Expression[][]; + + constructor( + argExpression: Expression, + caseClauses: SwitchExpressionClause[], + defaultExpression: PossiblyUpdatingExpression, + type: SequenceType, + ) { + const specificity = new Specificity({}); + super( + specificity, + [ + argExpression, + ...caseClauses.map((clause) => clause.caseClauseExpression), + defaultExpression, + ].concat(...caseClauses.map((clause) => clause.tests.map((test) => test))), + { + canBeStaticallyEvaluated: false, + peer: false, + resultOrder: RESULT_ORDERINGS.UNSORTED, + subtree: false, + }, + type, + ); + this._argExpression = argExpression; + this._amountOfCases = caseClauses.length; + this._testsByCase = caseClauses.map((clause) => clause.tests); + } + + public performFunctionalEvaluation( + dynamicContext: DynamicContext, + executionParameters: ExecutionParameters, + sequenceCallbacks: ((dynamicContext: DynamicContext) => ISequence)[], + ) { + // Pick the argumentExpression. + const evaluatedExpression = atomizeSequence( + sequenceCallbacks[0](dynamicContext), + executionParameters, + ); + + // Map over all values the type test, and return the result. + return evaluatedExpression.switchCases({ + multiple: () => { + throw errXPTY0004( + 'The operand for a switch expression should result in zero or one item', + ); + }, + default: () => { + const singleValue = evaluatedExpression.first(); + const isEmpty = !singleValue; + + for (let i = 0; i < this._amountOfCases; i++) { + const results = this._testsByCase[i].map((x) => + x.evaluateMaybeStatically(dynamicContext, executionParameters), + ); + + for (const result of results) { + const atomizedResult = atomizeSequence(result, executionParameters); + if (atomizedResult.isEmpty()) { + if (isEmpty) { + return sequenceCallbacks[i + 1](dynamicContext); + } + continue; + } + + if (!atomizedResult.isSingleton()) { + throw errXPTY0004( + 'The operand for a switch case should result in zero or one item', + ); + } + + if (isEmpty) { + continue; + } + + const first = atomizedResult.first(); + + if ( + itemDeepEqual( + dynamicContext, + executionParameters, + null, + singleValue, + first, + ).next(IterationHint.NONE).value + ) { + return sequenceCallbacks[i + 1](dynamicContext); + } + } + } + + return sequenceCallbacks[this._amountOfCases + 1](dynamicContext); + }, + }); + } + + public performStaticEvaluation(staticContext: StaticContext) { + super.performStaticEvaluation(staticContext); + + if (this._argExpression.isUpdating) { + throw errXUST0001(); + } + } +} + +export default SwitchExpression; diff --git a/src/parsing/astHelper.ts b/src/parsing/astHelper.ts index 14998d4fc..47b1bfc3c 100644 --- a/src/parsing/astHelper.ts +++ b/src/parsing/astHelper.ts @@ -84,7 +84,7 @@ function getTextContent(ast: IAST): string { */ function getTypeDeclaration(ast: IAST): SequenceType { const typeDeclarationAst = getFirstChild(ast, 'typeDeclaration'); - if (!typeDeclarationAst || getFirstChild(typeDeclarationAst, 'voidSequenceType')) { + if (!typeDeclarationAst) { return { type: ValueType.ITEM, mult: SequenceMultiplicity.ZERO_OR_MORE }; } diff --git a/src/parsing/compileAstToExpression.ts b/src/parsing/compileAstToExpression.ts index babe7aec5..39fb3c103 100644 --- a/src/parsing/compileAstToExpression.ts +++ b/src/parsing/compileAstToExpression.ts @@ -68,6 +68,7 @@ import ElementConstructor from '../expressions/xquery/ElementConstructor'; import PIConstructor from '../expressions/xquery/PIConstructor'; import TextConstructor from '../expressions/xquery/TextConstructor'; import TypeSwitchExpression from '../expressions/xquery/TypeSwitchExpression'; +import SwitchExpression from '../expressions/xquery/SwitchExpression'; import astHelper, { IAST } from './astHelper'; const COMPILATION_OPTIONS = { @@ -204,6 +205,8 @@ function compile(ast: IAST, compilationOptions: CompilationOptions): Expression case 'typeswitchExpr': return typeswitchExpr(ast, compilationOptions); + case 'switchExpr': + return switchExpr(ast, compilationOptions); // XQuery node constructors case 'elementConstructor': @@ -1481,7 +1484,7 @@ function typeswitchExpr(ast: IAST, compilationOptions: CompilationOptions) { const caseClause = astHelper.getChildren(ast, 'typeswitchExprCaseClause'); const caseClauseExpressions = caseClause.map((caseClauseExpression) => { - const sequenceTypesAstNodes: IAST[] = + const caseNodes: IAST[] = astHelper.getChildren(caseClauseExpression, 'sequenceTypeUnion').length === 0 ? [astHelper.getFirstChild(caseClauseExpression, 'sequenceType')] : astHelper.getChildren( @@ -1496,7 +1499,7 @@ function typeswitchExpr(ast: IAST, compilationOptions: CompilationOptions) { return { caseClauseExpression: resultExpression, - typeTests: sequenceTypesAstNodes.map((sequenceTypeAstNode: IAST) => { + typeTests: caseNodes.map((sequenceTypeAstNode: IAST) => { const occurrenceIndicator = astHelper.getFirstChild( sequenceTypeAstNode, 'occurrenceIndicator', @@ -1522,6 +1525,44 @@ function typeswitchExpr(ast: IAST, compilationOptions: CompilationOptions) { return new TypeSwitchExpression(argExpr, caseClauseExpressions, defaultExpression, type); } +function switchExpr(ast: IAST, compilationOptions: CompilationOptions) { + if (!compilationOptions.allowXQuery) { + throw new Error('XPST0003: Use of XQuery functionality is not allowed in XPath context'); + } + + const type = astHelper.getAttribute(ast, 'type'); + + const argExpr = compile( + astHelper.getFirstChild(astHelper.getFirstChild(ast, 'argExpr'), '*'), + compilationOptions, + ); + + const caseClauses = astHelper.getChildren(ast, 'switchExprCaseClause'); + + const caseClauseExpressions = caseClauses.map((caseClauseExpression) => { + const caseNodes: IAST[] = astHelper.getChildren(caseClauseExpression, 'switchCaseExpr'); + + const resultExpression = compile( + astHelper.followPath(caseClauseExpression, ['resultExpr', '*']), + compilationOptions, + ) as PossiblyUpdatingExpression; + + return { + caseClauseExpression: resultExpression, + tests: caseNodes.map((caseNode) => + compile(astHelper.getFirstChild(caseNode, '*'), compilationOptions), + ), + }; + }); + + const defaultExpression = compile( + astHelper.followPath(ast, ['switchExprDefaultClause', 'resultExpr', '*']), + compilationOptions, + ) as PossiblyUpdatingExpression; + + return new SwitchExpression(argExpr, caseClauseExpressions, defaultExpression, type); +} + export default function (xPathAst: IAST, compilationOptions: CompilationOptions): Expression { return compile(xPathAst, compilationOptions); } diff --git a/src/parsing/prscParser.ts b/src/parsing/prscParser.ts index 1287f7a34..7f62f52f5 100644 --- a/src/parsing/prscParser.ts +++ b/src/parsing/prscParser.ts @@ -1813,25 +1813,33 @@ function generateParser(options: { outputDebugInfo: boolean; xquery: boolean }): const switchCaseClause: Parser = then( plus( - map(precededMultiple([tokens.CASE, whitespacePlus], switchCaseOperand), (x) => [ - 'switchCaseExpr', - x, - ]), + then( + map( + precededMultiple([tokens.CASE, whitespacePlus], cut(switchCaseOperand)), + (x) => ['switchCaseExpr', x], + ), + cut(whitespacePlus), + (x, _) => x, + ), ), - precededMultiple([whitespacePlus, tokens.RETURN, whitespacePlus], exprSingle), + cut(precededMultiple([tokens.RETURN, whitespacePlus], cut(exprSingle))), (operands, exprPart) => ['switchExprCaseClause', ...operands, ['resultExpr', exprPart]] as IAST, ); const switchExpr: Parser = then3( - precededMultiple([tokens.SWITCH, whitespace, tokens.BRACE_OPEN], expr), - precededMultiple( - [whitespace, tokens.BRACE_CLOSE, whitespace], - plus(followed(switchCaseClause, whitespace)), + precededMultiple([tokens.SWITCH, whitespace, tokens.BRACE_OPEN], cut(expr)), + cut( + precededMultiple( + [whitespace, tokens.BRACE_CLOSE, cut(whitespace)], + plus(followed(switchCaseClause, whitespace)), + ), ), - precededMultiple( - [tokens.DEFAULT, whitespacePlus, tokens.RETURN, whitespacePlus], - exprSingle, + cut( + precededMultiple( + [tokens.DEFAULT, whitespacePlus, tokens.RETURN, whitespacePlus], + exprSingle, + ), ), (exprPart, clauses, resultExpr) => [ 'switchExpr', diff --git a/test/assets/failingXQueryXTestNames.csv b/test/assets/failingXQueryXTestNames.csv index 91e30755d..70d33f288 100644 --- a/test/assets/failingXQueryXTestNames.csv +++ b/test/assets/failingXQueryXTestNames.csv @@ -2336,9 +2336,19 @@ K-FunctionProlog-3,Parser related error, Error: XQST0045: Functions and variable K-FunctionProlog-31,Parser related error, Error: XQST0045: Functions and variables may not be declared in one of the reserved namespace URIs. K-FunctionProlog-32,Parser related error, Error: XQST0045: Functions and variables may not be declared in one of the reserved namespace URIs. K-FunctionProlog-4,Parser related error, Error: XQST0045: Functions and variables may not be declared in one of the reserved namespace URIs. +K-FunctionProlog-46,Parser related error, Error: Type declaration "voidSequenceType" is not supported. +K-FunctionProlog-49,Parser related error, Error: Type declaration "voidSequenceType" is not supported. K-FunctionProlog-5,Parser related error, Error: XQST0045: Functions and variables may not be declared in one of the reserved namespace URIs. +K-FunctionProlog-50,Parser related error, Error: Type declaration "voidSequenceType" is not supported. +K-FunctionProlog-52,Parser related error, Error: Type declaration "voidSequenceType" is not supported. +K-FunctionProlog-53,Parser related error, Error: Type declaration "voidSequenceType" is not supported. +K-FunctionProlog-54,Parser related error, Error: Type declaration "voidSequenceType" is not supported. +K-FunctionProlog-55,Parser related error, Error: Type declaration "voidSequenceType" is not supported. +K-FunctionProlog-56,Parser related error, Error: Type declaration "voidSequenceType" is not supported. K-FunctionProlog-57,Parser related error, Error: XPST0081: Invalid prefix for input :none +K-FunctionProlog-65,Parser related error, Error: Type declaration "voidSequenceType" is not supported. K2-FunctionProlog-14,result was not equal +cbcl-function-decl-001,Parser related error, Error: Type declaration "voidSequenceType" is not supported. function-declaration-010,result was not equal function-declaration-016,result was not equal function-declaration-023,Parser related error, Error: XQST0045: Functions and variables may not be declared in one of the reserved namespace URIs. @@ -2670,8 +2680,6 @@ string-constructor-026,Parse error string-constructor-910,Parse error string-constructor-911,Parse error string-constructor-912,Parse error -switch-004,Parse error -switch-005,Parse error try-001,Parse error try-002,Parse error try-003,Parse error diff --git a/test/assets/runnableTestSets.csv b/test/assets/runnableTestSets.csv index 09794f252..9b8ff536b 100644 --- a/test/assets/runnableTestSets.csv +++ b/test/assets/runnableTestSets.csv @@ -408,7 +408,7 @@ prod-SequenceType,true prod-SquareArrayConstructor,true prod-StepExpr,true prod-StringConstructor,true -prod-SwitchExpr,false +prod-SwitchExpr,true prod-TreatExpr,false prod-TryCatchExpr,false prod-TypeswitchExpr,true diff --git a/test/assets/unrunnableTestCases.csv b/test/assets/unrunnableTestCases.csv index 013e0a8ee..19f02848d 100644 --- a/test/assets/unrunnableTestCases.csv +++ b/test/assets/unrunnableTestCases.csv @@ -1763,8 +1763,8 @@ base64-115,AssertionError: xs:hexBinary(xs:base64Binary(" AQIDBAUG BwgJCgsM DQ4P xs-double-004,AssertionError: expected [Function] to throw an error xs-error-006,Error: No selector counterpart for: typedFunctionTest. xs-error-007,Error: No selector counterpart for: typedFunctionTest. -xs-error-015,Error: No selector counterpart for: typedFunctionTest. -xs-error-016,Error: No selector counterpart for: typedFunctionTest. +xs-error-015,Error: Type declaration "voidSequenceType" is not supported. +xs-error-016,Error: Type declaration "voidSequenceType" is not supported. xs-error-020,Error: 1: (declare function local:identity($arg as xs:error?) ^ 2: { 3: $arg Error: XPST0003: Failed to parse script. Expected -,+,validate,(#,(,#,parent::,ancestor::,preceding-sibling::,preceding::,ancestor-or-self::,..,child::,descendant::,attribute::,self::,descendant-or-self::,following-sibling::,following::,document-node(,element,attribute,schema-element,schema-attribute(,processing-instruction(,processing-instruction(),comment(),text(),namespace-node(),node(),:*,Q,[A-Z_a-z\xC0-\xD6\xD8-\xF6\xF8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD],[\uD800-\uDB7F],/,// at <>:1:10 - 1:11 xs-error-031,AssertionError: Expected executing the XPath "for $x as xs:error in (1, 2, 3) return $x" to resolve to one of the expected results, but got AssertionError: expected [Function] to throw an error. xs-error-047,AssertionError: expected [Function] to throw error matching /FOER0000/ but got 'No selector counterpart for: treatExp…' @@ -2998,11 +2998,16 @@ K-FunctionProlog-29,AssertionError: expected [Function] to throw error matching K-FunctionProlog-36,AssertionError: expected [Function] to throw error matching /XPST0008/ but got 'XQDY0054: The variable myArg is decla…' K-FunctionProlog-37,AssertionError: expected [Function] to throw an error K-FunctionProlog-38,AssertionError: expected [Function] to throw an error -K-FunctionProlog-46,AssertionError: Expected executing the XPath " declare function local:myFunction($arg as empty-sequence()) { $arg }; local:myFunction(1)" to resolve to one of the expected results, but got AssertionError: expected [Function] to throw an error, AssertionError: expected [Function] to throw an error. -K-FunctionProlog-50,AssertionError: expected [Function] to throw an error +K-FunctionProlog-46,AssertionError: Expected executing the XPath " declare function local:myFunction($arg as empty-sequence()) { $arg }; local:myFunction(1)" to resolve to one of the expected results, but got AssertionError: expected [Function] to throw error matching /XPTY0004/ but got 'Type declaration "voidSequenceType" i…', AssertionError: expected [Function] to throw error matching /XPST0005/ but got 'Type declaration "voidSequenceType" i…'. +K-FunctionProlog-49,AssertionError: Expected executing the XPath " declare function local:myFunction($arg as empty-sequence()) { $arg }; empty(local:myFunction(()))" to resolve to one of the expected results, but got Error: Type declaration "voidSequenceType" is not supported., AssertionError: expected [Function] to throw error matching /XPST0005/ but got 'Type declaration "voidSequenceType" i…'. +K-FunctionProlog-50,AssertionError: expected [Function] to throw error matching /XPTY0004/ but got 'Type declaration "voidSequenceType" i…' +K-FunctionProlog-52,AssertionError: expected [Function] to throw error matching /FOER0000/ but got 'Type declaration "voidSequenceType" i…' +K-FunctionProlog-53,AssertionError: Expected executing the XPath "declare namespace my = "http://example.com/MyNamespace/"; declare variable $my:error-qname := QName("http:example.org/", "prefix:ncname"); declare function my:error($choice, $msg as xs:string) as empty-sequence() { if($choice) then error($my:error-qname, concat('No luck: ', $msg)) else () }; empty((my:error(false(), "msg"), my:error(false(), "The message")))" to resolve to one of the expected results, but got Error: Type declaration "voidSequenceType" is not supported., AssertionError: expected [Function] to throw error matching /XPST0005/ but got 'Type declaration "voidSequenceType" i…'. +K-FunctionProlog-56,AssertionError: Expected executing the XPath "declare namespace my = "http://example.com/MyNamespace/"; declare variable $my:error-qname := QName("http://example.com/MyErrorNS", "my:qName"); declare function my:error($choice, $msg as xs:string) as empty-sequence() { if($choice) then error($my:error-qname, concat('No luck: ', $msg)) else () }; empty((my:error(false(), "msg"), my:error(false(), "The message")))" to resolve to one of the expected results, but got Error: Type declaration "voidSequenceType" is not supported., AssertionError: expected [Function] to throw error matching /XPST0005/ but got 'Type declaration "voidSequenceType" i…'. K-FunctionProlog-57,AssertionError: expected [Function] to throw error matching /XPST0051/ but got 'XPST0081: Invalid prefix for input :n…' K-FunctionProlog-60,AssertionError: expected [Function] to throw error matching /XPST0008/ but got 'XQDY0054: The variable arg is declare…' K-FunctionProlog-61,AssertionError: expected [Function] to throw error matching /XPST0008/ but got 'XQDY0054: The variable arg3 is declar…' +K-FunctionProlog-65,AssertionError: Expected executing the XPath " declare function local:myFunction() as empty-sequence() { fn:error() }; QName("http://example.com/ANamespace", local:myFunction())" to resolve to one of the expected results, but got AssertionError: expected [Function] to throw error matching /XPTY0004/ but got 'Type declaration "voidSequenceType" i…', AssertionError: expected [Function] to throw error matching /FOER0000/ but got 'Type declaration "voidSequenceType" i…'. K2-FunctionProlog-1,Error: No selector counterpart for: treatExpr. K2-FunctionProlog-2,Error: No selector counterpart for: treatExpr. K2-FunctionProlog-3,Error: No selector counterpart for: treatExpr. @@ -3010,6 +3015,7 @@ K2-FunctionProlog-4,Error: No selector counterpart for: treatExpr. K2-FunctionProlog-19,Error: No selector counterpart for: computedDocumentConstructor. K2-FunctionProlog-25,Error: No selector counterpart for: treatExpr. K2-FunctionProlog-26,AssertionError: expected [Function] to throw an error +cbcl-function-decl-001,Error: Type declaration "voidSequenceType" is not supported. K2-GenCompEq-1,Error: No selector counterpart for: treatExpr. K2-GenCompEq-2,Error: No selector counterpart for: treatExpr. K2-GenCompEq-3,Error: No selector counterpart for: treatExpr. @@ -3443,6 +3449,7 @@ string-constructor-028,Error: 1: ( 2: declare variable $n external := :3:9 - 3:10 +switch-018,AssertionError: Expected XPath let $v := xs:time('00:00:00Z') return switch($v) case xs:time('24:00:00Z') return 1 default return 2 to resolve to 1: expected false to be true typeswitchhc16,Error: XPST0008, The variable i is not in scope. typeswitchhc20,Error: XPST0008, The variable i is not in scope. K-sequenceExprTypeswitch-6,Error: No selector counterpart for: voidSequenceType. @@ -3876,7 +3883,6 @@ UseCaseR31-002,Error: Not implemented: groupByClause is not implemented yet. UseCaseR31-003,Error: Not implemented: groupByClause is not implemented yet. UseCaseR31-004,Error: 1: let $result := ( ^ 2: declare namespace map="http://www.w3.org/2005/xpath-functions/map"; 3: Error: XPST0003: Failed to parse script. Expected end of input at <>:1:5 - 1:6 UseCaseR31-009,Error: 1: let $result := ( ^ 2: declare namespace map="http://www.w3.org/2005/xpath-functions/map"; 3: declare variable $book:= ( Error: XPST0003: Failed to parse script. Expected end of input at <>:1:5 - 1:6 -UseCaseR31-012,Error: No selector counterpart for: switchExpr. UseCaseR31-015,Error: Not implemented: groupByClause is not implemented yet. UseCaseR31-016,Error: 1: deep-equal(( ^ 2: declare variable $s :=[['A', 'DT'], ['bride', 'NN'], [',', ','], ['you', 'PRP'], ['know', 'VBP'], [',', ','], ['must', 'MD'], 3: ['appear', 'VB'], ['like', 'IN'], ['a', 'DT'], ['bride', 'NN'], [',', ','], ['but', 'CC'], ['my', 'PRP$'], Error: XPST0003: Failed to parse script. Expected end of input at <>:1:11 - 1:12 UseCaseR31-017,Error: 1: deep-equal(( ^ 2: declare variable $s :=[['A', 'DT'], ['bride', 'NN'], [',', ','], ['you', 'PRP'], ['know', 'VBP'], [',', ','], ['must', 'MD'], 3: ['appear', 'VB'], ['like', 'IN'], ['a', 'DT'], ['bride', 'NN'], [',', ','], ['but', 'CC'], ['my', 'PRP$'], Error: XPST0003: Failed to parse script. Expected end of input at <>:1:11 - 1:12 diff --git a/test/specs/parsing/xquery/SwitchExpression.tests.ts b/test/specs/parsing/xquery/SwitchExpression.tests.ts new file mode 100644 index 000000000..dcc6ad0c4 --- /dev/null +++ b/test/specs/parsing/xquery/SwitchExpression.tests.ts @@ -0,0 +1,102 @@ +import * as chai from 'chai'; + +import { evaluateXPath, evaluateXPathToNumber } from 'fontoxpath'; + +describe('Switch', () => { + it('works', () => + chai.assert.equal( + evaluateXPathToNumber( + ` +switch (1) +case 1 return 1 +default return 0`, + + null, + null, + null, + { + debug: true, + language: evaluateXPath.XQUERY_3_1_LANGUAGE, + }, + ), + 1, + )); + + it('works hitting the default case', () => + chai.assert.equal( + evaluateXPathToNumber( + ` +switch (0) +case 1 return 1 +default return 0`, + + null, + null, + null, + { + debug: true, + language: evaluateXPath.XQUERY_3_1_LANGUAGE, + }, + ), + 0, + )); + + it('works hitting the empty sequence case', () => + chai.assert.equal( + evaluateXPathToNumber( + ` +switch (()) +case () return 1 +default return 0`, + + null, + null, + null, + { + debug: true, + language: evaluateXPath.XQUERY_3_1_LANGUAGE, + }, + ), + 1, + )); + + it('works hitting the empty sequence case as a default', () => + chai.assert.equal( + evaluateXPathToNumber( + ` +switch (()) +case 1 return 1 +default return 0`, + + null, + null, + null, + { + debug: true, + language: evaluateXPath.XQUERY_3_1_LANGUAGE, + }, + ), + 0, + )); + + it('works hitting overload cases', () => + chai.assert.equal( + evaluateXPathToNumber( + ` +switch (1) +case () +case 1 return 1 + +default return 0`, + + null, + null, + null, + { + debug: true, + language: evaluateXPath.XQUERY_3_1_LANGUAGE, + }, + ), + 1, + )); +});