1use super::{Error, LineNumber, MaxValue};
2use crate::error;
3use std::collections::VecDeque;
4use std::convert::TryFrom;
5
6#[derive(Debug, Clone, PartialEq)]
7pub enum Token {
8 Unknown(String),
9 Whitespace(usize),
10 Literal(Literal),
11 Word(Word),
12 Operator(Operator),
13 Ident(Ident),
14 LParen,
15 RParen,
16 Comma,
17 Colon,
18 Semicolon,
19}
20
21impl Token {
22 pub fn scan_alphabetic(v: &mut VecDeque<Token>, mut s: &str) -> String {
23 while let Some((idx, len, token)) = [
24 ("RESTORE", Token::Word(Word::Restore)),
25 ("DEFDBL", Token::Word(Word::Defdbl)),
26 ("DEFINT", Token::Word(Word::Defint)),
27 ("DEFSNG", Token::Word(Word::Defsng)),
28 ("DEFSTR", Token::Word(Word::Defstr)),
29 ("DELETE", Token::Word(Word::Delete)),
30 ("RETURN", Token::Word(Word::Return)),
31 ("CLEAR", Token::Word(Word::Clear)),
32 ("ERASE", Token::Word(Word::Erase)),
33 ("GOSUB", Token::Word(Word::Gosub)),
34 ("INPUT", Token::Word(Word::Input)),
35 ("PRINT", Token::Word(Word::Print)),
36 ("RENUM", Token::Word(Word::Renum)),
37 ("TROFF", Token::Word(Word::Troff)),
38 ("WHILE", Token::Word(Word::While)),
39 ("CONT", Token::Word(Word::Cont)),
40 ("DATA", Token::Word(Word::Data)),
41 ("ELSE", Token::Word(Word::Else)),
42 ("GOTO", Token::Word(Word::Goto)),
43 ("NEXT", Token::Word(Word::Next)),
44 ("LIST", Token::Word(Word::List)),
45 ("LOAD", Token::Word(Word::Load)),
46 ("READ", Token::Word(Word::Read)),
47 ("SAVE", Token::Word(Word::Save)),
48 ("STEP", Token::Word(Word::Step)),
49 ("STOP", Token::Word(Word::Stop)),
50 ("SWAP", Token::Word(Word::Swap)),
51 ("THEN", Token::Word(Word::Then)),
52 ("TRON", Token::Word(Word::Tron)),
53 ("WEND", Token::Word(Word::Wend)),
54 ("AND", Token::Operator(Operator::And)),
55 ("CLS", Token::Word(Word::Cls)),
56 ("DEF", Token::Word(Word::Def)),
57 ("DIM", Token::Word(Word::Dim)),
58 ("END", Token::Word(Word::End)),
59 ("EQV", Token::Operator(Operator::Eqv)),
60 ("FOR", Token::Word(Word::For)),
61 ("IMP", Token::Operator(Operator::Imp)),
62 ("LET", Token::Word(Word::Let)),
63 ("MOD", Token::Operator(Operator::Modulo)),
64 ("NEW", Token::Word(Word::New)),
65 ("NOT", Token::Operator(Operator::Not)),
66 ("REM", Token::Word(Word::Rem1)),
67 ("RUN", Token::Word(Word::Run)),
68 ("XOR", Token::Operator(Operator::Xor)),
69 ("IF", Token::Word(Word::If)),
70 ("ON", Token::Word(Word::On)),
71 ("OR", Token::Operator(Operator::Or)),
72 ("TO", Token::Word(Word::To)),
73 ]
74 .iter()
75 .filter_map(|(ts, tk)| {
76 if let Some(idx) = s.find(ts) {
77 Some((idx, ts.len(), tk.clone()))
78 } else {
79 None
80 }
81 })
82 .min_by_key(|(i, _, _)| *i)
83 {
84 if idx == 0 {
85 v.push_back(token);
86 s = &s[len..];
87 } else {
88 v.push_back(Token::Ident(Ident::Plain(s[..idx].into())));
89 v.push_back(token);
90 s = &s[(idx + len)..];
91 }
92 }
93 s.to_string()
94 }
95
96 pub fn match_minutia(s: &str) -> Option<Token> {
97 match s {
98 "(" => Some(Token::LParen),
99 ")" => Some(Token::RParen),
100 "," => Some(Token::Comma),
101 ":" => Some(Token::Colon),
102 ";" => Some(Token::Semicolon),
103 "?" => Some(Token::Word(Word::Print)),
104 "'" => Some(Token::Word(Word::Rem2)),
105 "^" => Some(Token::Operator(Operator::Caret)),
106 "*" => Some(Token::Operator(Operator::Multiply)),
107 "/" => Some(Token::Operator(Operator::Divide)),
108 "\\" => Some(Token::Operator(Operator::DivideInt)),
109 "+" => Some(Token::Operator(Operator::Plus)),
110 "-" => Some(Token::Operator(Operator::Minus)),
111 "=" => Some(Token::Operator(Operator::Equal)),
112 "<" => Some(Token::Operator(Operator::Less)),
113 ">" => Some(Token::Operator(Operator::Greater)),
114 _ => None,
115 }
116 }
117
118 pub fn is_word(&self) -> bool {
119 match self {
120 Token::Word(_) => true,
121 Token::Ident(_) => true,
122 Token::Literal(_) => true,
123 Token::Operator(op) => op.is_word(),
124 _ => false,
125 }
126 }
127}
128
129impl std::fmt::Display for Token {
130 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
131 use Token::*;
132 match self {
133 Unknown(s) => write!(f, "{}", s),
134 Whitespace(u) => write!(f, "{s:>w$}", s = "", w = u),
135 Literal(s) => write!(f, "{}", s),
136 Word(s) => write!(f, "{}", s),
137 Operator(s) => write!(f, "{}", s),
138 Ident(s) => write!(f, "{}", s),
139 LParen => write!(f, "("),
140 RParen => write!(f, ")"),
141 Comma => write!(f, ","),
142 Colon => write!(f, ":"),
143 Semicolon => write!(f, ";"),
144 }
145 }
146}
147
148impl TryFrom<&Token> for LineNumber {
149 type Error = Error;
150 fn try_from(token: &Token) -> Result<Self, Self::Error> {
151 let msg = "INVALID LINE NUMBER";
152 if let Token::Literal(lit) = token {
153 let s = match lit {
154 Literal::Integer(s) => s,
155 Literal::Single(s) => s,
156 Literal::Double(s) => s,
157 Literal::Hex(_) | Literal::Octal(_) | Literal::String(_) => "",
158 };
159 if s.chars().all(|c| c.is_ascii_digit()) {
160 if let Ok(line) = s.parse::<u16>() {
161 if line <= LineNumber::max_value() {
162 return Ok(Some(line));
163 }
164 }
165 return Err(error!(Overflow; msg));
166 }
167 }
168 Err(error!(UndefinedLine; msg))
169 }
170}
171
172#[derive(Debug, Clone, PartialEq)]
173pub enum Literal {
174 Single(String),
175 Double(String),
176 Integer(String),
177 Hex(String),
178 Octal(String),
179 String(String),
180}
181
182impl std::fmt::Display for Literal {
183 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
184 use Literal::*;
185 match self {
186 Single(s) => write!(f, "{}", s),
187 Double(s) => write!(f, "{}", s),
188 Integer(s) => write!(f, "{}", s),
189 Hex(s) => write!(f, "&H{}", s),
190 Octal(s) => write!(f, "&{}", s),
191 String(s) => write!(f, "\"{}\"", s),
192 }
193 }
194}
195
196#[derive(Debug, Clone, PartialEq)]
197pub enum Word {
198 Clear,
199 Cls,
200 Cont,
201 Data,
202 Def,
203 Defdbl,
204 Defint,
205 Defsng,
206 Defstr,
207 Delete,
208 Dim,
209 Else,
210 End,
211 Erase,
212 For,
213 Gosub,
214 Goto,
215 If,
216 Input,
217 Let,
218 List,
219 Load,
220 New,
221 Next,
222 On,
223 Print,
224 Read,
225 Rem1,
226 Rem2,
227 Renum,
228 Restore,
229 Return,
230 Save,
231 Step,
232 Stop,
233 Swap,
234 Run,
235 Then,
236 To,
237 Troff,
238 Tron,
239 Wend,
240 While,
241}
242
243impl std::fmt::Display for Word {
244 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
245 use Word::*;
246 match self {
247 Clear => write!(f, "CLEAR"),
248 Cls => write!(f, "CLS"),
249 Cont => write!(f, "CONT"),
250 Data => write!(f, "DATA"),
251 Def => write!(f, "DEF"),
252 Defdbl => write!(f, "DEFDBL"),
253 Defint => write!(f, "DEFINT"),
254 Defsng => write!(f, "DEFSNG"),
255 Defstr => write!(f, "DEFSTR"),
256 Delete => write!(f, "DELETE"),
257 Dim => write!(f, "DIM"),
258 Else => write!(f, "ELSE"),
259 End => write!(f, "END"),
260 Erase => write!(f, "ERASE"),
261 For => write!(f, "FOR"),
262 Gosub => write!(f, "GOSUB"),
263 Goto => write!(f, "GOTO"),
264 If => write!(f, "IF"),
265 Input => write!(f, "INPUT"),
266 Let => write!(f, "LET"),
267 List => write!(f, "LIST"),
268 Load => write!(f, "LOAD"),
269 New => write!(f, "NEW"),
270 Next => write!(f, "NEXT"),
271 On => write!(f, "ON"),
272 Print => write!(f, "PRINT"),
273 Read => write!(f, "READ"),
274 Rem1 => write!(f, "REM"),
275 Rem2 => write!(f, "'"),
276 Renum => write!(f, "RENUM"),
277 Restore => write!(f, "RESTORE"),
278 Return => write!(f, "RETURN"),
279 Run => write!(f, "RUN"),
280 Save => write!(f, "SAVE"),
281 Step => write!(f, "STEP"),
282 Stop => write!(f, "STOP"),
283 Swap => write!(f, "SWAP"),
284 Then => write!(f, "THEN"),
285 To => write!(f, "TO"),
286 Troff => write!(f, "TROFF"),
287 Tron => write!(f, "TRON"),
288 Wend => write!(f, "WEND"),
289 While => write!(f, "WHILE"),
290 }
291 }
292}
293
294#[derive(Debug, Clone, PartialEq)]
295pub enum Operator {
296 Caret,
297 Multiply,
298 Divide,
299 DivideInt,
300 Modulo,
301 Plus,
302 Minus,
303 Equal,
304 NotEqual,
305 Less,
306 LessEqual,
307 Greater,
308 GreaterEqual,
309 Not,
310 And,
311 Or,
312 Xor,
313 Imp,
314 Eqv,
315}
316
317impl Operator {
318 pub fn is_word(&self) -> bool {
319 use Operator::*;
320 match self {
321 Caret | Multiply | Divide | DivideInt | Plus | Minus | Equal | NotEqual | Less
322 | LessEqual | Greater | GreaterEqual => false,
323 Modulo | Not | And | Or | Xor | Imp | Eqv => true,
324 }
325 }
326}
327
328impl std::fmt::Display for Operator {
329 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
330 use Operator::*;
331 match self {
332 Caret => write!(f, "^"),
333 Multiply => write!(f, "*"),
334 Divide => write!(f, "/"),
335 DivideInt => write!(f, "\\"),
336 Modulo => write!(f, "MOD"),
337 Plus => write!(f, "+"),
338 Minus => write!(f, "-"),
339 Equal => write!(f, "="),
340 NotEqual => write!(f, "<>"),
341 Less => write!(f, "<"),
342 LessEqual => write!(f, "<="),
343 Greater => write!(f, ">"),
344 GreaterEqual => write!(f, ">="),
345 Not => write!(f, "NOT"),
346 And => write!(f, "AND"),
347 Or => write!(f, "OR"),
348 Xor => write!(f, "XOR"),
349 Imp => write!(f, "IMP"),
350 Eqv => write!(f, "EQV"),
351 }
352 }
353}
354
355#[derive(Debug, Clone, PartialEq, Eq, Hash)]
356pub enum Ident {
357 Plain(String),
358 String(String),
359 Single(String),
360 Double(String),
361 Integer(String),
362}
363
364impl std::fmt::Display for Ident {
365 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
366 use Ident::*;
367 match self {
368 Plain(s) => write!(f, "{}", s),
369 String(s) => write!(f, "{}", s),
370 Single(s) => write!(f, "{}", s),
371 Double(s) => write!(f, "{}", s),
372 Integer(s) => write!(f, "{}", s),
373 }
374 }
375}