Skip to content

Commit 2f91482

Browse files
committed
feat: rewrite the linter for the string ' ;' in Lean
1 parent cae8fab commit 2f91482

File tree

3 files changed

+27
-7
lines changed

3 files changed

+27
-7
lines changed

Mathlib/Tactic/Linter/TextBased.lean

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ inductive StyleError where
5858
| windowsLineEnding
5959
/-- A line contains trailing whitespace. -/
6060
| trailingWhitespace
61+
/-- A line contains the string " ;" -/
62+
| semicolon
6163
deriving BEq
6264

6365
/-- How to format style errors -/
@@ -79,6 +81,7 @@ def StyleError.errorMessage (err : StyleError) : String := match err with
7981
| windowsLineEnding => "This line ends with a windows line ending (\r\n): please use Unix line\
8082
endings (\n) instead"
8183
| trailingWhitespace => "This line ends with some whitespace: please remove this"
84+
| semicolon => "This line contains a space before a semicolon"
8285

8386
/-- The error code for a given style error. Keep this in sync with `parse?_errorContext` below! -/
8487
-- FUTURE: we're matching the old codes in `lint-style.py` for compatibility;
@@ -87,6 +90,7 @@ def StyleError.errorCode (err : StyleError) : String := match err with
8790
| StyleError.adaptationNote => "ERR_ADN"
8891
| StyleError.windowsLineEnding => "ERR_WIN"
8992
| StyleError.trailingWhitespace => "ERR_TWS"
93+
| StyleError.semicolon => "ERR_SEM"
9094

9195
/-- Context for a style error: the actual error, the line number in the file we're reading
9296
and the path to the file. -/
@@ -164,6 +168,7 @@ def parse?_errorContext (line : String) : Option ErrorContext := Id.run do
164168
-- Use default values for parameters which are ignored for comparing style exceptions.
165169
-- NB: keep this in sync with `compare` above!
166170
| "ERR_ADN" => some (StyleError.adaptationNote)
171+
| "ERR_SEM" => some (StyleError.semicolon)
167172
| "ERR_TWS" => some (StyleError.trailingWhitespace)
168173
| "ERR_WIN" => some (StyleError.windowsLineEnding)
169174
| _ => none
@@ -219,6 +224,22 @@ def trailingWhitespaceLinter : TextbasedLinter := fun lines ↦ Id.run do
219224
return (errors, if errors.size > 0 then some fixedLines else none)
220225

221226

227+
/-- Lint a collection of input strings for the substring " ;". -/
228+
def semicolonLinter : TextbasedLinter := fun lines ↦ Id.run do
229+
let mut errors := Array.mkEmpty 0
230+
let mut fixedLines := lines
231+
for (line, idx) in lines.zipWithIndex do
232+
let pos := line.find (· == ';')
233+
if pos != line.endPos && line.get (line.prev pos) == ' ' then
234+
let indent := line.length - line.trimLeft.length
235+
let replaced := (line.trimLeft.replace " ;" "; ").replace " " " "
236+
errors := errors.push (StyleError.semicolon, idx + 1)
237+
-- Concatenate "indent" spaces... better ways to do so welcome!
238+
let space := "".intercalate (List.replicate indent " ")
239+
fixedLines := fixedLines.set! idx s!"{space}{replaced}"
240+
return (errors, if errors.size > 0 then some fixedLines else none)
241+
242+
222243
/-- Whether a collection of lines consists *only* of imports, blank lines and single-line comments.
223244
In practice, this means it's an imports-only file and exempt from almost all linting. -/
224245
def isImportsOnlyFile (lines : Array String) : Bool :=
@@ -230,7 +251,7 @@ end
230251

231252
/-- All text-based linters registered in this file. -/
232253
def allLinters : Array TextbasedLinter := #[
233-
adaptationNoteLinter, trailingWhitespaceLinter
254+
adaptationNoteLinter, semicolonLinter, trailingWhitespaceLinter
234255
]
235256

236257

scripts/lint-style.py

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@
3838

3939
ERR_IBY = 11 # isolated by
4040
ERR_IWH = 22 # isolated where
41-
ERR_SEM = 13 # the substring " ;"
4241
ERR_CLN = 16 # line starts with a colon
4342
ERR_IND = 17 # second line not correctly indented
4443
ERR_ARR = 18 # space after "←"
@@ -197,9 +196,6 @@ def isolated_by_dot_semicolon_check(lines, path):
197196
line = f"{indent}{line.lstrip()[3:]}"
198197
elif line.lstrip() == "where":
199198
errors += [(ERR_IWH, line_nr, path)]
200-
if " ;" in line:
201-
errors += [(ERR_SEM, line_nr, path)]
202-
line = line.replace(" ;", ";")
203199
if line.lstrip().startswith(":"):
204200
errors += [(ERR_CLN, line_nr, path)]
205201
newlines.append((line_nr, line))
@@ -236,8 +232,6 @@ def format_errors(errors):
236232
output_message(path, line_nr, "ERR_IBY", "Line is an isolated 'by'")
237233
if errno == ERR_IWH:
238234
output_message(path, line_nr, "ERR_IWH", "Line is an isolated where")
239-
if errno == ERR_SEM:
240-
output_message(path, line_nr, "ERR_SEM", "Line contains a space before a semicolon")
241235
if errno == ERR_CLN:
242236
output_message(path, line_nr, "ERR_CLN", "Put : and := before line breaks, not after")
243237
if errno == ERR_IND:

scripts/nolints-style.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,8 @@ Mathlib/Tactic/Linter/TextBased.lean : line 84 : ERR_ADN : Found the string "Ada
1515
Mathlib/Tactic/Linter/TextBased.lean : line 274 : ERR_ADN : Found the string "Adaptation note:", please use the #adaptation_note command instead
1616
Mathlib/Tactic/Linter/TextBased.lean : line 279 : ERR_ADN : Found the string "Adaptation note:", please use the #adaptation_note command instead
1717
Mathlib/Tactic/Linter/TextBased.lean : line 280 : ERR_ADN : Found the string "Adaptation note:", please use the #adaptation_note command instead
18+
19+
-- The linter for the substring " ;" fires on its own implementation.
20+
Mathlib/Tactic/Linter/TextBased.lean : line 69 : ERR_SEM : This line contains a space before a semicolon
21+
Mathlib/Tactic/Linter/TextBased.lean : line 336 : ERR_SEM : This line contains a space before a semicolon
22+
Mathlib/Tactic/Linter/TextBased.lean : line 345 : ERR_SEM : This line contains a space before a semicolon

0 commit comments

Comments
 (0)