-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: port validation of parameter lists (#573)
Closes partially #543. ### Summary of Changes Show an error if a parameter list: * has more parameters after a variadic one, * has optional parameters and a variadic one, or * has required parameters after optional ones.
- Loading branch information
1 parent
af13e28
commit bd73bc5
Showing
6 changed files
with
456 additions
and
14 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
59 changes: 59 additions & 0 deletions
59
src/language/validation/other/declarations/parameterLists.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
import { SdsParameterList } from '../../../generated/ast.js'; | ||
import { ValidationAcceptor } from 'langium'; | ||
|
||
export const CODE_PARAMETER_LIST_OPTIONAL_AND_VARIADIC = 'parameter-list/optional-and-variadic'; | ||
export const CODE_PARAMETER_LIST_REQUIRED_AFTER_OPTIONAL = 'parameter-list/required-after-optional'; | ||
export const CODE_PARAMETER_LIST_VARIADIC_NOT_LAST = 'parameter-list/variadic-not-last'; | ||
|
||
export const parameterListMustNotHaveOptionalAndVariadicParameters = ( | ||
node: SdsParameterList, | ||
accept: ValidationAcceptor, | ||
) => { | ||
const hasOptional = node.parameters.find((p) => p.defaultValue); | ||
if (hasOptional) { | ||
const variadicParameters = node.parameters.filter((p) => p.variadic); | ||
|
||
for (const variadic of variadicParameters) { | ||
accept('error', 'A callable with optional parameters must not have a variadic parameter.', { | ||
node: variadic, | ||
property: 'name', | ||
code: CODE_PARAMETER_LIST_OPTIONAL_AND_VARIADIC, | ||
}); | ||
} | ||
} | ||
}; | ||
|
||
export const parameterListMustNotHaveRequiredParametersAfterOptionalParameters = ( | ||
node: SdsParameterList, | ||
accept: ValidationAcceptor, | ||
) => { | ||
let foundOptional = false; | ||
for (const parameter of node.parameters) { | ||
if (parameter.defaultValue) { | ||
foundOptional = true; | ||
} else if (foundOptional && !parameter.variadic) { | ||
accept('error', 'After the first optional parameter all parameters must be optional.', { | ||
node: parameter, | ||
property: 'name', | ||
code: CODE_PARAMETER_LIST_REQUIRED_AFTER_OPTIONAL, | ||
}); | ||
} | ||
} | ||
}; | ||
|
||
export const parameterListVariadicParameterMustBeLast = (node: SdsParameterList, accept: ValidationAcceptor) => { | ||
let foundVariadic = false; | ||
for (const parameter of node.parameters) { | ||
if (foundVariadic) { | ||
accept('error', 'After a variadic parameter no more parameters must be specified.', { | ||
node: parameter, | ||
property: 'name', | ||
code: CODE_PARAMETER_LIST_VARIADIC_NOT_LAST, | ||
}); | ||
} | ||
|
||
if (parameter.variadic) { | ||
foundVariadic = true; | ||
} | ||
} | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
126 changes: 126 additions & 0 deletions
126
...ion/other/declarations/parameter lists/must not have required after optional/main.sdstest
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
package tests.validation.other.declarations.parameterLists.mustNotHaveRequiredAfterOptional | ||
|
||
// $TEST$ no error "After the first optional parameter all parameters must be optional." | ||
// $TEST$ no error "After the first optional parameter all parameters must be optional." | ||
// $TEST$ error "After the first optional parameter all parameters must be optional." | ||
// $TEST$ no error "After the first optional parameter all parameters must be optional." | ||
// $TEST$ no error "After the first optional parameter all parameters must be optional." | ||
annotation MyAnnotation1(»a«: Int, »b«: Int = 1, »c«: Int, »d«: Int = 2, vararg »e«: Int) | ||
|
||
// $TEST$ no error "After the first optional parameter all parameters must be optional." | ||
// $TEST$ no error "After the first optional parameter all parameters must be optional." | ||
annotation MyAnnotation2(»a«: Int, »b«: Int = 1) | ||
|
||
// $TEST$ no error "After the first optional parameter all parameters must be optional." | ||
annotation MyAnnotation3(»a«: Int) | ||
|
||
|
||
// $TEST$ no error "After the first optional parameter all parameters must be optional." | ||
// $TEST$ no error "After the first optional parameter all parameters must be optional." | ||
// $TEST$ error "After the first optional parameter all parameters must be optional." | ||
// $TEST$ no error "After the first optional parameter all parameters must be optional." | ||
// $TEST$ no error "After the first optional parameter all parameters must be optional." | ||
class MyClass1(»a«: Int, »b«: Int = 1, »c«: Int, »d«: Int = 2, vararg »e«: Int) | ||
|
||
// $TEST$ no error "After the first optional parameter all parameters must be optional." | ||
// $TEST$ no error "After the first optional parameter all parameters must be optional." | ||
class MyClass2(»a«: Int, »b«: Int = 1) | ||
|
||
// $TEST$ no error "After the first optional parameter all parameters must be optional." | ||
class MyClass3(»a«: Int) | ||
|
||
|
||
enum MyEnum { | ||
// $TEST$ no error "After the first optional parameter all parameters must be optional." | ||
// $TEST$ no error "After the first optional parameter all parameters must be optional." | ||
// $TEST$ error "After the first optional parameter all parameters must be optional." | ||
// $TEST$ no error "After the first optional parameter all parameters must be optional." | ||
// $TEST$ no error "After the first optional parameter all parameters must be optional." | ||
MyEnumVariant1(»a«: Int, »b«: Int = 1, »c«: Int, »d«: Int = 2, vararg »e«: Int) | ||
|
||
// $TEST$ no error "After the first optional parameter all parameters must be optional." | ||
// $TEST$ no error "After the first optional parameter all parameters must be optional." | ||
MyEnumVariant2(»a«: Int, »b«: Int = 1) | ||
|
||
// $TEST$ no error "After the first optional parameter all parameters must be optional." | ||
MyEnumVariant3(»a«: Int) | ||
} | ||
|
||
|
||
// $TEST$ no error "After the first optional parameter all parameters must be optional." | ||
// $TEST$ no error "After the first optional parameter all parameters must be optional." | ||
// $TEST$ error "After the first optional parameter all parameters must be optional." | ||
// $TEST$ no error "After the first optional parameter all parameters must be optional." | ||
// $TEST$ no error "After the first optional parameter all parameters must be optional." | ||
fun myFunction1(»a«: Int, »b«: Int = 1, »c«: Int, »d«: Int = 2, vararg »e«: Int) | ||
|
||
// $TEST$ no error "After the first optional parameter all parameters must be optional." | ||
// $TEST$ no error "After the first optional parameter all parameters must be optional." | ||
fun myFunction2(»a«: Int, »b«: Int = 1) | ||
|
||
// $TEST$ no error "After the first optional parameter all parameters must be optional." | ||
fun myFunction3(»a«: Int) | ||
|
||
|
||
// $TEST$ no error "After the first optional parameter all parameters must be optional." | ||
// $TEST$ no error "After the first optional parameter all parameters must be optional." | ||
// $TEST$ error "After the first optional parameter all parameters must be optional." | ||
// $TEST$ no error "After the first optional parameter all parameters must be optional." | ||
// $TEST$ no error "After the first optional parameter all parameters must be optional." | ||
segment mySegment1(»a«: Int, »b«: Int = 1, »c«: Int, »d«: Int = 2, vararg »e«: Int) {} | ||
|
||
// $TEST$ no error "After the first optional parameter all parameters must be optional." | ||
// $TEST$ no error "After the first optional parameter all parameters must be optional." | ||
segment mySegment2(»a«: Int, »b«: Int = 1) {} | ||
|
||
// $TEST$ no error "After the first optional parameter all parameters must be optional." | ||
segment mySegment3(»a«: Int) {} | ||
|
||
|
||
pipeline myPipeline { | ||
// $TEST$ no error "After the first optional parameter all parameters must be optional." | ||
// $TEST$ no error "After the first optional parameter all parameters must be optional." | ||
// $TEST$ error "After the first optional parameter all parameters must be optional." | ||
// $TEST$ no error "After the first optional parameter all parameters must be optional." | ||
// $TEST$ no error "After the first optional parameter all parameters must be optional." | ||
(»a«: Int, »b«: Int = 1, »c«: Int, »d«: Int = 2, vararg »e«: Int) {}; | ||
|
||
// $TEST$ no error "After the first optional parameter all parameters must be optional." | ||
// $TEST$ no error "After the first optional parameter all parameters must be optional." | ||
(»a«: Int, »b«: Int = 1) {}; | ||
|
||
// $TEST$ no error "After the first optional parameter all parameters must be optional." | ||
(»a«: Int) {}; | ||
|
||
|
||
// $TEST$ no error "After the first optional parameter all parameters must be optional." | ||
// $TEST$ no error "After the first optional parameter all parameters must be optional." | ||
// $TEST$ error "After the first optional parameter all parameters must be optional." | ||
// $TEST$ no error "After the first optional parameter all parameters must be optional." | ||
// $TEST$ no error "After the first optional parameter all parameters must be optional." | ||
(»a«: Int, »b«: Int = 1, »c«: Int, »d«: Int = 2, vararg »e«: Int) -> 1; | ||
|
||
// $TEST$ no error "After the first optional parameter all parameters must be optional." | ||
// $TEST$ no error "After the first optional parameter all parameters must be optional." | ||
(»a«: Int, »b«: Int = 1) -> 1; | ||
|
||
// $TEST$ no error "After the first optional parameter all parameters must be optional." | ||
(»a«: Int) -> 1; | ||
} | ||
|
||
|
||
fun myFunction4( | ||
// $TEST$ no error "After the first optional parameter all parameters must be optional." | ||
// $TEST$ no error "After the first optional parameter all parameters must be optional." | ||
// $TEST$ error "After the first optional parameter all parameters must be optional." | ||
// $TEST$ no error "After the first optional parameter all parameters must be optional." | ||
// $TEST$ no error "After the first optional parameter all parameters must be optional." | ||
p1: (»a«: Int, »b«: Int = 1, »c«: Int, »d«: Int = 2, vararg »e«: Int) -> (), | ||
|
||
// $TEST$ no error "After the first optional parameter all parameters must be optional." | ||
// $TEST$ no error "After the first optional parameter all parameters must be optional." | ||
p2: (»a«: Int, »b«: Int = 1) -> (), | ||
|
||
// $TEST$ no error "After the first optional parameter all parameters must be optional." | ||
p3: (»a«: Int) -> (), | ||
) |
Oops, something went wrong.