Skip to content

Commit

Permalink
Add IN6 rule for continuation line on broken expressions
Browse files Browse the repository at this point in the history
  • Loading branch information
jvsqzj authored and kevv87 committed Jan 31, 2025
1 parent 6812633 commit c411fa4
Show file tree
Hide file tree
Showing 5 changed files with 164 additions and 4 deletions.
3 changes: 2 additions & 1 deletion example_files/example_lint_cfg.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@
"nsp_trailing": {},
"long_lines": { "max_length": 80 },
"in3": { "indentation_spaces": 4 },
"in9": { "indentation_spaces": 4 },
"continuation_line": { "indentation_spaces": 4 },
"in9": { "indentation_spaces": 4 }
}
14 changes: 12 additions & 2 deletions src/lint/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,16 @@ use serde::{Deserialize, Serialize};
use rules::{instantiate_rules, CurrentRules};
use rules::{spacing::{SpBraceOptions, SpPunctOptions, NspFunparOptions,
NspInparenOptions, NspUnaryOptions, NspTrailingOptions},
indentation::{LongLineOptions, IN3Options, IN9Options},
indentation::{LongLineOptions, IN3Options,
IN9Options, ContinuationLineOptions},
};
use crate::analysis::{DMLError, IsolatedAnalysis, LocalDMLError};
use crate::analysis::parsing::tree::TreeElement;
use crate::file_management::CanonPath;
use crate::vfs::{Error, TextFile};
use crate::analysis::parsing::structure::TopAst;
use crate::lint::rules::indentation::MAX_LENGTH_DEFAULT;
use crate::lint::rules::indentation::{MAX_LENGTH_DEFAULT,
INDENTATION_LEVEL_DEFAULT};

pub fn parse_lint_cfg(path: PathBuf) -> Result<LintCfg, String> {
debug!("Reading Lint configuration from {:?}", path);
Expand Down Expand Up @@ -55,6 +57,8 @@ pub struct LintCfg {
#[serde(default)]
pub in3: Option<IN3Options>,
#[serde(default)]
pub continuation_line: Option<ContinuationLineOptions>,
#[serde(default)]
pub in9: Option<IN9Options>,
}

Expand All @@ -71,6 +75,9 @@ impl Default for LintCfg {
max_length: MAX_LENGTH_DEFAULT,
}),
in3: Some(IN3Options{indentation_spaces: 4}),
continuation_line: Some(ContinuationLineOptions {
indentation_spaces: INDENTATION_LEVEL_DEFAULT,
}),
in9: Some(IN9Options{indentation_spaces: 4}),
}
}
Expand Down Expand Up @@ -124,6 +131,9 @@ pub fn begin_style_check(ast: TopAst, file: String, rules: &CurrentRules) -> Res
rules.nsp_trailing.check(&mut linting_errors, row, line);
}

// Continuation line check
rules.continuation_line.check(&mut linting_errors, &lines);

Ok(linting_errors)
}

Expand Down
80 changes: 80 additions & 0 deletions src/lint/rules/indentation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use serde::{Deserialize, Serialize};
use super::Rule;

pub const MAX_LENGTH_DEFAULT: u32 = 80;
pub const INDENTATION_LEVEL_DEFAULT: u32 = 4;

#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
pub struct LongLineOptions {
Expand Down Expand Up @@ -161,6 +162,85 @@ impl Rule for IN3Rule {
}
}

// IN6: Continuation Line
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
pub struct ContinuationLineOptions {
pub indentation_spaces: u32,
}

pub struct ContinuationLineRule {
pub enabled: bool,
pub indentation_spaces: u32,
}

impl ContinuationLineRule {
pub fn from_options(options: &Option<ContinuationLineOptions>) -> ContinuationLineRule {
match options {
Some(continuation_line) => ContinuationLineRule {
enabled: true,
indentation_spaces: continuation_line.indentation_spaces,
},
None => ContinuationLineRule {
enabled: false,
indentation_spaces: INDENTATION_LEVEL_DEFAULT,
},
}
}

pub fn check(&self, acc: &mut Vec<LocalDMLError>, lines: &[&str]) {
if !self.enabled {
return;
}

let arithmetic_operators = ["+", "-", "*", "/", "%", "="];
let comparison_operators = ["==", "!=", "<", ">", "<=", ">="];
let logical_operators = ["&&", "||"];
let bitwise_operators = ["&", "|", "<<", ">>"];

let operators = [
&arithmetic_operators[..],
&comparison_operators[..],
&logical_operators[..],
&bitwise_operators[..],
];

for (i, line) in lines.iter().enumerate() {
if let Some(last_char) = line.trim().chars().last() {
if operators.iter().any(|ops| ops.contains(&last_char.to_string().as_str())) {
let next_line = lines.get(i + 1);
if let Some(next_line) = next_line {
let expected_indent = line.chars().take_while(|c| c.is_whitespace()).count() + self.indentation_spaces as usize;
let actual_indent = next_line.chars().take_while(|c| c.is_whitespace()).count();
if actual_indent != expected_indent {
let msg = ContinuationLineRule::description().to_owned();
let dmlerror = LocalDMLError {
range: Range::new(
Row::new_zero_indexed((i + 1) as u32),
Row::new_zero_indexed((i + 1) as u32),
Column::new_zero_indexed(0),
Column::new_zero_indexed(next_line.len() as u32)
),
description: msg,
};
acc.push(dmlerror);
}
}
}
}
}
}
}

impl Rule for ContinuationLineRule {
fn name() -> &'static str {
"CONTINUATION_LINE"
}

fn description() -> &'static str {
"Continuation line not indented correctly"
}
}

pub struct IN9Rule {
pub enabled: bool,
indentation_spaces: u32
Expand Down
4 changes: 3 additions & 1 deletion src/lint/rules/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ pub mod test;
use spacing::{SpBracesRule,
SpPunctRule, NspFunparRule, NspInparenRule,
NspUnaryRule, NspTrailingRule};
use indentation::{LongLinesRule, IN3Rule, IN9Rule};
use indentation::{LongLinesRule, IN3Rule, IN9Rule, ContinuationLineRule};
use crate::lint::LintCfg;

pub struct CurrentRules {
Expand All @@ -17,6 +17,7 @@ pub struct CurrentRules {
pub nsp_trailing: NspTrailingRule,
pub long_lines: LongLinesRule,
pub in3: IN3Rule,
pub continuation_line: ContinuationLineRule,
pub in9: IN9Rule
}

Expand All @@ -30,6 +31,7 @@ pub fn instantiate_rules(cfg: &LintCfg) -> CurrentRules {
nsp_trailing: NspTrailingRule { enabled: cfg.nsp_trailing.is_some() },
long_lines: LongLinesRule::from_options(&cfg.long_lines),
in3: IN3Rule::from_options(&cfg.in3),
continuation_line: ContinuationLineRule::from_options(&cfg.continuation_line),
in9: IN9Rule::from_options(&cfg.in9),
}
}
Expand Down
67 changes: 67 additions & 0 deletions src/lint/rules/test/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -213,4 +213,71 @@ fn in9_correct_case_indent() {
assert_snippet(IN9_INCORRECT_CASE_INDENT, 4, &rules);
}

pub static IN6_CONTINUATION_LINE_INCORRECT: &str = "
method set_irq() {
interrupt_enabled =
irq_enabled(interrupt_device);
}
";

pub static IN6_CONTINUATION_LINE_INCORRECT_2: &str = "
bank regs {
register control size 4 @ 0x00 {
field enable @ [0];
field mode @ [2:1];
field status @ [31:3] {
param init_val = (1 << 2) |
(1 << 1);
}
}
}
";

pub static IN6_CONTINUATION_LINE_INCORRECT_3: &str = "
method write(uint64 value) {
local uint64 a = value;
local uint64 result = a <<
2;
log info: 'Writing to register, result after left shift = %x', result;
}
";

pub static IN6_CONTINUATION_LINE_OK: &str = "
method set_irq() {
interrupt_enabled =
irq_enabled(interrupt_device);
}
";

pub static IN6_CONTINUATION_LINE_OK_2: &str = "
method calculate_sum(uint64 a, uint64 b) -> (uint64) {
return (a + b) * (a - b) +
(a * b);
}
";

pub static IN6_CONTINUATION_LINE_OK_3: &str = "
bank regs {
register example_register size 4 @ 0x00 {
method read() -> (uint64) {
local uint64 value = (this.val + 10) *
(this.val - 5);
return value;
}
}
}
";

#[test]
fn in6_continuation_line() {
let rules = set_up();

assert_snippet(IN6_CONTINUATION_LINE_INCORRECT, 1, &rules);
assert_snippet(IN6_CONTINUATION_LINE_INCORRECT_2, 1, &rules);
assert_snippet(IN6_CONTINUATION_LINE_INCORRECT_3, 1, &rules);
assert_snippet(IN6_CONTINUATION_LINE_OK, 0, &rules);
assert_snippet(IN6_CONTINUATION_LINE_OK_2, 0, &rules);
assert_snippet(IN6_CONTINUATION_LINE_OK_3, 0, &rules);
}

}

0 comments on commit c411fa4

Please sign in to comment.