use crate::generator::parser::{
command::{argument::minecraft::MinecraftEntityAnchor, resource_location::ResourceLocation},
Line, SelectorValue,
};
use std::{collections::BTreeMap, fmt::Display, str::FromStr};
pub(crate) struct Partition<'l> {
pub(crate) start: Position,
pub(crate) end: Position,
pub(crate) regular_lines: &'l [(usize, String, Line)],
pub(crate) terminator: Terminator<'l>,
}
pub(crate) enum Terminator<'l> {
ConfigurableBreakpoint {
position_in_line: SuspensionPositionInLine,
},
FunctionCall {
column_index: usize,
line: &'l str,
name: &'l ResourceLocation,
anchor: &'l Option<MinecraftEntityAnchor>,
selectors: &'l BTreeMap<usize, SelectorValue>,
},
Return,
}
pub(crate) fn partition<'l>(lines: &'l [(usize, String, Line)]) -> Vec<Partition<'l>> {
let mut partitions = Vec::new();
let mut end = Position {
line_number: 1,
position_in_line: PositionInLine::Entry,
};
for (line_index, (_line_number, line, command)) in lines.iter().enumerate() {
let line_number = line_index + 1;
if let Line::Empty | Line::Comment = command {
continue;
}
let start = end;
end = Position {
line_number,
position_in_line: PositionInLine::Breakpoint,
};
let include_start_line = start.position_in_line == PositionInLine::Entry
|| start.position_in_line == PositionInLine::Breakpoint;
let start_regular_line_index = start.line_number - if include_start_line { 1 } else { 0 };
partitions.push(Partition {
start,
end,
regular_lines: &lines[start_regular_line_index..line_index],
terminator: Terminator::ConfigurableBreakpoint {
position_in_line: SuspensionPositionInLine::Breakpoint,
},
});
if let Line::FunctionCall {
column_index,
name,
anchor,
selectors,
..
} = command
{
let start = end;
end = Position {
line_number,
position_in_line: PositionInLine::Function,
};
partitions.push(Partition {
start,
end,
regular_lines: &[],
terminator: Terminator::FunctionCall {
column_index: *column_index,
line,
name,
anchor,
selectors,
},
});
}
}
if end.position_in_line == PositionInLine::Entry {
let start = end;
end = Position {
line_number: start.line_number,
position_in_line: PositionInLine::Breakpoint,
};
partitions.push(Partition {
start,
end,
regular_lines: &[],
terminator: Terminator::ConfigurableBreakpoint {
position_in_line: SuspensionPositionInLine::Breakpoint,
},
})
}
if end.position_in_line == PositionInLine::Function {
let start = end;
let last_line = start.line_number >= lines.len();
let line_number = start.line_number + if last_line { 0 } else { 1 };
let position_in_line = if last_line {
SuspensionPositionInLine::AfterFunction
} else {
SuspensionPositionInLine::Breakpoint
};
end = Position {
line_number,
position_in_line: position_in_line.into(),
};
partitions.push(Partition {
start,
end,
regular_lines: &[],
terminator: Terminator::ConfigurableBreakpoint { position_in_line },
});
}
let start = end;
end = Position {
line_number: lines.len(),
position_in_line: PositionInLine::Return,
};
let start_regular_line_index = start.line_number
- if start.position_in_line == PositionInLine::Breakpoint {
1
} else {
0
};
partitions.push(Partition {
start,
end,
regular_lines: &lines[start_regular_line_index..lines.len()],
terminator: Terminator::Return,
});
partitions
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub(crate) struct Position {
pub(crate) line_number: usize,
pub(crate) position_in_line: PositionInLine,
}
impl FromStr for Position {
type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> {
fn from_str_inner(s: &str) -> Option<Position> {
let (line_number, position_in_line) = s.split_once('_')?;
let line_number = line_number.parse().ok()?;
let position_in_line = position_in_line.parse().ok()?;
Some(Position {
line_number,
position_in_line,
})
}
from_str_inner(s).ok_or(())
}
}
impl Display for Position {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}_{}", self.line_number, self.position_in_line)
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub(crate) enum PositionInLine {
Entry,
Breakpoint,
Function,
AfterFunction,
Return,
}
impl FromStr for PositionInLine {
type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"entry" => Ok(PositionInLine::Entry),
"breakpoint" => Ok(PositionInLine::Breakpoint),
"function" => Ok(PositionInLine::Function),
"after_function" => Ok(PositionInLine::AfterFunction),
"return" => Ok(PositionInLine::Return),
_ => Err(()),
}
}
}
impl Display for PositionInLine {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
PositionInLine::Entry => write!(f, "entry"),
PositionInLine::Breakpoint => write!(f, "breakpoint"),
PositionInLine::Function => write!(f, "function"),
PositionInLine::AfterFunction => write!(f, "after_function"),
PositionInLine::Return => write!(f, "return"),
}
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum SuspensionPositionInLine {
Breakpoint,
AfterFunction,
}
impl From<SuspensionPositionInLine> for PositionInLine {
fn from(value: SuspensionPositionInLine) -> Self {
match value {
SuspensionPositionInLine::Breakpoint => PositionInLine::Breakpoint,
SuspensionPositionInLine::AfterFunction => PositionInLine::AfterFunction,
}
}
}
impl FromStr for SuspensionPositionInLine {
type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"breakpoint" => Ok(SuspensionPositionInLine::Breakpoint),
"after_function" => Ok(SuspensionPositionInLine::AfterFunction),
_ => Err(()),
}
}
}
impl Display for SuspensionPositionInLine {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
SuspensionPositionInLine::Breakpoint => write!(f, "breakpoint"),
SuspensionPositionInLine::AfterFunction => write!(f, "after_function"),
}
}
}