ffmt 0.4.3__tar.gz → 0.4.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {ffmt-0.4.3 → ffmt-0.4.4}/Cargo.lock +26 -26
- {ffmt-0.4.3 → ffmt-0.4.4}/Cargo.toml +1 -1
- {ffmt-0.4.3 → ffmt-0.4.4}/PKG-INFO +1 -1
- {ffmt-0.4.3 → ffmt-0.4.4}/pyproject.toml +1 -1
- {ffmt-0.4.3 → ffmt-0.4.4}/src/classifier.rs +77 -1
- {ffmt-0.4.3 → ffmt-0.4.4}/tests/bugfixes.rs +60 -0
- {ffmt-0.4.3 → ffmt-0.4.4}/tests/classifier.rs +55 -0
- {ffmt-0.4.3 → ffmt-0.4.4}/.github/workflows/ci.yml +0 -0
- {ffmt-0.4.3 → ffmt-0.4.4}/.github/workflows/release.yml +0 -0
- {ffmt-0.4.3 → ffmt-0.4.4}/.github/workflows/update-readme-version.yml +0 -0
- {ffmt-0.4.3 → ffmt-0.4.4}/.gitignore +0 -0
- {ffmt-0.4.3 → ffmt-0.4.4}/.markdownlint.json +0 -0
- {ffmt-0.4.3 → ffmt-0.4.4}/.pre-commit-hooks.yaml +0 -0
- {ffmt-0.4.3 → ffmt-0.4.4}/.readthedocs.yml +0 -0
- {ffmt-0.4.3 → ffmt-0.4.4}/LICENSE +0 -0
- {ffmt-0.4.3 → ffmt-0.4.4}/README.md +0 -0
- {ffmt-0.4.3 → ffmt-0.4.4}/action.yml +0 -0
- {ffmt-0.4.3 → ffmt-0.4.4}/docs/ci.md +0 -0
- {ffmt-0.4.3 → ffmt-0.4.4}/docs/configuration.md +0 -0
- {ffmt-0.4.3 → ffmt-0.4.4}/docs/editors.md +0 -0
- {ffmt-0.4.3 → ffmt-0.4.4}/docs/getting-started.md +0 -0
- {ffmt-0.4.3 → ffmt-0.4.4}/docs/index.md +0 -0
- {ffmt-0.4.3 → ffmt-0.4.4}/docs/requirements.txt +0 -0
- {ffmt-0.4.3 → ffmt-0.4.4}/mkdocs.yml +0 -0
- {ffmt-0.4.3 → ffmt-0.4.4}/src/align.rs +0 -0
- {ffmt-0.4.3 → ffmt-0.4.4}/src/case_norm.rs +0 -0
- {ffmt-0.4.3 → ffmt-0.4.4}/src/cli.rs +0 -0
- {ffmt-0.4.3 → ffmt-0.4.4}/src/config.rs +0 -0
- {ffmt-0.4.3 → ffmt-0.4.4}/src/formatter.rs +0 -0
- {ffmt-0.4.3 → ffmt-0.4.4}/src/keyword_norm.rs +0 -0
- {ffmt-0.4.3 → ffmt-0.4.4}/src/lib.rs +0 -0
- {ffmt-0.4.3 → ffmt-0.4.4}/src/lsp.rs +0 -0
- {ffmt-0.4.3 → ffmt-0.4.4}/src/main.rs +0 -0
- {ffmt-0.4.3 → ffmt-0.4.4}/src/reader.rs +0 -0
- {ffmt-0.4.3 → ffmt-0.4.4}/src/scope.rs +0 -0
- {ffmt-0.4.3 → ffmt-0.4.4}/src/unicode.rs +0 -0
- {ffmt-0.4.3 → ffmt-0.4.4}/src/whitespace.rs +0 -0
- {ffmt-0.4.3 → ffmt-0.4.4}/tests/bughunt_classifier.rs +0 -0
- {ffmt-0.4.3 → ffmt-0.4.4}/tests/bughunt_cli.rs +0 -0
- {ffmt-0.4.3 → ffmt-0.4.4}/tests/bughunt_norm.rs +0 -0
- {ffmt-0.4.3 → ffmt-0.4.4}/tests/case_norm.rs +0 -0
- {ffmt-0.4.3 → ffmt-0.4.4}/tests/cli_bugs.rs +0 -0
- {ffmt-0.4.3 → ffmt-0.4.4}/tests/config_integration.rs +0 -0
- {ffmt-0.4.3 → ffmt-0.4.4}/tests/fixtures/blank_lines.expected.fpp +0 -0
- {ffmt-0.4.3 → ffmt-0.4.4}/tests/fixtures/blank_lines.input.fpp +0 -0
- {ffmt-0.4.3 → ffmt-0.4.4}/tests/fixtures/call_block.expected.fpp +0 -0
- {ffmt-0.4.3 → ffmt-0.4.4}/tests/fixtures/call_block.input.fpp +0 -0
- {ffmt-0.4.3 → ffmt-0.4.4}/tests/fixtures/directives.expected.fpp +0 -0
- {ffmt-0.4.3 → ffmt-0.4.4}/tests/fixtures/directives.input.fpp +0 -0
- {ffmt-0.4.3 → ffmt-0.4.4}/tests/fixtures/doxygen_spacing.expected.fpp +0 -0
- {ffmt-0.4.3 → ffmt-0.4.4}/tests/fixtures/doxygen_spacing.input.fpp +0 -0
- {ffmt-0.4.3 → ffmt-0.4.4}/tests/fixtures/fypp.expected.fpp +0 -0
- {ffmt-0.4.3 → ffmt-0.4.4}/tests/fixtures/fypp.input.fpp +0 -0
- {ffmt-0.4.3 → ffmt-0.4.4}/tests/fixtures/member_access_wrap.expected.fpp +0 -0
- {ffmt-0.4.3 → ffmt-0.4.4}/tests/fixtures/member_access_wrap.input.fpp +0 -0
- {ffmt-0.4.3 → ffmt-0.4.4}/tests/fixtures/simple.expected.fpp +0 -0
- {ffmt-0.4.3 → ffmt-0.4.4}/tests/fixtures/simple.input.fpp +0 -0
- {ffmt-0.4.3 → ffmt-0.4.4}/tests/fixtures/trailing_comment_wrap.expected.fpp +0 -0
- {ffmt-0.4.3 → ffmt-0.4.4}/tests/fixtures/trailing_comment_wrap.input.fpp +0 -0
- {ffmt-0.4.3 → ffmt-0.4.4}/tests/integration.rs +0 -0
- {ffmt-0.4.3 → ffmt-0.4.4}/tests/reader.rs +0 -0
- {ffmt-0.4.3 → ffmt-0.4.4}/tests/scope.rs +0 -0
- {ffmt-0.4.3 → ffmt-0.4.4}/tests/whitespace.rs +0 -0
|
@@ -63,12 +63,12 @@ dependencies = [
|
|
|
63
63
|
|
|
64
64
|
[[package]]
|
|
65
65
|
name = "bstr"
|
|
66
|
-
version = "1.12.
|
|
66
|
+
version = "1.12.3"
|
|
67
67
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
68
|
-
checksum = "
|
|
68
|
+
checksum = "5cee35f73844aa3014bb606320a6c1f010249dbdf43342fe54b5a4f6a8ed4b79"
|
|
69
69
|
dependencies = [
|
|
70
70
|
"memchr",
|
|
71
|
-
"
|
|
71
|
+
"serde_core",
|
|
72
72
|
]
|
|
73
73
|
|
|
74
74
|
[[package]]
|
|
@@ -119,9 +119,9 @@ checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570"
|
|
|
119
119
|
|
|
120
120
|
[[package]]
|
|
121
121
|
name = "crossbeam-deque"
|
|
122
|
-
version = "0.8.
|
|
122
|
+
version = "0.8.7"
|
|
123
123
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
124
|
-
checksum = "
|
|
124
|
+
checksum = "5181e0de7b61eb03a81e347d6dd8797bae9da5146707b51077e2d71a54ec0ceb"
|
|
125
125
|
dependencies = [
|
|
126
126
|
"crossbeam-epoch",
|
|
127
127
|
"crossbeam-utils",
|
|
@@ -129,18 +129,18 @@ dependencies = [
|
|
|
129
129
|
|
|
130
130
|
[[package]]
|
|
131
131
|
name = "crossbeam-epoch"
|
|
132
|
-
version = "0.9.
|
|
132
|
+
version = "0.9.20"
|
|
133
133
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
134
|
-
checksum = "
|
|
134
|
+
checksum = "2d6914041f254d6e9176c01941b21115dcfb7089e55135a35411081bd106ef3f"
|
|
135
135
|
dependencies = [
|
|
136
136
|
"crossbeam-utils",
|
|
137
137
|
]
|
|
138
138
|
|
|
139
139
|
[[package]]
|
|
140
140
|
name = "crossbeam-utils"
|
|
141
|
-
version = "0.8.
|
|
141
|
+
version = "0.8.22"
|
|
142
142
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
143
|
-
checksum = "
|
|
143
|
+
checksum = "61803da095bee82a81bb1a452ecc25d3b2f1416d1897eb86430c6159ef717c17"
|
|
144
144
|
|
|
145
145
|
[[package]]
|
|
146
146
|
name = "either"
|
|
@@ -156,7 +156,7 @@ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
|
|
|
156
156
|
|
|
157
157
|
[[package]]
|
|
158
158
|
name = "ffmt"
|
|
159
|
-
version = "0.4.
|
|
159
|
+
version = "0.4.4"
|
|
160
160
|
dependencies = [
|
|
161
161
|
"clap",
|
|
162
162
|
"ignore",
|
|
@@ -194,9 +194,9 @@ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
|
|
194
194
|
|
|
195
195
|
[[package]]
|
|
196
196
|
name = "ignore"
|
|
197
|
-
version = "0.4.
|
|
197
|
+
version = "0.4.28"
|
|
198
198
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
199
|
-
checksum = "
|
|
199
|
+
checksum = "2adf14691c72bcfc1058740436a35bdd3ae9c07d1a941ef00b749e9ea16aefa7"
|
|
200
200
|
dependencies = [
|
|
201
201
|
"crossbeam-deque",
|
|
202
202
|
"globset",
|
|
@@ -232,15 +232,15 @@ checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
|
|
|
232
232
|
|
|
233
233
|
[[package]]
|
|
234
234
|
name = "log"
|
|
235
|
-
version = "0.4.
|
|
235
|
+
version = "0.4.33"
|
|
236
236
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
237
|
-
checksum = "
|
|
237
|
+
checksum = "0ceec5bc11778974d1bcb055b18002eba7f4b3518b6a0081b3af5f21666da9ad"
|
|
238
238
|
|
|
239
239
|
[[package]]
|
|
240
240
|
name = "memchr"
|
|
241
|
-
version = "2.8.
|
|
241
|
+
version = "2.8.3"
|
|
242
242
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
243
|
-
checksum = "
|
|
243
|
+
checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98"
|
|
244
244
|
|
|
245
245
|
[[package]]
|
|
246
246
|
name = "once_cell_polyfill"
|
|
@@ -259,9 +259,9 @@ dependencies = [
|
|
|
259
259
|
|
|
260
260
|
[[package]]
|
|
261
261
|
name = "quote"
|
|
262
|
-
version = "1.0.
|
|
262
|
+
version = "1.0.46"
|
|
263
263
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
264
|
-
checksum = "
|
|
264
|
+
checksum = "dfbc457d0c7a0759a614551b11a6409e5951f6c7537be1f1b7682b9ae9230368"
|
|
265
265
|
dependencies = [
|
|
266
266
|
"proc-macro2",
|
|
267
267
|
]
|
|
@@ -288,9 +288,9 @@ dependencies = [
|
|
|
288
288
|
|
|
289
289
|
[[package]]
|
|
290
290
|
name = "regex"
|
|
291
|
-
version = "1.
|
|
291
|
+
version = "1.13.0"
|
|
292
292
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
293
|
-
checksum = "
|
|
293
|
+
checksum = "2a0e75113e14dc5acb068cd0786884f214f1312650a3d36d269f5c4f3cdee8a2"
|
|
294
294
|
dependencies = [
|
|
295
295
|
"aho-corasick",
|
|
296
296
|
"memchr",
|
|
@@ -300,9 +300,9 @@ dependencies = [
|
|
|
300
300
|
|
|
301
301
|
[[package]]
|
|
302
302
|
name = "regex-automata"
|
|
303
|
-
version = "0.4.
|
|
303
|
+
version = "0.4.15"
|
|
304
304
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
305
|
-
checksum = "
|
|
305
|
+
checksum = "1f388202e4b80542a0921078cc23b6333bcf1409c1e3f86404cae4766a6131db"
|
|
306
306
|
dependencies = [
|
|
307
307
|
"aho-corasick",
|
|
308
308
|
"memchr",
|
|
@@ -384,9 +384,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
|
|
384
384
|
|
|
385
385
|
[[package]]
|
|
386
386
|
name = "syn"
|
|
387
|
-
version = "2.0.
|
|
387
|
+
version = "2.0.118"
|
|
388
388
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
389
|
-
checksum = "
|
|
389
|
+
checksum = "1b9ae57f904213ebb649ce6895b8a66c66f0203b9319718f69a5612a065b1422"
|
|
390
390
|
dependencies = [
|
|
391
391
|
"proc-macro2",
|
|
392
392
|
"quote",
|
|
@@ -491,6 +491,6 @@ dependencies = [
|
|
|
491
491
|
|
|
492
492
|
[[package]]
|
|
493
493
|
name = "zmij"
|
|
494
|
-
version = "1.0.
|
|
494
|
+
version = "1.0.23"
|
|
495
495
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
496
|
-
checksum = "
|
|
496
|
+
checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b"
|
|
@@ -480,6 +480,66 @@ fn classify_fortran(trimmed: &str) -> LineKind {
|
|
|
480
480
|
LineKind::FortranStatement
|
|
481
481
|
}
|
|
482
482
|
|
|
483
|
+
/// Split a Fortran line into its top-level statements at semicolons, ignoring
|
|
484
|
+
/// semicolons inside string literals and stopping at an inline comment.
|
|
485
|
+
/// Returns the trimmed pieces (empty pieces are kept so callers can skip them).
|
|
486
|
+
fn split_top_level_statements(line: &str) -> Vec<&str> {
|
|
487
|
+
let bytes = line.as_bytes();
|
|
488
|
+
let mut pieces = Vec::new();
|
|
489
|
+
let mut start = 0;
|
|
490
|
+
let mut in_string = false;
|
|
491
|
+
let mut quote = b' ';
|
|
492
|
+
let mut i = 0;
|
|
493
|
+
while i < bytes.len() {
|
|
494
|
+
let b = bytes[i];
|
|
495
|
+
if in_string {
|
|
496
|
+
if b == quote {
|
|
497
|
+
// Doubled quote is an escape — stay inside the string.
|
|
498
|
+
if i + 1 < bytes.len() && bytes[i + 1] == quote {
|
|
499
|
+
i += 2;
|
|
500
|
+
continue;
|
|
501
|
+
}
|
|
502
|
+
in_string = false;
|
|
503
|
+
}
|
|
504
|
+
i += 1;
|
|
505
|
+
continue;
|
|
506
|
+
}
|
|
507
|
+
match b {
|
|
508
|
+
b'\'' | b'"' => {
|
|
509
|
+
in_string = true;
|
|
510
|
+
quote = b;
|
|
511
|
+
}
|
|
512
|
+
b'!' => break, // inline comment — nothing after it is a statement
|
|
513
|
+
b';' => {
|
|
514
|
+
pieces.push(line[start..i].trim());
|
|
515
|
+
start = i + 1;
|
|
516
|
+
}
|
|
517
|
+
_ => {}
|
|
518
|
+
}
|
|
519
|
+
i += 1;
|
|
520
|
+
}
|
|
521
|
+
pieces.push(line[start..].trim());
|
|
522
|
+
pieces
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
/// Net indentation effect of a line's top-level statements: +1 per block
|
|
526
|
+
/// opener, -1 per block closer, 0 for everything else (continuations,
|
|
527
|
+
/// statements). A self-contained single-line construct nets to 0.
|
|
528
|
+
fn net_block_delta(pieces: &[&str]) -> i32 {
|
|
529
|
+
let mut delta = 0;
|
|
530
|
+
for &piece in pieces {
|
|
531
|
+
if piece.is_empty() {
|
|
532
|
+
continue;
|
|
533
|
+
}
|
|
534
|
+
match classify_fortran(piece) {
|
|
535
|
+
LineKind::FortranBlockOpen => delta += 1,
|
|
536
|
+
LineKind::FortranBlockClose => delta -= 1,
|
|
537
|
+
_ => {}
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
delta
|
|
541
|
+
}
|
|
542
|
+
|
|
483
543
|
/// Classify a logical line.
|
|
484
544
|
pub fn classify(line: &str) -> LineKind {
|
|
485
545
|
let trimmed = line.trim();
|
|
@@ -518,7 +578,23 @@ pub fn classify(line: &str) -> LineKind {
|
|
|
518
578
|
}
|
|
519
579
|
|
|
520
580
|
// 6. Fortran
|
|
521
|
-
classify_fortran(trimmed)
|
|
581
|
+
let kind = classify_fortran(trimmed);
|
|
582
|
+
|
|
583
|
+
// A construct that opens AND closes on the same line (e.g.
|
|
584
|
+
// `do d = 1, n; s = s + d; end do`) has a net-zero indent effect. The
|
|
585
|
+
// leading keyword makes `classify_fortran` report a block opener, which
|
|
586
|
+
// would leak an indent level onto every following line. When the opener's
|
|
587
|
+
// matching closer is on the same line (net delta 0), treat the whole line
|
|
588
|
+
// as a plain statement instead — a block opener and a statement both sit at
|
|
589
|
+
// the current depth, so the line's own indentation is unchanged.
|
|
590
|
+
if kind == LineKind::FortranBlockOpen {
|
|
591
|
+
let pieces = split_top_level_statements(trimmed);
|
|
592
|
+
if pieces.len() > 1 && net_block_delta(&pieces) == 0 {
|
|
593
|
+
return LineKind::FortranStatement;
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
kind
|
|
522
598
|
}
|
|
523
599
|
|
|
524
600
|
/// Extract the scope name from a Fortran block-opening line.
|
|
@@ -726,3 +726,63 @@ fn test_keyword_case_upper_works() {
|
|
|
726
726
|
"identifier was uppercased:\n{out}"
|
|
727
727
|
);
|
|
728
728
|
}
|
|
729
|
+
|
|
730
|
+
// --- Single-line `do ...; end do` leaked an indent level (issue #5) ---
|
|
731
|
+
|
|
732
|
+
#[test]
|
|
733
|
+
fn test_single_line_do_does_not_leak_indent() {
|
|
734
|
+
// The `do ...; ...; end do` opens and closes on one line (net-zero indent).
|
|
735
|
+
// The following statement must stay at the SAME indent as the `do` line,
|
|
736
|
+
// not be over-indented by one level.
|
|
737
|
+
let src = "module m\n\
|
|
738
|
+
contains\n\
|
|
739
|
+
subroutine demo(n)\n\
|
|
740
|
+
integer, intent(in) :: n\n\
|
|
741
|
+
integer :: d, s\n\
|
|
742
|
+
s = 0\n\
|
|
743
|
+
do d = 1, n; s = s + d; end do\n\
|
|
744
|
+
s = s + 1\n\
|
|
745
|
+
end subroutine demo\n\
|
|
746
|
+
end module m\n";
|
|
747
|
+
let out = ffmt::format_string(src);
|
|
748
|
+
assert!(
|
|
749
|
+
out.contains(" do d = 1, n; s = s + d; end do\n s = s + 1\n"),
|
|
750
|
+
"single-line do leaked an indent level:\n{out}"
|
|
751
|
+
);
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
#[test]
|
|
755
|
+
fn test_single_line_do_output_is_idempotent() {
|
|
756
|
+
// Running ffmt twice must be a no-op (the correct output is the fixed point).
|
|
757
|
+
let src = "module m\n\
|
|
758
|
+
contains\n\
|
|
759
|
+
subroutine demo(n)\n\
|
|
760
|
+
integer, intent(in) :: n\n\
|
|
761
|
+
integer :: d, s\n\
|
|
762
|
+
s = 0\n\
|
|
763
|
+
do d = 1, n; s = s + d; end do\n\
|
|
764
|
+
s = s + 1\n\
|
|
765
|
+
end subroutine demo\n\
|
|
766
|
+
end module m\n";
|
|
767
|
+
let once = ffmt::format_string(src);
|
|
768
|
+
let twice = ffmt::format_string(&once);
|
|
769
|
+
assert_eq!(once, twice, "formatting is not idempotent");
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
#[test]
|
|
773
|
+
fn test_nested_single_line_do_does_not_compound_indent() {
|
|
774
|
+
// Two single-line constructs in sequence must each net to zero; the final
|
|
775
|
+
// statement stays at the subroutine-body indent (8 spaces).
|
|
776
|
+
let src = "program p\n\
|
|
777
|
+
integer :: i, j, s\n\
|
|
778
|
+
s = 0\n\
|
|
779
|
+
do i = 1, 3; s = s + i; end do\n\
|
|
780
|
+
if (s > 0) then; s = s + 1; end if\n\
|
|
781
|
+
s = s + 1\n\
|
|
782
|
+
end program p\n";
|
|
783
|
+
let out = ffmt::format_string(src);
|
|
784
|
+
assert!(
|
|
785
|
+
out.contains(" s = s + 1\nend program p\n"),
|
|
786
|
+
"single-line constructs compounded the indent:\n{out}"
|
|
787
|
+
);
|
|
788
|
+
}
|
|
@@ -387,3 +387,58 @@ fn test_interface_operator() {
|
|
|
387
387
|
LineKind::FortranBlockOpen
|
|
388
388
|
);
|
|
389
389
|
}
|
|
390
|
+
|
|
391
|
+
// --- Self-contained single-line constructs (issue #5) ---
|
|
392
|
+
// A construct that opens and closes on the same line has a net-zero indent
|
|
393
|
+
// effect, so it must classify as a statement (not a block opener), otherwise
|
|
394
|
+
// the trailing lines leak an indent level.
|
|
395
|
+
#[test]
|
|
396
|
+
fn test_single_line_do_is_statement() {
|
|
397
|
+
assert_eq!(
|
|
398
|
+
classify("do d = 1, n; s = s + d; end do"),
|
|
399
|
+
LineKind::FortranStatement
|
|
400
|
+
);
|
|
401
|
+
}
|
|
402
|
+
#[test]
|
|
403
|
+
fn test_single_line_if_then_is_statement() {
|
|
404
|
+
assert_eq!(
|
|
405
|
+
classify("if (x > 0) then; y = 1; end if"),
|
|
406
|
+
LineKind::FortranStatement
|
|
407
|
+
);
|
|
408
|
+
}
|
|
409
|
+
#[test]
|
|
410
|
+
fn test_single_line_block_is_statement() {
|
|
411
|
+
assert_eq!(
|
|
412
|
+
classify("block; call foo; end block"),
|
|
413
|
+
LineKind::FortranStatement
|
|
414
|
+
);
|
|
415
|
+
}
|
|
416
|
+
#[test]
|
|
417
|
+
fn test_single_line_associate_is_statement() {
|
|
418
|
+
assert_eq!(
|
|
419
|
+
classify("associate (a => b); x = a; end associate"),
|
|
420
|
+
LineKind::FortranStatement
|
|
421
|
+
);
|
|
422
|
+
}
|
|
423
|
+
#[test]
|
|
424
|
+
fn test_single_line_if_then_else_is_statement() {
|
|
425
|
+
// A continuation (else) between the opener and closer must not disturb the
|
|
426
|
+
// net-zero balance.
|
|
427
|
+
assert_eq!(
|
|
428
|
+
classify("if (x) then; a = 1; else; a = 2; end if"),
|
|
429
|
+
LineKind::FortranStatement
|
|
430
|
+
);
|
|
431
|
+
}
|
|
432
|
+
#[test]
|
|
433
|
+
fn test_do_with_body_no_end_stays_open() {
|
|
434
|
+
// Opener with a same-line body but NO closer still opens a scope.
|
|
435
|
+
assert_eq!(classify("do i = 1, n; a = 1"), LineKind::FortranBlockOpen);
|
|
436
|
+
}
|
|
437
|
+
#[test]
|
|
438
|
+
fn test_do_reopening_after_close_stays_open() {
|
|
439
|
+
// Opens, closes, opens again: net +1 → still a block opener.
|
|
440
|
+
assert_eq!(
|
|
441
|
+
classify("do i = 1, n; end do; do j = 1, m"),
|
|
442
|
+
LineKind::FortranBlockOpen
|
|
443
|
+
);
|
|
444
|
+
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|