1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115
use duckscript::types::instruction::{Instruction, InstructionType}; use std::cmp::min; #[cfg(test)] #[path = "./instruction_query_test.rs"] mod instruction_query_test; #[derive(Debug, Clone)] pub(crate) struct Positions { pub(crate) middle: Vec<usize>, pub(crate) end: usize, } fn get_start(start: Option<usize>) -> usize { match start { Some(value) => value, None => 0, } } fn get_end(end: Option<usize>, instructions: &Vec<Instruction>) -> usize { match end { Some(value) => min(instructions.len(), value), None => instructions.len(), } } pub(crate) fn find_commands( instructions: &Vec<Instruction>, start_names: &Vec<String>, middle_names: &Vec<String>, end_names: &Vec<String>, start: Option<usize>, end: Option<usize>, allow_recursive: bool, start_blocks: &Vec<String>, end_blocks: &Vec<String>, ) -> Result<Option<Positions>, String> { if start_names.is_empty() || end_names.is_empty() { Err("No command names/aliases provided for search.".to_string()) } else { let start_index = get_start(start); let end_index = get_end(end, instructions); let mut positions = Positions { middle: vec![], end: 0, }; let mut skip_to = start_index; let mut block_delta = 0; for line in start_index..end_index { if line >= skip_to { let instruction = &instructions[line]; match instruction.instruction_type { InstructionType::Script(ref script_instruction) => { match script_instruction.command { Some(ref command) => { if start_blocks.contains(command) { block_delta = block_delta + 1; } else if middle_names.contains(command) { positions.middle.push(line); } else if end_blocks.contains(command) && block_delta > 0 { block_delta = block_delta - 1; } else if end_names.contains(command) { positions.end = line; return Ok(Some(positions)); } else if start_names.contains(command) { if allow_recursive { match find_commands( instructions, start_names, middle_names, end_names, Some(line + 1), Some(end_index), allow_recursive, start_blocks, end_blocks, ) { Ok(positions_options) => match positions_options { Some(sub_positions) => { skip_to = sub_positions.end + 1; () } None => return Err(format!("Unsupported nested structure: {} found but end of structure not found.",command).to_string()), }, Err(error) => return Err(error), }; } else { return Err(format!( "Unsupported nested structure: {} found.", command ) .to_string()); } } () } None => (), } } _ => (), } } } Err(format!( "Missing end of structure for start names: {:?} start: {} end: {}", &start_names, start_index, end_index ) .to_string()) } }