@@ -2,10 +2,21 @@ use super::post_conversion_linter::PostConversionLinter;
22use rusty_common:: * ;
33use rusty_parser:: * ;
44
5- use crate :: core:: LintResult ;
6- use crate :: core :: { LintError , LintErrorPos } ;
5+ use crate :: core:: * ;
6+ use crate :: { no_op_visitor , no_pos_visitor } ;
77use std:: collections:: HashSet ;
88
9+ /// In QBasic, if you have anywhere in the program a variable of user defined type,
10+ /// e.g. `DIM A AS Person`,
11+ /// then you can't have anywhere else in the program a variable that starts with
12+ /// that name followed by a dot,
13+ /// e.g. `DIM A.B$` is illegal.
14+ ///
15+ /// The QBasic behavior is probably done at the parsing level,
16+ /// but here we catch it at the linter.
17+ /// QBasic's behavior is to throw the error:
18+ /// "Expected: , or end-of-statement"
19+ /// and the error location is reported at the dot.
920#[ derive( Default ) ]
1021pub struct DotsLinter {
1122 user_defined_names : HashSet < CaseInsensitiveString > ,
@@ -128,9 +139,9 @@ impl NoDotNamesCheck<(&Expression, Position), LintErrorPos> for DotsLinter {
128139
129140impl PostConversionLinter for DotsLinter {
130141 fn visit_program ( & mut self , p : & Program ) -> Result < ( ) , LintErrorPos > {
131- let mut collector = UserDefinedNamesCollector :: default ( ) ;
132- collector. visit_program ( p) ?;
133- self . user_defined_names = collector. user_defined_names ;
142+ let mut collector = UserDefinedNamesCollector :: visitor ( ) ;
143+ collector. visit ( p) ?;
144+ self . user_defined_names = collector. delegate ( ) . user_defined_names ;
134145 self . visit_global_statements ( p)
135146 }
136147
@@ -177,43 +188,46 @@ impl PostConversionLinter for DotsLinter {
177188 }
178189}
179190
191+ /// Collects names of parameters or variables that are of a user defined type.
180192#[ derive( Default ) ]
181193struct UserDefinedNamesCollector {
182194 user_defined_names : HashSet < CaseInsensitiveString > ,
183195}
184196
197+ no_op_visitor ! ( UserDefinedNamesCollector : DefType , FunctionDeclaration , SubDeclaration , UserDefinedType ) ;
198+ no_pos_visitor ! ( UserDefinedNamesCollector ) ;
199+
185200impl UserDefinedNamesCollector {
186- fn visit_names < T > ( & mut self , params : & Vec < Positioned < TypedName < T > > > )
187- where
188- T : VarTypeToUserDefinedRecursively ,
189- {
190- self . user_defined_names . extend (
191- params
192- . iter ( )
193- . map ( |dim_var_pos| & dim_var_pos. element )
194- . filter ( |dim_name| dim_name. var_type . as_user_defined_recursively ( ) . is_some ( ) )
195- . map ( |dim_name| & dim_name. bare_name )
196- . cloned ( ) ,
197- ) ;
198- }
199- }
200-
201- impl PostConversionLinter for UserDefinedNamesCollector {
202- fn visit_function_implementation (
203- & mut self ,
204- f : & FunctionImplementation ,
205- ) -> Result < ( ) , LintErrorPos > {
206- self . visit_names ( & f. params ) ;
207- self . visit_statements ( & f. body )
201+ pub fn visitor ( ) -> impl Visitor < Program > + DelegateVisitor < Self > + SetPosition {
202+ DeepStatementVisitor :: new ( Self :: default ( ) )
208203 }
204+ }
209205
210- fn visit_sub_implementation ( & mut self , s : & SubImplementation ) -> Result < ( ) , LintErrorPos > {
211- self . visit_names ( & s . params ) ;
212- self . visit_statements ( & s . body )
206+ impl < T > Visitor < SubprogramImplementation < T > > for UserDefinedNamesCollector {
207+ fn visit ( & mut self , element : & SubprogramImplementation < T > ) -> VisitResult {
208+ self . visit ( & element . params )
213209 }
210+ }
214211
215- fn visit_dim ( & mut self , dim_list : & DimList ) -> Result < ( ) , LintErrorPos > {
216- self . visit_names ( & dim_list. variables ) ;
212+ impl Visitor < Statement > for UserDefinedNamesCollector {
213+ fn visit ( & mut self , element : & Statement ) -> VisitResult {
214+ match element {
215+ Statement :: Dim ( dim_list) | Statement :: Redim ( dim_list) => {
216+ self . visit ( & dim_list. variables )
217+ }
218+ _ => Ok ( ( ) ) ,
219+ }
220+ }
221+ }
222+
223+ impl < T > Visitor < TypedName < T > > for UserDefinedNamesCollector
224+ where
225+ T : VarTypeToUserDefinedRecursively ,
226+ {
227+ fn visit ( & mut self , element : & TypedName < T > ) -> VisitResult {
228+ if element. var_type . as_user_defined_recursively ( ) . is_some ( ) {
229+ self . user_defined_names . insert ( element. bare_name . clone ( ) ) ;
230+ }
217231 Ok ( ( ) )
218232 }
219233}
0 commit comments