MCPcopy Create free account
hub / github.com/ScriptedAlchemy/tracedecay / extract_subroutines

Method extract_subroutines

src/extraction/msbasic2_extractor.rs:314–450  ·  view source on GitHub ↗

Synthesize subroutine Function nodes from REM-labelled sections that end with RETURN. MS BASIC 2.0 has no formal subroutine syntax. We detect patterns like: ```basic 100 REM LOG A MESSAGE 110 REM PARAMS: ... 200 PRINT ... 210 RETURN ``` A REM line (or consecutive REM lines) followed by code ending with RETURN is treated as a subroutine. The REM text becomes the docstring, and a function name is d

(state: &mut ExtractionState, lines: &[BasicLine<'_>])

Source from the content-addressed store, hash-verified

312 /// is treated as a subroutine. The REM text becomes the docstring, and a
313 /// function name is derived from the first REM text.
314 fn extract_subroutines(state: &mut ExtractionState, lines: &[BasicLine<'_>]) {
315 let mut i = 0;
316 while i < lines.len() {
317 // Look for a REM line that starts a potential subroutine.
318 if lines[i].statement_kind == "comment" {
319 // Gather consecutive REM lines.
320 let rem_start = i;
321 let mut rem_comments: Vec<String> = Vec::new();
322 while i < lines.len() && lines[i].statement_kind == "comment" {
323 if let Some(ref text) = lines[i].comment_text {
324 rem_comments.push(text.clone());
325 }
326 i += 1;
327 }
328
329 // Check if the lines following the REM block end with RETURN.
330 let body_start = i;
331 let mut body_end = i;
332 let mut has_return = false;
333 while body_end < lines.len() {
334 if lines[body_end].statement_kind == "return_statement" {
335 has_return = true;
336 body_end += 1;
337 break;
338 }
339 // Stop at the next REM block (which would be the start of another subroutine).
340 if lines[body_end].statement_kind == "comment" {
341 break;
342 }
343 body_end += 1;
344 }
345
346 if has_return && body_start < body_end {
347 // Derive a function name from the first REM comment.
348 let fn_name = derive_function_name(&rem_comments);
349 let docstring = if rem_comments.is_empty() {
350 None
351 } else {
352 Some(rem_comments.join("\n"))
353 };
354
355 // The subroutine spans from the first REM line to the RETURN line.
356 let first_node = lines[rem_start].node;
357 let last_node = lines[body_end - 1].node;
358 let start_line = first_node.start_position().row as u32;
359 let end_line = last_node.end_position().row as u32;
360 let start_column = first_node.start_position().column as u32;
361 let end_column = last_node.end_position().column as u32;
362 let qualified_name = format!("{}::{}", state.qualified_prefix(), fn_name);
363 let fn_id = generate_node_id(
364 &state.file_path,
365 &NodeKind::Function,
366 &fn_name,
367 start_line,
368 );
369
370 // Count complexity by walking body lines' AST nodes.
371 let mut branches: u32 = 0;

Callers

nothing calls this directly

Calls 7

derive_function_nameFunction · 0.85
generate_node_idFunction · 0.85
pushMethod · 0.80
kindMethod · 0.80
is_emptyMethod · 0.45
parent_node_idMethod · 0.45

Tested by

no test coverage detected