kami_parser/
multiline_lexer.rs

1use crate::lexer::{TokenType, Token, push_token, tokenize};
2
3fn add_table(tokens: &mut Vec<Token>, table: &mut Token) {
4	if !table.subtokens.is_empty() {
5		tokens.push(table.clone());
6		*table = Token::init(TokenType::Table, String::new());
7	}
8}
9
10fn table_parse(input: &String) -> Token {
11	enum CellMode {
12		None,
13		Column,
14		Row,
15		Attr,
16	}
17	let mut nullify = false;
18	let mut out: Vec<Token> = Vec::new();
19	let mut starting_cell = true;
20	let mut current_cell = Token::init(TokenType::TableCell, String::new());
21	let mut cell_mode = CellMode::None;
22	let mut current_cell_col = String::new();
23	let mut current_cell_row = String::new();
24	let mut rowattr = String::new();
25	for ch in input.chars() {
26		if starting_cell {
27			// If it's writing the cell starter token
28			match ch {
29				'*' => {
30					match cell_mode {
31						CellMode::Attr => current_cell.attributes += &ch.to_string(),
32						_ => current_cell.class = TokenType::TableHeader,
33					}
34				},
35				'r' => {
36					match cell_mode {
37						CellMode::Attr => current_cell.attributes += &ch.to_string(),
38						_ => cell_mode = CellMode::Row,
39					}
40				},
41				'c' => {
42					match cell_mode {
43						CellMode::Attr => current_cell.attributes += &ch.to_string(),
44						_ => cell_mode = CellMode::Column,
45					}
46				},
47				'0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' => {
48					match cell_mode {
49						CellMode::Column => current_cell_col += &ch.to_string(),
50						CellMode::Row => current_cell_row += &ch.to_string(),
51						CellMode::Attr => current_cell.attributes += &ch.to_string(),
52						_ => panic!("Found a digit in an unexpected position in cell token"),
53					}
54				},
55				'{' => {
56					cell_mode = CellMode::Attr;
57					current_cell.attributes += &ch.to_string();
58				}
59				'}'=> {
60					match cell_mode {
61						CellMode::Attr => {
62							cell_mode = CellMode::None;
63						},
64						_ => panic!("{}", "Found a } outside an attribute sequence"),
65					}
66				},
67				'|' => {
68					nullify = false;
69					starting_cell = true;
70					current_cell = Token::init(TokenType::TableCell, String::new());
71					cell_mode = CellMode::None;
72					current_cell_row = String::new();
73					current_cell_col = String::new();
74				},
75				'-' => nullify = true,
76				' ' => {
77					match cell_mode {
78						CellMode::Attr => current_cell.attributes += &ch.to_string(),
79						_ => {
80							starting_cell = false;
81							let mut close_atter = !current_cell.attributes.is_empty();
82							if !current_cell_col.is_empty() || !current_cell_row.is_empty() {
83								if !close_atter {
84									current_cell.attributes += "{";
85									close_atter = true;
86								}
87								if !current_cell_row.is_empty() {
88									current_cell.attributes += &(" rowspan=\"".to_owned() + &current_cell_row + "\"");
89								}
90								if !current_cell_col.is_empty() {
91									current_cell.attributes += &(" colspan=\"".to_owned() + &current_cell_col + "\"");
92								}
93							}
94							if close_atter { current_cell.attributes += "}" }
95						}
96					}
97				},
98				_ => {
99					match cell_mode {
100						CellMode::Attr => current_cell.attributes += &ch.to_string(),
101						_ => panic!("Unexpected character in table cell initiation"),
102					}
103				},
104			}
105		} else {
106			// If it's writing the content of the cell
107			match ch {
108				'|' => {
109					if !nullify {
110						current_cell.subtokens = tokenize(&current_cell.content.trim_end_matches('\t')).0;
111						out.push(current_cell.clone());
112					}
113					nullify = false;
114					starting_cell = true;
115					current_cell = Token::init(TokenType::TableCell, String::new());
116					cell_mode = CellMode::None;
117					current_cell_row = String::new();
118					current_cell_col = String::new();
119				},
120				_ => current_cell.content += &ch.to_string(),
121			}
122		}
123	}
124	if !current_cell.attributes.is_empty() && current_cell.content.is_empty() {
125		current_cell.attributes += "}";
126		rowattr = current_cell.attributes;
127	}
128	let mut outok = Token::init_sub(TokenType::TableRow, out, String::new());
129	outok.attributes = rowattr;
130	outok
131}
132
133pub(crate) fn block_lexer(lines: &Vec<Vec<Token>>) -> Vec<Token>{
134	let mut blocks: Vec<Token> = Vec::new();
135	let mut current_block: Token;
136	let mut lists: Vec<Token> = Vec::new();
137	let mut table: Token = Token::init(TokenType::Table, String::new());
138	let mut next_attr: String = String::new();
139	for line in lines.iter() {
140		match line.first() {
141			None => add_table(&mut blocks, &mut table),
142			Some(ftoken) => {
143				match ftoken.class {
144					TokenType::TableRow => {
145						if table.subtokens.is_empty() {
146							table.attributes = next_attr.clone();
147							next_attr = String::new();
148						}
149						table.subtokens.push(table_parse(&ftoken.content));
150					},
151					TokenType::ListEl => {
152						add_table(&mut blocks, &mut table);
153						let fltoken = { 
154							let mut ft = ftoken.clone();
155							ft.subtokens = line[1..].to_vec();
156							ft
157						};
158						match lists.last_mut() {
159							None => {
160								let mut new_sublist = Token::init_sub(TokenType::UList, vec![fltoken.to_owned()], fltoken.content.to_owned());
161								new_sublist.attributes = next_attr.clone();	
162								lists.push(new_sublist);
163								next_attr = String::new();
164							},
165							Some(x) => {
166								match x.class {
167									TokenType::UList => {
168										if get_list_depth(&x) == get_list_depth(&fltoken) {
169											x.subtokens.push(fltoken.to_owned());
170										} else if get_list_depth(&x) < get_list_depth(&fltoken) {
171											let mut new_sublist = Token::init_sub(TokenType::UList, vec![fltoken.to_owned()], fltoken.content.to_owned());
172											new_sublist.attributes = next_attr.clone();	
173											lists.push(new_sublist);
174											next_attr = String::new();
175										}
176										else {
177											let new_sublist = Token::init_sub(TokenType::UList, vec![fltoken.to_owned()], fltoken.content.to_owned());
178											lists.push(new_sublist);
179										}
180									},
181									TokenType::OList => {
182										lists.push(Token::init_sub(TokenType::UList, vec![fltoken.to_owned()], fltoken.content.to_owned()));
183									},
184									_ => panic!("This wasn't supposed to be possible at all"),
185								}
186							},
187						}
188					},
189					TokenType::NumberedListEl => {
190						add_table(&mut blocks, &mut table);
191						let fltoken = { 
192							let mut ft = ftoken.clone();
193							ft.subtokens = line[1..].to_vec();
194							ft
195						};
196						match lists.last_mut() {
197							None => {
198								let mut new_sublist = Token::init_sub(TokenType::OList, vec![fltoken.to_owned()], fltoken.content.to_owned());
199								new_sublist.attributes = next_attr.clone();
200								next_attr = String::new();
201								lists.push(new_sublist);
202							},
203							Some(x) => {
204								match x.class {
205									TokenType::OList => {
206										if get_list_depth(&x) == get_list_depth(&fltoken) {
207											x.subtokens.push(fltoken.to_owned());
208										} else if get_list_depth(&x) < get_list_depth(&fltoken) {
209											let mut new_sublist = Token::init_sub(TokenType::OList, vec![fltoken.to_owned()], fltoken.content.to_owned());
210											new_sublist.attributes = next_attr.clone();	
211											lists.push(new_sublist);
212											next_attr = String::new();
213										}
214										else {
215											let new_sublist = Token::init_sub(TokenType::OList, vec![fltoken.to_owned()], fltoken.content.to_owned());
216											lists.push(new_sublist);
217										}
218									},
219									TokenType::UList => {
220										lists.push(Token::init_sub(TokenType::OList, vec![fltoken.to_owned()], fltoken.content.to_owned()));
221									},
222									_ => panic!("This wasn't supposed to be possible at all"),
223								}
224							},
225						}
226					},
227					TokenType::Html => {
228						add_table(&mut blocks, &mut table);
229						if !lists.is_empty() {
230							push_token(&mut blocks, &Token::init_sub(TokenType::ListBlock, lists.clone(), String::new()));
231						}
232						current_block = ftoken.clone();
233						current_block.subtokens = line[1..].to_vec();
234						push_token(&mut blocks, &current_block);
235					}
236					TokenType::Attr => {
237						if !lists.is_empty() {
238							push_token(&mut blocks, &Token::init_sub(TokenType::ListBlock, lists.clone(), String::new()));
239							lists = Vec::new();
240						}
241						if line.len() > 1 {
242							current_block = Token::n_para();
243							current_block.attributes = line[0].content.to_owned();
244							current_block.subtokens = line[1..].to_vec();
245							push_token(&mut blocks, &current_block);
246						} else {
247							next_attr = ftoken.content.to_owned();
248						}
249					},
250					TokenType::Header => {
251						add_table(&mut blocks, &mut table);
252						if !lists.is_empty() {
253							push_token(&mut blocks, &Token::init_sub(TokenType::ListBlock, lists.clone(), String::new()));
254							lists = Vec::new();
255						}
256						current_block = ftoken.clone();
257						current_block.subtokens = line[1..].to_vec();
258						push_token(&mut blocks, &current_block);
259					},
260					TokenType::Image => {
261						add_table(&mut blocks, &mut table);
262						if !lists.is_empty() {
263							push_token(&mut blocks, &Token::init_sub(TokenType::ListBlock, lists.clone(), String::new()));
264							lists = Vec::new();
265						}
266						if line.len() > 1 {
267							current_block = Token::n_para();
268							current_block.subtokens = line.clone();
269							push_token(&mut blocks, &current_block);
270						} else {
271							current_block = ftoken.clone();
272							push_token(&mut blocks, &current_block);
273						}
274					}
275					_ => {
276						add_table(&mut blocks, &mut table);
277						if !lists.is_empty() {
278							push_token(&mut blocks, &Token::init_sub(TokenType::ListBlock, lists.clone(), String::new()));
279							lists = Vec::new();
280						}
281						current_block = Token::n_para();
282						current_block.subtokens = line.clone();
283						match blocks.last_mut() {
284							None => push_token(&mut blocks, &current_block),
285							Some(x) => {
286								let first_char = current_block.subtokens.first_mut().expect("An empty string got to the paragraph parser.");
287								if &first_char.content[0..1] == " " {
288									x.subtokens.push(Token::init(TokenType::LineBreak, "\n".to_owned()));
289									first_char.content = "\n".to_owned() + &first_char.content[1..];
290									x.subtokens.append(&mut current_block.subtokens);
291								} else {
292									push_token(&mut blocks, &current_block);
293								}
294							},
295						}
296					}
297				}
298			}
299		}
300	}
301	add_table(&mut blocks, &mut table);
302	if !lists.is_empty() {
303		push_token(&mut blocks, &Token::init_sub(TokenType::ListBlock, lists.clone(), String::new()));
304	}
305	blocks
306}
307
308pub(crate) fn get_list_depth(token: &Token) -> usize {
309	match token.class {
310		TokenType::UList | TokenType::ListEl | TokenType::OList | TokenType::NumberedListEl => token.content.len() - 1,
311		_ => panic!("Passed a non-list token to get_list_depth"),
312	}
313}