1use lalrpop_util::lexer::Token;
2
3#[derive(Debug, Clone, PartialEq)]
4pub enum ModalityToken {
5 Model,
6 Graph,
7 Arrow,
8 Colon,
9 Plus,
10 Minus,
11 Ident(String),
12 Whitespace,
13 Comment,
14 Eof,
15}
16
17pub struct Lexer {
18 input: Vec<char>,
19 position: usize,
20}
21
22impl Lexer {
23 pub fn new(input: &str) -> Self {
24 Self {
25 input: input.chars().collect(),
26 position: 0,
27 }
28 }
29
30 fn peek(&self) -> Option<char> {
31 if self.position < self.input.len() {
32 Some(self.input[self.position])
33 } else {
34 None
35 }
36 }
37
38 fn advance(&mut self) {
39 self.position += 1;
40 }
41
42 fn skip_whitespace(&mut self) {
43 while let Some(ch) = self.peek() {
44 if ch.is_whitespace() {
45 self.advance();
46 } else {
47 break;
48 }
49 }
50 }
51
52 fn read_identifier(&mut self) -> String {
53 let mut ident = String::new();
54 while let Some(ch) = self.peek() {
55 if ch.is_alphanumeric() || ch == '_' {
56 ident.push(ch);
57 self.advance();
58 } else {
59 break;
60 }
61 }
62 ident
63 }
64
65 fn read_comment(&mut self) {
66 while let Some(ch) = self.peek() {
68 if ch == '\n' {
69 break;
70 }
71 self.advance();
72 }
73 }
74
75 pub fn next_token(&mut self) -> ModalityToken {
76 self.skip_whitespace();
77
78 if self.position >= self.input.len() {
79 return ModalityToken::Eof;
80 }
81
82 let ch = self.input[self.position];
83 self.advance();
84
85 match ch {
86 '/' => {
87 if let Some('/') = self.peek() {
88 self.advance();
89 self.read_comment();
90 self.next_token() } else {
92 ModalityToken::Eof
94 }
95 }
96 ':' => ModalityToken::Colon,
97 '+' => ModalityToken::Plus,
98 '-' => {
99 if let Some('>') = self.peek() {
100 self.advance();
101 ModalityToken::Arrow
102 } else {
103 ModalityToken::Minus
104 }
105 }
106 'm' => {
107 let ident = self.read_identifier();
108 if ident == "model" {
109 ModalityToken::Model
110 } else {
111 ModalityToken::Ident(ident)
112 }
113 }
114 'g' => {
115 let ident = self.read_identifier();
116 if ident == "graph" {
117 ModalityToken::Graph
118 } else {
119 ModalityToken::Ident(ident)
120 }
121 }
122 _ if ch.is_alphabetic() || ch == '_' => {
123 let mut ident = String::from(ch);
124 ident.push_str(&self.read_identifier());
125 ModalityToken::Ident(ident)
126 }
127 _ => ModalityToken::Eof, }
129 }
130}
131
132impl Iterator for Lexer {
133 type Item = ModalityToken;
134
135 fn next(&mut self) -> Option<Self::Item> {
136 let token = self.next_token();
137 if token == ModalityToken::Eof {
138 None
139 } else {
140 Some(token)
141 }
142 }
143}