mcfunction_debugger/generator/
partition.rs1use crate::generator::parser::{
20 command::{argument::minecraft::MinecraftEntityAnchor, resource_location::ResourceLocation},
21 Line, SelectorValue,
22};
23use std::{collections::BTreeMap, fmt::Display, str::FromStr};
24
25pub(crate) struct Partition<'l> {
26 pub(crate) start: Position,
27 pub(crate) end: Position,
28 pub(crate) regular_lines: &'l [(usize, String, Line)],
29 pub(crate) terminator: Terminator<'l>,
30}
31
32pub(crate) enum Terminator<'l> {
33 ConfigurableBreakpoint {
34 position_in_line: SuspensionPositionInLine,
35 },
36 FunctionCall {
37 column_index: usize,
38 line: &'l str,
39 name: &'l ResourceLocation,
40 anchor: &'l Option<MinecraftEntityAnchor>,
41 selectors: &'l BTreeMap<usize, SelectorValue>,
42 },
43 Return,
44}
45
46pub(crate) fn partition<'l>(lines: &'l [(usize, String, Line)]) -> Vec<Partition<'l>> {
47 let mut partitions = Vec::new();
48 let mut end = Position {
49 line_number: 1,
50 position_in_line: PositionInLine::Entry,
51 };
52
53 for (line_index, (_line_number, line, command)) in lines.iter().enumerate() {
55 let line_number = line_index + 1;
56 if let Line::Empty | Line::Comment = command {
57 continue;
58 }
59 let start = end;
60 end = Position {
61 line_number,
62 position_in_line: PositionInLine::Breakpoint,
63 };
64 let include_start_line = start.position_in_line == PositionInLine::Entry
65 || start.position_in_line == PositionInLine::Breakpoint;
66 let start_regular_line_index = start.line_number - if include_start_line { 1 } else { 0 };
67 partitions.push(Partition {
68 start,
69 end,
70 regular_lines: &lines[start_regular_line_index..line_index],
71 terminator: Terminator::ConfigurableBreakpoint {
72 position_in_line: SuspensionPositionInLine::Breakpoint,
73 },
74 });
75
76 if let Line::FunctionCall {
77 column_index,
78 name,
79 anchor,
80 selectors,
81 ..
82 } = command
83 {
84 let start = end;
85 end = Position {
86 line_number,
87 position_in_line: PositionInLine::Function,
88 };
89 partitions.push(Partition {
90 start,
91 end,
92 regular_lines: &[],
93 terminator: Terminator::FunctionCall {
94 column_index: *column_index,
95 line,
96 name,
97 anchor,
98 selectors,
99 },
100 });
101 }
102 }
103 if end.position_in_line == PositionInLine::Entry {
104 let start = end;
105 end = Position {
106 line_number: start.line_number,
107 position_in_line: PositionInLine::Breakpoint,
108 };
109 partitions.push(Partition {
110 start,
111 end,
112 regular_lines: &[],
113 terminator: Terminator::ConfigurableBreakpoint {
114 position_in_line: SuspensionPositionInLine::Breakpoint,
115 },
116 })
117 }
118
119 if end.position_in_line == PositionInLine::Function {
120 let start = end;
121 let last_line = start.line_number >= lines.len();
122 let line_number = start.line_number + if last_line { 0 } else { 1 };
123 let position_in_line = if last_line {
124 SuspensionPositionInLine::AfterFunction
125 } else {
126 SuspensionPositionInLine::Breakpoint
127 };
128 end = Position {
129 line_number,
130 position_in_line: position_in_line.into(),
131 };
132 partitions.push(Partition {
133 start,
134 end,
135 regular_lines: &[],
136 terminator: Terminator::ConfigurableBreakpoint { position_in_line },
137 });
138 }
139
140 let start = end;
141 end = Position {
142 line_number: lines.len(),
143 position_in_line: PositionInLine::Return,
144 };
145 let start_regular_line_index = start.line_number
146 - if start.position_in_line == PositionInLine::Breakpoint {
147 1
148 } else {
149 0
150 };
151 partitions.push(Partition {
152 start,
153 end,
154 regular_lines: &lines[start_regular_line_index..lines.len()],
155 terminator: Terminator::Return,
156 });
157 partitions
158}
159
160#[derive(Clone, Copy, Debug, Eq, PartialEq)]
161pub(crate) struct Position {
162 pub(crate) line_number: usize,
163 pub(crate) position_in_line: PositionInLine,
164}
165impl FromStr for Position {
166 type Err = ();
167
168 fn from_str(s: &str) -> Result<Self, Self::Err> {
169 fn from_str_inner(s: &str) -> Option<Position> {
170 let (line_number, position_in_line) = s.split_once('_')?;
171 let line_number = line_number.parse().ok()?;
172 let position_in_line = position_in_line.parse().ok()?;
173 Some(Position {
174 line_number,
175 position_in_line,
176 })
177 }
178 from_str_inner(s).ok_or(())
179 }
180}
181impl Display for Position {
182 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
183 write!(f, "{}_{}", self.line_number, self.position_in_line)
184 }
185}
186#[derive(Clone, Copy, Debug, Eq, PartialEq)]
187pub(crate) enum PositionInLine {
188 Entry,
189 Breakpoint,
190 Function,
191 AfterFunction,
192 Return,
193}
194impl FromStr for PositionInLine {
195 type Err = ();
196
197 fn from_str(s: &str) -> Result<Self, Self::Err> {
198 match s {
199 "entry" => Ok(PositionInLine::Entry),
200 "breakpoint" => Ok(PositionInLine::Breakpoint),
201 "function" => Ok(PositionInLine::Function),
202 "after_function" => Ok(PositionInLine::AfterFunction),
203 "return" => Ok(PositionInLine::Return),
204 _ => Err(()),
205 }
206 }
207}
208impl Display for PositionInLine {
209 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
210 match self {
211 PositionInLine::Entry => write!(f, "entry"),
212 PositionInLine::Breakpoint => write!(f, "breakpoint"),
213 PositionInLine::Function => write!(f, "function"),
214 PositionInLine::AfterFunction => write!(f, "after_function"),
215 PositionInLine::Return => write!(f, "return"),
216 }
217 }
218}
219
220#[derive(Clone, Copy, Debug, Eq, PartialEq)]
221pub enum SuspensionPositionInLine {
222 Breakpoint,
223 AfterFunction,
224}
225impl From<SuspensionPositionInLine> for PositionInLine {
226 fn from(value: SuspensionPositionInLine) -> Self {
227 match value {
228 SuspensionPositionInLine::Breakpoint => PositionInLine::Breakpoint,
229 SuspensionPositionInLine::AfterFunction => PositionInLine::AfterFunction,
230 }
231 }
232}
233impl FromStr for SuspensionPositionInLine {
234 type Err = ();
235
236 fn from_str(s: &str) -> Result<Self, Self::Err> {
237 match s {
238 "breakpoint" => Ok(SuspensionPositionInLine::Breakpoint),
239 "after_function" => Ok(SuspensionPositionInLine::AfterFunction),
240 _ => Err(()),
241 }
242 }
243}
244impl Display for SuspensionPositionInLine {
245 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
246 match self {
247 SuspensionPositionInLine::Breakpoint => write!(f, "breakpoint"),
248 SuspensionPositionInLine::AfterFunction => write!(f, "after_function"),
249 }
250 }
251}