Skip to content

Commit 32428fb

Browse files
committed
refactor: Use VariableInfo from linter Context in generator
The `VariableInfo` in `Expression` is not really used in the parser, except for its `expression_type` field. As a first step of removing `VariableInfo` from the `Expression` in the parser, we're exposing the Linter's `Context` (which has this information) to the Instruction Generator. There, the Instruction Generator can get the necessary information from the Linter's Context, instead of the `Expression`.
1 parent a821a08 commit 32428fb

13 files changed

Lines changed: 155 additions & 70 deletions

File tree

rusty_basic/src/bin/rusty_basic.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
use rusty_basic::instruction_generator::generate_instructions;
1+
use rusty_basic::instruction_generator::{generate_instructions, unwrap_linter_context};
22
use rusty_basic::interpreter::{new_default_interpreter, InterpreterTrait};
3-
use rusty_linter::{lint, HasUserDefinedTypes};
3+
use rusty_linter::{lint, Context};
44
use rusty_parser::parse_main_file;
55
use rusty_parser::Program;
66
use std::env;
@@ -33,10 +33,10 @@ fn on_parsed(program: Program, run_options: RunOptions) {
3333
}
3434
}
3535

36-
fn on_linted(program: Program, linter_context: impl HasUserDefinedTypes, run_options: RunOptions) {
37-
// TODO propagate linter_context to instruction_generator, so that it won't read VariableInfo from Expression
38-
let instruction_generator_result = generate_instructions(program);
39-
let mut interpreter = new_default_interpreter(linter_context);
36+
fn on_linted(program: Program, linter_context: Context, run_options: RunOptions) {
37+
let (linter_names, user_defined_types) = unwrap_linter_context(linter_context);
38+
let instruction_generator_result = generate_instructions(program, linter_names);
39+
let mut interpreter = new_default_interpreter(user_defined_types);
4040
run_options.set_current_dir_if_apache();
4141
match interpreter.interpret(instruction_generator_result) {
4242
Ok(_) => (),

rusty_basic/src/instruction_generator/expression.rs

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -109,20 +109,28 @@ impl InstructionGenerator {
109109
let Positioned { element: expr, pos } = expr_pos;
110110

111111
match expr {
112-
Expression::Variable(var_name, VariableInfo { shared, .. }) => {
112+
Expression::Variable(var_name, ..) => {
113+
let linter_var_info: &VariableInfo = self
114+
.linter_names
115+
.get_resolved_variable_info(&self.current_subprogram, &var_name);
116+
113117
self.push(
114118
Instruction::VarPathName(RootPath {
115119
name: var_name,
116-
shared,
120+
shared: linter_var_info.shared,
117121
}),
118122
pos,
119123
);
120124
}
121-
Expression::ArrayElement(array_name, indices, VariableInfo { shared, .. }) => {
125+
Expression::ArrayElement(array_name, indices, ..) => {
126+
let linter_var_info: &VariableInfo = self
127+
.linter_names
128+
.get_resolved_variable_info(&self.current_subprogram, &array_name);
129+
122130
self.push(
123131
Instruction::VarPathName(RootPath {
124132
name: array_name,
125-
shared,
133+
shared: linter_var_info.shared,
126134
}),
127135
pos,
128136
);

rusty_basic/src/instruction_generator/instruction_generator.rs

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,25 +4,31 @@ use crate::instruction_generator::subprogram_info::{
44
};
55
use crate::RuntimeError;
66
use rusty_common::{AtPos, CaseInsensitiveString, Position, Positioned};
7-
use rusty_linter::SubprogramName;
8-
use rusty_parser::BuiltInFunction;
7+
use rusty_linter::{Context, Names, SubprogramName};
98
use rusty_parser::BuiltInSub;
109
use rusty_parser::{
1110
BareName, DimVar, Expression, ExpressionPos, ExpressionType, FileHandle,
1211
FunctionImplementation, GlobalStatement, HasExpressionType, Name, Parameter, Program,
1312
QualifiedName, Statement, Statements, SubImplementation, TypeQualifier,
1413
};
14+
use rusty_parser::{BuiltInFunction, UserDefinedTypes};
1515
use rusty_variant::Variant;
1616

17+
pub fn unwrap_linter_context(linter_context: Context) -> (Names, UserDefinedTypes) {
18+
let (pre_linter_result, _, linter_names) = linter_context.unwrap();
19+
let (_, _, user_defined_types) = pre_linter_result.unwrap();
20+
(linter_names, user_defined_types)
21+
}
22+
1723
/// Generates instructions for the given program.
18-
pub fn generate_instructions(program: Program) -> InstructionGeneratorResult {
24+
pub fn generate_instructions(program: Program, linter_names: Names) -> InstructionGeneratorResult {
1925
// pass 1: collect function/sub names -> parameter names, in order to use them in function/sub calls
2026
// the parameter names and types are needed
2127
let mut subprogram_info_collector = SubprogramInfoCollector::default();
2228
subprogram_info_collector.visit(&program);
2329
let subprogram_parameters: SubprogramInfoRepository = subprogram_info_collector.into();
2430
// pass 2 generate with labels still unresolved
25-
let mut generator = InstructionGenerator::new(subprogram_parameters);
31+
let mut generator = InstructionGenerator::new(subprogram_parameters, linter_names);
2632
generator.generate_unresolved(program);
2733
let InstructionGenerator {
2834
instructions,
@@ -260,15 +266,17 @@ pub struct InstructionGenerator {
260266
pub statement_addresses: Vec<usize>,
261267
pub subprogram_info_repository: SubprogramInfoRepository,
262268
pub current_subprogram: Option<SubprogramName>,
269+
pub linter_names: Names,
263270
}
264271

265272
impl InstructionGenerator {
266-
fn new(subprogram_info_repository: SubprogramInfoRepository) -> Self {
273+
fn new(subprogram_info_repository: SubprogramInfoRepository, linter_names: Names) -> Self {
267274
Self {
268275
instructions: vec![],
269276
statement_addresses: vec![],
270277
subprogram_info_repository,
271278
current_subprogram: None,
279+
linter_names,
272280
}
273281
}
274282

rusty_basic/src/instruction_generator/test_utils.rs

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,20 @@
11
use crate::instruction_generator::{
2-
generate_instructions, Instruction, InstructionGeneratorResult, InstructionPos,
2+
generate_instructions, unwrap_linter_context, Instruction, InstructionGeneratorResult,
3+
InstructionPos,
34
};
45
use rusty_common::NoPosContainer;
5-
use rusty_linter::{lint, HasUserDefinedTypes};
6-
use rusty_parser::parse;
6+
use rusty_linter::lint;
7+
use rusty_parser::{parse, UserDefinedTypes};
78

89
pub fn generate_instructions_str_with_types(
910
input: &str,
10-
) -> (InstructionGeneratorResult, impl HasUserDefinedTypes) {
11+
) -> (InstructionGeneratorResult, UserDefinedTypes) {
1112
let program = parse(input);
12-
let (linted_program, user_defined_types_holder) = lint(program).expect("Linter should succeed");
13+
let (linted_program, linter_context) = lint(program).expect("Linter should succeed");
14+
let (linter_names, user_defined_types) = unwrap_linter_context(linter_context);
1315
(
14-
generate_instructions(linted_program),
15-
user_defined_types_holder,
16+
generate_instructions(linted_program, linter_names),
17+
user_defined_types,
1618
)
1719
}
1820

rusty_basic/src/interpreter/interpreter.rs

Lines changed: 14 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,7 @@ use rusty_parser::UserDefinedTypes;
2424
use rusty_variant::Variant;
2525
use std::collections::VecDeque;
2626

27-
pub struct Interpreter<
28-
TStdlib: Stdlib,
29-
TStdIn: Input,
30-
TStdOut: Printer,
31-
TLpt1: Printer,
32-
U: HasUserDefinedTypes,
33-
> {
27+
pub struct Interpreter<TStdlib: Stdlib, TStdIn: Input, TStdOut: Printer, TLpt1: Printer> {
3428
/// Offers system calls
3529
stdlib: TStdlib,
3630

@@ -49,7 +43,7 @@ pub struct Interpreter<
4943
screen: Box<dyn Screen>,
5044

5145
/// Holds the definition of user defined types
52-
linter_context: U,
46+
user_defined_types: UserDefinedTypes,
5347

5448
/// Contains variables and constants, collects function/sub arguments.
5549
context: Context,
@@ -87,16 +81,16 @@ pub struct Interpreter<
8781
def_seg: Option<usize>,
8882
}
8983

90-
impl<TStdlib: Stdlib, TStdIn: Input, TStdOut: Printer, TLpt1: Printer, U: HasUserDefinedTypes>
91-
HasUserDefinedTypes for Interpreter<TStdlib, TStdIn, TStdOut, TLpt1, U>
84+
impl<TStdlib: Stdlib, TStdIn: Input, TStdOut: Printer, TLpt1: Printer> HasUserDefinedTypes
85+
for Interpreter<TStdlib, TStdIn, TStdOut, TLpt1>
9286
{
9387
fn user_defined_types(&self) -> &UserDefinedTypes {
94-
self.linter_context.user_defined_types()
88+
&self.user_defined_types
9589
}
9690
}
9791

98-
impl<TStdlib: Stdlib, TStdIn: Input, TStdOut: Printer, TLpt1: Printer, U: HasUserDefinedTypes>
99-
InterpreterTrait for Interpreter<TStdlib, TStdIn, TStdOut, TLpt1, U>
92+
impl<TStdlib: Stdlib, TStdIn: Input, TStdOut: Printer, TLpt1: Printer> InterpreterTrait
93+
for Interpreter<TStdlib, TStdIn, TStdOut, TLpt1>
10094
{
10195
type TStdlib = TStdlib;
10296
type TStdIn = TStdIn;
@@ -237,33 +231,32 @@ impl<TStdlib: Stdlib, TStdIn: Input, TStdOut: Printer, TLpt1: Printer, U: HasUse
237231
}
238232
}
239233

240-
pub type DefaultInterpreter<U> = Interpreter<
234+
pub type DefaultInterpreter = Interpreter<
241235
DefaultStdlib,
242236
ReadInputSource<std::io::Stdin>,
243237
WritePrinter<std::io::Stdout>,
244238
WritePrinter<Lpt1Write>,
245-
U,
246239
>;
247240

248-
pub fn new_default_interpreter<U: HasUserDefinedTypes>(linter_context: U) -> DefaultInterpreter<U> {
241+
pub fn new_default_interpreter(user_defined_types: UserDefinedTypes) -> DefaultInterpreter {
249242
let stdlib = DefaultStdlib;
250243
let stdin = ReadInputSource::new(std::io::stdin());
251244
let stdout = WritePrinter::new(std::io::stdout());
252245
let lpt1 = WritePrinter::new(Lpt1Write {});
253246
let screen = CrossTermScreen::default();
254-
Interpreter::new(stdlib, stdin, stdout, lpt1, screen, linter_context)
247+
Interpreter::new(stdlib, stdin, stdout, lpt1, screen, user_defined_types)
255248
}
256249

257-
impl<TStdlib: Stdlib, TStdIn: Input, TStdOut: Printer, TLpt1: Printer, U: HasUserDefinedTypes>
258-
Interpreter<TStdlib, TStdIn, TStdOut, TLpt1, U>
250+
impl<TStdlib: Stdlib, TStdIn: Input, TStdOut: Printer, TLpt1: Printer>
251+
Interpreter<TStdlib, TStdIn, TStdOut, TLpt1>
259252
{
260253
pub fn new<TScreen: Screen + 'static>(
261254
stdlib: TStdlib,
262255
stdin: TStdIn,
263256
stdout: TStdOut,
264257
lpt1: TLpt1,
265258
screen: TScreen,
266-
linter_context: U,
259+
user_defined_types: UserDefinedTypes,
267260
) -> Self {
268261
Self {
269262
stdlib,
@@ -277,7 +270,7 @@ impl<TStdlib: Stdlib, TStdIn: Input, TStdOut: Printer, TLpt1: Printer, U: HasUse
277270
register_stack: vec![Registers::new()],
278271
stacktrace: vec![],
279272
file_manager: FileManager::new(),
280-
linter_context,
273+
user_defined_types,
281274
var_path_stack: VecDeque::new(),
282275
by_ref_stack: VecDeque::new(),
283276
function_result: None,

rusty_basic/src/interpreter/test_utils.rs

Lines changed: 24 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
11
use crate::instruction_generator::test_utils::generate_instructions_str_with_types;
2-
use crate::instruction_generator::{generate_instructions, InstructionGeneratorResult};
2+
use crate::instruction_generator::{
3+
generate_instructions, unwrap_linter_context, InstructionGeneratorResult,
4+
};
35
use crate::interpreter::interpreter::Interpreter;
46
use crate::interpreter::interpreter_trait::InterpreterTrait;
57
use crate::interpreter::read_input::ReadInputSource;
68
use crate::interpreter::screen::{CrossTermScreen, HeadlessScreen};
79
use crate::interpreter::write_printer::WritePrinter;
810
use crate::interpreter::Stdlib;
911
use crate::RuntimeErrorPos;
10-
use rusty_linter;
11-
use rusty_linter::{lint, HasUserDefinedTypes};
12-
use rusty_parser::parse_main_file;
12+
use rusty_linter::lint;
13+
use rusty_parser::{parse_main_file, UserDefinedTypes};
1314
use std::collections::HashMap;
1415
use std::fs::File;
1516
use std::io::Read;
@@ -30,15 +31,15 @@ impl<S> MockInterpreterTrait for S where
3031
{
3132
}
3233

33-
fn mock_interpreter_for_user_defined_types<U: HasUserDefinedTypes>(
34-
user_defined_types_holder: U,
34+
fn mock_interpreter_for_user_defined_types(
35+
user_defined_types: UserDefinedTypes,
3536
) -> impl MockInterpreterTrait {
3637
let stdlib = MockStdlib::default();
37-
mock_interpreter_for_user_defined_types_stdlib(user_defined_types_holder, stdlib)
38+
mock_interpreter_for_user_defined_types_stdlib(user_defined_types, stdlib)
3839
}
3940

40-
fn mock_interpreter_for_user_defined_types_stdlib<U: HasUserDefinedTypes>(
41-
user_defined_types_holder: U,
41+
fn mock_interpreter_for_user_defined_types_stdlib(
42+
user_defined_types: UserDefinedTypes,
4243
stdlib: MockStdlib,
4344
) -> impl MockInterpreterTrait {
4445
let stdin = ReadInputSource::new(MockStdin { stdin: vec![] });
@@ -54,7 +55,7 @@ fn mock_interpreter_for_user_defined_types_stdlib<U: HasUserDefinedTypes>(
5455
stdout,
5556
lpt1,
5657
HeadlessScreen {},
57-
user_defined_types_holder,
58+
user_defined_types,
5859
)
5960
} else {
6061
Interpreter::new(
@@ -63,20 +64,20 @@ fn mock_interpreter_for_user_defined_types_stdlib<U: HasUserDefinedTypes>(
6364
stdout,
6465
lpt1,
6566
CrossTermScreen::default(),
66-
user_defined_types_holder,
67+
user_defined_types,
6768
)
6869
}
6970
}
7071

7172
pub fn mock_interpreter_for_input(
7273
input: &str,
7374
) -> (InstructionGeneratorResult, impl MockInterpreterTrait) {
74-
let (instruction_generator_result, user_defined_types_holder) =
75+
let (instruction_generator_result, user_defined_types) =
7576
generate_instructions_str_with_types(input);
7677
// println!("{:#?}", instruction_generator_result.instructions);
7778
(
7879
instruction_generator_result,
79-
mock_interpreter_for_user_defined_types(user_defined_types_holder),
80+
mock_interpreter_for_user_defined_types(user_defined_types),
8081
)
8182
}
8283

@@ -96,12 +97,12 @@ pub fn interpret_err(input: &str) -> RuntimeErrorPos {
9697
}
9798

9899
pub fn interpret_with_raw_input(input: &str, raw_input: &str) -> impl MockInterpreterTrait {
99-
let (instruction_generator_result, user_defined_types_holder) =
100+
let (instruction_generator_result, user_defined_types) =
100101
generate_instructions_str_with_types(input);
101102
// for i in instructions.iter() {
102103
// println!("{:?}", i.as_ref());
103104
// }
104-
let mut interpreter = mock_interpreter_for_user_defined_types(user_defined_types_holder);
105+
let mut interpreter = mock_interpreter_for_user_defined_types(user_defined_types);
105106
if !raw_input.is_empty() {
106107
interpreter.stdin().add_next_input(raw_input);
107108
}
@@ -112,11 +113,11 @@ pub fn interpret_with_raw_input(input: &str, raw_input: &str) -> impl MockInterp
112113
}
113114

114115
pub fn interpret_with_env(input: &str, stdlib: MockStdlib) -> impl MockInterpreterTrait {
115-
let (instruction_generator_result, user_defined_types_holder) =
116+
let (instruction_generator_result, user_defined_types) =
116117
generate_instructions_str_with_types(input);
117118
// println!("{:#?}", instructions);
118119
let mut interpreter =
119-
mock_interpreter_for_user_defined_types_stdlib(user_defined_types_holder, stdlib);
120+
mock_interpreter_for_user_defined_types_stdlib(user_defined_types, stdlib);
120121
interpreter
121122
.interpret(instruction_generator_result)
122123
.map(|_| interpreter)
@@ -127,8 +128,9 @@ pub fn interpret_file(filename: &str) -> Result<impl MockInterpreterTrait, Runti
127128
let file_path = format!("../fixtures/{}", filename);
128129
let f = File::open(file_path).expect("Could not read bas file");
129130
let program = parse_main_file(f).unwrap();
130-
let (linted_program, user_defined_types) = lint(program).unwrap();
131-
let instruction_generator_result = generate_instructions(linted_program);
131+
let (linted_program, linter_context) = lint(program).unwrap();
132+
let (linter_names, user_defined_types) = unwrap_linter_context(linter_context);
133+
let instruction_generator_result = generate_instructions(linted_program, linter_names);
132134
let mut interpreter = mock_interpreter_for_user_defined_types(user_defined_types);
133135
interpreter
134136
.interpret(instruction_generator_result)
@@ -142,8 +144,9 @@ pub fn interpret_file_with_raw_input(
142144
let file_path = format!("../fixtures/{}", filename);
143145
let f = File::open(file_path).expect("Could not read bas file");
144146
let program = parse_main_file(f).unwrap();
145-
let (linted_program, user_defined_types) = lint(program).unwrap();
146-
let instruction_generator_result = generate_instructions(linted_program);
147+
let (linted_program, linter_context) = lint(program).unwrap();
148+
let (linter_names, user_defined_types) = unwrap_linter_context(linter_context);
149+
let instruction_generator_result = generate_instructions(linted_program, linter_names);
147150
let mut interpreter = mock_interpreter_for_user_defined_types(user_defined_types);
148151
if !raw_input.is_empty() {
149152
interpreter.stdin().add_next_input(raw_input);

rusty_linter/src/converter/common/context.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,10 @@ impl Context {
4545
}
4646
}
4747

48+
pub fn unwrap(self) -> (PreLinterResult, TypeResolverImpl, Names) {
49+
(self.pre_linter_result, self.resolver, self.names)
50+
}
51+
4852
pub fn is_in_subprogram(&self) -> bool {
4953
self.names.is_in_subprogram()
5054
}

rusty_linter/src/converter/expr_rules/variable.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,16 @@ impl VarResolve for AssignToFunction {
206206
if ctx.names.is_in_function(name.bare_name()) {
207207
let converted_name = try_qualify(name, function_qualifier).with_err_at(&extra.pos)?;
208208
let expr_type = ExpressionType::BuiltIn(function_qualifier);
209-
let expr = Expression::Variable(converted_name, VariableInfo::new_local(expr_type));
209+
let variable_info = VariableInfo::new_local(expr_type);
210+
211+
// store this in the name context too to make it easier for instruction generator
212+
// TODO add unit test
213+
// TODO what if the name already exists?
214+
ctx.names
215+
.insert_compact(converted_name.bare_name().clone(), variable_info.clone());
216+
217+
let expr = Expression::Variable(converted_name, variable_info);
218+
210219
Ok(expr)
211220
} else {
212221
Err(LintError::DuplicateDefinition.at_pos(extra.pos))

0 commit comments

Comments
 (0)