basic/lang/
token.rs

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}