Skip to content

Commit dae42c0

Browse files
committed
refactor: Introducing ref_to_value_visitor
`ref_to_value_visitor` visits a reference and returns a new (owned) value. Adapted the parameter resolution part of `pre_linter/main` to use the `RefToValueVisitor` trait, resulting in less boilerplate code around collections and `Position`.
1 parent 7bd3ce0 commit dae42c0

4 files changed

Lines changed: 83 additions & 39 deletions

File tree

rusty_linter/src/converter/dim_rules/validation.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use crate::names::ManyNamesTrait;
66
use rusty_common::{AtPos, Position, Positioned};
77
use rusty_parser::{DimVar, Parameter, TypedName, VarType};
88

9-
pub fn validate<T>(
9+
pub fn validate<T: VarType>(
1010
var_name: &TypedName<T>,
1111
ctx: &Context,
1212
pos: Position,
@@ -90,7 +90,7 @@ impl CannotClashWithFunctions for Parameter {
9090
}
9191
}
9292

93-
fn user_defined_type_must_exist<T>(
93+
fn user_defined_type_must_exist<T: VarType>(
9494
var_name: &TypedName<T>,
9595
ctx: &Context,
9696
) -> Result<(), LintErrorPos>

rusty_linter/src/core/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ mod const_value_resolver;
33
mod error;
44
mod qb_casting;
55
mod qualify_variant;
6+
mod ref_to_value_visitor;
67
mod string_length;
78
mod traits;
89
mod type_resolver;
@@ -15,6 +16,7 @@ pub use self::const_value_resolver::*;
1516
pub use self::error::*;
1617
pub use self::qb_casting::*;
1718
pub use self::qualify_variant::*;
19+
pub use self::ref_to_value_visitor::*;
1820
pub use self::string_length::*;
1921
pub use self::traits::*;
2022
pub use self::type_resolver::*;
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
use rusty_common::{AtPos, Positioned};
2+
3+
/// Visits an element by ref and returns a new value.
4+
pub trait RefToValueVisitor<I, O, E> {
5+
fn ref_to_value_visit(&mut self, element: &I) -> Result<O, E>;
6+
}
7+
8+
// Blanket implementation for Vec
9+
10+
impl<P, I, O, E> RefToValueVisitor<Vec<I>, Vec<O>, E> for P
11+
where
12+
P: RefToValueVisitor<I, O, E>,
13+
{
14+
fn ref_to_value_visit(&mut self, element: &Vec<I>) -> Result<Vec<O>, E> {
15+
element.iter().map(|p| self.ref_to_value_visit(p)).collect()
16+
}
17+
}
18+
19+
// Blanket implementation for Positioned
20+
21+
impl<P, I, O, E> RefToValueVisitor<Positioned<I>, Positioned<O>, Positioned<E>> for P
22+
where
23+
P: RefToValueVisitor<I, O, E>,
24+
{
25+
fn ref_to_value_visit(
26+
&mut self,
27+
element: &Positioned<I>,
28+
) -> Result<Positioned<O>, Positioned<E>> {
29+
let Positioned { element, pos } = element;
30+
match self.ref_to_value_visit(element) {
31+
Ok(ok) => Ok(ok.at_pos(*pos)),
32+
Err(err) => Err(err.at_pos(*pos)),
33+
}
34+
}
35+
}

rusty_linter/src/pre_linter/main.rs

Lines changed: 44 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ impl Visitor<FunctionDeclaration> for MainContext {
5151
name: Positioned { element: name, .. },
5252
parameters: params,
5353
} = f;
54-
let param_types: ResolvedParamTypes = self.on_parameters(params)?;
54+
let param_types: ResolvedParamTypes = self.resolve_parameters(params)?;
5555
let bare_name = name.bare_name();
5656
let q = name.qualify(&self.resolver);
5757
let signature = Signature::new_function(q, param_types);
@@ -67,7 +67,7 @@ impl Visitor<FunctionImplementation> for MainContext {
6767
params,
6868
..
6969
} = f;
70-
let param_types: ResolvedParamTypes = self.on_parameters(params)?;
70+
let param_types: ResolvedParamTypes = self.resolve_parameters(params)?;
7171
let bare_name = name.bare_name();
7272
let q = name.qualify(&self.resolver);
7373
let signature = Signature::new_function(q, param_types);
@@ -84,7 +84,7 @@ impl Visitor<SubDeclaration> for MainContext {
8484
},
8585
parameters: params,
8686
} = s;
87-
let param_types: ResolvedParamTypes = self.on_parameters(params)?;
87+
let param_types: ResolvedParamTypes = self.resolve_parameters(params)?;
8888
let signature = Signature::new_sub(param_types);
8989
self.subs
9090
.add_declaration(bare_name.clone(), signature.at_pos(self.declaration_pos))
@@ -100,7 +100,7 @@ impl Visitor<SubImplementation> for MainContext {
100100
params,
101101
..
102102
} = s;
103-
let param_types: ResolvedParamTypes = self.on_parameters(params)?;
103+
let param_types: ResolvedParamTypes = self.resolve_parameters(params)?;
104104
let signature = Signature::new_sub(param_types);
105105
self.subs
106106
.add_implementation(bare_name.clone(), signature.at_pos(self.declaration_pos))
@@ -131,33 +131,36 @@ impl MainContext {
131131
)
132132
}
133133

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-
137-
fn on_parameters(&self, parameters: &Parameters) -> Result<ResolvedParamTypes, LintErrorPos> {
138-
parameters
139-
.iter()
140-
.map(|p| self.on_parameter_pos(p))
141-
.collect()
134+
fn resolve_parameters(
135+
&mut self,
136+
parameters: &Parameters,
137+
) -> Result<ResolvedParamTypes, LintErrorPos> {
138+
self.ref_to_value_visit(parameters).map(|v| v.no_pos())
142139
}
143140

144-
fn on_parameter_pos(
145-
&self,
146-
parameter_pos: &ParameterPos,
147-
) -> Result<ResolvedParamType, LintErrorPos> {
148-
self.on_parameter(&parameter_pos.element)
149-
.with_err_at(parameter_pos)
141+
fn post_visit_functions(&self) -> Result<(), LintErrorPos> {
142+
self.functions.ensure_declarations_are_implemented()?;
143+
self.functions
144+
.ensure_does_not_clash_with_built_in(|name| BuiltInFunction::try_parse(name).is_some())
150145
}
151146

152-
fn on_parameter(&self, parameter: &Parameter) -> Result<ResolvedParamType, LintError> {
153-
self.resolve_param_type(parameter.bare_name(), parameter.var_type())
147+
fn post_visit_subs(&self) -> Result<(), LintErrorPos> {
148+
// not checking if declarations are present, because in MONEY.BAS there
149+
// are two SUBs declared but not implemented (and not called either)
150+
self.subs.ensure_does_not_clash_with_built_in(|name| {
151+
BuiltInSub::parse_non_keyword_sub(name.as_ref()).is_some()
152+
})
154153
}
154+
}
155+
156+
impl<T> RefToValueVisitor<T, ResolvedParamType, LintError> for MainContext
157+
where
158+
T: AsRef<BareName> + AsRef<ParamType>,
159+
{
160+
fn ref_to_value_visit(&mut self, element: &T) -> Result<ResolvedParamType, LintError> {
161+
let bare_name: &BareName = element.as_ref();
162+
let param_type: &ParamType = element.as_ref();
155163

156-
fn resolve_param_type(
157-
&self,
158-
bare_name: &BareName,
159-
param_type: &ParamType,
160-
) -> Result<ResolvedParamType, LintError> {
161164
match param_type {
162165
ParamType::Bare => {
163166
let q = bare_name.qualify(&self.resolver);
@@ -175,24 +178,28 @@ impl MainContext {
175178
}
176179
}
177180
ParamType::Array(element_type) => {
178-
let element_param_type =
179-
self.resolve_param_type(bare_name, element_type.as_ref())?;
181+
let temp = RefParamName(bare_name, element_type);
182+
let element_param_type = self.ref_to_value_visit(&temp)?;
180183
Ok(ResolvedParamType::Array(Box::new(element_param_type)))
181184
}
182185
}
183186
}
187+
}
184188

185-
fn post_visit_functions(&self) -> Result<(), LintErrorPos> {
186-
self.functions.ensure_declarations_are_implemented()?;
187-
self.functions
188-
.ensure_does_not_clash_with_built_in(|name| BuiltInFunction::try_parse(name).is_some())
189+
/// This is the same as [Parameter],
190+
/// but the memebers are references.
191+
/// It's needed due to the recursive implementation of `RefToValueVisitor`
192+
/// and the recursive (`Box`) implementation of `ParamType::Array`.
193+
struct RefParamName<'a>(&'a BareName, &'a ParamType);
194+
195+
impl<'a> AsRef<BareName> for RefParamName<'a> {
196+
fn as_ref(&self) -> &BareName {
197+
self.0
189198
}
199+
}
190200

191-
fn post_visit_subs(&self) -> Result<(), LintErrorPos> {
192-
// not checking if declarations are present, because in MONEY.BAS there
193-
// are two SUBs declared but not implemented (and not called either)
194-
self.subs.ensure_does_not_clash_with_built_in(|name| {
195-
BuiltInSub::parse_non_keyword_sub(name.as_ref()).is_some()
196-
})
201+
impl<'a> AsRef<ParamType> for RefParamName<'a> {
202+
fn as_ref(&self) -> &ParamType {
203+
self.1
197204
}
198205
}

0 commit comments

Comments
 (0)