Skip to content

Commit 7c563be

Browse files
committed
refactor: Simplify converter for statements
The converter of statements would convert a `Statement` to an `Option<Statement>`. The only case where it would return `None` was the `CONST` statement, as the `CONST` statement is not needed after the linter is done. Keeping the `CONST` in there and ignoring it is not harmful either though, so it's better to do that, at the benefit of having a simplified mapping function.
1 parent 73fc458 commit 7c563be

File tree

8 files changed

+76
-82
lines changed

8 files changed

+76
-82
lines changed

rusty_basic/src/instruction_generator/statement.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,11 @@ impl Visitor<StatementPos> for InstructionGenerator {
2626
Statement::Assignment(left_side, right_side) => {
2727
self.generate_assignment_instructions(left_side, right_side, pos)
2828
}
29-
Statement::Const(_, _) => panic!("Constants should have been reduced by const_reducer"),
29+
Statement::Const(_, _) => {
30+
// The CONST statement does not generate any instructions,
31+
// because the linter has replaced expressions that reference constants
32+
// with their actual value.
33+
}
3034
Statement::SubCall(n, args) => self.generate_sub_call_instructions(n.at_pos(pos), args),
3135
Statement::BuiltInSubCall(n, args) => {
3236
self.generate_built_in_sub_call_instructions(n, args, pos)

rusty_linter/src/converter/common/traits.rs

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1+
use rusty_common::{AtPos, Position, Positioned};
2+
13
use crate::converter::common::Context;
2-
use crate::core::LintErrorPos;
4+
use crate::core::{LintErrorPos, LintPosResult};
35

46
/// Convert from the current type into the target type O.
57
/// By default, O is the same as the current type.
@@ -32,6 +34,24 @@ where
3234
}
3335
}
3436

37+
// Blanket implementation for Positioned in combination with the next trait
38+
39+
impl<T, O> Convertible<Positioned<O>> for Positioned<T>
40+
where
41+
T: ConvertibleIn<Position, O>,
42+
{
43+
fn convert(self, ctx: &mut Context) -> Result<Positioned<O>, LintErrorPos> {
44+
let Self {
45+
element: statement,
46+
pos,
47+
} = self;
48+
statement
49+
.convert_in(ctx, pos)
50+
.map(|converted| converted.at_pos(pos))
51+
.patch_err_pos(&pos)
52+
}
53+
}
54+
3555
/// Convert from the current type into the target type O,
3656
/// using additional information in the value U.
3757
/// By default, O is the same as the current type.

rusty_linter/src/converter/dim_rules/param_rules.rs

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,10 @@
11
use crate::converter::common::Context;
2-
use crate::converter::common::Convertible;
32
use crate::converter::common::ConvertibleIn;
43
use crate::converter::dim_rules::param_type_rules::on_param_type;
54
use crate::converter::dim_rules::validation;
65
use crate::core::LintErrorPos;
7-
use crate::core::LintPosResult;
8-
use rusty_common::AtPos;
96
use rusty_common::Position;
10-
use rusty_parser::{Parameter, ParameterPos};
11-
12-
impl Convertible for ParameterPos {
13-
fn convert(self, ctx: &mut Context) -> Result<Self, LintErrorPos> {
14-
let Self { element, pos } = self;
15-
element
16-
.convert_in(ctx, pos)
17-
.map(|p| p.at_pos(pos))
18-
.patch_err_pos(&pos)
19-
}
20-
}
7+
use rusty_parser::Parameter;
218

229
impl ConvertibleIn<Position> for Parameter {
2310
fn convert_in(self, ctx: &mut Context, pos: Position) -> Result<Self, LintErrorPos> {

rusty_linter/src/converter/statement/const_rules.rs

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ pub fn on_const(
99
ctx: &mut Context,
1010
left_side: NamePos,
1111
right_side: ExpressionPos,
12-
) -> Result<(), LintErrorPos> {
12+
) -> Result<Statement, LintErrorPos> {
1313
const_cannot_clash_with_existing_names(ctx, &left_side)?;
1414
new_const(ctx, left_side, right_side)
1515
}
@@ -38,10 +38,10 @@ fn new_const(
3838
ctx: &mut Context,
3939
left_side: NamePos,
4040
right_side: ExpressionPos,
41-
) -> Result<(), LintErrorPos> {
41+
) -> Result<Statement, LintErrorPos> {
4242
let Positioned {
4343
element: const_name,
44-
..
44+
pos,
4545
} = left_side;
4646
let value_before_casting = ctx.names.resolve_const(&right_side)?;
4747
let value_qualifier = qualifier_of_const_variant(&value_before_casting);
@@ -54,6 +54,12 @@ fn new_const(
5454
};
5555
ctx.names
5656
.names_mut()
57-
.insert_const(const_name.into(), final_value);
58-
Ok(())
57+
.insert_const(const_name.bare_name().clone(), final_value);
58+
59+
// here we could return the simplified resolved value of the constant
60+
// instead of keeping `right_side`.
61+
// However the `CONST` statement gets ignored anyway. It stored the resolved
62+
// value in the context, so all expressions that reference it
63+
// will use it.
64+
Ok(Statement::Const(const_name.at_pos(pos), right_side))
5965
}

rusty_linter/src/converter/statement/main.rs

Lines changed: 21 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -3,102 +3,71 @@ use crate::converter::common::Convertible;
33
use crate::converter::common::ConvertibleIn;
44
use crate::converter::common::{DimContext, ExprContext};
55
use crate::converter::statement::{assignment, const_rules};
6+
use crate::core::NameContext;
67
use crate::core::{LintError, LintErrorPos};
7-
use crate::core::{LintPosResult, NameContext};
88
use rusty_common::*;
9-
use rusty_parser::{ExitObject, Statement, StatementPos, Statements};
9+
use rusty_parser::{ExitObject, Statement};
1010

11-
impl Convertible<Option<Self>> for StatementPos {
12-
fn convert(self, ctx: &mut Context) -> Result<Option<Self>, LintErrorPos> {
13-
let Self {
14-
element: statement,
15-
pos,
16-
} = self;
17-
statement
18-
.convert_in(ctx, pos)
19-
.map(|opt_statement| opt_statement.map(|s| s.at_pos(pos)))
20-
.patch_err_pos(&pos)
21-
}
22-
}
23-
24-
impl ConvertibleIn<Position, Option<Self>> for Statement {
25-
fn convert_in(self, ctx: &mut Context, pos: Position) -> Result<Option<Self>, LintErrorPos> {
11+
impl ConvertibleIn<Position> for Statement {
12+
fn convert_in(self, ctx: &mut Context, pos: Position) -> Result<Self, LintErrorPos> {
2613
match self {
27-
Self::Assignment(n, e) => assignment::on_assignment(n, e, ctx, pos).map(Some),
14+
Self::Assignment(n, e) => assignment::on_assignment(n, e, ctx, pos),
2815
// CONST is mapped to None and is filtered out
29-
Self::Const(n, e) => const_rules::on_const(ctx, n, e).map(|_| None),
30-
Self::SubCall(n, args) => ctx.sub_call(n, args).map(Some),
16+
Self::Const(n, e) => const_rules::on_const(ctx, n, e),
17+
Self::SubCall(n, args) => ctx.sub_call(n, args),
3118
Self::BuiltInSubCall(built_in_sub, args) => {
3219
let converted_args = args.convert_in(ctx, ExprContext::Argument)?;
33-
Ok(Self::BuiltInSubCall(built_in_sub, converted_args)).map(Some)
20+
Ok(Self::BuiltInSubCall(built_in_sub, converted_args))
3421
}
35-
Self::IfBlock(i) => i.convert(ctx).map(Statement::IfBlock).map(Some),
36-
Self::SelectCase(s) => s.convert(ctx).map(Statement::SelectCase).map(Some),
37-
Self::ForLoop(f) => f.convert(ctx).map(Statement::ForLoop).map(Some),
38-
Self::While(c) => c.convert(ctx).map(Statement::While).map(Some),
39-
Self::DoLoop(do_loop) => do_loop.convert(ctx).map(Statement::DoLoop).map(Some),
22+
Self::IfBlock(i) => i.convert(ctx).map(Statement::IfBlock),
23+
Self::SelectCase(s) => s.convert(ctx).map(Statement::SelectCase),
24+
Self::ForLoop(f) => f.convert(ctx).map(Statement::ForLoop),
25+
Self::While(c) => c.convert(ctx).map(Statement::While),
26+
Self::DoLoop(do_loop) => do_loop.convert(ctx).map(Statement::DoLoop),
4027
Self::Return(opt_label) => {
4128
if opt_label.is_some() && ctx.is_in_subprogram() {
4229
// cannot have RETURN with explicit label inside subprogram
4330
Err(LintError::IllegalInSubFunction.at_no_pos())
4431
} else {
45-
Ok(Self::Return(opt_label)).map(Some)
32+
Ok(Self::Return(opt_label))
4633
}
4734
}
4835
Self::Resume(resume_option) => {
4936
if ctx.is_in_subprogram() {
5037
Err(LintError::IllegalInSubFunction.at_no_pos())
5138
} else {
52-
Ok(Self::Resume(resume_option)).map(Some)
39+
Ok(Self::Resume(resume_option))
5340
}
5441
}
5542
Self::Exit(exit_object) => match ctx.names.get_name_context() {
5643
NameContext::Global => Err(LintError::IllegalOutsideSubFunction.at_no_pos()),
5744
NameContext::Sub => {
5845
if exit_object == ExitObject::Sub {
59-
Ok(Self::Exit(exit_object)).map(Some)
46+
Ok(Self::Exit(exit_object))
6047
} else {
6148
Err(LintError::IllegalInSubFunction.at_no_pos())
6249
}
6350
}
6451
NameContext::Function => {
6552
if exit_object == ExitObject::Function {
66-
Ok(Self::Exit(exit_object)).map(Some)
53+
Ok(Self::Exit(exit_object))
6754
} else {
6855
Err(LintError::IllegalInSubFunction.at_no_pos())
6956
}
7057
}
7158
},
72-
Self::Dim(dim_list) => dim_list
73-
.convert_in_default(ctx)
74-
.map(Statement::Dim)
75-
.map(Some),
59+
Self::Dim(dim_list) => dim_list.convert_in_default(ctx).map(Statement::Dim),
7660
Self::Redim(dim_list) => dim_list
7761
.convert_in(ctx, DimContext::Redim)
78-
.map(Statement::Redim)
79-
.map(Some),
80-
Self::Print(print) => print.convert(ctx).map(Statement::Print).map(Some),
62+
.map(Statement::Redim),
63+
Self::Print(print) => print.convert(ctx).map(Statement::Print),
8164
Self::OnError(_)
8265
| Self::Label(_)
8366
| Self::GoTo(_)
8467
| Self::GoSub(_)
8568
| Self::Comment(_)
8669
| Self::End
87-
| Self::System => Ok(self).map(Some),
70+
| Self::System => Ok(self),
8871
}
8972
}
9073
}
91-
92-
impl Convertible for Statements {
93-
fn convert(self, ctx: &mut Context) -> Result<Self, LintErrorPos> {
94-
self.into_iter()
95-
.map(|s| s.convert(ctx))
96-
.map(|res| match res {
97-
Ok(Some(s)) => Some(Ok(s)),
98-
Err(e) => Some(Err(e)),
99-
Ok(None) => None,
100-
})
101-
.flat_map(|opt| opt.into_iter())
102-
.collect()
103-
}
104-
}

rusty_linter/src/post_linter/expression_reducer.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,12 @@ pub trait ExpressionReducer {
110110
Statement::Assignment(reduced_left, reduced_right)
111111
})
112112
}
113-
Statement::Const(left, _) => panic!("Linter should have removed Const {:?}", left),
113+
Statement::Const(left, right) => {
114+
// The converter is smart enough to replace Expressions that reference
115+
// constants with their actual value, so the `CONST` statement isn't used
116+
// any further.
117+
Ok(Statement::Const(left, right))
118+
}
114119
Statement::SubCall(b, e) => self
115120
.visit_sub_call(b, e)
116121
.map(|(reduced_name, reduced_expr)| Statement::SubCall(reduced_name, reduced_expr)),

rusty_linter/src/post_linter/post_conversion_linter.rs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -65,9 +65,6 @@ pub trait PostConversionLinter {
6565
fn visit_statement(&mut self, s: &Statement) -> Result<(), LintErrorPos> {
6666
match s {
6767
Statement::Assignment(left, right) => self.visit_assignment(left, right),
68-
Statement::Const(left, _) => {
69-
panic!("Linter should have removed Const statements {:?}", left)
70-
}
7168
Statement::SubCall(b, e) => self.visit_sub_call(b, e),
7269
Statement::BuiltInSubCall(b, e) => self.visit_built_in_sub_call(b, e),
7370
Statement::IfBlock(i) => self.visit_if_block(i),
@@ -85,7 +82,7 @@ pub trait PostConversionLinter {
8582
Statement::Resume(resume_option) => self.visit_resume(resume_option),
8683
Statement::Return(opt_label) => self.visit_return(opt_label.as_ref()),
8784
Statement::Exit(exit_object) => self.visit_exit(*exit_object),
88-
Statement::End | Statement::System => Ok(()),
85+
Statement::Const(_, _) | Statement::End | Statement::System => Ok(()),
8986
}
9087
}
9188

rusty_linter/src/tests/constant.rs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,7 @@ use crate::assert_linter_ok_global_statements;
33
use crate::core::LintError;
44
use crate::tests::test_utils::linter_ok;
55
use rusty_common::*;
6-
use rusty_parser::{
7-
BareName, BuiltInStyle, Expression, GlobalStatement, ParamType, Parameter, Print, Statement,
8-
SubImplementation, TypeQualifier,
9-
};
6+
use rusty_parser::*;
107

118
#[test]
129
fn function_call_not_allowed() {
@@ -109,6 +106,10 @@ fn test_constant_definition_and_usage_in_print() {
109106
"#;
110107
assert_linter_ok_global_statements!(
111108
program,
109+
Statement::Const(
110+
Name::from("X").at_rc(2, 11),
111+
Expression::StringLiteral("hello".to_owned()).at_rc(2, 15)
112+
),
112113
Statement::Print(Print::one(
113114
Expression::StringLiteral("hello".to_owned()).at_rc(3, 11)
114115
))
@@ -127,6 +128,11 @@ fn test_constant_definition_and_usage_in_sub_call_arg() {
127128
assert_eq!(
128129
linter_ok(program),
129130
vec![
131+
GlobalStatement::Statement(Statement::Const(
132+
Name::from("X").at_rc(2, 11),
133+
Expression::StringLiteral("hello".to_owned()).at_rc(2, 15)
134+
),)
135+
.at_rc(2, 5),
130136
GlobalStatement::Statement(Statement::SubCall(
131137
"MySub".into(),
132138
vec![Expression::StringLiteral("hello".to_owned()).at_rc(3, 11)]

0 commit comments

Comments
 (0)