Skip to content

Commit b5db0c1

Browse files
committed
extract code-blocks, run code-blocks, parse rustc output
1 parent 25bcf8b commit b5db0c1

File tree

9 files changed

+438
-43
lines changed

9 files changed

+438
-43
lines changed

exts/coding_guidelines/__init__.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,12 @@
1111
from .common import logger, get_tqdm, bar_format, logging
1212
from sphinx.domains import Domain
1313

14+
import logging
15+
16+
# Get the Sphinx logger
17+
logger = logging.getLogger('sphinx')
18+
logger.setLevel(logging.ERROR)
19+
1420
class CodingGuidelinesDomain(Domain):
1521
name = "coding-guidelines"
1622
label = "Rust Standard Library"

exts/coding_guidelines/rust_examples_test.py

Lines changed: 0 additions & 38 deletions
This file was deleted.

exts/rust-code-runner/__init__.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
2+
from . import rust_examples_aggregate
3+
from . import rustc
4+
import os
5+
def setup(app):
6+
7+
app.output_rust_file = "exts/rust-code-runner/generated.rs"
8+
if os.path.isfile(app.output_rust_file):
9+
with open(app.output_rust_file, 'w'):
10+
pass
11+
12+
# we hook into 'source-read' because data is mutable at this point and easier to parse
13+
# and it also makes this extension indepandant from `needs`
14+
#
15+
app.connect('source-read', rust_examples_aggregate.preprocess_rst_for_rust_code)
16+
app.connect('build-finished', rustc.check_rust_test_errors)
17+
return {
18+
'version': '0.1',
19+
'parallel_read_safe': False,
20+
}

exts/rust-code-runner/generated.rs

Lines changed: 232 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,232 @@
1+
// ==== Code Block 1 ====
2+
#[test]
3+
fn test_block_coding_guidelines_expressions_1() {
4+
#[repr(C)]
5+
struct Base {
6+
position: (u32, u32)
7+
}
8+
}
9+
10+
// ==== Code Block 2 ====
11+
#[test]
12+
fn test_block_coding_guidelines_expressions_2() {
13+
#[repr(C)]
14+
struct Base {
15+
position: (u32, u32)
16+
}
17+
}
18+
19+
// ==== Code Block 1 ====
20+
#[test]
21+
fn test_block_coding_guidelines_macros_1() {
22+
fn example_function() {
23+
// Non-compliant implementation
24+
}
25+
}
26+
27+
// ==== Code Block 2 ====
28+
#[test]
29+
fn test_block_coding_guidelines_macros_2() {
30+
fn example_function() {
31+
// Compliant implementation
32+
}
33+
}
34+
35+
// ==== Code Block 3 ====
36+
#[test]
37+
fn test_block_coding_guidelines_macros_3() {
38+
// TODO
39+
}
40+
41+
// ==== Code Block 4 ====
42+
#[test]
43+
fn test_block_coding_guidelines_macros_4() {
44+
// TODO
45+
}
46+
47+
// ==== Code Block 5 ====
48+
#[test]
49+
fn test_block_coding_guidelines_macros_5() {
50+
// HIDDEN START
51+
use std::vec::*;
52+
// HIDDEN END
53+
macro_rules! increment_and_double {
54+
($x:expr) => {
55+
{
56+
$x += 1; // mutation is implicit
57+
$x * 2
58+
}
59+
};
60+
}
61+
let mut num = 5;
62+
let vv = Vec![];
63+
let result = increment_and_double!(num);
64+
println!("Result: {}, Num: {}", result, num);
65+
// Result: 12, Num: 6
66+
}
67+
68+
// ==== Code Block 6 ====
69+
#[test]
70+
fn test_block_coding_guidelines_macros_6() {
71+
fn increment_and_double(x: &mut i32) -> i32 {
72+
*x += 1; // mutation is explicit
73+
*x * 2
74+
}
75+
let mut num = 5;
76+
let result = increment_and_double(&mut num);
77+
println!("Result: {}, Num: {}", result, num);
78+
// Result: 12, Num: 6
79+
}
80+
81+
// ==== Code Block 7 ====
82+
#[test]
83+
fn test_block_coding_guidelines_macros_7() {
84+
fn example_function() {
85+
// Non-compliant implementation
86+
}
87+
}
88+
89+
// ==== Code Block 8 ====
90+
#[test]
91+
fn test_block_coding_guidelines_macros_8() {
92+
fn example_function() {
93+
// Compliant implementation
94+
}
95+
}
96+
97+
// ==== Code Block 9 ====
98+
#[test]
99+
fn test_block_coding_guidelines_macros_9() {
100+
fn example_function() {
101+
// Non-compliant implementation
102+
}
103+
}
104+
105+
// ==== Code Block 10 ====
106+
#[test]
107+
fn test_block_coding_guidelines_macros_10() {
108+
fn example_function() {
109+
// Compliant implementation
110+
}
111+
}
112+
113+
// ==== Code Block 11 ====
114+
#[test]
115+
fn test_block_coding_guidelines_macros_11() {
116+
fn example_function() {
117+
// Non-compliant implementation
118+
}
119+
}
120+
121+
// ==== Code Block 12 ====
122+
#[test]
123+
fn test_block_coding_guidelines_macros_12() {
124+
fn example_function() {
125+
// Compliant implementation
126+
}
127+
}
128+
129+
// ==== Code Block 13 ====
130+
#[test]
131+
fn test_block_coding_guidelines_macros_13() {
132+
fn example_function() {
133+
// Non-compliant implementation
134+
}
135+
}
136+
137+
// ==== Code Block 14 ====
138+
#[test]
139+
fn test_block_coding_guidelines_macros_14() {
140+
fn example_function() {
141+
// Compliant implementation
142+
}
143+
}
144+
145+
// ==== Code Block 15 ====
146+
#[test]
147+
fn test_block_coding_guidelines_macros_15() {
148+
#[tokio::main] // non-compliant
149+
async fn maind() {
150+
//dd
151+
}
152+
}
153+
154+
// ==== Code Block 16 ====
155+
#[test]
156+
fn test_block_coding_guidelines_macros_16() {
157+
fn example_function() {
158+
// Compliant implementation
159+
}
160+
}
161+
162+
// ==== Code Block 17 ====
163+
#[test]
164+
fn test_block_coding_guidelines_macros_17() {
165+
fn example_function() {
166+
// Non-compliant implementation
167+
}
168+
}
169+
170+
// ==== Code Block 18 ====
171+
#[test]
172+
fn test_block_coding_guidelines_macros_18() {
173+
// HIDDEN START
174+
use std::fs;
175+
use std::io::{self, Read};
176+
// HIDDEN END
177+
}
178+
179+
// ==== Code Block 1 ====
180+
#[test]
181+
fn test_block_coding_guidelines_types_and_traits_1() {
182+
fn calculate_next_position(current: u32, velocity: u32) -> u32 {
183+
// Potential for silent overflow in release builds
184+
current + velocity
185+
}
186+
}
187+
188+
// ==== Code Block 2 ====
189+
#[test]
190+
fn test_block_coding_guidelines_types_and_traits_2() {
191+
fn calculate_next_position(current: u32, velocity: u32) -> u32 {
192+
// Explicitly handle potential overflow with checked addition
193+
current.checked_add(velocity).expect("Position calculation overflowed")
194+
}
195+
}
196+
197+
// ==== Code Block 1 ====
198+
#[test]
199+
fn test_block_process_style_guideline_1() {
200+
fn calculate_next_position(current: u32, velocity: u32) -> u32 {
201+
// Potential for silent overflow in release builds
202+
current + velocity
203+
}
204+
}
205+
206+
// ==== Code Block 2 ====
207+
#[test]
208+
fn test_block_process_style_guideline_2() {
209+
fn calculate_next_position(current: u32, velocity: u32) -> u32 {
210+
// Explicitly handle potential overflow with checked addition
211+
current.checked_add(velocity).expect("Position calculation overflowed")
212+
}
213+
}
214+
215+
// ==== Code Block 3 ====
216+
#[test]
217+
fn test_block_process_style_guideline_3() {
218+
fn calculate_next_position(current: u32, velocity: u32) -> u32 {
219+
// Potential for silent overflow in release builds
220+
current + velocity
221+
}
222+
}
223+
224+
// ==== Code Block 4 ====
225+
#[test]
226+
fn test_block_process_style_guideline_4() {
227+
fn calculate_next_position(current: u32, velocity: u32) -> u32 {
228+
// Explicitly handle potential overflow with checked addition
229+
current.checked_add(velocity).expect("Position calculation overflowed")
230+
}
231+
}
232+
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
from sphinx.errors import SphinxError
2+
import logging
3+
import re
4+
5+
logger = logging.getLogger('sphinx')
6+
# reducing errors temporarly for dev
7+
logger.setLevel(logging.ERROR)
8+
9+
class ExecuteRustExamples(SphinxError):
10+
category = "ExecuteRustExamples Error"
11+
12+
13+
def extract_code_blocks(text):
14+
pattern = re.compile(
15+
r"\.\. code-block:: rust\s*\n(?:(?:\s*\n)+)?((?: {2,}.*(?:\n|$))+)",
16+
re.MULTILINE
17+
)
18+
19+
matches = pattern.findall(text)
20+
blocks = []
21+
for i, block in enumerate(matches):
22+
lines = block.splitlines()
23+
non_empty_lines = [line for line in lines if line.strip()]
24+
processed_block = "\n".join(non_empty_lines)
25+
blocks.append(processed_block)
26+
27+
# print(f"====== code block {i + 1} ========")
28+
# print(processed_block)
29+
# print("====== end code block ========")
30+
31+
return blocks
32+
33+
def strip_hidden(code_block):
34+
lines = code_block.splitlines()
35+
result = []
36+
hidden = []
37+
is_hidden = False
38+
39+
for line in lines:
40+
stripped_for_marker_check = line[2:] if line.startswith(" ") else line
41+
if "// HIDDEN START" in stripped_for_marker_check:
42+
is_hidden = True
43+
continue
44+
if "// HIDDEN END" in stripped_for_marker_check:
45+
is_hidden = False
46+
continue
47+
if not is_hidden:
48+
result.append(line)
49+
else:
50+
hidden.append(line)
51+
return "\n".join(result), "\n".join(hidden)
52+
53+
def remove_hidden_blocks_from_document(source_text):
54+
code_block_re = re.compile(
55+
r"(\.\. code-block:: rust\s*\n\n)((?: {2}.*\n)+)",
56+
re.DOTALL
57+
)
58+
# callback for replacing
59+
def replacer(match):
60+
prefix = match.group(1)
61+
code_content = match.group(2)
62+
cleaned_code, hidden_code = strip_hidden(code_content)
63+
print("============")
64+
print(hidden_code)
65+
print("============")
66+
return prefix + cleaned_code
67+
68+
modified_text = code_block_re.sub(replacer, source_text)
69+
return modified_text
70+
71+
72+
def preprocess_rst_for_rust_code(app, docname, source):
73+
74+
original_content = source[0]
75+
code_blocks = extract_code_blocks(original_content)
76+
modified_content = remove_hidden_blocks_from_document(original_content)
77+
source[0] = modified_content
78+
79+
print(f"Original content length: {len(original_content)}")
80+
print(f"Extracted {len(code_blocks)} code blocks")
81+
82+
output_path = "exts/rust-code-runner/generated.rs"
83+
safe_docname = docname.replace("/", "_").replace("-", "_")
84+
with open(output_path, "a", encoding="utf-8") as f:
85+
for i, block in enumerate(code_blocks, start=1):
86+
f.write(f"// ==== Code Block {i} ====\n")
87+
f.write("#[test]\n")
88+
f.write(f"fn test_block_{safe_docname}_{i}() {{\n")
89+
for line in block.splitlines():
90+
f.write(f" {line}\n")
91+
f.write("}\n\n")

0 commit comments

Comments
 (0)