Skip to content

Commit 3bbf476

Browse files
committed
refactor: Migrated UserDefinedNamesCollector to the new Visitor pattern
1 parent bbb53db commit 3bbf476

3 files changed

Lines changed: 64 additions & 46 deletions

File tree

rusty_linter/src/core/visitor.rs

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -61,9 +61,12 @@ where
6161
}
6262
}
6363

64-
/// Creates a delegate visitor for the given type T.
65-
pub trait DelegateVisitor<T> {
66-
fn delegate(&mut self) -> impl Visitor<T>;
64+
/// A visitor that delegates some functionality to another visitor.
65+
pub trait DelegateVisitor<P> {
66+
/// Returns the delegate visitor.
67+
/// Typically called after the visit is done, in order to extract
68+
/// information from the underlying visitor.
69+
fn delegate(self) -> P;
6770
}
6871

6972
delegate_visitor!(
@@ -257,12 +260,6 @@ macro_rules! delegate_visitor {
257260
pub fn new(delegate: P) -> Self {
258261
Self { delegate }
259262
}
260-
261-
/// Returns the delegate back.
262-
#[allow(unused)]
263-
pub fn delegate(self) -> P {
264-
self.delegate
265-
}
266263
}
267264

268265
impl<P> SetPosition for $name<P>
@@ -273,5 +270,11 @@ macro_rules! delegate_visitor {
273270
self.delegate.set_position(pos);
274271
}
275272
}
273+
274+
impl<P> DelegateVisitor<P> for $name<P> {
275+
fn delegate(self) -> P {
276+
self.delegate
277+
}
278+
}
276279
};
277280
}

rusty_linter/src/post_linter/dots_linter.rs

Lines changed: 46 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,21 @@ use super::post_conversion_linter::PostConversionLinter;
22
use rusty_common::*;
33
use 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};
77
use 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)]
1021
pub struct DotsLinter {
1122
user_defined_names: HashSet<CaseInsensitiveString>,
@@ -128,9 +139,9 @@ impl NoDotNamesCheck<(&Expression, Position), LintErrorPos> for DotsLinter {
128139

129140
impl 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)]
181193
struct UserDefinedNamesCollector {
182194
user_defined_names: HashSet<CaseInsensitiveString>,
183195
}
184196

197+
no_op_visitor!(UserDefinedNamesCollector: DefType, FunctionDeclaration, SubDeclaration, UserDefinedType);
198+
no_pos_visitor!(UserDefinedNamesCollector);
199+
185200
impl 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
}

rusty_linter/src/pre_linter/main.rs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -118,21 +118,22 @@ impl Visitor<Statement> for MainContext {
118118

119119
impl Visitor<UserDefinedType> for MainContext {
120120
fn visit(&mut self, user_defined_type: &UserDefinedType) -> VisitResult {
121-
self.delegate().visit(user_defined_type)
121+
self.user_defined_types_visitor().visit(user_defined_type)
122122
}
123123
}
124124

125-
impl DelegateVisitor<UserDefinedType> for MainContext {
126-
fn delegate(&mut self) -> impl Visitor<UserDefinedType> {
125+
impl MainContext {
126+
fn user_defined_types_visitor(&mut self) -> impl Visitor<UserDefinedType> + use<'_> {
127127
super::user_defined_type_visitor::UserDefinedTypeVisitor::new(
128128
&mut self.user_defined_types,
129129
self.declaration_pos,
130130
&self.global_constants,
131131
)
132132
}
133-
}
134133

135-
impl MainContext {
134+
// TODO the remaining logic regarding parameters is a different kind of Visitor
135+
// with a possible signature visit(&mut self, element: &T) -> Result<U, LintErrorPos>
136+
136137
fn on_parameters(&self, parameters: &Parameters) -> Result<ResolvedParamTypes, LintErrorPos> {
137138
parameters
138139
.iter()

0 commit comments

Comments
 (0)