libperl_macrogen/
token_source.rs1use crate::error::Result;
7use crate::intern::StringInterner;
8use crate::source::{FileRegistry, SourceLocation};
9use crate::token::{Token, TokenKind};
10
11pub trait TokenSource {
13 fn next_token(&mut self) -> Result<Token>;
15
16 fn unget_token(&mut self, token: Token);
18
19 fn interner(&self) -> &StringInterner;
21
22 fn interner_mut(&mut self) -> &mut StringInterner;
24
25 fn files(&self) -> &FileRegistry;
27
28 fn is_file_in_target(&self, file_id: crate::source::FileId) -> bool {
31 let _ = file_id;
32 false
33 }
34}
35
36pub struct TokenSlice {
40 tokens: Vec<Token>,
41 pos: usize,
42 interner: StringInterner,
43 files: FileRegistry,
44 eof_loc: SourceLocation,
45 lookahead: Vec<Token>,
47}
48
49impl TokenSlice {
50 pub fn new(tokens: Vec<Token>, interner: StringInterner, files: FileRegistry) -> Self {
57 let eof_loc = tokens.last()
59 .map(|t| t.loc.clone())
60 .unwrap_or_default();
61
62 Self {
63 tokens,
64 pos: 0,
65 interner,
66 files,
67 eof_loc,
68 lookahead: Vec::new(),
69 }
70 }
71
72 pub fn position(&self) -> usize {
74 self.pos
75 }
76
77 pub fn remaining(&self) -> usize {
79 self.tokens.len().saturating_sub(self.pos)
80 }
81}
82
83impl TokenSource for TokenSlice {
84 fn next_token(&mut self) -> Result<Token> {
85 if let Some(token) = self.lookahead.pop() {
87 return Ok(token);
88 }
89 if self.pos < self.tokens.len() {
90 let token = self.tokens[self.pos].clone();
91 self.pos += 1;
92 Ok(token)
93 } else {
94 Ok(Token::new(TokenKind::Eof, self.eof_loc.clone()))
96 }
97 }
98
99 fn unget_token(&mut self, token: Token) {
100 self.lookahead.push(token);
101 }
102
103 fn interner(&self) -> &StringInterner {
104 &self.interner
105 }
106
107 fn interner_mut(&mut self) -> &mut StringInterner {
108 &mut self.interner
109 }
110
111 fn files(&self) -> &FileRegistry {
112 &self.files
113 }
114}
115
116pub struct TokenSliceRef<'a> {
121 tokens: Vec<Token>,
122 pos: usize,
123 interner: &'a StringInterner,
124 files: &'a FileRegistry,
125 eof_loc: SourceLocation,
126 lookahead: Vec<Token>,
128}
129
130impl<'a> TokenSliceRef<'a> {
131 pub fn new(
133 tokens: Vec<Token>,
134 interner: &'a StringInterner,
135 files: &'a FileRegistry,
136 ) -> Self {
137 let eof_loc = tokens.last()
138 .map(|t| t.loc.clone())
139 .unwrap_or_default();
140
141 Self {
142 tokens,
143 pos: 0,
144 interner,
145 files,
146 eof_loc,
147 lookahead: Vec::new(),
148 }
149 }
150
151 pub fn next_token(&mut self) -> Result<Token> {
153 if let Some(token) = self.lookahead.pop() {
154 return Ok(token);
155 }
156 if self.pos < self.tokens.len() {
157 let token = self.tokens[self.pos].clone();
158 self.pos += 1;
159 Ok(token)
160 } else {
161 Ok(Token::new(TokenKind::Eof, self.eof_loc.clone()))
162 }
163 }
164
165 pub fn interner(&self) -> &StringInterner {
167 self.interner
168 }
169
170 pub fn files(&self) -> &FileRegistry {
172 self.files
173 }
174}
175
176impl<'a> TokenSource for TokenSliceRef<'a> {
177 fn next_token(&mut self) -> Result<Token> {
178 if let Some(token) = self.lookahead.pop() {
179 return Ok(token);
180 }
181 if self.pos < self.tokens.len() {
182 let token = self.tokens[self.pos].clone();
183 self.pos += 1;
184 Ok(token)
185 } else {
186 Ok(Token::new(TokenKind::Eof, self.eof_loc.clone()))
187 }
188 }
189
190 fn unget_token(&mut self, token: Token) {
191 self.lookahead.push(token);
192 }
193
194 fn interner(&self) -> &StringInterner {
195 self.interner
196 }
197
198 fn interner_mut(&mut self) -> &mut StringInterner {
199 panic!("interner_mut() called on TokenSliceRef - use from_source_with_typedefs()")
202 }
203
204 fn files(&self) -> &FileRegistry {
205 self.files
206 }
207}
208
209#[cfg(test)]
210mod tests {
211 use super::*;
212 use std::path::PathBuf;
213
214 #[test]
215 fn test_token_slice_empty() {
216 let interner = StringInterner::new();
217 let mut files = FileRegistry::new();
218 files.register(PathBuf::from("test.c"));
219
220 let mut slice = TokenSlice::new(vec![], interner, files);
221
222 let token = slice.next_token().unwrap();
223 assert!(matches!(token.kind, TokenKind::Eof));
224 }
225
226 #[test]
227 fn test_token_slice_tokens() {
228 let mut interner = StringInterner::new();
229 let mut files = FileRegistry::new();
230 let file_id = files.register(PathBuf::from("test.c"));
231 let loc = SourceLocation::new(file_id, 1, 1);
232
233 let foo = interner.intern("foo");
234 let tokens = vec![
235 Token::new(TokenKind::Ident(foo), loc.clone()),
236 Token::new(TokenKind::Plus, loc.clone()),
237 Token::new(TokenKind::IntLit(42), loc.clone()),
238 ];
239
240 let mut slice = TokenSlice::new(tokens, interner, files);
241
242 assert_eq!(slice.remaining(), 3);
243
244 let t1 = slice.next_token().unwrap();
245 assert!(matches!(t1.kind, TokenKind::Ident(_)));
246
247 let t2 = slice.next_token().unwrap();
248 assert!(matches!(t2.kind, TokenKind::Plus));
249
250 let t3 = slice.next_token().unwrap();
251 assert!(matches!(t3.kind, TokenKind::IntLit(42)));
252
253 let t4 = slice.next_token().unwrap();
254 assert!(matches!(t4.kind, TokenKind::Eof));
255
256 assert_eq!(slice.remaining(), 0);
257 }
258}