diff --git a/rusty_basic/src/bin/rusty_basic.rs b/rusty_basic/src/bin/rusty_basic.rs index 362f7745..239706a1 100644 --- a/rusty_basic/src/bin/rusty_basic.rs +++ b/rusty_basic/src/bin/rusty_basic.rs @@ -3,7 +3,7 @@ use std::fs::File; use rusty_basic::instruction_generator::{generate_instructions, unwrap_linter_context}; use rusty_basic::interpreter::{InterpreterTrait, new_default_interpreter}; -use rusty_linter::{Context, lint}; +use rusty_linter::core::{LinterContext, lint}; use rusty_parser::{Program, parse_main_file}; fn main() { @@ -33,7 +33,7 @@ fn on_parsed(program: Program, run_options: RunOptions) { } } -fn on_linted(program: Program, linter_context: Context, run_options: RunOptions) { +fn on_linted(program: Program, linter_context: LinterContext, run_options: RunOptions) { let (linter_names, user_defined_types) = unwrap_linter_context(linter_context); let instruction_generator_result = generate_instructions(program, linter_names); let mut interpreter = new_default_interpreter(user_defined_types); diff --git a/rusty_basic/src/instruction_generator/calls.rs b/rusty_basic/src/instruction_generator/calls.rs index ab337393..8fd2eed7 100644 --- a/rusty_basic/src/instruction_generator/calls.rs +++ b/rusty_basic/src/instruction_generator/calls.rs @@ -1,5 +1,5 @@ use rusty_common::{AtPos, Position, Positioned}; -use rusty_linter::SubprogramName; +use rusty_linter::core::ScopeName; use rusty_parser::*; use crate::instruction_generator::{AddressOrLabel, Instruction, InstructionGenerator}; @@ -42,18 +42,18 @@ impl InstructionGenerator { ) { let Positioned { element: name, pos } = function_name; let qualified_name = name.demand_qualified(); - let subprogram_name = SubprogramName::Function(qualified_name.clone()); + let scope_name = ScopeName::Function(qualified_name.clone()); // cloning to fight the borrow checker let function_parameters: Vec = self .subprogram_info_repository - .get_subprogram_info(&subprogram_name) + .get_subprogram_info(&scope_name) .params .clone(); self.generate_push_named_args_instructions(&function_parameters, &args, pos); - self.push_stack(subprogram_name.clone(), pos); + self.push_stack(scope_name.clone(), pos); let index = self.instructions.len(); self.push(Instruction::PushRet(index + 2), pos); - self.jump_to_subprogram(&subprogram_name, pos); + self.jump_to_subprogram(&scope_name, pos); // TODO find different way for by ref args // stash by-ref variables self.generate_stash_by_ref_args(&args); @@ -69,18 +69,18 @@ impl InstructionGenerator { pub fn generate_sub_call_instructions(&mut self, sub_call: SubCall, pos: Position) { let (name, args) = sub_call.into(); - let subprogram_name = SubprogramName::Sub(name); + let scope_name = ScopeName::Sub(name); // cloning to fight the borrow checker let sub_impl_parameters: Vec = self .subprogram_info_repository - .get_subprogram_info(&subprogram_name) + .get_subprogram_info(&scope_name) .params .clone(); self.generate_push_named_args_instructions(&sub_impl_parameters, &args, pos); - self.push_stack(subprogram_name.clone(), pos); + self.push_stack(scope_name.clone(), pos); let index = self.instructions.len(); self.push(Instruction::PushRet(index + 2), pos); // points to "generate_stash_by_ref_args" - self.jump_to_subprogram(&subprogram_name, pos); + self.jump_to_subprogram(&scope_name, pos); self.generate_stash_by_ref_args(&args); self.push(Instruction::PopStack, pos); self.generate_un_stash_by_ref_args(&args); @@ -148,20 +148,20 @@ impl InstructionGenerator { } } - fn push_stack(&mut self, subprogram_name: SubprogramName, pos: Position) { + fn push_stack(&mut self, scope_name: ScopeName, pos: Position) { if self .subprogram_info_repository - .get_subprogram_info(&subprogram_name) + .get_subprogram_info(&scope_name) .is_static { - self.push(Instruction::PushStaticStack(subprogram_name), pos); + self.push(Instruction::PushStaticStack(scope_name), pos); } else { self.push(Instruction::PushStack, pos); } } - fn jump_to_subprogram(&mut self, subprogram_name: &SubprogramName, pos: Position) { - let label: BareName = Self::format_subprogram_label(subprogram_name); + fn jump_to_subprogram(&mut self, scope_name: &ScopeName, pos: Position) { + let label: BareName = Self::format_subprogram_label(scope_name); self.push(Instruction::Jump(AddressOrLabel::Unresolved(label)), pos); } } diff --git a/rusty_basic/src/instruction_generator/dim.rs b/rusty_basic/src/instruction_generator/dim.rs index 9172c3b5..f227de7f 100644 --- a/rusty_basic/src/instruction_generator/dim.rs +++ b/rusty_basic/src/instruction_generator/dim.rs @@ -1,4 +1,5 @@ use rusty_common::*; +use rusty_linter::core::ScopeName; use rusty_parser::*; use rusty_variant::Variant; @@ -45,13 +46,12 @@ impl InstructionGenerator { impl InstructionGenerator { fn is_in_static_subprogram(&self) -> bool { - match &self.current_subprogram { - Some(subprogram_name) => { - self.subprogram_info_repository - .get_subprogram_info(subprogram_name) - .is_static - } - _ => false, + if self.current_subprogram == ScopeName::Global { + false + } else { + self.subprogram_info_repository + .get_subprogram_info(&self.current_subprogram) + .is_static } } diff --git a/rusty_basic/src/instruction_generator/expression.rs b/rusty_basic/src/instruction_generator/expression.rs index 25b34512..a22aebbd 100644 --- a/rusty_basic/src/instruction_generator/expression.rs +++ b/rusty_basic/src/instruction_generator/expression.rs @@ -1,4 +1,5 @@ use rusty_common::*; +use rusty_linter::core::VariableInfo; use rusty_parser::*; use rusty_variant::Variant; diff --git a/rusty_basic/src/instruction_generator/main.rs b/rusty_basic/src/instruction_generator/main.rs index 83c3ffd8..b895a6b5 100644 --- a/rusty_basic/src/instruction_generator/main.rs +++ b/rusty_basic/src/instruction_generator/main.rs @@ -1,5 +1,6 @@ use rusty_common::{AtPos, CaseInsensitiveString, Position, Positioned}; -use rusty_linter::{Context, Names, SubprogramName}; +use rusty_linter::core::{LinterContext, ScopeName}; +use rusty_linter::names::Names; use rusty_parser::{ Assignment, BareName, BuiltInFunction, BuiltInSub, DimVar, Expression, ExpressionType, FileHandle, FunctionImplementation, GlobalStatement, HasExpressionType, Name, Parameter, Program, Statement, Statements, SubImplementation, TypeQualifier, UserDefinedTypes }; @@ -11,10 +12,8 @@ use crate::instruction_generator::subprogram_info::{ SubprogramInfoCollector, SubprogramInfoRepository }; -pub fn unwrap_linter_context(linter_context: Context) -> (Names, UserDefinedTypes) { - let (pre_linter_result, linter_names) = linter_context.into(); - let user_defined_types = pre_linter_result.into(); - (linter_names, user_defined_types) +pub fn unwrap_linter_context(linter_context: LinterContext) -> (Names, UserDefinedTypes) { + (linter_context.names, linter_context.user_defined_types) } /// Generates instructions for the given program. @@ -181,7 +180,7 @@ pub enum Instruction { PushUnnamedByRef, PushStack, - PushStaticStack(SubprogramName), + PushStaticStack(ScopeName), PopStack, EnqueueToReturnStack(usize), @@ -264,7 +263,7 @@ pub struct InstructionGenerator { pub instructions: Vec, pub statement_addresses: Vec, pub subprogram_info_repository: SubprogramInfoRepository, - pub current_subprogram: Option, + pub current_subprogram: ScopeName, pub linter_names: Names, } @@ -274,7 +273,7 @@ impl InstructionGenerator { instructions: vec![], statement_addresses: vec![], subprogram_info_repository, - current_subprogram: None, + current_subprogram: ScopeName::Global, linter_names, } } @@ -375,7 +374,7 @@ impl InstructionGenerator { let qualifier = function_name .qualifier() .expect("Expected qualified function name"); - self.mark_current_subprogram(SubprogramName::Function(function_name), pos); + self.mark_current_subprogram(ScopeName::Function(function_name), pos); // set default value self.push(Instruction::AllocateBuiltIn(qualifier), pos); self.subprogram_body(body, pos); @@ -397,16 +396,21 @@ impl InstructionGenerator { body, .. } = sub_implementation; - self.mark_current_subprogram(SubprogramName::Sub(name), pos); + self.mark_current_subprogram(ScopeName::Sub(name), pos); self.subprogram_body(body, pos); } - fn mark_current_subprogram(&mut self, subprogram_name: SubprogramName, pos: Position) { + fn mark_current_subprogram(&mut self, scope_name: ScopeName, pos: Position) { + debug_assert_ne!( + scope_name, + ScopeName::Global, + "should not mark global scope" + ); self.push( - Instruction::Label(Self::format_subprogram_label(&subprogram_name)), + Instruction::Label(Self::format_subprogram_label(&scope_name)), pos, ); - self.current_subprogram = Some(subprogram_name); + self.current_subprogram = scope_name; } fn subprogram_body(&mut self, block: Statements, pos: Position) { @@ -469,20 +473,23 @@ impl InstructionGenerator { self.statement_addresses.push(self.instructions.len()); } - pub fn format_subprogram_label(subprogram_name: &SubprogramName) -> BareName { - let s: String = match subprogram_name { - SubprogramName::Function(function_name) => { + pub fn format_subprogram_label(scope_name: &ScopeName) -> BareName { + let s: String = match scope_name { + ScopeName::Function(function_name) => { let mut s: String = String::new(); s.push_str(":fun:"); s.push_str(&function_name.to_string()); s } - SubprogramName::Sub(sub_name) => { + ScopeName::Sub(sub_name) => { let mut s: String = String::new(); s.push_str(":sub:"); s.push_str(sub_name.as_ref()); s } + ScopeName::Global => { + panic!("Should not generate label for global scope") + } }; BareName::new(s) } diff --git a/rusty_basic/src/instruction_generator/subprogram_info.rs b/rusty_basic/src/instruction_generator/subprogram_info.rs index ef603a53..4341f5c2 100644 --- a/rusty_basic/src/instruction_generator/subprogram_info.rs +++ b/rusty_basic/src/instruction_generator/subprogram_info.rs @@ -1,7 +1,7 @@ use std::collections::HashMap; use rusty_common::Positioned; -use rusty_linter::SubprogramName; +use rusty_linter::core::ScopeName; use rusty_parser::*; /// Holds information about a subprogram that is needed at runtime. @@ -27,7 +27,7 @@ impl SubprogramInfo { #[derive(Default)] pub struct SubprogramInfoCollector { - map: HashMap, + map: HashMap, } impl SubprogramInfoCollector { @@ -51,30 +51,28 @@ impl SubprogramInfoCollector { fn visit_function_implementation(&mut self, f: &FunctionImplementation) { let function_name = f.name.element.clone().demand_qualified(); - let subprogram_name = SubprogramName::Function(function_name); - self.map.insert(subprogram_name, SubprogramInfo::new(f)); + let scope_name = ScopeName::Function(function_name); + self.map.insert(scope_name, SubprogramInfo::new(f)); } fn visit_sub_implementation(&mut self, s: &SubImplementation) { let sub_name = s.name.element.clone(); - let subprogram_name = SubprogramName::Sub(sub_name); - self.map.insert(subprogram_name, SubprogramInfo::new(s)); + let scope_name = ScopeName::Sub(sub_name); + self.map.insert(scope_name, SubprogramInfo::new(s)); } } pub struct SubprogramInfoRepository { - map: HashMap, + map: HashMap, } impl SubprogramInfoRepository { - pub fn new(map: HashMap) -> Self { + pub fn new(map: HashMap) -> Self { Self { map } } - pub fn get_subprogram_info(&self, subprogram_name: &SubprogramName) -> &SubprogramInfo { - self.map - .get(subprogram_name) - .expect("Function/Sub not found") + pub fn get_subprogram_info(&self, scope_name: &ScopeName) -> &SubprogramInfo { + self.map.get(scope_name).expect("Function/Sub not found") } } diff --git a/rusty_basic/src/instruction_generator/test_utils.rs b/rusty_basic/src/instruction_generator/test_utils.rs index b4c90538..c3705b0b 100644 --- a/rusty_basic/src/instruction_generator/test_utils.rs +++ b/rusty_basic/src/instruction_generator/test_utils.rs @@ -1,5 +1,5 @@ use rusty_common::NoPosContainer; -use rusty_linter::lint; +use rusty_linter::core::lint; use rusty_parser::{UserDefinedTypes, parse}; use crate::instruction_generator::{ diff --git a/rusty_basic/src/interpreter/built_ins/chr.rs b/rusty_basic/src/interpreter/built_ins/chr.rs index 8f66f6f4..7d0022e9 100644 --- a/rusty_basic/src/interpreter/built_ins/chr.rs +++ b/rusty_basic/src/interpreter/built_ins/chr.rs @@ -1,4 +1,4 @@ -use rusty_linter::QBNumberCast; +use rusty_linter::core::QBNumberCast; use rusty_parser::BuiltInFunction; use crate::RuntimeError; diff --git a/rusty_basic/src/interpreter/built_ins/color.rs b/rusty_basic/src/interpreter/built_ins/color.rs index 1092bd23..2bda36e7 100644 --- a/rusty_basic/src/interpreter/built_ins/color.rs +++ b/rusty_basic/src/interpreter/built_ins/color.rs @@ -1,4 +1,4 @@ -use rusty_linter::QBNumberCast; +use rusty_linter::core::QBNumberCast; use crate::RuntimeError; use crate::interpreter::interpreter_trait::InterpreterTrait; diff --git a/rusty_basic/src/interpreter/built_ins/def_seg.rs b/rusty_basic/src/interpreter/built_ins/def_seg.rs index 66c5b56b..50fd1d51 100644 --- a/rusty_basic/src/interpreter/built_ins/def_seg.rs +++ b/rusty_basic/src/interpreter/built_ins/def_seg.rs @@ -1,4 +1,4 @@ -use rusty_linter::QBNumberCast; +use rusty_linter::core::QBNumberCast; use crate::RuntimeError; use crate::interpreter::interpreter_trait::InterpreterTrait; diff --git a/rusty_basic/src/interpreter/built_ins/input.rs b/rusty_basic/src/interpreter/built_ins/input.rs index 254f8c28..0bac02db 100644 --- a/rusty_basic/src/interpreter/built_ins/input.rs +++ b/rusty_basic/src/interpreter/built_ins/input.rs @@ -1,6 +1,6 @@ use std::convert::TryFrom; -use rusty_linter::qualifier_of_variant; +use rusty_linter::core::qualifier_of_variant; use rusty_parser::{FileHandle, TypeQualifier}; use rusty_variant::Variant; diff --git a/rusty_basic/src/interpreter/built_ins/mkd.rs b/rusty_basic/src/interpreter/built_ins/mkd.rs index dde03b27..75fc3963 100644 --- a/rusty_basic/src/interpreter/built_ins/mkd.rs +++ b/rusty_basic/src/interpreter/built_ins/mkd.rs @@ -1,4 +1,4 @@ -use rusty_linter::QBNumberCast; +use rusty_linter::core::QBNumberCast; use rusty_parser::BuiltInFunction; use rusty_variant::f64_to_bytes; diff --git a/rusty_basic/src/interpreter/built_ins/open.rs b/rusty_basic/src/interpreter/built_ins/open.rs index a6dba539..6f80e86c 100644 --- a/rusty_basic/src/interpreter/built_ins/open.rs +++ b/rusty_basic/src/interpreter/built_ins/open.rs @@ -1,4 +1,4 @@ -use rusty_linter::QBNumberCast; +use rusty_linter::core::QBNumberCast; use rusty_parser::{FileAccess, FileHandle, FileMode}; use rusty_variant::Variant; diff --git a/rusty_basic/src/interpreter/built_ins/poke.rs b/rusty_basic/src/interpreter/built_ins/poke.rs index 07ea9b9f..0ad1f0a5 100644 --- a/rusty_basic/src/interpreter/built_ins/poke.rs +++ b/rusty_basic/src/interpreter/built_ins/poke.rs @@ -1,4 +1,4 @@ -use rusty_linter::QBNumberCast; +use rusty_linter::core::QBNumberCast; use super::peek::INDICATOR_KEYS_ADDRESS; use crate::RuntimeError; diff --git a/rusty_basic/src/interpreter/built_ins/read.rs b/rusty_basic/src/interpreter/built_ins/read.rs index ede073cd..3d7be767 100644 --- a/rusty_basic/src/interpreter/built_ins/read.rs +++ b/rusty_basic/src/interpreter/built_ins/read.rs @@ -1,4 +1,4 @@ -use rusty_linter::{CastVariant, qualifier_of_variant}; +use rusty_linter::core::{CastVariant, qualifier_of_variant}; use crate::RuntimeError; use crate::interpreter::interpreter_trait::InterpreterTrait; diff --git a/rusty_basic/src/interpreter/built_ins/space.rs b/rusty_basic/src/interpreter/built_ins/space.rs index 6d33f3b0..eb3ddc05 100644 --- a/rusty_basic/src/interpreter/built_ins/space.rs +++ b/rusty_basic/src/interpreter/built_ins/space.rs @@ -1,4 +1,4 @@ -use rusty_linter::QBNumberCast; +use rusty_linter::core::QBNumberCast; use rusty_parser::BuiltInFunction; use crate::RuntimeError; diff --git a/rusty_basic/src/interpreter/built_ins/string_fn.rs b/rusty_basic/src/interpreter/built_ins/string_fn.rs index 92662287..57315816 100644 --- a/rusty_basic/src/interpreter/built_ins/string_fn.rs +++ b/rusty_basic/src/interpreter/built_ins/string_fn.rs @@ -1,4 +1,4 @@ -use rusty_linter::QBNumberCast; +use rusty_linter::core::QBNumberCast; use rusty_parser::BuiltInFunction; use rusty_variant::Variant; diff --git a/rusty_basic/src/interpreter/context.rs b/rusty_basic/src/interpreter/context.rs index c7227ade..45691488 100644 --- a/rusty_basic/src/interpreter/context.rs +++ b/rusty_basic/src/interpreter/context.rs @@ -1,7 +1,7 @@ use std::collections::HashMap; use rusty_common::CaseInsensitiveString; -use rusty_linter::{QBNumberCast, SubprogramName}; +use rusty_linter::core::{QBNumberCast, ScopeName}; use rusty_parser::{BareName, BuiltInFunction, TypeQualifier}; use rusty_variant::{UserDefinedTypeValue, VArray, Variant, bytes_to_i32, i32_to_bytes}; @@ -19,7 +19,7 @@ pub struct Context { states: Vec, memory_blocks: Vec, // static memory blocks (for STATIC function/sub) - static_memory_blocks: HashMap, + static_memory_blocks: HashMap, } impl Context { @@ -49,11 +49,11 @@ impl Context { self.do_push_new(variables, false); } - pub fn stop_collecting_arguments_static(&mut self, subprogram_name: SubprogramName) { + pub fn stop_collecting_arguments_static(&mut self, scope_name: ScopeName) { // current state must be argument collecting state let arguments = self.do_pop().arguments.expect("Expected argument state"); // ensure memory block for this subprogram - match self.static_memory_blocks.get(&subprogram_name) { + match self.static_memory_blocks.get(&scope_name) { Some(existing_memory_block_index) => { let memory_block_index = *existing_memory_block_index; self.memory_blocks[memory_block_index] @@ -65,7 +65,7 @@ impl Context { let variables = Variables::from(arguments); let memory_block_index = self.do_push_new(variables, true); self.static_memory_blocks - .insert(subprogram_name, memory_block_index); + .insert(scope_name, memory_block_index); } } } diff --git a/rusty_basic/src/interpreter/error.rs b/rusty_basic/src/interpreter/error.rs index e5a07493..ef34ae35 100644 --- a/rusty_basic/src/interpreter/error.rs +++ b/rusty_basic/src/interpreter/error.rs @@ -1,4 +1,4 @@ -use rusty_linter::LintError; +use rusty_linter::core::LintError; use rusty_variant::{SubscriptOutOfRangeError, VariantError}; use crate::error_envelope::ErrorEnvelope; diff --git a/rusty_basic/src/interpreter/handlers/cast.rs b/rusty_basic/src/interpreter/handlers/cast.rs index c6f15494..fe1a96cb 100644 --- a/rusty_basic/src/interpreter/handlers/cast.rs +++ b/rusty_basic/src/interpreter/handlers/cast.rs @@ -1,4 +1,4 @@ -use rusty_linter::CastVariant; +use rusty_linter::core::CastVariant; use rusty_parser::TypeQualifier; use rusty_variant::Variant; diff --git a/rusty_basic/src/interpreter/handlers/logical.rs b/rusty_basic/src/interpreter/handlers/logical.rs index d16dd7f6..5dd1320b 100644 --- a/rusty_basic/src/interpreter/handlers/logical.rs +++ b/rusty_basic/src/interpreter/handlers/logical.rs @@ -1,4 +1,4 @@ -use rusty_linter::CastVariant; +use rusty_linter::core::CastVariant; use rusty_parser::TypeQualifier; use crate::RuntimeError; diff --git a/rusty_basic/src/interpreter/handlers/var_path.rs b/rusty_basic/src/interpreter/handlers/var_path.rs index f6588b95..97d1d3bb 100644 --- a/rusty_basic/src/interpreter/handlers/var_path.rs +++ b/rusty_basic/src/interpreter/handlers/var_path.rs @@ -1,4 +1,4 @@ -use rusty_linter::QBNumberCast; +use rusty_linter::core::QBNumberCast; use rusty_parser::BareName; use rusty_variant::Variant; diff --git a/rusty_basic/src/interpreter/interpreter_trait.rs b/rusty_basic/src/interpreter/interpreter_trait.rs index ee1a0835..902b6757 100644 --- a/rusty_basic/src/interpreter/interpreter_trait.rs +++ b/rusty_basic/src/interpreter/interpreter_trait.rs @@ -1,6 +1,5 @@ use std::collections::VecDeque; -use rusty_linter::HasUserDefinedTypes; use rusty_variant::Variant; use crate::RuntimeErrorPos; @@ -12,7 +11,7 @@ use crate::interpreter::io::{FileManager, Input, Printer}; use crate::interpreter::registers::{RegisterStack, Registers}; use crate::interpreter::screen::Screen; -pub trait InterpreterTrait: HasUserDefinedTypes { +pub trait InterpreterTrait { type TStdlib: Stdlib; type TStdIn: Input; type TStdOut: Printer; diff --git a/rusty_basic/src/interpreter/main.rs b/rusty_basic/src/interpreter/main.rs index e4c4c6d7..78d3f9fd 100644 --- a/rusty_basic/src/interpreter/main.rs +++ b/rusty_basic/src/interpreter/main.rs @@ -1,7 +1,7 @@ use std::collections::VecDeque; use rusty_common::*; -use rusty_linter::{HasUserDefinedTypes, QBNumberCast}; +use rusty_linter::core::QBNumberCast; use rusty_parser::UserDefinedTypes; use rusty_variant::Variant; @@ -83,14 +83,6 @@ pub struct Interpreter, } -impl HasUserDefinedTypes - for Interpreter -{ - fn user_defined_types(&self) -> &UserDefinedTypes { - &self.user_defined_types - } -} - impl InterpreterTrait for Interpreter { @@ -397,9 +389,9 @@ impl self.context.stop_collecting_arguments(); self.stacktrace.insert(0, pos); } - Instruction::PushStaticStack(subprogram_name) => { + Instruction::PushStaticStack(scope_name) => { self.context - .stop_collecting_arguments_static(subprogram_name.clone()); + .stop_collecting_arguments_static(scope_name.clone()); self.stacktrace.insert(0, pos); } Instruction::PopStack => { @@ -504,13 +496,13 @@ impl .map(|res| res.map_err(RuntimeError::from)) .collect(); let args = r_args.with_err_at(&pos)?; - let v = allocate_array(args, element_type, self.user_defined_types()) + let v = allocate_array(args, element_type, &self.user_defined_types) .with_err_at(&pos)?; self.registers_mut().set_a(v); } Instruction::AllocateUserDefined(user_defined_type_name) => { let v = - allocate_user_defined_type(user_defined_type_name, self.user_defined_types()); + allocate_user_defined_type(user_defined_type_name, &self.user_defined_types); self.registers_mut().set_a(v); } Instruction::VarPathName(root_path) => { diff --git a/rusty_basic/src/interpreter/test_utils.rs b/rusty_basic/src/interpreter/test_utils.rs index be35af95..1fab3756 100644 --- a/rusty_basic/src/interpreter/test_utils.rs +++ b/rusty_basic/src/interpreter/test_utils.rs @@ -2,7 +2,7 @@ use std::collections::HashMap; use std::fs::File; use std::io::Read; -use rusty_linter::lint; +use rusty_linter::core::lint; use rusty_parser::{UserDefinedTypes, parse_main_file}; use crate::RuntimeErrorPos; diff --git a/rusty_basic/src/interpreter/variant_casts.rs b/rusty_basic/src/interpreter/variant_casts.rs index 2948ced8..28a3b88b 100644 --- a/rusty_basic/src/interpreter/variant_casts.rs +++ b/rusty_basic/src/interpreter/variant_casts.rs @@ -1,6 +1,6 @@ use std::convert::TryFrom; -use rusty_linter::QBNumberCast; +use rusty_linter::core::QBNumberCast; use rusty_parser::FileHandle; use rusty_variant::Variant; diff --git a/rusty_linter/src/built_ins/arg_validation.rs b/rusty_linter/src/built_ins/arg_validation.rs index f5a68623..38ad2e18 100644 --- a/rusty_linter/src/built_ins/arg_validation.rs +++ b/rusty_linter/src/built_ins/arg_validation.rs @@ -1,6 +1,6 @@ use rusty_common::{AtPos, Position}; use rusty_parser::{ - Expression, ExpressionPos, ExpressionTrait, ExpressionType, Expressions, HasExpressionType, TypeQualifier, VariableInfo + Expression, ExpressionPos, ExpressionTrait, ExpressionType, Expressions, HasExpressionType, TypeQualifier }; use crate::core::{CanCastTo, LintError, LintErrorPos}; @@ -105,13 +105,7 @@ impl ArgValidation for Expressions { fn require_string_variable(&self, index: usize) -> Result<(), LintErrorPos> { match self.expr(index) { - Expression::Variable( - _, - VariableInfo { - expression_type: ExpressionType::BuiltIn(TypeQualifier::DollarString), - .. - }, - ) => Ok(()), + Expression::Variable(_, ExpressionType::BuiltIn(TypeQualifier::DollarString)) => Ok(()), Expression::Variable(_, _) => Err(LintError::ArgumentTypeMismatch.at(&self[index])), _ => Err(LintError::VariableRequired.at(&self[index])), } @@ -119,19 +113,8 @@ impl ArgValidation for Expressions { fn require_string_ref(&self, index: usize) -> Result<(), LintErrorPos> { match self.expr(index) { - Expression::Variable( - _, - VariableInfo { - expression_type, .. - }, - ) - | Expression::ArrayElement( - _, - _, - VariableInfo { - expression_type, .. - }, - ) + Expression::Variable(_, expression_type) + | Expression::ArrayElement(_, _, expression_type) | Expression::Property(_, _, expression_type) => { if expression_type.can_cast_to(&TypeQualifier::DollarString) { Ok(()) @@ -145,19 +128,8 @@ impl ArgValidation for Expressions { fn require_variable_of_built_in_type(&self, index: usize) -> Result<(), LintErrorPos> { match self.expr(index) { - Expression::Variable( - _, - VariableInfo { - expression_type, .. - }, - ) - | Expression::ArrayElement( - _, - _, - VariableInfo { - expression_type, .. - }, - ) + Expression::Variable(_, expression_type) + | Expression::ArrayElement(_, _, expression_type) | Expression::Property(_, _, expression_type) => match expression_type { ExpressionType::BuiltIn(_) | ExpressionType::FixedLengthString(_) => Ok(()), _ => Err(LintError::ArgumentTypeMismatch.at(&self[index])), diff --git a/rusty_linter/src/built_ins/data.rs b/rusty_linter/src/built_ins/data.rs index cd47bfe8..783ff5b3 100644 --- a/rusty_linter/src/built_ins/data.rs +++ b/rusty_linter/src/built_ins/data.rs @@ -1,14 +1,10 @@ use rusty_common::{AtPos, Position}; use rusty_parser::{Expression, ExpressionPos, Expressions}; -use crate::core::{LintError, LintErrorPos, NameContext}; +use crate::core::{LintError, LintErrorPos, ScopeKind}; -pub fn lint( - args: &Expressions, - name_context: NameContext, - pos: Position, -) -> Result<(), LintErrorPos> { - if name_context == NameContext::Global { +pub fn lint(args: &Expressions, scope_kind: ScopeKind, pos: Position) -> Result<(), LintErrorPos> { + if scope_kind == ScopeKind::Global { args.iter().try_for_each(require_constant) } else { Err(LintError::IllegalInSubFunction.at_pos(pos)) diff --git a/rusty_linter/src/built_ins/lbound.rs b/rusty_linter/src/built_ins/lbound.rs index 4d1e8024..468b26c8 100644 --- a/rusty_linter/src/built_ins/lbound.rs +++ b/rusty_linter/src/built_ins/lbound.rs @@ -1,5 +1,5 @@ use rusty_common::{AtPos, Position, Positioned}; -use rusty_parser::{Expression, ExpressionType, Expressions, TypeQualifier, VariableInfo}; +use rusty_parser::{Expression, ExpressionType, Expressions, TypeQualifier}; use crate::core::{CanCastTo, LintError, LintErrorPos}; @@ -14,14 +14,7 @@ pub fn lint(args: &Expressions, pos: Position) -> Result<(), LintErrorPos> { element: first, pos: first_pos, } = args.first().unwrap(); - if let Expression::Variable( - _, - VariableInfo { - expression_type: ExpressionType::Array(_), - .. - }, - ) = first - { + if let Expression::Variable(_, ExpressionType::Array(_)) = first { if args.len() == 2 { if args[1].can_cast_to(&TypeQualifier::PercentInteger) { Ok(()) diff --git a/rusty_linter/src/built_ins/mod.rs b/rusty_linter/src/built_ins/mod.rs index dd71fe93..ccf37b8d 100644 --- a/rusty_linter/src/built_ins/mod.rs +++ b/rusty_linter/src/built_ins/mod.rs @@ -49,13 +49,13 @@ mod width; use rusty_common::Position; use rusty_parser::{BuiltInFunction, BuiltInSub, Expressions}; -use crate::core::{LintErrorPos, NameContext}; +use crate::core::{LintErrorPos, ScopeKind}; pub fn lint_sub_call( built_in_sub: &BuiltInSub, pos: Position, args: &Expressions, - name_context: NameContext, + scope_kind: ScopeKind, ) -> Result<(), LintErrorPos> { match built_in_sub { BuiltInSub::Beep => beep::lint(args, pos), @@ -63,7 +63,7 @@ pub fn lint_sub_call( BuiltInSub::Close => close::lint(args), BuiltInSub::Cls => cls::lint(args, pos), BuiltInSub::Color => color::lint(args, pos), - BuiltInSub::Data => data::lint(args, name_context, pos), + BuiltInSub::Data => data::lint(args, scope_kind, pos), BuiltInSub::DefSeg => def_seg::lint(args, pos), BuiltInSub::Environ => environ_sub::lint(args, pos), BuiltInSub::Field => field::lint(args, pos), diff --git a/rusty_linter/src/converter/common/context.rs b/rusty_linter/src/converter/common/context.rs deleted file mode 100644 index 66aa7f7a..00000000 --- a/rusty_linter/src/converter/common/context.rs +++ /dev/null @@ -1,61 +0,0 @@ -use rusty_parser::*; - -use crate::core::*; -use crate::names::Names; -use crate::pre_linter::PreLinterResult; - -pub struct Context { - pre_linter_result: PreLinterResult, - pub resolver: TypeResolverImpl, - // TODO make this private - pub names: Names, -} - -impl TypeResolver for Context { - fn char_to_qualifier(&self, ch: char) -> TypeQualifier { - self.resolver.char_to_qualifier(ch) - } -} - -impl HasSubprograms for Context { - fn functions(&self) -> &SignatureMap { - self.pre_linter_result.functions() - } - fn subs(&self) -> &SignatureMap { - self.pre_linter_result.subs() - } -} - -impl HasUserDefinedTypes for Context { - fn user_defined_types(&self) -> &UserDefinedTypes { - self.pre_linter_result.user_defined_types() - } -} - -impl Context { - pub fn new(pre_linter_result: PreLinterResult) -> Self { - Self { - pre_linter_result, - resolver: TypeResolverImpl::new(), - names: Names::new(), - } - } - - pub fn is_in_subprogram(&self) -> bool { - self.names.is_in_subprogram() - } - - /// Gets the function qualifier of the function identified by the given bare name. - /// If no such function exists, returns `None`. - pub fn function_qualifier(&self, bare_name: &BareName) -> Option { - self.functions() - .get(bare_name) - .and_then(|function_signature_pos| function_signature_pos.element.qualifier()) - } -} - -impl From for (PreLinterResult, Names) { - fn from(value: Context) -> Self { - (value.pre_linter_result, value.names) - } -} diff --git a/rusty_linter/src/converter/common/traits.rs b/rusty_linter/src/converter/common/convertible.rs similarity index 70% rename from rusty_linter/src/converter/common/traits.rs rename to rusty_linter/src/converter/common/convertible.rs index 6c0ff76e..a4364fd2 100644 --- a/rusty_linter/src/converter/common/traits.rs +++ b/rusty_linter/src/converter/common/convertible.rs @@ -1,12 +1,11 @@ use rusty_common::{AtPos, Position, Positioned}; -use crate::converter::common::Context; -use crate::core::LintErrorPos; +use crate::core::{LintErrorPos, LinterContext}; /// Convert from the current type into the target type O. /// By default, O is the same as the current type. pub trait Convertible: Sized { - fn convert(self, ctx: &mut Context) -> Result; + fn convert(self, ctx: &mut LinterContext) -> Result; } // Blanket implementation for Option @@ -15,7 +14,7 @@ impl Convertible> for Option where T: Convertible, { - fn convert(self, ctx: &mut Context) -> Result, LintErrorPos> { + fn convert(self, ctx: &mut LinterContext) -> Result, LintErrorPos> { match self { Some(t) => t.convert(ctx).map(Some), None => Ok(None), @@ -29,7 +28,7 @@ impl Convertible> for Vec where T: Convertible, { - fn convert(self, ctx: &mut Context) -> Result, LintErrorPos> { + fn convert(self, ctx: &mut LinterContext) -> Result, LintErrorPos> { self.into_iter().map(|t| t.convert(ctx)).collect() } } @@ -40,7 +39,7 @@ impl Convertible> for Positioned where T: ConvertibleIn, { - fn convert(self, ctx: &mut Context) -> Result, LintErrorPos> { + fn convert(self, ctx: &mut LinterContext) -> Result, LintErrorPos> { let Self { element: statement, pos, @@ -55,9 +54,9 @@ where /// using additional information in the value U. /// By default, O is the same as the current type. pub trait ConvertibleIn: Sized { - fn convert_in(self, ctx: &mut Context, value: U) -> Result; + fn convert_in(self, ctx: &mut LinterContext, value: U) -> Result; - fn convert_in_default(self, ctx: &mut Context) -> Result + fn convert_in_default(self, ctx: &mut LinterContext) -> Result where U: Default, { @@ -71,7 +70,7 @@ impl ConvertibleIn> for Option where T: ConvertibleIn, { - fn convert_in(self, ctx: &mut Context, extra: U) -> Result, LintErrorPos> { + fn convert_in(self, ctx: &mut LinterContext, extra: U) -> Result, LintErrorPos> { match self { Some(t) => t.convert_in(ctx, extra).map(Some), None => Ok(None), @@ -86,7 +85,7 @@ where T: ConvertibleIn, U: Clone, { - fn convert_in(self, ctx: &mut Context, extra: U) -> Result, LintErrorPos> { + fn convert_in(self, ctx: &mut LinterContext, extra: U) -> Result, LintErrorPos> { self.into_iter() .map(|t| t.convert_in(ctx, extra.clone())) .collect() diff --git a/rusty_linter/src/converter/common/mod.rs b/rusty_linter/src/converter/common/mod.rs index c79a0212..a285638c 100644 --- a/rusty_linter/src/converter/common/mod.rs +++ b/rusty_linter/src/converter/common/mod.rs @@ -1,8 +1,6 @@ -mod context; +mod convertible; mod program_rules; -mod traits; mod types; -pub use self::context::*; -pub use self::traits::*; +pub use self::convertible::*; pub use self::types::*; diff --git a/rusty_linter/src/converter/common/program_rules.rs b/rusty_linter/src/converter/common/program_rules.rs index 6d335e9a..7fdb6a48 100644 --- a/rusty_linter/src/converter/common/program_rules.rs +++ b/rusty_linter/src/converter/common/program_rules.rs @@ -3,17 +3,17 @@ use rusty_parser::{ DimVar, FunctionImplementation, GlobalStatement, GlobalStatementPos, Program, Statement, Statements, SubImplementation }; -use crate::converter::common::{Context, Convertible, ConvertibleIn}; -use crate::core::{IntoQualified, LintErrorPos, SubprogramName}; +use crate::converter::common::{Convertible, ConvertibleIn}; +use crate::core::{IntoQualified, LintErrorPos, LinterContext, ScopeName}; use crate::names::ImplicitVars; impl Convertible for Program { - fn convert(self, ctx: &mut Context) -> Result { + fn convert(self, ctx: &mut LinterContext) -> Result { // collect the global statements let mut global_statements: Self = vec![]; for Positioned { element, pos } in self { let expanded_statements_for_element = element.convert_in(ctx, pos)?; - global_statements.extend(expanded_statements_for_element.into_iter()); + global_statements.extend(expanded_statements_for_element); } // collect implicitly defined variables @@ -36,7 +36,7 @@ impl Convertible for Program { impl ConvertibleIn> for GlobalStatement { fn convert_in( self, - ctx: &mut Context, + ctx: &mut LinterContext, pos: Position, ) -> Result, LintErrorPos> { match self { @@ -59,7 +59,7 @@ impl ConvertibleIn> for GlobalStatement { fn on_function_implementation( function_implementation: FunctionImplementation, - ctx: &mut Context, + ctx: &mut LinterContext, ) -> Result { let FunctionImplementation { name: Positioned { @@ -75,7 +75,7 @@ fn on_function_implementation( let resolved_function_name = unresolved_function_name.to_qualified(&ctx.resolver); // push a new naming scope for the FUNCTION - ctx.names.push(SubprogramName::Function( + ctx.names.push(ScopeName::Function( resolved_function_name.clone().demand_qualified(), )); @@ -85,7 +85,7 @@ fn on_function_implementation( let mapped = FunctionImplementation { name: resolved_function_name.at_pos(pos), params, - body: convert_block_hoisting_implicit_vars_and_pop_name_scope(body, ctx)?, + body: convert_block_hoisting_implicit_vars_and_pop_scope(body, ctx)?, is_static, }; Ok(mapped) @@ -93,7 +93,7 @@ fn on_function_implementation( fn on_sub_implementation( sub_implementation: SubImplementation, - ctx: &mut Context, + ctx: &mut LinterContext, ) -> Result { let SubImplementation { name, @@ -103,14 +103,14 @@ fn on_sub_implementation( } = sub_implementation; // push a new naming scope for the SUB - ctx.names.push(SubprogramName::Sub(name.element.clone())); + ctx.names.push(ScopeName::Sub(name.element.clone())); // convert the parameters let params = params.convert(ctx)?; let mapped = SubImplementation { name, params, - body: convert_block_hoisting_implicit_vars_and_pop_name_scope(body, ctx)?, + body: convert_block_hoisting_implicit_vars_and_pop_scope(body, ctx)?, is_static, }; Ok(mapped) @@ -125,12 +125,12 @@ fn on_sub_implementation( // DIM C // DIM A // A = B + C -fn convert_block_hoisting_implicit_vars_and_pop_name_scope( +fn convert_block_hoisting_implicit_vars_and_pop_scope( statements: Statements, - ctx: &mut Context, + ctx: &mut LinterContext, ) -> Result { let mut result = statements.convert(ctx)?; - let implicit_vars = collect_implicit_vars_and_pop_name_scope(ctx); + let implicit_vars = collect_implicit_vars_and_pop_scope(ctx); let mut implicit_dim: Statements = implicit_vars .into_iter() .map( @@ -147,7 +147,7 @@ fn convert_block_hoisting_implicit_vars_and_pop_name_scope( fn on_statement( statement: Statement, - ctx: &mut Context, + ctx: &mut LinterContext, pos: Position, ) -> Result, LintErrorPos> { // a statement might be converted into multiple statements due to implicit vars @@ -159,11 +159,11 @@ fn on_statement( .collect()) } -fn collect_implicit_vars_and_pop_name_scope(ctx: &mut Context) -> ImplicitVars { +fn collect_implicit_vars_and_pop_scope(ctx: &mut LinterContext) -> ImplicitVars { // collect implicit vars let mut implicit_vars = ImplicitVars::new(); implicit_vars.append(ctx.names.get_implicit_vars_mut()); - // restore the global naming scope + // restore the global scope name ctx.names.pop(); implicit_vars } diff --git a/rusty_linter/src/converter/dim_rules/array_dimension.rs b/rusty_linter/src/converter/dim_rules/array_dimension.rs index 05c7eee1..a6bbb494 100644 --- a/rusty_linter/src/converter/dim_rules/array_dimension.rs +++ b/rusty_linter/src/converter/dim_rules/array_dimension.rs @@ -1,10 +1,10 @@ use rusty_parser::ArrayDimension; -use crate::converter::common::{Context, Convertible, ConvertibleIn}; -use crate::core::LintErrorPos; +use crate::converter::common::{Convertible, ConvertibleIn}; +use crate::core::{LintErrorPos, LinterContext}; impl Convertible for ArrayDimension { - fn convert(self, ctx: &mut Context) -> Result { + fn convert(self, ctx: &mut LinterContext) -> Result { Ok(Self { lbound: self.lbound.convert_in_default(ctx)?, ubound: self.ubound.convert_in_default(ctx)?, diff --git a/rusty_linter/src/converter/dim_rules/dim_type_rules.rs b/rusty_linter/src/converter/dim_rules/dim_type_rules.rs index bd3438bb..751ba4f1 100644 --- a/rusty_linter/src/converter/dim_rules/dim_type_rules.rs +++ b/rusty_linter/src/converter/dim_rules/dim_type_rules.rs @@ -1,13 +1,15 @@ use rusty_common::*; use rusty_parser::*; -use crate::converter::common::{DimNameState, *}; -use crate::core::{IntoTypeQualifier, LintError, LintErrorPos, ValidateStringLength}; +use crate::converter::common::{Convertible, DimContext, DimNameState}; +use crate::core::{ + IntoTypeQualifier, LintError, LintErrorPos, LinterContext, ValidateStringLength +}; pub fn on_dim_type( dim_type: DimType, bare_name: &BareName, - ctx: &mut Context, + ctx: &mut LinterContext, extra: DimNameState, ) -> Result { match dim_type { @@ -27,7 +29,7 @@ pub fn on_dim_type( } pub fn bare_to_dim_type( - ctx: &mut Context, + ctx: &mut LinterContext, bare_name: &BareName, pos: Position, ) -> Result { @@ -37,7 +39,7 @@ pub fn bare_to_dim_type( } fn require_compact_can_be_defined( - ctx: &Context, + ctx: &LinterContext, bare_name: &BareName, q: TypeQualifier, pos: Position, @@ -60,7 +62,7 @@ fn require_compact_can_be_defined( } pub fn built_in_to_dim_type( - ctx: &mut Context, + ctx: &mut LinterContext, bare_name: &BareName, q: TypeQualifier, built_in_style: BuiltInStyle, @@ -79,7 +81,7 @@ pub fn built_in_to_dim_type( } fn require_extended_can_be_defined( - ctx: &Context, + ctx: &LinterContext, bare_name: &BareName, pos: Position, ) -> Result<(), LintErrorPos> { @@ -90,7 +92,7 @@ fn require_extended_can_be_defined( } fn fixed_length_string_to_dim_type( - ctx: &mut Context, + ctx: &mut LinterContext, bare_name: &BareName, length_expression: &ExpressionPos, ) -> Result { @@ -103,7 +105,7 @@ fn fixed_length_string_to_dim_type( } pub fn user_defined_to_dim_type( - ctx: &mut Context, + ctx: &mut LinterContext, bare_name: &BareName, user_defined_type: BareNamePos, pos: Position, @@ -113,7 +115,7 @@ pub fn user_defined_to_dim_type( } fn array_to_dim_type( - ctx: &mut Context, + ctx: &mut LinterContext, extra: DimNameState, bare_name: &BareName, array_dimensions: ArrayDimensions, diff --git a/rusty_linter/src/converter/dim_rules/main.rs b/rusty_linter/src/converter/dim_rules/main.rs index f92b39e5..d52ee85d 100644 --- a/rusty_linter/src/converter/dim_rules/main.rs +++ b/rusty_linter/src/converter/dim_rules/main.rs @@ -1,14 +1,18 @@ use rusty_common::*; use rusty_parser::*; -use crate::converter::common::{Context, ConvertibleIn, DimContext, DimNameState}; +use crate::converter::common::{ConvertibleIn, DimContext, DimNameState}; use crate::converter::dim_rules::dim_type_rules::on_dim_type; use crate::converter::dim_rules::redim::on_redim_type; use crate::converter::dim_rules::validation; -use crate::core::{LintError, LintErrorPos}; +use crate::core::{LintError, LintErrorPos, LinterContext}; impl ConvertibleIn for DimList { - fn convert_in(self, ctx: &mut Context, dim_context: DimContext) -> Result { + fn convert_in( + self, + ctx: &mut LinterContext, + dim_context: DimContext, + ) -> Result { let Self { variables, shared } = self; let mut new_variables = DimVars::new(); for Positioned { element, pos } in variables { @@ -28,7 +32,11 @@ impl ConvertibleIn for DimList { } impl ConvertibleIn for DimVar { - fn convert_in(self, ctx: &mut Context, extra: DimNameState) -> Result { + fn convert_in( + self, + ctx: &mut LinterContext, + extra: DimNameState, + ) -> Result { validation::validate(&self, ctx, extra.pos)?; let shared = extra.shared; shared_illegal_in_sub_function(ctx, shared, extra.pos)?; @@ -46,7 +54,7 @@ impl ConvertibleIn for DimVar { } fn shared_illegal_in_sub_function( - ctx: &Context, + ctx: &LinterContext, shared: bool, pos: Position, ) -> Result<(), LintErrorPos> { diff --git a/rusty_linter/src/converter/dim_rules/param_rules.rs b/rusty_linter/src/converter/dim_rules/param_rules.rs index 605b1990..d28beadb 100644 --- a/rusty_linter/src/converter/dim_rules/param_rules.rs +++ b/rusty_linter/src/converter/dim_rules/param_rules.rs @@ -1,13 +1,13 @@ use rusty_common::Position; use rusty_parser::Parameter; -use crate::converter::common::{Context, ConvertibleIn}; +use crate::converter::common::ConvertibleIn; use crate::converter::dim_rules::param_type_rules::on_param_type; use crate::converter::dim_rules::validation; -use crate::core::LintErrorPos; +use crate::core::{LintErrorPos, LinterContext}; impl ConvertibleIn for Parameter { - fn convert_in(self, ctx: &mut Context, pos: Position) -> Result { + fn convert_in(self, ctx: &mut LinterContext, pos: Position) -> Result { validation::validate(&self, ctx, pos)?; let (bare_name, var_type) = self.into(); let var_type = on_param_type(var_type, &bare_name, ctx, pos)?; diff --git a/rusty_linter/src/converter/dim_rules/param_type_rules.rs b/rusty_linter/src/converter/dim_rules/param_type_rules.rs index 16a875f8..45c4586f 100644 --- a/rusty_linter/src/converter/dim_rules/param_type_rules.rs +++ b/rusty_linter/src/converter/dim_rules/param_type_rules.rs @@ -1,14 +1,13 @@ use rusty_common::Position; use rusty_parser::{BareName, ParamType}; -use crate::converter::common::Context; use crate::converter::dim_rules::dim_type_rules; -use crate::core::LintErrorPos; +use crate::core::{LintErrorPos, LinterContext}; pub fn on_param_type( dim_type: ParamType, bare_name: &BareName, - ctx: &mut Context, + ctx: &mut LinterContext, pos: Position, ) -> Result { match dim_type { @@ -26,7 +25,7 @@ pub fn on_param_type( } fn param_array_to_param_type( - ctx: &mut Context, + ctx: &mut LinterContext, pos: Position, bare_name: &BareName, element_type: ParamType, diff --git a/rusty_linter/src/converter/dim_rules/redim.rs b/rusty_linter/src/converter/dim_rules/redim.rs index 5848fa34..502a57a1 100644 --- a/rusty_linter/src/converter/dim_rules/redim.rs +++ b/rusty_linter/src/converter/dim_rules/redim.rs @@ -1,13 +1,15 @@ use rusty_common::*; use rusty_parser::*; -use crate::converter::common::{Context, Convertible, DimNameState}; -use crate::core::{IntoTypeQualifier, LintError, LintErrorPos, ValidateStringLength}; +use crate::converter::common::{Convertible, DimNameState}; +use crate::core::{ + IntoTypeQualifier, LintError, LintErrorPos, LinterContext, RedimInfo, ValidateStringLength, VariableInfo +}; pub fn on_redim_type( var_type: DimType, bare_name: &BareName, - ctx: &mut Context, + ctx: &mut LinterContext, extra: DimNameState, ) -> Result<(DimType, Option), LintErrorPos> { if let DimType::Array(array_dimensions, element_type) = var_type { @@ -30,7 +32,7 @@ pub fn on_redim_type( } fn to_dim_type( - ctx: &mut Context, + ctx: &mut LinterContext, extra: DimNameState, bare_name: &BareName, array_dimensions: &ArrayDimensions, @@ -69,7 +71,7 @@ fn to_dim_type( } fn bare_to_dim_type( - ctx: &mut Context, + ctx: &mut LinterContext, extra: DimNameState, bare_name: &BareName, array_dimensions: &ArrayDimensions, @@ -128,7 +130,7 @@ fn bare_to_dim_type( } fn built_in_to_dim_type( - ctx: &mut Context, + ctx: &mut LinterContext, bare_name: &BareName, array_dimensions: &ArrayDimensions, q: TypeQualifier, @@ -178,7 +180,7 @@ fn require_built_in_array( } fn fixed_length_string_to_dim_type( - ctx: &mut Context, + ctx: &mut LinterContext, extra: DimNameState, bare_name: &BareName, array_dimensions: &ArrayDimensions, @@ -214,7 +216,7 @@ fn require_fixed_length_string_array( } fn user_defined_type_to_dim_type( - ctx: &mut Context, + ctx: &mut LinterContext, bare_name: &BareName, array_dimensions: &ArrayDimensions, user_defined_type: BareNamePos, diff --git a/rusty_linter/src/converter/dim_rules/validation.rs b/rusty_linter/src/converter/dim_rules/validation.rs index 6ae42c3e..645adf1d 100644 --- a/rusty_linter/src/converter/dim_rules/validation.rs +++ b/rusty_linter/src/converter/dim_rules/validation.rs @@ -1,14 +1,11 @@ use rusty_common::{AtPos, Position, Positioned}; use rusty_parser::{AsBareName, DimVar, Parameter, TypedName, VarType}; -use crate::converter::common::Context; -use crate::core::{ - ConstLookup, HasSubprograms, HasUserDefinedTypes, IntoTypeQualifier, LintError, LintErrorPos -}; +use crate::core::{ConstLookup, IntoTypeQualifier, LintError, LintErrorPos, LinterContext}; pub fn validate( var_name: &TypedName, - ctx: &Context, + ctx: &LinterContext, pos: Position, ) -> Result<(), LintErrorPos> where @@ -21,12 +18,12 @@ where cannot_clash_with_local_constants(var_name, ctx, pos) } -fn cannot_clash_with_subs( +fn cannot_clash_with_subs( var_name: &TypedName, - ctx: &C, + ctx: &LinterContext, pos: Position, ) -> Result<(), LintErrorPos> { - if ctx.subs().contains_key(var_name.as_bare_name()) { + if ctx.subs.contains_key(var_name.as_bare_name()) { Err(LintError::DuplicateDefinition.at_pos(pos)) } else { Ok(()) @@ -35,7 +32,7 @@ fn cannot_clash_with_subs( fn cannot_clash_with_local_constants( var_name: &TypedName, - ctx: &Context, + ctx: &LinterContext, pos: Position, ) -> Result<(), LintErrorPos> { match ctx.names.names().get_const_value(var_name.as_bare_name()) { @@ -45,17 +42,20 @@ fn cannot_clash_with_local_constants( } pub trait CannotClashWithFunctions { - fn cannot_clash_with_functions(&self, ctx: &Context, pos: Position) - -> Result<(), LintErrorPos>; + fn cannot_clash_with_functions( + &self, + ctx: &LinterContext, + pos: Position, + ) -> Result<(), LintErrorPos>; } impl CannotClashWithFunctions for DimVar { fn cannot_clash_with_functions( &self, - ctx: &Context, + ctx: &LinterContext, pos: Position, ) -> Result<(), LintErrorPos> { - if ctx.functions().contains_key(self.as_bare_name()) { + if ctx.functions.contains_key(self.as_bare_name()) { Err(LintError::DuplicateDefinition.at_pos(pos)) } else { Ok(()) @@ -66,7 +66,7 @@ impl CannotClashWithFunctions for DimVar { impl CannotClashWithFunctions for Parameter { fn cannot_clash_with_functions( &self, - ctx: &Context, + ctx: &LinterContext, pos: Position, ) -> Result<(), LintErrorPos> { if let Some(func_qualifier) = ctx.function_qualifier(self.as_bare_name()) { @@ -92,7 +92,7 @@ impl CannotClashWithFunctions for Parameter { fn user_defined_type_must_exist( var_name: &TypedName, - ctx: &Context, + ctx: &LinterContext, ) -> Result<(), LintErrorPos> where T: VarType, @@ -102,7 +102,7 @@ where element: type_name, pos, }) => { - if ctx.user_defined_types().contains_key(type_name) { + if ctx.user_defined_types.contains_key(type_name) { Ok(()) } else { Err(LintError::TypeNotDefined.at(pos)) diff --git a/rusty_linter/src/converter/expr_rules/binary.rs b/rusty_linter/src/converter/expr_rules/binary.rs index 87ba185d..357a2a67 100644 --- a/rusty_linter/src/converter/expr_rules/binary.rs +++ b/rusty_linter/src/converter/expr_rules/binary.rs @@ -1,10 +1,10 @@ use rusty_parser::{Expression, ExpressionPos, Operator}; -use crate::converter::common::{Context, ConvertibleIn, ExprContextPos}; -use crate::core::{LintErrorPos, binary_cast}; +use crate::converter::common::{ConvertibleIn, ExprContextPos}; +use crate::core::{LintErrorPos, LinterContext, binary_cast}; pub fn convert( - ctx: &mut Context, + ctx: &mut LinterContext, extra: ExprContextPos, binary_operator: Operator, left: ExpressionPos, diff --git a/rusty_linter/src/converter/expr_rules/built_in_function.rs b/rusty_linter/src/converter/expr_rules/built_in_function.rs index 9bc3fdfe..bdab3d86 100644 --- a/rusty_linter/src/converter/expr_rules/built_in_function.rs +++ b/rusty_linter/src/converter/expr_rules/built_in_function.rs @@ -1,14 +1,13 @@ use rusty_common::Position; use rusty_parser::{BuiltInFunction, Expression, Expressions}; -use crate::converter::common::Context; use crate::converter::expr_rules::function::{ convert_function_args, functions_must_have_arguments }; -use crate::core::LintErrorPos; +use crate::core::{LintErrorPos, LinterContext}; pub fn convert( - ctx: &mut Context, + ctx: &mut LinterContext, built_in_function: BuiltInFunction, pos: Position, args: Expressions, diff --git a/rusty_linter/src/converter/expr_rules/function.rs b/rusty_linter/src/converter/expr_rules/function.rs index b2f4d2bc..b322608c 100644 --- a/rusty_linter/src/converter/expr_rules/function.rs +++ b/rusty_linter/src/converter/expr_rules/function.rs @@ -1,14 +1,14 @@ use rusty_common::{AtPos, Position}; -use rusty_parser::{ - AsBareName, BareName, Expression, ExpressionType, Expressions, Name, VariableInfo -}; +use rusty_parser::{AsBareName, BareName, Expression, ExpressionType, Expressions, Name}; -use crate::converter::common::{Context, ConvertibleIn, ExprContext, ExprContextPos}; +use crate::converter::common::{ConvertibleIn, ExprContext, ExprContextPos}; use crate::converter::expr_rules::qualify_name::*; -use crate::core::{IntoQualified, IntoTypeQualifier, LintError, LintErrorPos, LintResult}; +use crate::core::{ + IntoQualified, IntoTypeQualifier, LintError, LintErrorPos, LintResult, LinterContext, VariableInfo +}; pub fn convert( - ctx: &mut Context, + ctx: &mut LinterContext, extra: ExprContextPos, name: Name, args: Expressions, @@ -28,7 +28,7 @@ pub fn convert( } fn resolve_function( - ctx: &mut Context, + ctx: &mut LinterContext, name: Name, args: Expressions, pos: Position, @@ -54,11 +54,11 @@ fn resolve_function( } trait FuncResolve { - fn can_handle(&mut self, ctx: &Context, name: &Name) -> bool; + fn can_handle(&mut self, ctx: &LinterContext, name: &Name) -> bool; fn resolve( &self, - ctx: &mut Context, + ctx: &mut LinterContext, extra: ExprContextPos, name: Name, args: Expressions, @@ -78,19 +78,19 @@ impl ExistingArrayWithParenthesis { } } - fn get_var_info<'a>(ctx: &'a Context, name: &Name) -> Option<&'a VariableInfo> { + fn get_var_info<'a>(ctx: &'a LinterContext, name: &Name) -> Option<&'a VariableInfo> { Self::get_extended_var_info(ctx, name.as_bare_name()) .or_else(|| Self::get_compact_var_info(ctx, name)) } fn get_extended_var_info<'a>( - ctx: &'a Context, + ctx: &'a LinterContext, bare_name: &BareName, ) -> Option<&'a VariableInfo> { ctx.names.get_extended_var_recursively(bare_name) } - fn get_compact_var_info<'a>(ctx: &'a Context, name: &Name) -> Option<&'a VariableInfo> { + fn get_compact_var_info<'a>(ctx: &'a LinterContext, name: &Name) -> Option<&'a VariableInfo> { let qualifier = name.qualify(ctx); ctx.names .get_compact_var_recursively(name.as_bare_name(), qualifier) @@ -98,14 +98,14 @@ impl ExistingArrayWithParenthesis { } impl FuncResolve for ExistingArrayWithParenthesis { - fn can_handle(&mut self, ctx: &Context, name: &Name) -> bool { + fn can_handle(&mut self, ctx: &LinterContext, name: &Name) -> bool { self.var_info = Self::get_var_info(ctx, name).cloned(); self.is_array() } fn resolve( &self, - ctx: &mut Context, + ctx: &mut LinterContext, extra: ExprContextPos, name: Name, args: Expressions, @@ -114,9 +114,7 @@ impl FuncResolve for ExistingArrayWithParenthesis { let converted_args = args.convert_in(ctx, extra.element)?; // convert name let VariableInfo { - expression_type, - shared, - redim_info, + expression_type, .. } = self.var_info.clone().unwrap(); match expression_type { ExpressionType::Array(element_type) => { @@ -126,11 +124,7 @@ impl FuncResolve for ExistingArrayWithParenthesis { let result_expr = Expression::ArrayElement( converted_name, converted_args, - VariableInfo { - expression_type: element_type.as_ref().clone(), - shared, - redim_info, - }, + element_type.as_ref().clone(), ); Ok(result_expr) } @@ -151,7 +145,7 @@ pub fn functions_must_have_arguments( } pub fn convert_function_args( - ctx: &mut Context, + ctx: &mut LinterContext, args: Expressions, ) -> Result { args.convert_in(ctx, ExprContext::Argument) diff --git a/rusty_linter/src/converter/expr_rules/main.rs b/rusty_linter/src/converter/expr_rules/main.rs index 7525caad..0e1567d4 100644 --- a/rusty_linter/src/converter/expr_rules/main.rs +++ b/rusty_linter/src/converter/expr_rules/main.rs @@ -1,11 +1,11 @@ use rusty_common::*; use rusty_parser::*; -use crate::converter::common::{Context, ConvertibleIn, ExprContext, ExprContextPos}; +use crate::converter::common::{ConvertibleIn, ExprContext, ExprContextPos}; use crate::converter::expr_rules::{ binary, built_in_function, function, property, unary, variable }; -use crate::core::LintErrorPos; +use crate::core::{LintErrorPos, LinterContext}; // // ExpressionPos ConvertibleIn @@ -14,7 +14,7 @@ use crate::core::LintErrorPos; impl ConvertibleIn for ExpressionPos { fn convert_in( self, - ctx: &mut Context, + ctx: &mut LinterContext, expr_context: ExprContext, ) -> Result { let Self { element: expr, pos } = self; @@ -26,7 +26,7 @@ impl ConvertibleIn for ExpressionPos { impl ConvertibleIn for Box { fn convert_in( self, - ctx: &mut Context, + ctx: &mut LinterContext, expr_context: ExprContext, ) -> Result { let unboxed = *self; @@ -39,7 +39,11 @@ impl ConvertibleIn for Box { // impl ConvertibleIn for Expression { - fn convert_in(self, ctx: &mut Context, extra: ExprContextPos) -> Result { + fn convert_in( + self, + ctx: &mut LinterContext, + extra: ExprContextPos, + ) -> Result { match self { // literals Self::SingleLiteral(_) @@ -60,10 +64,10 @@ impl ConvertibleIn for Expression { binary::convert(ctx, extra, binary_operator, *left, *right) } // variables - Self::Variable(name, variable_info) => { - variable::convert(ctx, extra, name, variable_info) + Self::Variable(name, expression_type) => { + variable::convert(ctx, extra, name, expression_type) } - Self::ArrayElement(_name, _indices, _variable_info) => { + Self::ArrayElement(_name, _indices, _expression_type) => { panic!( "Parser is not supposed to produce any ArrayElement expressions, only FunctionCall" ) diff --git a/rusty_linter/src/converter/expr_rules/property.rs b/rusty_linter/src/converter/expr_rules/property.rs index 6a3eff20..ce7b7a45 100644 --- a/rusty_linter/src/converter/expr_rules/property.rs +++ b/rusty_linter/src/converter/expr_rules/property.rs @@ -1,16 +1,16 @@ use rusty_common::{AtPos, Position, Positioned}; use rusty_parser::{ - AsBareName, BareName, ElementType, Expression, ExpressionType, HasExpressionType, Name, ToBareName, UserDefinedType, VariableInfo + AsBareName, BareName, ElementType, Expression, ExpressionType, HasExpressionType, Name, ToBareName, UserDefinedType }; -use crate::converter::common::{Context, ConvertibleIn, ExprContext, ExprContextPos}; +use crate::converter::common::{ConvertibleIn, ExprContext, ExprContextPos}; use crate::converter::expr_rules::variable::{ AssignToFunction, ExistingConst, ExistingVar, VarAsUserDefinedFunctionCall, VarResolve, add_as_new_implicit_var }; -use crate::core::{HasUserDefinedTypes, LintError, LintErrorPos}; +use crate::core::{LintError, LintErrorPos, LinterContext}; pub fn convert( - ctx: &mut Context, + ctx: &mut LinterContext, extra: ExprContextPos, left_side: Box, property_name: Name, @@ -48,12 +48,7 @@ pub fn convert( // functions cannot return udf so no need to check them match &resolved_left_side { - Expression::Variable( - _name, - VariableInfo { - expression_type, .. - }, - ) => { + Expression::Variable(_name, expression_type) => { let temp_expression_type = expression_type.clone(); existing_property_expression_type( ctx, @@ -64,13 +59,7 @@ pub fn convert( true, ) } - Expression::ArrayElement( - _name, - _indices, - VariableInfo { - expression_type, .. - }, - ) => { + Expression::ArrayElement(_name, _indices, expression_type) => { let temp_expression_type = expression_type.clone(); existing_property_expression_type( ctx, @@ -107,7 +96,7 @@ fn try_fold(left_side: &Expression, property_name: Name) -> Option { } fn existing_property_expression_type( - ctx: &mut Context, + ctx: &mut LinterContext, extra: ExprContextPos, resolved_left_side: Expression, expression_type: &ExpressionType, @@ -139,13 +128,13 @@ fn existing_property_expression_type( } fn existing_property_user_defined_type_name( - ctx: &Context, + ctx: &LinterContext, resolved_left_side: Expression, user_defined_type_name: &BareName, property_name: Name, pos: Position, ) -> Result { - match ctx.user_defined_types().get(user_defined_type_name) { + match ctx.user_defined_types.get(user_defined_type_name) { Some(user_defined_type) => existing_property_user_defined_type( resolved_left_side, user_defined_type, diff --git a/rusty_linter/src/converter/expr_rules/qualify_name.rs b/rusty_linter/src/converter/expr_rules/qualify_name.rs index 4c18b79c..ec61f3cb 100644 --- a/rusty_linter/src/converter/expr_rules/qualify_name.rs +++ b/rusty_linter/src/converter/expr_rules/qualify_name.rs @@ -1,6 +1,6 @@ use rusty_parser::{AsBareName, BuiltInFunction, ExpressionType, Name, ToBareName, TypeQualifier}; -use crate::LintError; +use crate::core::LintError; /// Validates and normalizes the given name pub fn qualify_name(expression_type: &ExpressionType, name: Name) -> Result { diff --git a/rusty_linter/src/converter/expr_rules/unary.rs b/rusty_linter/src/converter/expr_rules/unary.rs index 9792d209..8a60e6f2 100644 --- a/rusty_linter/src/converter/expr_rules/unary.rs +++ b/rusty_linter/src/converter/expr_rules/unary.rs @@ -3,11 +3,11 @@ use rusty_parser::{ Expression, ExpressionPos, ExpressionType, HasExpressionType, TypeQualifier, UnaryOperator }; -use crate::converter::common::{Context, ConvertibleIn, ExprContextPos}; -use crate::core::{LintError, LintErrorPos}; +use crate::converter::common::{ConvertibleIn, ExprContextPos}; +use crate::core::{LintError, LintErrorPos, LinterContext}; pub fn convert( - ctx: &mut Context, + ctx: &mut LinterContext, extra: ExprContextPos, unary_operator: UnaryOperator, child: ExpressionPos, diff --git a/rusty_linter/src/converter/expr_rules/variable.rs b/rusty_linter/src/converter/expr_rules/variable.rs index 54760fc8..0c46e3f1 100644 --- a/rusty_linter/src/converter/expr_rules/variable.rs +++ b/rusty_linter/src/converter/expr_rules/variable.rs @@ -1,20 +1,20 @@ use rusty_common::{AtPos, Position}; use rusty_parser::{ - AsBareName, BuiltInFunction, BuiltInStyle, DimType, Expression, ExpressionType, Name, TypeQualifier, VariableInfo + AsBareName, BuiltInFunction, BuiltInStyle, DimType, Expression, ExpressionType, Name, TypeQualifier }; use rusty_variant::Variant; -use crate::converter::common::{Context, ExprContext, ExprContextPos}; +use crate::converter::common::{ExprContext, ExprContextPos}; use crate::converter::expr_rules::qualify_name::*; use crate::core::{ - ConstLookup, HasSubprograms, IntoQualified, IntoTypeQualifier, LintError, LintErrorPos, LintResult, qualifier_of_const_variant + ConstLookup, IntoQualified, IntoTypeQualifier, LintError, LintErrorPos, LintResult, LinterContext, VariableInfo, qualifier_of_const_variant }; pub fn convert( - ctx: &mut Context, + ctx: &mut LinterContext, extra: ExprContextPos, name: Name, - variable_info: VariableInfo, + expression_type: ExpressionType, ) -> Result { // validation rules validate(ctx, &name, extra.pos)?; @@ -42,19 +42,23 @@ pub fn convert( Ok(add_as_new_implicit_var(ctx, extra, name)) } else { // repack as unresolved - Ok(Expression::Variable(name, variable_info)) + Ok(Expression::Variable(name, expression_type)) } } -fn validate(ctx: &Context, name: &Name, pos: Position) -> Result<(), LintErrorPos> { - if ctx.subs().contains_key(name.as_bare_name()) { +fn validate(ctx: &LinterContext, name: &Name, pos: Position) -> Result<(), LintErrorPos> { + if ctx.subs.contains_key(name.as_bare_name()) { return Err(LintError::DuplicateDefinition.at_pos(pos)); } Ok(()) } -pub fn add_as_new_implicit_var(ctx: &mut Context, extra: ExprContextPos, name: Name) -> Expression { +pub fn add_as_new_implicit_var( + ctx: &mut LinterContext, + extra: ExprContextPos, + name: Name, +) -> Expression { let resolved_name = name.to_qualified(ctx); let bare_name = resolved_name.as_bare_name(); @@ -66,20 +70,20 @@ pub fn add_as_new_implicit_var(ctx: &mut Context, extra: ExprContextPos, name: N None, ); - let var_info = VariableInfo::new_built_in(q, false); + let expression_type = ExpressionType::BuiltIn(q); let pos = extra.pos; ctx.names .get_implicit_vars_mut() .push(resolved_name.clone().demand_qualified().at_pos(pos)); - Expression::Variable(resolved_name, var_info) + Expression::Variable(resolved_name, expression_type) } pub trait VarResolve { - fn can_handle(&mut self, ctx: &Context, name: &Name) -> bool; + fn can_handle(&mut self, ctx: &LinterContext, name: &Name) -> bool; fn resolve( &self, - ctx: &mut Context, + ctx: &mut LinterContext, extra: ExprContextPos, name: Name, ) -> Result; @@ -91,7 +95,7 @@ pub struct ExistingVar { } impl VarResolve for ExistingVar { - fn can_handle(&mut self, ctx: &Context, name: &Name) -> bool { + fn can_handle(&mut self, ctx: &LinterContext, name: &Name) -> bool { let bare_name = name.as_bare_name(); self.var_info = ctx.names.get_extended_var_recursively(bare_name).cloned(); if self.var_info.is_some() { @@ -105,14 +109,14 @@ impl VarResolve for ExistingVar { fn resolve( &self, - _ctx: &mut Context, + _ctx: &mut LinterContext, extra: ExprContextPos, name: Name, ) -> Result { let variable_info = self.var_info.clone().unwrap(); - let expression_type = &variable_info.expression_type; - let converted_name = qualify_name(expression_type, name).with_err_at(&extra.pos)?; - Ok(Expression::Variable(converted_name, variable_info)) + let expression_type = variable_info.expression_type; + let converted_name = qualify_name(&expression_type, name).with_err_at(&extra.pos)?; + Ok(Expression::Variable(converted_name, expression_type)) } } @@ -138,7 +142,7 @@ impl ExistingConst { } impl VarResolve for ExistingConst { - fn can_handle(&mut self, ctx: &Context, name: &Name) -> bool { + fn can_handle(&mut self, ctx: &LinterContext, name: &Name) -> bool { self.opt_v = if self.use_recursion { ctx.names .get_const_value_recursively(name.as_bare_name()) @@ -154,7 +158,7 @@ impl VarResolve for ExistingConst { fn resolve( &self, - _ctx: &mut Context, + _ctx: &mut LinterContext, extra: ExprContextPos, name: Name, ) -> Result { @@ -186,7 +190,7 @@ pub struct AssignToFunction { } impl VarResolve for AssignToFunction { - fn can_handle(&mut self, ctx: &Context, name: &Name) -> bool { + fn can_handle(&mut self, ctx: &LinterContext, name: &Name) -> bool { let bare_name = name.as_bare_name(); match ctx.function_qualifier(bare_name) { Some(function_qualifier) => { @@ -199,7 +203,7 @@ impl VarResolve for AssignToFunction { fn resolve( &self, - ctx: &mut Context, + ctx: &mut LinterContext, extra: ExprContextPos, name: Name, ) -> Result { @@ -207,15 +211,15 @@ impl VarResolve for AssignToFunction { if ctx.names.is_in_function(name.as_bare_name()) { let converted_name = try_qualify(name, function_qualifier).with_err_at(&extra.pos)?; let expr_type = ExpressionType::BuiltIn(function_qualifier); - let variable_info = VariableInfo::new_local(expr_type); + let variable_info = VariableInfo::new_local(expr_type.clone()); // store this in the name context too to make it easier for instruction generator // TODO add unit test // TODO what if the name already exists? ctx.names - .insert_compact(converted_name.as_bare_name().clone(), variable_info.clone()); + .insert_compact(converted_name.as_bare_name().clone(), variable_info); - let expr = Expression::Variable(converted_name, variable_info); + let expr = Expression::Variable(converted_name, expr_type); Ok(expr) } else { @@ -230,14 +234,14 @@ pub struct VarAsBuiltInFunctionCall { } impl VarResolve for VarAsBuiltInFunctionCall { - fn can_handle(&mut self, _ctx: &Context, name: &Name) -> bool { + fn can_handle(&mut self, _ctx: &LinterContext, name: &Name) -> bool { self.built_in_function = BuiltInFunction::try_parse(name.as_bare_name()); self.built_in_function.is_some() } fn resolve( &self, - _ctx: &mut Context, + _ctx: &mut LinterContext, extra: ExprContextPos, name: Name, ) -> Result { @@ -256,14 +260,14 @@ pub struct VarAsUserDefinedFunctionCall { } impl VarResolve for VarAsUserDefinedFunctionCall { - fn can_handle(&mut self, ctx: &Context, name: &Name) -> bool { + fn can_handle(&mut self, ctx: &LinterContext, name: &Name) -> bool { self.function_qualifier = ctx.function_qualifier(name.as_bare_name()); self.function_qualifier.is_some() } fn resolve( &self, - _ctx: &mut Context, + _ctx: &mut LinterContext, extra: ExprContextPos, name: Name, ) -> Result { diff --git a/rusty_linter/src/converter/mod.rs b/rusty_linter/src/converter/mod.rs index 9b8b02bd..3c6ba7d0 100644 --- a/rusty_linter/src/converter/mod.rs +++ b/rusty_linter/src/converter/mod.rs @@ -1,21 +1,7 @@ //! Converter is the main logic of the linter, where most validation takes place, //! as well as resolving variable types. -mod common; +//! To convert a program, invoke the convert method of the Convertible trait on it. +pub mod common; mod dim_rules; mod expr_rules; mod statement; - -use rusty_parser::Program; - -pub use self::common::Context; -use crate::converter::common::Convertible; -use crate::core::LintErrorPos; -use crate::pre_linter::PreLinterResult; - -pub fn convert( - program: Program, - pre_linter_result: PreLinterResult, -) -> Result<(Context, Program), LintErrorPos> { - let mut context = Context::new(pre_linter_result); - program.convert(&mut context).map(|p| (context, p)) -} diff --git a/rusty_linter/src/converter/statement/assignment.rs b/rusty_linter/src/converter/statement/assignment.rs index 37e416dc..bd0db5f6 100644 --- a/rusty_linter/src/converter/statement/assignment.rs +++ b/rusty_linter/src/converter/statement/assignment.rs @@ -1,12 +1,12 @@ use rusty_common::{AtPos, Position, Positioned}; use rusty_parser::{Assignment, Expression, ExpressionPos, Statement}; -use crate::converter::common::{Context, ConvertibleIn, ExprContext}; -use crate::core::LintErrorPos; +use crate::converter::common::{ConvertibleIn, ExprContext}; +use crate::core::{LintErrorPos, LinterContext}; pub fn on_assignment( a: Assignment, - ctx: &mut Context, + ctx: &mut LinterContext, pos: Position, ) -> Result { let (left, right) = a.into(); @@ -27,7 +27,7 @@ mod assignment_pre_conversion_validation_rules { use crate::core::LintError; pub fn validate( - ctx: &mut Context, + ctx: &mut LinterContext, left_side: &Expression, pos: Position, ) -> Result<(), LintErrorPos> { @@ -35,7 +35,7 @@ mod assignment_pre_conversion_validation_rules { } fn cannot_assign_to_const( - ctx: &mut Context, + ctx: &mut LinterContext, input: &Expression, pos: Position, ) -> Result<(), LintErrorPos> { diff --git a/rusty_linter/src/converter/statement/const_rules.rs b/rusty_linter/src/converter/statement/const_rules.rs index aacb61b8..7daa75cb 100644 --- a/rusty_linter/src/converter/statement/const_rules.rs +++ b/rusty_linter/src/converter/statement/const_rules.rs @@ -1,19 +1,18 @@ use rusty_common::*; use rusty_parser::*; -use crate::converter::common::Context; use crate::core::{ - CastVariant, ConstEvaluator, HasSubprograms, LintError, LintErrorPos, LintResult, qualifier_of_const_variant + CastVariant, ConstEvaluator, LintError, LintErrorPos, LintResult, LinterContext, qualifier_of_const_variant }; -pub fn on_const(ctx: &mut Context, c: Constant) -> Result { +pub fn on_const(ctx: &mut LinterContext, c: Constant) -> Result { let (left_side, right_side) = c.into(); const_cannot_clash_with_existing_names(ctx, &left_side)?; new_const(ctx, left_side, right_side) } fn const_cannot_clash_with_existing_names( - ctx: &mut Context, + ctx: &mut LinterContext, left_side: &NamePos, ) -> Result<(), LintErrorPos> { let Positioned { @@ -23,8 +22,8 @@ fn const_cannot_clash_with_existing_names( if ctx .names .contains_any_locally_or_contains_extended_recursively(const_name.as_bare_name()) - || ctx.subs().contains_key(const_name.as_bare_name()) - || ctx.functions().contains_key(const_name.as_bare_name()) + || ctx.subs.contains_key(const_name.as_bare_name()) + || ctx.functions.contains_key(const_name.as_bare_name()) { Err(LintError::DuplicateDefinition.at(const_name_pos)) } else { @@ -33,7 +32,7 @@ fn const_cannot_clash_with_existing_names( } fn new_const( - ctx: &mut Context, + ctx: &mut LinterContext, left_side: NamePos, right_side: ExpressionPos, ) -> Result { diff --git a/rusty_linter/src/converter/statement/do_loop.rs b/rusty_linter/src/converter/statement/do_loop.rs index fe6aadda..e63d9dd4 100644 --- a/rusty_linter/src/converter/statement/do_loop.rs +++ b/rusty_linter/src/converter/statement/do_loop.rs @@ -1,10 +1,10 @@ use rusty_parser::DoLoop; -use crate::converter::common::{Context, Convertible, ConvertibleIn}; -use crate::core::LintErrorPos; +use crate::converter::common::{Convertible, ConvertibleIn}; +use crate::core::{LintErrorPos, LinterContext}; impl Convertible for DoLoop { - fn convert(self, ctx: &mut Context) -> Result { + fn convert(self, ctx: &mut LinterContext) -> Result { Ok(Self { condition: self.condition.convert_in_default(ctx)?, statements: self.statements.convert(ctx)?, diff --git a/rusty_linter/src/converter/statement/for_loop.rs b/rusty_linter/src/converter/statement/for_loop.rs index f452c562..522fcd44 100644 --- a/rusty_linter/src/converter/statement/for_loop.rs +++ b/rusty_linter/src/converter/statement/for_loop.rs @@ -1,10 +1,10 @@ use rusty_parser::ForLoop; -use crate::converter::common::{Context, Convertible, ConvertibleIn, ExprContext}; -use crate::core::LintErrorPos; +use crate::converter::common::{Convertible, ConvertibleIn, ExprContext}; +use crate::core::{LintErrorPos, LinterContext}; impl Convertible for ForLoop { - fn convert(self, ctx: &mut Context) -> Result { + fn convert(self, ctx: &mut LinterContext) -> Result { let variable_name = self .variable_name .convert_in(ctx, ExprContext::Assignment)?; diff --git a/rusty_linter/src/converter/statement/if_blocks.rs b/rusty_linter/src/converter/statement/if_blocks.rs index 4377ee7b..acd886c8 100644 --- a/rusty_linter/src/converter/statement/if_blocks.rs +++ b/rusty_linter/src/converter/statement/if_blocks.rs @@ -1,10 +1,10 @@ use rusty_parser::{ConditionalBlock, IfBlock}; -use crate::converter::common::{Context, Convertible, ConvertibleIn}; -use crate::core::LintErrorPos; +use crate::converter::common::{Convertible, ConvertibleIn}; +use crate::core::{LintErrorPos, LinterContext}; impl Convertible for ConditionalBlock { - fn convert(self, ctx: &mut Context) -> Result { + fn convert(self, ctx: &mut LinterContext) -> Result { Ok(Self { condition: self.condition.convert_in_default(ctx)?, statements: self.statements.convert(ctx)?, @@ -13,7 +13,7 @@ impl Convertible for ConditionalBlock { } impl Convertible for IfBlock { - fn convert(self, ctx: &mut Context) -> Result { + fn convert(self, ctx: &mut LinterContext) -> Result { let if_block = self.if_block.convert(ctx)?; let else_if_blocks = self.else_if_blocks.convert(ctx)?; let else_block = self.else_block.convert(ctx)?; diff --git a/rusty_linter/src/converter/statement/main.rs b/rusty_linter/src/converter/statement/main.rs index 7dbdcda6..768e75ad 100644 --- a/rusty_linter/src/converter/statement/main.rs +++ b/rusty_linter/src/converter/statement/main.rs @@ -1,12 +1,12 @@ use rusty_common::*; use rusty_parser::{ExitObject, Statement}; -use crate::converter::common::{Context, Convertible, ConvertibleIn, DimContext, ExprContext}; +use crate::converter::common::{Convertible, ConvertibleIn, DimContext, ExprContext}; use crate::converter::statement::{assignment, const_rules}; -use crate::core::{LintError, LintErrorPos, NameContext}; +use crate::core::{LintError, LintErrorPos, LinterContext, ScopeKind}; impl ConvertibleIn for Statement { - fn convert_in(self, ctx: &mut Context, pos: Position) -> Result { + fn convert_in(self, ctx: &mut LinterContext, pos: Position) -> Result { match self { Self::Assignment(a) => assignment::on_assignment(a, ctx, pos), // CONST is mapped to None and is filtered out @@ -37,16 +37,16 @@ impl ConvertibleIn for Statement { Ok(Self::Resume(resume_option)) } } - Self::Exit(exit_object) => match ctx.names.get_name_context() { - NameContext::Global => Err(LintError::IllegalOutsideSubFunction.at_pos(pos)), - NameContext::Sub => { + Self::Exit(exit_object) => match ctx.names.get_current_scope_kind() { + ScopeKind::Global => Err(LintError::IllegalOutsideSubFunction.at_pos(pos)), + ScopeKind::Sub => { if exit_object == ExitObject::Sub { Ok(Self::Exit(exit_object)) } else { Err(LintError::IllegalInSubFunction.at_pos(pos)) } } - NameContext::Function => { + ScopeKind::Function => { if exit_object == ExitObject::Function { Ok(Self::Exit(exit_object)) } else { diff --git a/rusty_linter/src/converter/statement/print.rs b/rusty_linter/src/converter/statement/print.rs index 35981fb0..a416766b 100644 --- a/rusty_linter/src/converter/statement/print.rs +++ b/rusty_linter/src/converter/statement/print.rs @@ -1,10 +1,10 @@ use rusty_parser::{Print, PrintArg}; -use crate::converter::common::{Context, Convertible, ConvertibleIn}; -use crate::core::LintErrorPos; +use crate::converter::common::{Convertible, ConvertibleIn}; +use crate::core::{LintErrorPos, LinterContext}; impl Convertible for Print { - fn convert(self, ctx: &mut Context) -> Result { + fn convert(self, ctx: &mut LinterContext) -> Result { Ok(Self { format_string: self.format_string.convert_in_default(ctx)?, args: self.args.convert(ctx)?, @@ -14,7 +14,7 @@ impl Convertible for Print { } impl Convertible for PrintArg { - fn convert(self, ctx: &mut Context) -> Result { + fn convert(self, ctx: &mut LinterContext) -> Result { match self { Self::Expression(e) => e.convert_in_default(ctx).map(Self::Expression), _ => Ok(self), diff --git a/rusty_linter/src/converter/statement/select_case.rs b/rusty_linter/src/converter/statement/select_case.rs index e413764d..7e7ec275 100644 --- a/rusty_linter/src/converter/statement/select_case.rs +++ b/rusty_linter/src/converter/statement/select_case.rs @@ -1,10 +1,10 @@ use rusty_parser::{CaseBlock, CaseExpression, SelectCase}; -use crate::converter::common::{Context, Convertible, ConvertibleIn}; -use crate::core::LintErrorPos; +use crate::converter::common::{Convertible, ConvertibleIn}; +use crate::core::{LintErrorPos, LinterContext}; impl Convertible for SelectCase { - fn convert(self, ctx: &mut Context) -> Result { + fn convert(self, ctx: &mut LinterContext) -> Result { let expr = self.expr.convert_in_default(ctx)?; let case_blocks = self.case_blocks.convert(ctx)?; let else_block = self.else_block.convert(ctx)?; @@ -19,7 +19,7 @@ impl Convertible for SelectCase { } impl Convertible for CaseBlock { - fn convert(self, ctx: &mut Context) -> Result { + fn convert(self, ctx: &mut LinterContext) -> Result { let (expression_list, statements) = self.into(); let expression_list = expression_list.convert(ctx)?; let statements = statements.convert(ctx)?; @@ -28,7 +28,7 @@ impl Convertible for CaseBlock { } impl Convertible for CaseExpression { - fn convert(self, ctx: &mut Context) -> Result { + fn convert(self, ctx: &mut LinterContext) -> Result { match self { Self::Simple(e) => e.convert_in_default(ctx).map(CaseExpression::Simple), Self::Is(op, e) => e.convert_in_default(ctx).map(|e| Self::Is(op, e)), diff --git a/rusty_linter/src/converter/statement/sub_call.rs b/rusty_linter/src/converter/statement/sub_call.rs index f4a12b9d..3602158c 100644 --- a/rusty_linter/src/converter/statement/sub_call.rs +++ b/rusty_linter/src/converter/statement/sub_call.rs @@ -1,9 +1,9 @@ use rusty_parser::{BuiltInSub, Statement, SubCall}; -use crate::converter::common::{Context, ConvertibleIn, ExprContext}; -use crate::core::LintErrorPos; +use crate::converter::common::{ConvertibleIn, ExprContext}; +use crate::core::{LintErrorPos, LinterContext}; -impl Context { +impl LinterContext { pub fn sub_call(&mut self, sub_call: SubCall) -> Result { let (sub_name, args) = sub_call.into(); let converted_args = args.convert_in(self, ExprContext::Argument)?; diff --git a/rusty_linter/src/core/traits.rs b/rusty_linter/src/core/can_cast_to.rs similarity index 91% rename from rusty_linter/src/core/traits.rs rename to rusty_linter/src/core/can_cast_to.rs index c47fb768..9bc99236 100644 --- a/rusty_linter/src/core/traits.rs +++ b/rusty_linter/src/core/can_cast_to.rs @@ -1,17 +1,6 @@ -use rusty_parser::{ - Expression, ExpressionPos, ExpressionType, HasExpressionType, TypeQualifier, UserDefinedTypes -}; +use rusty_parser::{Expression, ExpressionPos, ExpressionType, HasExpressionType, TypeQualifier}; -use crate::core::{ResolvedParamType, SignatureMap}; - -pub trait HasSubprograms { - fn functions(&self) -> &SignatureMap; - fn subs(&self) -> &SignatureMap; -} - -pub trait HasUserDefinedTypes { - fn user_defined_types(&self) -> &UserDefinedTypes; -} +use crate::core::ResolvedParamType; /// Checks if a type can be cast into another type. pub trait CanCastTo { diff --git a/rusty_linter/src/core/linter_context.rs b/rusty_linter/src/core/linter_context.rs new file mode 100644 index 00000000..82930897 --- /dev/null +++ b/rusty_linter/src/core/linter_context.rs @@ -0,0 +1,46 @@ +use rusty_parser::*; + +use crate::core::*; +use crate::names::Names; + +pub struct LinterContext { + pub functions: SignatureMap, + pub subs: SignatureMap, + pub user_defined_types: UserDefinedTypes, + pub resolver: TypeResolverImpl, + pub names: Names, +} + +impl TypeResolver for LinterContext { + fn char_to_qualifier(&self, ch: char) -> TypeQualifier { + self.resolver.char_to_qualifier(ch) + } +} + +impl LinterContext { + pub fn new( + functions: SignatureMap, + subs: SignatureMap, + user_defined_types: UserDefinedTypes, + ) -> Self { + Self { + functions, + subs, + user_defined_types, + resolver: TypeResolverImpl::new(), + names: Names::new(), + } + } + + pub fn is_in_subprogram(&self) -> bool { + self.names.is_in_subprogram() + } + + /// Gets the function qualifier of the function identified by the given bare name. + /// If no such function exists, returns `None`. + pub fn function_qualifier(&self, bare_name: &BareName) -> Option { + self.functions + .get(bare_name) + .and_then(|function_signature_pos| function_signature_pos.element.qualifier()) + } +} diff --git a/rusty_linter/src/core/main.rs b/rusty_linter/src/core/main.rs new file mode 100644 index 00000000..81cce93b --- /dev/null +++ b/rusty_linter/src/core/main.rs @@ -0,0 +1,15 @@ +use rusty_parser::Program; + +use crate::converter::common::Convertible; +use crate::core::{LintErrorPos, LinterContext}; +use crate::post_linter::post_linter; +use crate::pre_linter::pre_lint_program; + +pub fn lint(program: Program) -> Result<(Program, LinterContext), LintErrorPos> { + // first pass, get user defined types and functions/subs + let mut context = pre_lint_program(&program)?; + // convert to fully typed + let program = program.convert(&mut context)?; + // lint and reduce + post_linter(program, &context).map(|program| (program, context)) +} diff --git a/rusty_linter/src/core/mod.rs b/rusty_linter/src/core/mod.rs index 868c23ab..1b48dcea 100644 --- a/rusty_linter/src/core/mod.rs +++ b/rusty_linter/src/core/mod.rs @@ -1,31 +1,35 @@ +mod can_cast_to; mod casting; mod const_value_resolver; mod error; -mod name_context; +mod linter_context; +mod main; +mod name_scope; mod qb_casting; mod qualify_variant; mod ref_to_value_visitor; mod resolved_param_type; mod signature; mod string_length; -mod subprogram_name; -mod traits; mod type_resolver; mod type_resolver_impl; +mod variable_info; mod visitor; +pub use self::can_cast_to::*; pub use self::casting::*; pub use self::const_value_resolver::*; pub use self::error::*; -pub use self::name_context::*; +pub use self::linter_context::*; +pub use self::main::*; +pub use self::name_scope::*; pub use self::qb_casting::*; pub use self::qualify_variant::*; pub use self::ref_to_value_visitor::*; pub use self::resolved_param_type::*; pub use self::signature::*; pub use self::string_length::*; -pub use self::subprogram_name::*; -pub use self::traits::*; pub use self::type_resolver::*; pub use self::type_resolver_impl::*; +pub use self::variable_info::*; pub use self::visitor::*; diff --git a/rusty_linter/src/core/name_context.rs b/rusty_linter/src/core/name_context.rs deleted file mode 100644 index d8232045..00000000 --- a/rusty_linter/src/core/name_context.rs +++ /dev/null @@ -1,6 +0,0 @@ -#[derive(Clone, Copy, Debug, Eq, PartialEq)] -pub enum NameContext { - Global, - Sub, - Function, -} diff --git a/rusty_linter/src/core/name_scope.rs b/rusty_linter/src/core/name_scope.rs new file mode 100644 index 00000000..454fb143 --- /dev/null +++ b/rusty_linter/src/core/name_scope.rs @@ -0,0 +1,31 @@ +use rusty_parser::{BareName, Name}; + +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum ScopeKind { + Global, + Sub, + Function, +} + +/// Holds the resolved name of a subprogram. +#[derive(Clone, Debug, Eq, Hash, PartialEq)] +pub enum ScopeName { + /// The global scope. + Global, + + /// The resolved qualified name of a function. + Function(Name), + + /// The resolved name of a sub. + Sub(BareName), +} + +impl From<&ScopeName> for ScopeKind { + fn from(scope_name: &ScopeName) -> Self { + match scope_name { + ScopeName::Global => Self::Global, + ScopeName::Function(_) => Self::Function, + ScopeName::Sub(_) => Self::Sub, + } + } +} diff --git a/rusty_linter/src/core/signature.rs b/rusty_linter/src/core/signature.rs index 866201dc..4bbab99f 100644 --- a/rusty_linter/src/core/signature.rs +++ b/rusty_linter/src/core/signature.rs @@ -8,35 +8,28 @@ use crate::core::ResolvedParamTypes; /// The signature of a FUNCTION or SUB. /// Consists of the resolved parameter types and, in case of a FUNCTION, the return type. #[derive(PartialEq)] -pub struct Signature { - /// The return type of a FUNCTION, or None if this is the signature of a SUB. - q: Option, +pub enum Signature { + /// The signature of a FUNCTION consists of the resolved parameter types + /// and the return type. + Function(ResolvedParamTypes, TypeQualifier), - /// The resolved parameter types. - param_types: ResolvedParamTypes, + /// The signature of a SUB consists of the resolved parameter types. + Sub(ResolvedParamTypes), } impl Signature { - pub fn new_sub(param_types: ResolvedParamTypes) -> Self { - Self { - q: None, - param_types, - } - } - - pub fn new_function(q: TypeQualifier, param_types: ResolvedParamTypes) -> Self { - Self { - q: Some(q), - param_types, - } - } - pub fn qualifier(&self) -> Option { - self.q.as_ref().copied() + match self { + Self::Function(_, q) => Some(*q), + Self::Sub(_) => None, + } } pub fn param_types(&self) -> &ResolvedParamTypes { - &self.param_types + match self { + Self::Function(param_types, _) => param_types, + Self::Sub(param_types) => param_types, + } } } @@ -46,9 +39,12 @@ impl Signature { impl PartialEq for Signature { fn eq(&self, other: &TypeQualifier) -> bool { - match &self.q { - Some(q) => q == other, - _ => false, + if let Self::Function(_, q) = self + && q == other + { + true + } else { + false } } } diff --git a/rusty_linter/src/core/subprogram_name.rs b/rusty_linter/src/core/subprogram_name.rs deleted file mode 100644 index 9e80faa7..00000000 --- a/rusty_linter/src/core/subprogram_name.rs +++ /dev/null @@ -1,11 +0,0 @@ -use rusty_parser::{BareName, Name}; - -/// Holds the resolved name of a subprogram. -#[derive(Clone, Debug, Eq, Hash, PartialEq)] -pub enum SubprogramName { - /// The resolved qualified name of a function. - Function(Name), - - /// The resolved name of a sub. - Sub(BareName), -} diff --git a/rusty_parser/src/core/variable_info.rs b/rusty_linter/src/core/variable_info.rs similarity index 95% rename from rusty_parser/src/core/variable_info.rs rename to rusty_linter/src/core/variable_info.rs index a5b3c9dc..60a4215b 100644 --- a/rusty_parser/src/core/variable_info.rs +++ b/rusty_linter/src/core/variable_info.rs @@ -1,4 +1,4 @@ -use crate::{BareName, ExpressionType, TypeQualifier}; +use rusty_parser::{BareName, ExpressionType, TypeQualifier}; /// Additional info for variable expression #[derive(Clone, Debug, PartialEq)] diff --git a/rusty_linter/src/core/visitor.rs b/rusty_linter/src/core/visitor.rs index de41a7aa..cfcb6712 100644 --- a/rusty_linter/src/core/visitor.rs +++ b/rusty_linter/src/core/visitor.rs @@ -1,7 +1,7 @@ use rusty_common::{Position, Positioned}; use rusty_parser::*; -use crate::LintErrorPos; +use crate::core::LintErrorPos; /// The result of a visitor. pub type VisitResult = Result<(), LintErrorPos>; diff --git a/rusty_linter/src/lib.rs b/rusty_linter/src/lib.rs index 52a502e8..f487353e 100644 --- a/rusty_linter/src/lib.rs +++ b/rusty_linter/src/lib.rs @@ -1,29 +1,8 @@ mod built_ins; mod converter; -mod core; -mod names; +pub mod core; +pub mod names; mod post_linter; mod pre_linter; #[cfg(test)] mod tests; - -use rusty_parser::Program; - -pub use self::converter::Context; -pub use self::core::{ - CastVariant, HasUserDefinedTypes, LintError, QBNumberCast, SubprogramName, qualifier_of_variant -}; -pub use self::names::Names; -use crate::converter::convert; -use crate::core::LintErrorPos; -use crate::post_linter::post_linter; -use crate::pre_linter::pre_lint_program; - -pub fn lint(program: Program) -> Result<(Program, Context), LintErrorPos> { - // first pass, get user defined types and functions/subs - let pre_linter_result = pre_lint_program(&program)?; - // convert to fully typed - let (context, program) = convert(program, pre_linter_result)?; - // lint and reduce - post_linter(program, &context).map(|program| (program, context)) -} diff --git a/rusty_linter/src/names/compacts.rs b/rusty_linter/src/names/compacts.rs index 4e32d7bd..f112eea0 100644 --- a/rusty_linter/src/names/compacts.rs +++ b/rusty_linter/src/names/compacts.rs @@ -1,8 +1,9 @@ use std::collections::HashMap; -use rusty_parser::{BuiltInStyle, TypeQualifier, VariableInfo}; +use rusty_parser::{BuiltInStyle, TypeQualifier}; use rusty_variant::Variant; +use crate::core::VariableInfo; use crate::names::traits::SingleNameTrait; /// Stores information about compact variables of the same name. @@ -10,11 +11,13 @@ use crate::names::traits::SingleNameTrait; /// With compact variables, it's possible to have the same name /// but with different types e.g. `A$` and `A%`. #[derive(Default)] -pub struct Compacts(HashMap); +pub struct Compacts { + map: HashMap, +} impl SingleNameTrait for Compacts { fn get_compact(&self, qualifier: TypeQualifier) -> Option<&VariableInfo> { - self.0.get(&qualifier) + self.map.get(&qualifier) } fn get_extended(&self) -> Option<&VariableInfo> { @@ -26,7 +29,7 @@ impl SingleNameTrait for Compacts { } fn collect_var_info(&self, only_shared: bool) -> Vec<(BuiltInStyle, &VariableInfo)> { - self.0 + self.map .values() .filter(|v| v.shared || !only_shared) .map(|v| (BuiltInStyle::Compact, v)) @@ -40,7 +43,7 @@ impl SingleNameTrait for Compacts { .expect("Should be resolved"); // if it already exists, it should be a REDIM - debug_assert!(match self.0.get(&q) { + debug_assert!(match self.map.get(&q) { Some(existing_v) => { existing_v.redim_info.is_some() } @@ -49,6 +52,6 @@ impl SingleNameTrait for Compacts { } }); - self.0.insert(q, variable_info); + self.map.insert(q, variable_info); } } diff --git a/rusty_linter/src/names/mod.rs b/rusty_linter/src/names/mod.rs index eb41f13e..40912be9 100644 --- a/rusty_linter/src/names/mod.rs +++ b/rusty_linter/src/names/mod.rs @@ -1,9 +1,9 @@ mod compacts; mod implicit_vars; -mod main; mod name_info; mod names_inner; +mod names_outer; mod traits; pub use implicit_vars::ImplicitVars; -pub use main::Names; +pub use names_outer::Names; diff --git a/rusty_linter/src/names/name_info.rs b/rusty_linter/src/names/name_info.rs index 3b92e2b2..b58d0dfb 100644 --- a/rusty_linter/src/names/name_info.rs +++ b/rusty_linter/src/names/name_info.rs @@ -1,46 +1,57 @@ -use rusty_parser::{BuiltInStyle, TypeQualifier, VariableInfo}; +use rusty_parser::{BuiltInStyle, TypeQualifier}; use rusty_variant::Variant; +use crate::core::VariableInfo; use crate::names::compacts::Compacts; use crate::names::traits::SingleNameTrait; /// Stores information about a constant or variable name. /// The name itself isn't stored here. -pub struct NameInfo(NameInfoInner); +pub struct NameInfo { + inner: NameInfoInner, +} impl NameInfo { pub fn constant(v: Variant) -> Self { - Self(NameInfoInner::Constant(v)) + Self { + inner: NameInfoInner::Constant { value: v }, + } } pub fn compacts() -> Self { - Self(NameInfoInner::Compacts(Compacts::default())) + Self { + inner: NameInfoInner::Compacts { + compacts: Compacts::default(), + }, + } } pub fn extended(variable_info: VariableInfo) -> Self { - Self(NameInfoInner::Extended(variable_info)) + Self { + inner: NameInfoInner::Extended { variable_info }, + } } } impl SingleNameTrait for NameInfo { fn get_compact(&self, qualifier: TypeQualifier) -> Option<&VariableInfo> { - self.0.get_compact(qualifier) + self.inner.get_compact(qualifier) } fn get_extended(&self) -> Option<&VariableInfo> { - self.0.get_extended() + self.inner.get_extended() } fn get_const_value(&self) -> Option<&Variant> { - self.0.get_const_value() + self.inner.get_const_value() } fn collect_var_info(&self, only_shared: bool) -> Vec<(BuiltInStyle, &VariableInfo)> { - self.0.collect_var_info(only_shared) + self.inner.collect_var_info(only_shared) } fn insert_compact(&mut self, variable_info: VariableInfo) { - self.0.insert_compact(variable_info); + self.inner.insert_compact(variable_info); } } @@ -48,50 +59,50 @@ impl SingleNameTrait for NameInfo { /// The external struct is preventing direct access to the enum members /// outside of the module. enum NameInfoInner { - Constant(Variant), - Compacts(Compacts), - Extended(VariableInfo), + Constant { value: Variant }, + Compacts { compacts: Compacts }, + Extended { variable_info: VariableInfo }, } impl SingleNameTrait for NameInfoInner { fn get_compact(&self, qualifier: TypeQualifier) -> Option<&VariableInfo> { match self { - Self::Compacts(compacts) => compacts.get_compact(qualifier), + Self::Compacts { compacts } => compacts.get_compact(qualifier), _ => None, } } fn get_extended(&self) -> Option<&VariableInfo> { match self { - Self::Extended(v) => Some(v), + Self::Extended { variable_info } => Some(variable_info), _ => None, } } fn get_const_value(&self) -> Option<&Variant> { match self { - Self::Constant(v) => Some(v), + Self::Constant { value } => Some(value), _ => None, } } fn collect_var_info(&self, only_shared: bool) -> Vec<(BuiltInStyle, &VariableInfo)> { match self { - Self::Compacts(compacts) => compacts.collect_var_info(only_shared), - Self::Extended(v) => { - if v.shared || !only_shared { - vec![(BuiltInStyle::Extended, v)] + Self::Compacts { compacts } => compacts.collect_var_info(only_shared), + Self::Extended { variable_info } => { + if variable_info.shared || !only_shared { + vec![(BuiltInStyle::Extended, variable_info)] } else { vec![] } } - Self::Constant(_) => vec![], + Self::Constant { .. } => vec![], } } fn insert_compact(&mut self, variable_info: VariableInfo) { match self { - Self::Compacts(compacts) => compacts.insert_compact(variable_info), + Self::Compacts { compacts } => compacts.insert_compact(variable_info), _ => panic!("Cannot insert compact because it already exists as CONST or extended"), } } diff --git a/rusty_linter/src/names/names_inner.rs b/rusty_linter/src/names/names_inner.rs index e7934182..743a82ae 100644 --- a/rusty_linter/src/names/names_inner.rs +++ b/rusty_linter/src/names/names_inner.rs @@ -1,34 +1,36 @@ use std::collections::HashMap; -use rusty_parser::{AsBareName, BareName, Name, TypeQualifier, VariableInfo}; +use rusty_parser::{AsBareName, BareName, Name, TypeQualifier}; use rusty_variant::Variant; -use crate::core::ConstLookup; +use crate::core::{ConstLookup, VariableInfo}; use crate::names::name_info::NameInfo; use crate::names::traits::{ManyNamesTrait, SingleNameTrait}; /// Stores information about multiple constants or variable names. /// This struct does not support multiple levels (e.g. `FUNCTION` or `SUB`). #[derive(Default)] -pub struct NamesInner(HashMap); +pub struct NamesInner { + map: HashMap, +} impl NamesInner { /// Returns true if this name is a constant, or an extended variable, /// or a compact variable. In the case of compact variables, multiple may /// exist with the same bare name, e.g. `A$` and `A%`. pub fn contains_key(&self, bare_name: &BareName) -> bool { - self.0.contains_key(bare_name) + self.map.contains_key(bare_name) } pub fn insert_const(&mut self, bare_name: BareName, v: Variant) { - debug_assert!(!self.0.contains_key(&bare_name)); - self.0.insert(bare_name, NameInfo::constant(v)); + debug_assert!(!self.map.contains_key(&bare_name)); + self.map.insert(bare_name, NameInfo::constant(v)); } pub fn insert_extended(&mut self, bare_name: BareName, variable_context: VariableInfo) { // if it exists as REDIM extended, it's okay // all other cases where it already exists are not okay - debug_assert!(match self.0.get(&bare_name) { + debug_assert!(match self.map.get(&bare_name) { Some(name_info) => { match name_info.get_extended() { Some(e) => e.redim_info.is_some(), @@ -39,7 +41,7 @@ impl NamesInner { true } }); - self.0 + self.map .insert(bare_name, NameInfo::extended(variable_context)); } @@ -58,7 +60,7 @@ impl NamesInner { impl ConstLookup for NamesInner { fn get_const_value(&self, bare_name: &BareName) -> Option<&rusty_variant::Variant> { - self.0 + self.map .get(bare_name) .and_then(|name_info| name_info.get_const_value()) } @@ -66,13 +68,13 @@ impl ConstLookup for NamesInner { impl ManyNamesTrait for NamesInner { fn get_compact(&self, bare_name: &BareName, qualifier: TypeQualifier) -> Option<&VariableInfo> { - self.0 + self.map .get(bare_name) .and_then(|name_info| name_info.get_compact(qualifier)) } fn get_extended(&self, bare_name: &BareName) -> Option<&VariableInfo> { - self.0 + self.map .get(bare_name) .and_then(|name_info| name_info.get_extended()) } @@ -82,21 +84,21 @@ impl ManyNamesTrait for NamesInner { bare_name: &BareName, only_shared: bool, ) -> Vec<(rusty_parser::BuiltInStyle, &VariableInfo)> { - self.0 + self.map .get(bare_name) .map(|name_info| name_info.collect_var_info(only_shared)) .unwrap_or_default() } fn insert_compact(&mut self, bare_name: BareName, variable_info: VariableInfo) { - match self.0.get_mut(&bare_name) { + match self.map.get_mut(&bare_name) { Some(name_info) => { name_info.insert_compact(variable_info); } None => { let mut name_info = NameInfo::compacts(); name_info.insert_compact(variable_info); - self.0.insert(bare_name, name_info); + self.map.insert(bare_name, name_info); } } } diff --git a/rusty_linter/src/names/main.rs b/rusty_linter/src/names/names_outer.rs similarity index 74% rename from rusty_linter/src/names/main.rs rename to rusty_linter/src/names/names_outer.rs index 97ba3d86..2dc1c00c 100644 --- a/rusty_linter/src/names/main.rs +++ b/rusty_linter/src/names/names_outer.rs @@ -1,12 +1,10 @@ use std::collections::HashMap; use rusty_common::CaseInsensitiveString; -use rusty_parser::{ - AsBareName, BareName, BuiltInStyle, Name, RedimInfo, TypeQualifier, VarType, VariableInfo -}; +use rusty_parser::{AsBareName, BareName, BuiltInStyle, Name, TypeQualifier, VarType}; use rusty_variant::Variant; -use crate::core::{ConstLookup, NameContext, SubprogramName}; +use crate::core::{ConstLookup, RedimInfo, ScopeKind, ScopeName, VariableInfo}; use crate::names::ImplicitVars; use crate::names::names_inner::NamesInner; use crate::names::traits::ManyNamesTrait; @@ -31,56 +29,55 @@ e.g. A = 3.14 (resolves as A! by the default rules), A$ = "hello", A% = 1 5b. An extended variable cannot co-exist with other symbols of the same name */ -type Key = Option; - pub struct Names { - data: HashMap, - current_key: Key, + data: HashMap, + current_scope_name: ScopeName, } /// Stores the data relevant to one level only (i.e. global symbols, or a FUNCTION, or a SUB). /// Collects constant and variable names in [NamesInner] and implicit variables in [ImplicitVars]. -/// TODO merge [ImplicitVars] into [NamesInner] -/// TODO use bi_tuple macro #[derive(Default)] -struct NamesOneLevel(NamesInner, ImplicitVars); +struct NamesOneLevel { + names: NamesInner, + implicit_vars: ImplicitVars, +} impl Names { pub fn new() -> Self { - let mut data: HashMap = HashMap::new(); + let mut data: HashMap = HashMap::new(); // insert GLOBAL scope - data.insert(None, NamesOneLevel::default()); + data.insert(ScopeName::Global, NamesOneLevel::default()); Self { data, - current_key: None, + current_scope_name: ScopeName::Global, } } fn current_data(&self) -> &NamesOneLevel { - self.data.get(&self.current_key).unwrap() + self.data.get(&self.current_scope_name).unwrap() } fn current_data_mut(&mut self) -> &mut NamesOneLevel { - self.data.get_mut(&self.current_key).unwrap() + self.data.get_mut(&self.current_scope_name).unwrap() } pub fn get_implicit_vars_mut(&mut self) -> &mut ImplicitVars { - &mut self.current_data_mut().1 + &mut self.current_data_mut().implicit_vars } pub fn names(&self) -> &NamesInner { - &self.current_data().0 + &self.current_data().names } pub fn names_mut(&mut self) -> &mut NamesInner { - &mut self.current_data_mut().0 + &mut self.current_data_mut().names } /// Returns the global names, but only if we are currently within a sub program. fn global_names(&self) -> Option<&NamesInner> { - match &self.current_key { - Some(_) => self.data.get(&None).map(|x| &x.0), - None => None, + match &self.current_scope_name { + ScopeName::Global => None, + _ => self.data.get(&ScopeName::Global).map(|x| &x.names), } } @@ -159,40 +156,41 @@ impl Names { } pub fn is_in_function(&self, function_name: &BareName) -> bool { - match &self.current_key { - Some(SubprogramName::Function(f)) => f.as_bare_name() == function_name, + match &self.current_scope_name { + ScopeName::Function(f) => f.as_bare_name() == function_name, _ => false, } } pub fn is_in_subprogram(&self) -> bool { - self.current_key.is_some() + self.current_scope_name != ScopeName::Global } - pub fn get_name_context(&self) -> NameContext { - match &self.current_key { - Some(SubprogramName::Function(_)) => NameContext::Function, - Some(SubprogramName::Sub(_)) => NameContext::Sub, - None => NameContext::Global, - } + pub fn get_current_scope_kind(&self) -> ScopeKind { + ScopeKind::from(&self.current_scope_name) } - pub fn push(&mut self, subprogram_name: SubprogramName) { - let key = Some(subprogram_name); + pub fn push(&mut self, scope_name: ScopeName) { debug_assert!( - !self.data.contains_key(&key), + !self.data.contains_key(&scope_name), "should not encounter same function/sub twice!" ); - self.current_key = key.clone(); - self.data.insert(key, NamesOneLevel::default()); + debug_assert_ne!( + scope_name, + ScopeName::Global, + "should not push global scope" + ); + self.current_scope_name = scope_name.clone(); + self.data.insert(scope_name, NamesOneLevel::default()); } pub fn pop(&mut self) { - debug_assert!( - self.current_key.is_some(), + debug_assert_ne!( + self.current_scope_name, + ScopeName::Global, "should not pop context from the global level" ); - self.current_key = None; + self.current_scope_name = ScopeName::Global; } pub fn find_name_or_shared_in_parent( @@ -206,25 +204,21 @@ impl Names { result } - pub fn get_resolved_variable_info( - &self, - subprogram_name: &Option, - name: &Name, - ) -> &VariableInfo { + pub fn get_resolved_variable_info(&self, scope_name: &ScopeName, name: &Name) -> &VariableInfo { let one_level = self .data - .get(subprogram_name) - .unwrap_or_else(|| panic!("Subprogram {:?} should be resolved", subprogram_name)); - match one_level.0.get_variable_info_by_name(name) { + .get(scope_name) + .unwrap_or_else(|| panic!("Subprogram {:?} should be resolved", scope_name)); + match one_level.names.get_variable_info_by_name(name) { Some(i) => i, None => { - if subprogram_name.is_some() { + if scope_name != &ScopeName::Global { // try then parent level but only for SHARED let result = self .data - .get(&None) + .get(&ScopeName::Global) .expect("Global name scope missing!") - .0 + .names .get_variable_info_by_name(name) .unwrap_or_else(|| { panic!("Could not resolve {} even in global namespace", name) diff --git a/rusty_linter/src/names/traits.rs b/rusty_linter/src/names/traits.rs index 4786cb21..c7f259de 100644 --- a/rusty_linter/src/names/traits.rs +++ b/rusty_linter/src/names/traits.rs @@ -1,7 +1,7 @@ -use rusty_parser::{BareName, BuiltInStyle, TypeQualifier, VariableInfo}; +use rusty_parser::{BareName, BuiltInStyle, TypeQualifier}; use rusty_variant::Variant; -use crate::core::ConstLookup; +use crate::core::{ConstLookup, VariableInfo}; pub trait SingleNameTrait { fn get_compact(&self, qualifier: TypeQualifier) -> Option<&VariableInfo>; diff --git a/rusty_linter/src/post_linter/built_in_linter.rs b/rusty_linter/src/post_linter/built_in_linter.rs index b28a1204..574e4fd2 100644 --- a/rusty_linter/src/post_linter/built_in_linter.rs +++ b/rusty_linter/src/post_linter/built_in_linter.rs @@ -3,17 +3,17 @@ use rusty_parser::*; use super::post_conversion_linter::PostConversionLinter; use crate::built_ins::{lint_function_call, lint_sub_call}; -use crate::core::{LintErrorPos, NameContext}; +use crate::core::{LintErrorPos, ScopeKind}; /// Lints built-in functions and subs. pub struct BuiltInLinter { - name_context: NameContext, + scope_kind: ScopeKind, } impl BuiltInLinter { pub fn new() -> Self { Self { - name_context: NameContext::Global, + scope_kind: ScopeKind::Global, } } } @@ -23,16 +23,16 @@ impl PostConversionLinter for BuiltInLinter { &mut self, f: &FunctionImplementation, ) -> Result<(), LintErrorPos> { - self.name_context = NameContext::Function; + self.scope_kind = ScopeKind::Function; let result = self.visit_statements(&f.body); - self.name_context = NameContext::Global; + self.scope_kind = ScopeKind::Global; result } fn visit_sub_implementation(&mut self, s: &SubImplementation) -> Result<(), LintErrorPos> { - self.name_context = NameContext::Sub; + self.scope_kind = ScopeKind::Sub; let result = self.visit_statements(&s.body); - self.name_context = NameContext::Global; + self.scope_kind = ScopeKind::Global; result } @@ -43,7 +43,7 @@ impl PostConversionLinter for BuiltInLinter { ) -> Result<(), LintErrorPos> { let (built_in_sub, args) = built_in_sub_call.into(); self.visit_expressions(args)?; - lint_sub_call(built_in_sub, pos, args, self.name_context) + lint_sub_call(built_in_sub, pos, args, self.scope_kind) } fn visit_expression(&mut self, expr_pos: &ExpressionPos) -> Result<(), LintErrorPos> { diff --git a/rusty_linter/src/post_linter/for_next_counter_match_linter.rs b/rusty_linter/src/post_linter/for_next_counter_match_linter.rs index 2099c612..54bb110e 100644 --- a/rusty_linter/src/post_linter/for_next_counter_match_linter.rs +++ b/rusty_linter/src/post_linter/for_next_counter_match_linter.rs @@ -37,13 +37,7 @@ impl ForNextCounterMatch { pos, } = &f.variable_name; match var_expr { - Expression::Variable( - _, - VariableInfo { - expression_type: var_type, - .. - }, - ) => match var_type { + Expression::Variable(_, expression_type) => match expression_type { ExpressionType::BuiltIn(TypeQualifier::DollarString) => { Err(LintError::TypeMismatch.at_pos(*pos)) } @@ -51,7 +45,7 @@ impl ForNextCounterMatch { _ => Err(LintError::TypeMismatch.at_pos(*pos)), }, _ => panic!( - "It should not be possible for the FOR variable to be something othe than a variable" + "It should not be possible for the FOR variable to be something other than a variable" ), } } diff --git a/rusty_linter/src/post_linter/main.rs b/rusty_linter/src/post_linter/main.rs index a49554df..3f01235f 100644 --- a/rusty_linter/src/post_linter/main.rs +++ b/rusty_linter/src/post_linter/main.rs @@ -1,6 +1,6 @@ use rusty_parser::Program; -use crate::core::{HasSubprograms, LintErrorPos, Visitor}; +use crate::core::{LintErrorPos, LinterContext, Visitor}; use crate::post_linter::expression_reducer::ExpressionReducer; use crate::post_linter::post_conversion_linter::PostConversionLinter; use crate::post_linter::{ @@ -9,7 +9,7 @@ use crate::post_linter::{ pub fn post_linter( result: Program, - linter_context: &impl HasSubprograms, + linter_context: &LinterContext, ) -> Result { // lint apply_linters(&result, linter_context)?; @@ -18,10 +18,7 @@ pub fn post_linter( reducer.visit_program(result) } -fn apply_linters( - result: &Program, - linter_context: &impl HasSubprograms, -) -> Result<(), LintErrorPos> { +fn apply_linters(result: &Program, linter_context: &LinterContext) -> Result<(), LintErrorPos> { let mut linter = for_next_counter_match_linter::ForNextCounterMatch::visitor(); linter.visit(result)?; diff --git a/rusty_linter/src/post_linter/undefined_function_reducer.rs b/rusty_linter/src/post_linter/undefined_function_reducer.rs index 4014cdfb..5389a05c 100644 --- a/rusty_linter/src/post_linter/undefined_function_reducer.rs +++ b/rusty_linter/src/post_linter/undefined_function_reducer.rs @@ -1,17 +1,14 @@ use rusty_parser::{AsBareName, Expression}; use super::expression_reducer::*; -use crate::core::{HasSubprograms, LintErrorPos, binary_cast}; +use crate::core::{LintErrorPos, LinterContext, binary_cast}; /// Finds undefined functions and converts them to zeroes. -pub struct UndefinedFunctionReducer<'a, R> { - pub linter_context: &'a R, +pub struct UndefinedFunctionReducer<'a> { + pub linter_context: &'a LinterContext, } -impl<'a, R> ExpressionReducer for UndefinedFunctionReducer<'a, R> -where - R: HasSubprograms, -{ +impl<'a> ExpressionReducer for UndefinedFunctionReducer<'a> { fn visit_expression(&mut self, expression: Expression) -> Result { match expression { Expression::BinaryExpression(op, left, right, _) => { @@ -26,7 +23,7 @@ where Expression::FunctionCall(name, args) => { if self .linter_context - .functions() + .functions .contains_key(name.as_bare_name()) { Ok(Expression::FunctionCall( diff --git a/rusty_linter/src/post_linter/user_defined_function_linter.rs b/rusty_linter/src/post_linter/user_defined_function_linter.rs index 788ea3cd..46d3afee 100644 --- a/rusty_linter/src/post_linter/user_defined_function_linter.rs +++ b/rusty_linter/src/post_linter/user_defined_function_linter.rs @@ -4,8 +4,8 @@ use rusty_parser::*; use super::post_conversion_linter::PostConversionLinter; use crate::core::*; -pub struct UserDefinedFunctionLinter<'a, R> { - pub linter_context: &'a R, +pub struct UserDefinedFunctionLinter<'a> { + pub linter_context: &'a LinterContext, } pub fn lint_call_args( @@ -48,19 +48,10 @@ fn lint_by_ref_arg( ResolvedParamType::Array(boxed_element_type) => { // we can only pass an array by using the array name followed by parenthesis e.g. `Menu choice$()` match &arg_pos.element { - Expression::ArrayElement( - name, - args, - VariableInfo { - expression_type, .. - }, - ) => { + Expression::ArrayElement(name, args, expression_type) => { if args.is_empty() { - let dummy_expr = Expression::Variable( - name.clone(), - VariableInfo::new_local(expression_type.clone()), - ) - .at(arg_pos); + let dummy_expr = + Expression::Variable(name.clone(), expression_type.clone()).at(arg_pos); lint_by_ref_arg(&dummy_expr, boxed_element_type.as_ref()) } else { Err(LintError::ArgumentTypeMismatch.at(arg_pos)) @@ -125,20 +116,10 @@ fn arg_pos_to_expr_type_and_opt_args( arg_pos: &ExpressionPos, ) -> Option<(&ExpressionType, Option<&Expressions>)> { match &arg_pos.element { - Expression::Variable( - _, - VariableInfo { - expression_type, .. - }, - ) - | Expression::Property(_, _, expression_type) => Some((expression_type, None)), - Expression::ArrayElement( - _, - args, - VariableInfo { - expression_type, .. - }, - ) => Some((expression_type, Some(args))), + Expression::Variable(_, expression_type) | Expression::Property(_, _, expression_type) => { + Some((expression_type, None)) + } + Expression::ArrayElement(_, args, expression_type) => Some((expression_type, Some(args))), _ => None, } } @@ -150,10 +131,7 @@ fn has_at_least_one_arg(opt_args: Option<&Expressions>) -> bool { } } -impl<'a, R> UserDefinedFunctionLinter<'a, R> -where - R: HasSubprograms, -{ +impl<'a> UserDefinedFunctionLinter<'a> { fn visit_function( &self, name: &Name, @@ -162,7 +140,7 @@ where ) -> Result<(), LintErrorPos> { let qualifier = name.qualifier().expect("Unresolved function!"); let bare_name = name.as_bare_name(); - match self.linter_context.functions().get(bare_name) { + match self.linter_context.functions.get(bare_name) { Some(function_signature_pos) => { if function_signature_pos.element != qualifier { Err(LintError::TypeMismatch.at(function_signature_pos)) @@ -194,10 +172,7 @@ where } } -impl<'a, R> PostConversionLinter for UserDefinedFunctionLinter<'a, R> -where - R: HasSubprograms, -{ +impl<'a> PostConversionLinter for UserDefinedFunctionLinter<'a> { fn visit_expression(&mut self, expr_pos: &ExpressionPos) -> Result<(), LintErrorPos> { let Positioned { element: e, pos } = expr_pos; match e { diff --git a/rusty_linter/src/post_linter/user_defined_sub_linter.rs b/rusty_linter/src/post_linter/user_defined_sub_linter.rs index e2ef3230..072c1e42 100644 --- a/rusty_linter/src/post_linter/user_defined_sub_linter.rs +++ b/rusty_linter/src/post_linter/user_defined_sub_linter.rs @@ -3,19 +3,16 @@ use rusty_parser::SubCall; use super::post_conversion_linter::PostConversionLinter; use super::user_defined_function_linter::lint_call_args; -use crate::core::{HasSubprograms, LintError, LintErrorPos}; +use crate::core::{LintError, LintErrorPos, LinterContext}; -pub struct UserDefinedSubLinter<'a, R> { - pub linter_context: &'a R, +pub struct UserDefinedSubLinter<'a> { + pub linter_context: &'a LinterContext, } -impl<'a, R> PostConversionLinter for UserDefinedSubLinter<'a, R> -where - R: HasSubprograms, -{ +impl<'a> PostConversionLinter for UserDefinedSubLinter<'a> { fn visit_sub_call(&mut self, sub_call: &SubCall, pos: Position) -> Result<(), LintErrorPos> { let (name, args) = sub_call.into(); - match self.linter_context.subs().get(name) { + match self.linter_context.subs.get(name) { Some(sub_signature_pos) => { lint_call_args(args, sub_signature_pos.element.param_types(), pos) } diff --git a/rusty_linter/src/pre_linter/main.rs b/rusty_linter/src/pre_linter/main.rs index ae099375..03449f91 100644 --- a/rusty_linter/src/pre_linter/main.rs +++ b/rusty_linter/src/pre_linter/main.rs @@ -2,8 +2,8 @@ use rusty_common::*; use rusty_parser::*; use crate::core::*; +use crate::pre_linter::ConstantMap; use crate::pre_linter::sub_program_context::SubprogramContext; -use crate::pre_linter::{ConstantMap, PreLinterResult}; // CONST -> stored in global_constants // DEFINT -> stored in resolver @@ -20,13 +20,13 @@ struct MainContext { declaration_pos: Position, } -pub fn pre_lint_program(program: &Program) -> Result { +pub fn pre_lint_program(program: &Program) -> Result { let mut visitor = GlobalVisitor::new(MainContext::default()); visitor.visit(program)?; let ctx = visitor.delegate(); ctx.post_visit_functions()?; ctx.post_visit_subs()?; - Ok(PreLinterResult::new( + Ok(LinterContext::new( ctx.functions.implementations(), ctx.subs.implementations(), ctx.user_defined_types, @@ -55,7 +55,7 @@ impl Visitor for MainContext { let param_types: ResolvedParamTypes = self.resolve_parameters(params)?; let bare_name = name.as_bare_name(); let q = name.qualify(&self.resolver); - let signature = Signature::new_function(q, param_types); + let signature = Signature::Function(param_types, q); self.functions .add_declaration(bare_name.clone(), signature.at_pos(self.declaration_pos)) } @@ -71,7 +71,7 @@ impl Visitor for MainContext { let param_types: ResolvedParamTypes = self.resolve_parameters(params)?; let bare_name = name.as_bare_name(); let q = name.qualify(&self.resolver); - let signature = Signature::new_function(q, param_types); + let signature = Signature::Function(param_types, q); self.functions .add_implementation(bare_name.clone(), signature.at_pos(self.declaration_pos)) } @@ -86,7 +86,7 @@ impl Visitor for MainContext { parameters: params, } = s; let param_types: ResolvedParamTypes = self.resolve_parameters(params)?; - let signature = Signature::new_sub(param_types); + let signature = Signature::Sub(param_types); self.subs .add_declaration(bare_name.clone(), signature.at_pos(self.declaration_pos)) } @@ -102,7 +102,7 @@ impl Visitor for MainContext { .. } = s; let param_types: ResolvedParamTypes = self.resolve_parameters(params)?; - let signature = Signature::new_sub(param_types); + let signature = Signature::Sub(param_types); self.subs .add_implementation(bare_name.clone(), signature.at_pos(self.declaration_pos)) } diff --git a/rusty_linter/src/pre_linter/mod.rs b/rusty_linter/src/pre_linter/mod.rs index 265ef063..3d3652d5 100644 --- a/rusty_linter/src/pre_linter/mod.rs +++ b/rusty_linter/src/pre_linter/mod.rs @@ -1,9 +1,7 @@ mod constant_map; mod main; -mod pre_linter_result; mod sub_program_context; mod user_defined_type_visitor; pub use self::constant_map::*; pub use self::main::*; -pub use self::pre_linter_result::*; diff --git a/rusty_linter/src/pre_linter/pre_linter_result.rs b/rusty_linter/src/pre_linter/pre_linter_result.rs deleted file mode 100644 index 296f6fcd..00000000 --- a/rusty_linter/src/pre_linter/pre_linter_result.rs +++ /dev/null @@ -1,46 +0,0 @@ -use rusty_parser::UserDefinedTypes; - -use crate::HasUserDefinedTypes; -use crate::core::{HasSubprograms, SignatureMap}; - -/// Stores the result of the pre-linter. -pub struct PreLinterResult { - functions: SignatureMap, - subs: SignatureMap, - user_defined_types: UserDefinedTypes, -} - -impl PreLinterResult { - pub fn new( - functions: SignatureMap, - subs: SignatureMap, - user_defined_types: UserDefinedTypes, - ) -> Self { - Self { - functions, - subs, - user_defined_types, - } - } -} - -impl From for UserDefinedTypes { - fn from(value: PreLinterResult) -> Self { - value.user_defined_types - } -} - -impl HasSubprograms for PreLinterResult { - fn functions(&self) -> &SignatureMap { - &self.functions - } - fn subs(&self) -> &SignatureMap { - &self.subs - } -} - -impl HasUserDefinedTypes for PreLinterResult { - fn user_defined_types(&self) -> &UserDefinedTypes { - &self.user_defined_types - } -} diff --git a/rusty_linter/src/tests/array.rs b/rusty_linter/src/tests/array.rs index bddb80b1..62075c17 100644 --- a/rusty_linter/src/tests/array.rs +++ b/rusty_linter/src/tests/array.rs @@ -116,11 +116,7 @@ fn test_passing_array_parameter_with_parenthesis() { Expression::ArrayElement( "choice$".into(), vec![], - VariableInfo { - expression_type: ExpressionType::BuiltIn(TypeQualifier::DollarString), - shared: false, - redim_info: None - } + ExpressionType::BuiltIn(TypeQualifier::DollarString), ) .at_rc(4, 10) ] @@ -149,13 +145,7 @@ fn test_passing_array_parameter_with_parenthesis() { Expression::ArrayElement( "choice$".into(), vec![Expression::IntegerLiteral(1).at_rc(7, 22)], - VariableInfo { - expression_type: ExpressionType::BuiltIn( - TypeQualifier::DollarString - ), - shared: false, - redim_info: None - } + ExpressionType::BuiltIn(TypeQualifier::DollarString) ) .at_rc(7, 14) ) @@ -202,15 +192,15 @@ fn test_passing_array_without_parenthesis() { GlobalStatement::Statement(Statement::assignment( Expression::Variable( "X!".into(), - VariableInfo::new_local(ExpressionType::BuiltIn(TypeQualifier::BangSingle)) + ExpressionType::BuiltIn(TypeQualifier::BangSingle) ), Expression::BuiltInFunctionCall( BuiltInFunction::LBound, vec![ Expression::Variable( "choice$".into(), - VariableInfo::new_local(ExpressionType::Array(Box::new( - ExpressionType::BuiltIn(TypeQualifier::DollarString) + ExpressionType::Array(Box::new(ExpressionType::BuiltIn( + TypeQualifier::DollarString ))) ) .at_rc(3, 16) diff --git a/rusty_linter/src/tests/dim_assign_use_in_expr.rs b/rusty_linter/src/tests/dim_assign_use_in_expr.rs index 1584b643..55c0f08d 100644 --- a/rusty_linter/src/tests/dim_assign_use_in_expr.rs +++ b/rusty_linter/src/tests/dim_assign_use_in_expr.rs @@ -1,7 +1,7 @@ use rusty_common::*; use rusty_parser::*; -use crate::core::{HasUserDefinedTypes, LintError}; +use crate::core::LintError; use crate::tests::test_utils::*; use crate::{assert_linter_err, assert_linter_ok_global_statements}; @@ -129,7 +129,7 @@ fn user_defined_type() { .at_rc(8, 5) ] ); - let user_defined_types = user_defined_types_holder.user_defined_types(); + let user_defined_types = user_defined_types_holder.user_defined_types; assert_eq!( user_defined_types.len(), 1, diff --git a/rusty_linter/src/tests/test_utils.rs b/rusty_linter/src/tests/test_utils.rs index 5117b361..4d7b4783 100644 --- a/rusty_linter/src/tests/test_utils.rs +++ b/rusty_linter/src/tests/test_utils.rs @@ -1,14 +1,13 @@ use rusty_parser::{Program, parse}; -use crate::core::{HasUserDefinedTypes, LintErrorPos}; -use crate::lint; +use crate::core::{LintErrorPos, LinterContext, lint}; /// Lints the given string and returns the results. /// /// # Panics /// /// Panics if the parser or the linter have an error. -pub fn linter_ok_with_types(input: &str) -> (Program, impl HasUserDefinedTypes) { +pub fn linter_ok_with_types(input: &str) -> (Program, LinterContext) { let program = parse(input); lint(program).unwrap() } diff --git a/rusty_parser/src/built_ins/field.rs b/rusty_parser/src/built_ins/field.rs index ef16c3c2..538fc275 100644 --- a/rusty_parser/src/built_ins/field.rs +++ b/rusty_parser/src/built_ins/field.rs @@ -39,7 +39,7 @@ fn build_args( let variable_name: String = name.as_bare_name().to_string(); args.push(Expression::StringLiteral(variable_name).at_pos(pos)); // to lint the variable, not used at runtime - args.push(Expression::Variable(name, VariableInfo::unresolved()).at_pos(pos)); + args.push(Expression::Variable(name, ExpressionType::Unresolved).at_pos(pos)); } args } diff --git a/rusty_parser/src/built_ins/lset.rs b/rusty_parser/src/built_ins/lset.rs index 74dd892b..0b4c5547 100644 --- a/rusty_parser/src/built_ins/lset.rs +++ b/rusty_parser/src/built_ins/lset.rs @@ -21,7 +21,7 @@ pub fn parse() -> impl Parser Expressions { let Positioned { element: name, pos } = name_pos; let variable_name: String = name.as_bare_name().to_string(); - let name_expr_pos = Expression::Variable(name, VariableInfo::unresolved()).at_pos(pos); + let name_expr_pos = Expression::Variable(name, ExpressionType::Unresolved).at_pos(pos); vec![ // pass the name of the variable as a special argument Expression::StringLiteral(variable_name).at_pos(pos), diff --git a/rusty_parser/src/core/assignment.rs b/rusty_parser/src/core/assignment.rs index 8828cf62..b45a091c 100644 --- a/rusty_parser/src/core/assignment.rs +++ b/rusty_parser/src/core/assignment.rs @@ -148,7 +148,7 @@ mod tests { "ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLM.% = 42", Expression::Variable( "ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLM.%".into(), - VariableInfo::unresolved() + ExpressionType::Unresolved ) ); } @@ -295,7 +295,7 @@ mod tests { assert_eq!( program, Statement::assignment( - Expression::Variable("DIM$".into(), VariableInfo::unresolved()), + Expression::Variable("DIM$".into(), ExpressionType::Unresolved), "hello".as_lit_expr(1, 8) ) ); diff --git a/rusty_parser/src/core/mod.rs b/rusty_parser/src/core/mod.rs index abad72f6..71634cc9 100644 --- a/rusty_parser/src/core/mod.rs +++ b/rusty_parser/src/core/mod.rs @@ -37,7 +37,6 @@ mod type_qualifier; mod unary_operator; mod user_defined_type; mod var_name; -mod variable_info; mod while_wend; // export types @@ -70,4 +69,3 @@ pub use self::user_defined_type::{ Element, ElementPos, ElementType, UserDefinedType, UserDefinedTypes }; pub use self::var_name::*; -pub use self::variable_info::{RedimInfo, VariableInfo}; diff --git a/rusty_parser/src/expr/types.rs b/rusty_parser/src/expr/types.rs index dced4023..ed646a61 100644 --- a/rusty_parser/src/expr/types.rs +++ b/rusty_parser/src/expr/types.rs @@ -2,7 +2,7 @@ use rusty_bit_vec::{MIN_INTEGER, MIN_LONG}; use rusty_common::*; use crate::{ - BuiltInFunction, ExpressionType, FileHandle, HasExpressionType, Name, Operator, TypeQualifier, UnaryOperator, VariableInfo + BuiltInFunction, ExpressionType, FileHandle, HasExpressionType, Name, Operator, TypeQualifier, UnaryOperator }; // TODO move traits and logic that is linter specific to linter (including CanCastTo from common) @@ -14,7 +14,7 @@ pub enum Expression { StringLiteral(String), IntegerLiteral(i32), LongLiteral(i64), - Variable(Name, VariableInfo), + Variable(Name, ExpressionType), /// During parsing, arrays are also parsed as function calls. /// Only during linting can it be determined if it's an array or a function call. @@ -28,7 +28,7 @@ pub enum Expression { // the array indices Expressions, // the type of the elements (shared refers to the array itself) - VariableInfo, + ExpressionType, ), BuiltInFunctionCall(BuiltInFunction, Expressions), BinaryExpression( @@ -192,22 +192,19 @@ impl Expression { #[cfg(test)] pub fn var_unresolved(s: &str) -> Self { let name: Name = s.into(); - Self::Variable(name, VariableInfo::unresolved()) + Self::Variable(name, ExpressionType::Unresolved) } // TODO #[cfg(test)] but used by rusty_linter too pub fn var_resolved(s: &str) -> Self { let name: Name = s.into(); let expression_type = name.expression_type(); - Self::Variable(name, VariableInfo::new_local(expression_type)) + Self::Variable(name, expression_type) } // TODO #[cfg(test)] but used by rusty_linter too pub fn var_user_defined(name: &str, type_name: &str) -> Self { - Self::Variable( - name.into(), - VariableInfo::new_local(ExpressionType::UserDefined(type_name.into())), - ) + Self::Variable(name.into(), ExpressionType::UserDefined(type_name.into())) } fn flip_multiply_plus(l_op: &Operator, r_op: &Operator) -> bool { @@ -322,21 +319,10 @@ impl HasExpressionType for Expression { Self::StringLiteral(_) => ExpressionType::BuiltIn(TypeQualifier::DollarString), Self::IntegerLiteral(_) => ExpressionType::BuiltIn(TypeQualifier::PercentInteger), Self::LongLiteral(_) => ExpressionType::BuiltIn(TypeQualifier::AmpersandLong), - Self::Variable( - _, - VariableInfo { - expression_type, .. - }, - ) + Self::Variable(_, expression_type) | Self::Property(_, _, expression_type) | Self::BinaryExpression(_, _, _, expression_type) => expression_type.clone(), - Self::ArrayElement( - _, - args, - VariableInfo { - expression_type, .. - }, - ) => { + Self::ArrayElement(_, args, expression_type) => { if args.is_empty() { // this is the entire array ExpressionType::Array(Box::new(expression_type.clone())) diff --git a/rusty_parser/src/expr/variable.rs b/rusty_parser/src/expr/variable.rs index 14ab606a..650c9bd5 100644 --- a/rusty_parser/src/expr/variable.rs +++ b/rusty_parser/src/expr/variable.rs @@ -5,9 +5,7 @@ use rusty_pc::*; use crate::core::{name_as_tokens_p, token_to_type_qualifier}; use crate::input::StringView; use crate::pc_specific::WithPos; -use crate::{ - BareName, Expression, ExpressionPos, ExpressionType, Name, NameAsTokens, ParserError, VariableInfo -}; +use crate::{BareName, Expression, ExpressionPos, ExpressionType, Name, NameAsTokens, ParserError}; // variable ::= // | @@ -24,7 +22,7 @@ fn map_to_expr(name_as_tokens: NameAsTokens) -> Expression { if is_property_expr(&name_as_tokens) { map_to_property(name_as_tokens) } else { - Expression::Variable(name_as_tokens.into(), VariableInfo::unresolved()) + Expression::Variable(name_as_tokens.into(), ExpressionType::Unresolved) } } @@ -64,7 +62,7 @@ fn map_to_property(name_as_tokens: NameAsTokens) -> Expression { .collect(); let mut result = Expression::Variable( Name::bare(BareName::new(property_names.pop_front().unwrap())), - VariableInfo::unresolved(), + ExpressionType::Unresolved, ); while let Some(property_name) = property_names.pop_front() { let is_last = property_names.is_empty(); diff --git a/rusty_parser/src/test_utils.rs b/rusty_parser/src/test_utils.rs index 4c9af37a..c2ce8fdd 100644 --- a/rusty_parser/src/test_utils.rs +++ b/rusty_parser/src/test_utils.rs @@ -472,7 +472,7 @@ macro_rules! paren_exp { #[macro_export] macro_rules! expr { (var($name: literal)) => { - Expression::Variable(Name::from($name), VariableInfo::unresolved()) + Expression::Variable(Name::from($name), ExpressionType::Unresolved) }; (prop($first: literal.$second: literal)) => { diff --git a/rusty_variant/src/bits.rs b/rusty_variant/src/bits.rs index 66dabe7a..f934cdd4 100644 --- a/rusty_variant/src/bits.rs +++ b/rusty_variant/src/bits.rs @@ -121,7 +121,7 @@ fn f64_to_bits_for_normalized_value( // insert the significant bits for bit in int_bits .into_iter() - .chain(fraction_bits.into_iter()) + .chain(fraction_bits) .take(DOUBLE_SIGNIFICANT_BITS) { bits.push(bit);