1use crate::utils::ChUtils;
8
9#[derive(Clone, Debug, PartialEq)]
18pub struct Sub {
19 pub tokens: Vec<Token>,
20 pub method: SubMethod,
21}
22
23impl Sub {
24 pub fn new(tokens: Vec<Token>, method: SubMethod) -> Self {
26 Self { tokens, method }
27 }
28
29 pub fn empty() -> Self {
31 Self {
32 tokens: Vec::new(),
33 method: SubMethod::PAREN,
34 }
35 }
36}
37
38#[derive(Clone, Debug, PartialEq)]
43pub enum SubMethod {
44 PAREN,
45 ABS,
46}
47
48#[derive(Clone, Debug, PartialEq)]
49pub enum TokenType {
50 ILLEGAL,
51
52 NUMBER,
54
55 SUBEXP,
57 POINTER,
58 LPAREN,
59 RPAREN,
60 LABS,
61 RABS,
62
63 PLUS,
65 MINUS,
66 PRODUCT,
67 DIVIDE,
68 PERCENTAGE,
69 POWER,
70}
71
72#[derive(Clone, Debug, PartialEq)]
74pub struct Token {
75 pub typ: TokenType,
76 pub literal: String,
77 pub sub: Sub,
78 pub index: (i32, i32),
82}
83
84impl TokenType {
85 pub fn to_submethod(&self) -> SubMethod {
90 match self {
91 TokenType::LABS => SubMethod::ABS,
92 TokenType::RABS => SubMethod::ABS,
93 _ => SubMethod::PAREN, }
95 }
96}
97
98impl Token {
99 pub fn new(typ: TokenType, literal: String, sub: Sub, index: (i32, i32)) -> Self {
101 Self {
102 typ,
103 literal,
104 sub,
105 index,
106 }
107 }
108
109 pub fn new_sub(tokens: Vec<Token>, method: SubMethod) -> Self {
111 Self {
112 typ: TokenType::SUBEXP,
113 literal: String::new(),
114 sub: Sub { tokens, method },
115 index: Token::unknown_index(),
116 }
117 }
118
119 pub fn new_pointer(i: usize, method: SubMethod) -> Self {
122 Self {
123 typ: TokenType::POINTER,
124 literal: format!("{}", i),
125 sub: Sub::new(Vec::new(), method),
126 index: Token::unknown_index(),
127 }
128 }
129
130 pub fn from(mut literal: String, index: (i32, i32)) -> Self {
133 let typ: TokenType;
134
135 if literal.is_number() {
136 typ = TokenType::NUMBER;
137 } else {
138 typ = match literal.trim() {
139 "+" => TokenType::PLUS,
140 "-" => TokenType::MINUS,
141 "*" => TokenType::PRODUCT,
142 "•" => TokenType::PRODUCT,
143 "/" => TokenType::DIVIDE,
144 ":" => TokenType::DIVIDE,
145 "(" => TokenType::LPAREN,
146 ")" => TokenType::RPAREN,
147 "%" => TokenType::PERCENTAGE,
148 "^" => TokenType::POWER,
149 "[" => TokenType::LABS,
150 "]" => TokenType::RABS,
151 _ => TokenType::ILLEGAL,
152 }
153 }
154
155 literal.retain(|c| !c.is_whitespace());
157
158 return Self {
159 typ,
160 literal,
161 sub: Sub::empty(),
162 index,
163 };
164 }
165
166 pub fn empty() -> Self {
168 Self {
169 typ: TokenType::ILLEGAL,
170 literal: String::new(),
171 sub: Sub::empty(),
172 index: (0, 0),
173 }
174 }
175
176 pub fn to_submethod(&self) -> SubMethod {
181 match &self.typ {
182 TokenType::LABS => SubMethod::ABS,
183 TokenType::RABS => SubMethod::ABS,
184 _ => SubMethod::PAREN, }
186 }
187
188 pub fn unknown_index() -> (i32, i32) {
190 (-1, -1)
191 }
192
193 pub fn take_pointer_index(&self) -> Option<usize> {
196 if self.typ != TokenType::POINTER {
197 return None;
198 }
199
200 match self.literal.as_str().parse::<usize>() {
201 Err(_) => return None,
202 Ok(v) => return Some(v),
203 };
204 }
205
206 pub fn is_illegal(&self) -> bool {
208 match self.typ {
209 TokenType::ILLEGAL => true,
210 _ => false,
211 }
212 }
213
214 pub fn is_lparen(&self) -> bool {
216 match self.typ {
217 TokenType::LPAREN => true,
218 _ => false,
219 }
220 }
221
222 pub fn is_rparen(&self) -> bool {
224 match self.typ {
225 TokenType::RPAREN => true,
226 _ => false,
227 }
228 }
229
230 pub fn is_pointer(&self) -> bool {
232 match self.typ {
233 TokenType::POINTER => true,
234 _ => false,
235 }
236 }
237
238 pub fn is_sub_exp(&self) -> bool {
240 match self.typ {
241 TokenType::SUBEXP => true,
242 _ => false,
243 }
244 }
245
246 pub fn is_power(&self) -> bool {
248 match self.typ {
249 TokenType::POWER => true,
250 _ => false,
251 }
252 }
253
254 pub fn is_labs(&self) -> bool {
256 match self.typ {
257 TokenType::LABS => true,
258 _ => false,
259 }
260 }
261
262 pub fn is_rabs(&self) -> bool {
264 match self.typ {
265 TokenType::RABS => true,
266 _ => false,
267 }
268 }
269
270 pub fn matchto(&self, t: Token) -> bool {
274 let m = match self.typ {
275 TokenType::LPAREN => TokenType::RPAREN,
276 TokenType::LABS => TokenType::RABS,
277 _ => TokenType::ILLEGAL,
278 };
279
280 return m == t.typ;
281 }
282}
283
284#[cfg(test)]
285mod tests {
286 use super::*;
287 use std::collections::HashMap;
288
289 #[test]
290 fn new_sub_struct() {
291 let test_data: Vec<Sub> = vec![
292 Sub {
293 tokens: Vec::new(),
294 method: SubMethod::PAREN,
295 },
296 Sub {
297 tokens: Vec::new(),
298 method: SubMethod::ABS,
299 },
300 ];
301
302 for sub in test_data {
303 let res = Sub::new(sub.clone().tokens, sub.clone().method);
304 assert_eq!(res, sub)
305 }
306 }
307
308 #[test]
309 fn empty() {
310 let test_data: Vec<Sub> = vec![Sub {
311 tokens: Vec::new(),
312 method: SubMethod::PAREN,
313 }];
314
315 for sub in test_data {
316 let res = Sub::empty();
317 assert_eq!(res, sub)
318 }
319 }
320
321 #[test]
322 fn to_submethod() {
323 assert_eq!(TokenType::LABS.to_submethod(), SubMethod::ABS);
324 assert_eq!(TokenType::RABS.to_submethod(), SubMethod::ABS);
325 assert_eq!(TokenType::LPAREN.to_submethod(), SubMethod::PAREN);
326 assert_eq!(TokenType::RPAREN.to_submethod(), SubMethod::PAREN);
327 }
328
329 #[test]
330 fn new() {
331 let test_data: Vec<Token> = vec![
332 Token {
333 typ: TokenType::PLUS,
334 literal: String::from("+"),
335 sub: Sub::empty(),
336 index: (0, 0),
337 },
338 Token {
339 typ: TokenType::MINUS,
340 literal: String::from("-"),
341 sub: Sub::empty(),
342 index: (1, 1),
343 },
344 Token {
345 typ: TokenType::DIVIDE,
346 literal: String::from("/"),
347 sub: Sub::empty(),
348 index: (2, 2),
349 },
350 Token {
351 typ: TokenType::SUBEXP,
352 literal: String::from(""),
353 sub: Sub::new(
354 Vec::from([
355 Token::from(String::from("2"), (0, 0)),
356 Token::from(String::from("+"), (1, 1)),
357 Token::from(String::from("5"), (2, 2)),
358 ]),
359 SubMethod::PAREN,
360 ),
361 index: (0, 2),
362 },
363 ];
364
365 for t in test_data {
366 let res = Token::new(
367 t.clone().typ,
368 t.clone().literal,
369 t.clone().sub,
370 t.clone().index,
371 );
372
373 assert_eq!(res.typ, t.clone().typ);
374 assert_eq!(res.literal, t.clone().literal);
375 assert_eq!(res.sub, t.clone().sub);
376 assert_eq!(res.index, t.clone().index);
377 }
378 }
379
380 #[test]
381 fn new_sub() {
382 let test_data: HashMap<Vec<String>, Token> = HashMap::from([
383 (
384 vec![String::from("4"), String::from("+"), String::from("2")],
385 Token {
386 typ: TokenType::SUBEXP,
387 literal: String::new(),
388 sub: Sub::new(
389 Vec::from([
390 Token::from(String::from("4"), (0, 0)),
391 Token::from(String::from("+"), (0, 0)),
392 Token::from(String::from("2"), (0, 0)),
393 ]),
394 SubMethod::PAREN,
395 ),
396 index: Token::unknown_index(),
397 },
398 ),
399 (
400 vec![String::from("2"), String::from("+"), String::from("+")],
401 Token {
402 typ: TokenType::SUBEXP,
403 literal: String::new(),
404 sub: Sub::new(
405 Vec::from([
406 Token::from(String::from("2"), (0, 0)),
407 Token::from(String::from("+"), (0, 0)),
408 Token::from(String::from("+"), (0, 0)),
409 ]),
410 SubMethod::PAREN,
411 ),
412 index: Token::unknown_index(),
413 },
414 ),
415 ]);
416
417 for (t, expected) in test_data {
418 let tokens = t.into_iter().map(|tt| Token::from(tt, (0, 0))).collect();
419 let res = Token::new_sub(tokens, SubMethod::PAREN);
420
421 assert_eq!(res.typ, expected.clone().typ);
422 assert_eq!(res.literal, expected.clone().literal);
423 assert_eq!(res.sub, expected.clone().sub);
424 assert_eq!(res.index, expected.clone().index);
425 }
426 }
427
428 #[test]
429 fn new_pointer() {
430 let test_data: HashMap<usize, Token> = HashMap::from([
431 (
432 0,
433 Token::new(
434 TokenType::POINTER,
435 String::from("0"),
436 Sub::new(Vec::new(), SubMethod::PAREN),
437 (-1, -1),
438 ),
439 ),
440 (
441 99,
442 Token::new(
443 TokenType::POINTER,
444 String::from("99"),
445 Sub::new(Vec::new(), SubMethod::ABS),
446 (-1, -1),
447 ),
448 ),
449 ]);
450
451 for (i, expected) in test_data {
452 let token: Token = Token::new_pointer(i, expected.clone().sub.method);
453 assert_eq!(token, expected);
454 }
455 }
456
457 #[test]
458 fn from() {
459 let test_data: HashMap<(String, (i32, i32)), Token> = HashMap::from([
460 (
461 (String::from("42"), (0, 1)),
462 Token::new(TokenType::NUMBER, String::from("42"), Sub::empty(), (0, 1)),
463 ),
464 (
465 (String::from("}"), (0, 0)),
466 Token::new(TokenType::ILLEGAL, String::from("}"), Sub::empty(), (0, 0)),
467 ),
468 (
469 (String::from("+"), (0, 0)),
470 Token::new(TokenType::PLUS, String::from("+"), Sub::empty(), (0, 0)),
471 ),
472 (
473 (String::from("-"), (0, 0)),
474 Token::new(TokenType::MINUS, String::from("-"), Sub::empty(), (0, 0)),
475 ),
476 (
477 (String::from("*"), (0, 0)),
478 Token::new(TokenType::PRODUCT, String::from("*"), Sub::empty(), (0, 0)),
479 ),
480 (
481 (String::from("•"), (0, 0)),
482 Token::new(TokenType::PRODUCT, String::from("•"), Sub::empty(), (0, 0)),
483 ),
484 (
485 (String::from("/"), (0, 0)),
486 Token::new(TokenType::DIVIDE, String::from("/"), Sub::empty(), (0, 0)),
487 ),
488 (
489 (String::from(":"), (0, 0)),
490 Token::new(TokenType::DIVIDE, String::from(":"), Sub::empty(), (0, 0)),
491 ),
492 (
493 (String::from("%"), (0, 0)),
494 Token::new(
495 TokenType::PERCENTAGE,
496 String::from("%"),
497 Sub::empty(),
498 (0, 0),
499 ),
500 ),
501 ]);
502
503 for (v, expected) in test_data {
504 let res = Token::from(v.0, v.1);
505 assert_eq!(res, expected);
506 }
507 }
508
509 #[test]
510 fn unknown_index() {
511 assert_eq!(Token::unknown_index(), (-1, -1));
512 }
513
514 #[test]
515 fn take_pointer_index() {
516 let test_data: HashMap<Option<usize>, Token> = HashMap::from([
517 (None, Token::from(String::from("25"), (0, 1))),
518 (None, Token::from(String::from("-"), (0, 0))),
519 (Some(0), Token::new_pointer(0, SubMethod::PAREN)),
520 (Some(9), Token::new_pointer(9, SubMethod::PAREN)),
521 ]);
522
523 for (expected, token) in test_data {
524 assert_eq!(expected, token.take_pointer_index());
525 }
526 }
527
528 #[test]
529 fn is_illegal() {
530 let test_data: HashMap<bool, Token> = HashMap::from([
531 (false, Token::from(String::from("-25"), (0, 1))),
532 (false, Token::from(String::from("-"), (0, 0))),
533 (true, Token::from(String::from("}"), (0, 0))),
534 (true, Token::from(String::from("|"), (0, 0))),
535 ]);
536
537 for (expected, token) in test_data {
538 assert_eq!(expected, token.is_illegal());
539 }
540 }
541
542 #[test]
543 fn is_lparen() {
544 let test_data: HashMap<bool, Token> = HashMap::from([
545 (false, Token::from(String::from("-25"), (0, 1))),
546 (false, Token::from(String::from("-"), (0, 0))),
547 (false, Token::from(String::from(")"), (0, 0))),
548 (true, Token::from(String::from("("), (0, 0))),
549 ]);
550
551 for (expected, token) in test_data {
552 assert_eq!(expected, token.is_lparen());
553 }
554 }
555
556 #[test]
557 fn is_rparen() {
558 let test_data: HashMap<bool, Token> = HashMap::from([
559 (false, Token::from(String::from("-25"), (0, 1))),
560 (false, Token::from(String::from("-"), (0, 0))),
561 (false, Token::from(String::from("("), (0, 0))),
562 (true, Token::from(String::from(")"), (0, 0))),
563 ]);
564
565 for (expected, token) in test_data {
566 assert_eq!(expected, token.is_rparen());
567 }
568 }
569
570 #[test]
571 fn is_pointer() {
572 let test_data: HashMap<bool, Token> = HashMap::from([
573 (false, Token::from(String::from("-25"), (0, 1))),
574 (false, Token::from(String::from("-"), (0, 0))),
575 (false, Token::from(String::from("("), (0, 0))),
576 (true, Token::new_pointer(0, SubMethod::PAREN)),
577 ]);
578
579 for (expected, token) in test_data {
580 assert_eq!(expected, token.is_pointer());
581 }
582 }
583
584 #[test]
585 fn is_sub_exp() {
586 let test_data: HashMap<bool, Token> = HashMap::from([
587 (false, Token::from(String::from("-25"), (0, 1))),
588 (false, Token::from(String::from("-"), (0, 0))),
589 (false, Token::from(String::from("("), (0, 0))),
590 (true, Token::new_sub(vec![], SubMethod::PAREN)),
591 ]);
592
593 for (expected, token) in test_data {
594 assert_eq!(expected, token.is_sub_exp());
595 }
596 }
597
598 #[test]
599 fn is_power() {
600 let test_data: HashMap<bool, Token> = HashMap::from([
601 (false, Token::from(String::from("-25"), (0, 1))),
602 (false, Token::from(String::from("-"), (0, 0))),
603 (false, Token::from(String::from("("), (0, 0))),
604 (true, Token::from(String::from("^"), (0, 0))),
605 ]);
606
607 for (expected, token) in test_data {
608 assert_eq!(expected, token.is_power());
609 }
610 }
611
612 #[test]
613 fn is_labs() {
614 let test_data: HashMap<bool, Token> = HashMap::from([
615 (false, Token::from(String::from("-25"), (0, 1))),
616 (false, Token::from(String::from("-"), (0, 0))),
617 (false, Token::from(String::from("]"), (0, 0))),
618 (true, Token::from(String::from("["), (0, 0))),
619 ]);
620
621 for (expected, token) in test_data {
622 assert_eq!(expected, token.is_labs());
623 }
624 }
625
626 #[test]
627 fn is_rabs() {
628 let test_data: HashMap<bool, Token> = HashMap::from([
629 (false, Token::from(String::from("-25"), (0, 1))),
630 (false, Token::from(String::from("-"), (0, 0))),
631 (false, Token::from(String::from("["), (0, 0))),
632 (true, Token::from(String::from("]"), (0, 0))),
633 ]);
634
635 for (expected, token) in test_data {
636 assert_eq!(expected, token.is_rabs());
637 }
638 }
639
640 #[test]
641 fn matchto() {
642 let test_data: HashMap<bool, (Token, Token)> = HashMap::from([
643 (
644 true,
645 (
646 Token::from(String::from("("), (0, 0)),
647 Token::from(String::from(")"), (0, 0)),
648 ),
649 ),
650 (
651 true,
652 (
653 Token::from(String::from("["), (0, 0)),
654 Token::from(String::from("]"), (0, 0)),
655 ),
656 ),
657 (
658 false,
659 (
660 Token::from(String::from("0"), (0, 0)),
661 Token::from(String::from("1"), (0, 0)),
662 ),
663 ),
664 ]);
665
666 for (expected, tokens) in test_data {
667 assert_eq!(expected, tokens.0.matchto(tokens.1));
668 }
669 }
670}