1- import { SdsArgumentList } from '../../generated/ast.js' ;
2- import { ValidationAcceptor } from 'langium' ;
1+ import { isSdsAnnotation , isSdsCall , SdsAbstractCall , SdsArgumentList } from '../../generated/ast.js' ;
2+ import { getContainerOfType , ValidationAcceptor } from 'langium' ;
3+ import { SafeDsServices } from '../../safe-ds-module.js' ;
4+ import { argumentsOrEmpty , isRequiredParameter , parametersOrEmpty } from '../../helpers/nodeProperties.js' ;
5+ import { duplicatesBy } from '../../helpers/collectionUtils.js' ;
6+ import { isEmpty } from 'radash' ;
7+ import { pluralize } from '../../helpers/stringUtils.js' ;
38
9+ export const CODE_ARGUMENT_LIST_DUPLICATE_PARAMETER = 'argument-list/duplicate-parameter' ;
10+ export const CODE_ARGUMENT_LIST_MISSING_REQUIRED_PARAMETER = 'argument-list/missing-required-parameter' ;
411export const CODE_ARGUMENT_LIST_POSITIONAL_AFTER_NAMED = 'argument-list/positional-after-named' ;
12+ export const CODE_ARGUMENT_LIST_TOO_MANY_ARGUMENTS = 'argument-list/too-many-arguments' ;
513
614export const argumentListMustNotHavePositionalArgumentsAfterNamedArguments = (
715 node : SdsArgumentList ,
@@ -19,3 +27,107 @@ export const argumentListMustNotHavePositionalArgumentsAfterNamedArguments = (
1927 }
2028 }
2129} ;
30+
31+ export const argumentListMustNotHaveTooManyArguments = ( services : SafeDsServices ) => {
32+ const nodeMapper = services . helpers . NodeMapper ;
33+
34+ return ( node : SdsAbstractCall , accept : ValidationAcceptor ) : void => {
35+ const actualArgumentCount = argumentsOrEmpty ( node ) . length ;
36+
37+ // We can never have too many arguments in this case
38+ if ( actualArgumentCount === 0 ) {
39+ return ;
40+ }
41+
42+ // We already report other errors in those cases
43+ const callable = nodeMapper . callToCallableOrUndefined ( node ) ;
44+ if ( ! callable || ( isSdsCall ( node ) && isSdsAnnotation ( callable ) ) ) {
45+ return ;
46+ }
47+
48+ const parameters = parametersOrEmpty ( callable ) ;
49+ const maxArgumentCount = parameters . length ;
50+
51+ // All is good
52+ if ( actualArgumentCount <= maxArgumentCount ) {
53+ return ;
54+ }
55+
56+ const minArgumentCount = parameters . filter ( ( it ) => isRequiredParameter ( it ) ) . length ;
57+ const kind = pluralize ( Math . max ( minArgumentCount , maxArgumentCount ) , 'argument' ) ;
58+ if ( minArgumentCount === maxArgumentCount ) {
59+ accept ( 'error' , `Expected exactly ${ minArgumentCount } ${ kind } but got ${ actualArgumentCount } .` , {
60+ node,
61+ property : 'argumentList' ,
62+ code : CODE_ARGUMENT_LIST_TOO_MANY_ARGUMENTS ,
63+ } ) ;
64+ } else {
65+ accept (
66+ 'error' ,
67+ `Expected between ${ minArgumentCount } and ${ maxArgumentCount } ${ kind } but got ${ actualArgumentCount } .` ,
68+ {
69+ node,
70+ property : 'argumentList' ,
71+ code : CODE_ARGUMENT_LIST_TOO_MANY_ARGUMENTS ,
72+ } ,
73+ ) ;
74+ }
75+ } ;
76+ } ;
77+
78+ export const argumentListMustNotSetParameterMultipleTimes = ( services : SafeDsServices ) => {
79+ const nodeMapper = services . helpers . NodeMapper ;
80+ const argumentToParameterOrUndefined = nodeMapper . argumentToParameterOrUndefined . bind ( nodeMapper ) ;
81+
82+ return ( node : SdsArgumentList , accept : ValidationAcceptor ) : void => {
83+ // We already report other errors in this case
84+ const containingCall = getContainerOfType ( node , isSdsCall ) ;
85+ const callable = nodeMapper . callToCallableOrUndefined ( containingCall ) ;
86+ if ( isSdsAnnotation ( callable ) ) {
87+ return ;
88+ }
89+
90+ const args = argumentsOrEmpty ( node ) ;
91+ const duplicates = duplicatesBy ( args , argumentToParameterOrUndefined ) ;
92+
93+ for ( const duplicate of duplicates ) {
94+ const correspondingParameter = argumentToParameterOrUndefined ( duplicate ) ! ;
95+ accept ( 'error' , `The parameter '${ correspondingParameter . name } ' is already set.` , {
96+ node : duplicate ,
97+ code : CODE_ARGUMENT_LIST_DUPLICATE_PARAMETER ,
98+ } ) ;
99+ }
100+ } ;
101+ } ;
102+
103+ export const argumentListMustSetAllRequiredParameters = ( services : SafeDsServices ) => {
104+ const nodeMapper = services . helpers . NodeMapper ;
105+
106+ return ( node : SdsAbstractCall , accept : ValidationAcceptor ) : void => {
107+ const callable = nodeMapper . callToCallableOrUndefined ( node ) ;
108+
109+ // We already report other errors in those cases
110+ if ( ! callable || ( isSdsCall ( node ) && isSdsAnnotation ( callable ) ) ) {
111+ return ;
112+ }
113+
114+ const expectedParameters = parametersOrEmpty ( callable ) . filter ( ( it ) => isRequiredParameter ( it ) ) ;
115+ if ( isEmpty ( expectedParameters ) ) {
116+ return ;
117+ }
118+
119+ const actualParameters = argumentsOrEmpty ( node ) . map ( ( it ) => nodeMapper . argumentToParameterOrUndefined ( it ) ) ;
120+
121+ const missingTypeParameters = expectedParameters . filter ( ( it ) => ! actualParameters . includes ( it ) ) ;
122+ if ( ! isEmpty ( missingTypeParameters ) ) {
123+ const kind = pluralize ( missingTypeParameters . length , 'parameter' ) ;
124+ const missingParametersString = missingTypeParameters . map ( ( it ) => `'${ it . name } '` ) . join ( ', ' ) ;
125+
126+ accept ( 'error' , `The ${ kind } ${ missingParametersString } must be set here.` , {
127+ node,
128+ property : 'argumentList' ,
129+ code : CODE_ARGUMENT_LIST_MISSING_REQUIRED_PARAMETER ,
130+ } ) ;
131+ }
132+ } ;
133+ } ;
0 commit comments