use crate::area::Area;
use crate::code::UnOptCode;
pub(crate) const COMMANDS: &'static [char] = &['형', '항', '핫', '흣', '흡', '흑'];
const HEARTS: &'static [char] = &[
'♥', '❤', '💕', '💖', '💗', '💘', '💙', '💚', '💛', '💜', '💝', '♡',
];
pub fn is_hangul_syllable(c: char) -> bool {
'\u{AC00}' <= c && c <= '\u{D7A3}'
}
pub fn parse(code: String) -> Vec<UnOptCode> {
let mut res: Vec<UnOptCode> = Vec::new();
let mut hangul_count = 0usize;
let mut dot_count = 0usize;
let mut type_ = 10u8;
let mut loc = (1usize, 0usize);
let mut state = 0u8;
let mut area = Area::Nil;
let mut leaf = &mut area;
let mut qu_area = Area::Nil;
let mut qu_leaf = &mut qu_area;
let mut line_count = 0;
let mut last_line_started = 0;
let mut raw_command = String::new();
let mut max_pos = [0usize, 0usize, 0usize];
for (i, c) in code.chars().enumerate() {
if let Some(t) = "엉앙앗읏읍윽".find(c) {
max_pos[if t == 0 {
0
} else if t <= 6 {
1
} else {
2
}] = i;
}
}
for (i, c) in code.chars().enumerate() {
if c.is_whitespace() {
if c == '\n' {
line_count += 1;
last_line_started = i + 1;
}
continue;
}
state = match state {
0 | 2 => {
if let Some(mut t) = "형항핫흣흡흑혀하흐".find(c) {
t /= 3;
if t >= 6 && max_pos[t - 6] <= i {
continue;
}
if type_ != 10 {
res.push(UnOptCode::new(
type_,
hangul_count,
dot_count,
loc,
match qu_leaf {
Area::Val {
type_: _,
left: _,
ref mut right,
} => {
*right = Box::new(area);
qu_area
}
Area::Nil => area,
},
raw_command,
));
area = Area::Nil;
leaf = &mut area;
qu_area = Area::Nil;
qu_leaf = &mut qu_area;
}
type_ = t as u8;
hangul_count = 1;
dot_count = 0;
loc = (line_count + 1, i - last_line_started);
raw_command = c.to_string();
if t < 6 {
0
} else {
1
}
} else if ".…⋯⋮".contains(c) {
if state == 0 {
dot_count += if c == '.' { 1 } else { 3 };
raw_command.push(c);
}
state
} else if c == '?' {
match qu_leaf {
Area::Val {
type_: _,
left: _,
ref mut right,
} => {
*right = Box::new(Area::Val {
type_: 0,
left: Box::new(area),
right: Box::new(Area::Nil),
});
qu_leaf = &mut *right;
}
Area::Nil => {
qu_area = Area::Val {
type_: 0,
left: Box::new(area),
right: Box::new(Area::Nil),
};
qu_leaf = &mut qu_area;
}
}
area = Area::Nil;
leaf = &mut area;
raw_command.push(c);
2
} else if c == '!' {
match leaf {
Area::Val {
ref type_,
left: _,
ref mut right,
} => {
if *type_ <= 1 {
*right = match right.as_ref() {
Area::Val {
type_: t,
left: _,
right: _,
} => Box::new(Area::Val {
type_: 1,
left: Box::new(Area::new(*t)),
right: Box::new(Area::Nil),
}),
Area::Nil => Box::new(Area::new(1)),
};
leaf = &mut *right;
} else {
area = Area::Val {
type_: 1,
left: Box::new(Area::new(*type_)),
right: Box::new(Area::Nil),
};
leaf = &mut area;
}
}
Area::Nil => {
area = Area::new(1);
leaf = &mut area;
}
}
raw_command.push(c);
2
} else if let Some(mut t) = HEARTS.iter().position(|&x| x == c) {
t += 2;
match leaf {
Area::Val {
ref type_,
left: _,
ref mut right,
} => {
if *type_ <= 1 {
match right.as_ref() {
Area::Nil => {
*right = Box::new(Area::new(t as u8));
}
_ => {}
}
}
}
Area::Nil => {
area = Area::new(t as u8);
leaf = &mut area;
}
}
raw_command.push(c);
2
} else {
continue;
}
}
_ => {
if is_hangul_syllable(c) {
hangul_count += 1;
raw_command.push(c);
}
match type_ {
6 => {
if "엉".contains(c) {
type_ = 0;
dot_count = 0;
0
} else {
1
}
}
7 => {
if let Some(t) = "앙앗".find(c) {
type_ = (t / 3 + 1) as u8;
dot_count = 0;
0
} else {
1
}
}
_ => {
if let Some(t) = "읏읍윽".find(c) {
type_ = (t / 3 + 3) as u8;
dot_count = 0;
0
} else {
1
}
}
}
}
};
}
if type_ != 10 {
res.push(UnOptCode::new(
type_,
hangul_count,
dot_count,
loc,
match qu_leaf {
Area::Val {
type_: _,
left: _,
ref mut right,
} => {
*right = Box::new(area);
qu_area
}
Area::Nil => area,
},
raw_command,
));
}
res
}