Parse a single `line` node into a `BasicLine` struct.
(state: &ExtractionState, node: TsNode<'a>)
| 173 | |
| 174 | /// Parse a single `line` node into a `BasicLine` struct. |
| 175 | fn parse_line<'a>(state: &ExtractionState, node: TsNode<'a>) -> Option<BasicLine<'a>> { |
| 176 | let line_number_node = find_direct_child_by_kind(node, "line_number")?; |
| 177 | let line_number_text = state.node_text(line_number_node); |
| 178 | let line_number: u32 = line_number_text.trim().parse().unwrap_or(0); |
| 179 | |
| 180 | // Navigate: line -> statement_list -> statement -> specific_kind |
| 181 | let statement_list = find_direct_child_by_kind(node, "statement_list")?; |
| 182 | let statement = find_direct_child_by_kind(statement_list, "statement")?; |
| 183 | |
| 184 | // Get the first named child of statement (the actual statement type). |
| 185 | let mut stmt_cursor = statement.walk(); |
| 186 | let mut statement_kind = String::new(); |
| 187 | let mut comment_text = None; |
| 188 | if stmt_cursor.goto_first_child() { |
| 189 | let child = stmt_cursor.node(); |
| 190 | statement_kind = child.kind().to_string(); |
| 191 | if child.kind() == "comment" { |
| 192 | let text = state.node_text(child); |
| 193 | // Strip a leading "REM" keyword (case-insensitive) when present. |
| 194 | // Content-checked so non-ASCII text never lands the byte cut |
| 195 | // inside a multi-byte character. |
| 196 | let stripped = text |
| 197 | .get(..3) |
| 198 | .filter(|p| p.eq_ignore_ascii_case("REM")) |
| 199 | .map_or(text.as_str(), |_| &text[3..]) |
| 200 | .trim() |
| 201 | .to_string(); |
| 202 | comment_text = Some(stripped); |
| 203 | } |
| 204 | } |
| 205 | |
| 206 | Some(BasicLine { |
| 207 | node, |
| 208 | line_number, |
| 209 | statement_kind, |
| 210 | comment_text, |
| 211 | }) |
| 212 | } |
| 213 | |
| 214 | /// Extract LET statements that are outside subroutines as top-level constants. |
| 215 | /// |
nothing calls this directly
no test coverage detected