1use std::fmt;
2
3impl TryFrom<u8> for BasicTokenNoPrefix {
4 type Error = String;
5
6 fn try_from(value: u8) -> Result<Self, String> {
7 match value {
8 5 => Err(format!("{value} is invalid")),
9 _ => Ok(unsafe { std::mem::transmute(value) })
10 }
11 }
12}
13
14impl From<BasicTokenNoPrefix> for u8 {
15 fn from(val: BasicTokenNoPrefix) -> Self {
16 val as u8
17 }
18}
19
20#[derive(Copy, Clone, PartialEq, Debug)]
21#[repr(u8)]
22#[allow(missing_docs)]
23pub enum BasicTokenNoPrefix {
24 EndOfTokenisedLine = 0,
25
26 StatementSeparator = 1,
27
28 IntegerVariableDefinition = 2,
29 StringVariableDefinition = 3,
30 FloatingPointVariableDefinition = 4,
31
32 VarUnknown1 = 6,
33 VarUnknown2 = 7,
34 VarUnknown3 = 8,
35 CharTab = 9, VarUnknown5 = 0xA,
37
38 VariableDefinition1 = 0xB,
39 VariableDefinition2 = 0xC,
40 VariableDefinition3 = 0xD,
41
42 ConstantNumber0 = 0x0E,
43 ConstantNumber1 = 0x0F,
44 ConstantNumber2 = 0x10,
45 ConstantNumber3 = 0x11,
46 ConstantNumber4 = 0x12,
47 ConstantNumber5 = 0x13,
48 ConstantNumber6 = 0x14,
49 ConstantNumber7 = 0x15,
50 ConstantNumber8 = 0x16,
51 ConstantNumber9 = 0x17,
52 ConstantNumber10 = 0x18,
53
54 ValueIntegerDecimal8bits = 0x19,
55
56 ValueIntegerDecimal16bits = 0x1A,
57 ValueIntegerBinary16bits = 0x1B,
58 ValueIntegerHexadecimal16bits = 0x1C,
59
60 LineMemoryAddressPointer = 0x1D,
61 LineNumber = 0x1E,
62
63 ValueFloatingPoint = 0x1F,
64
65 CharSpace = 0x20,
66 CharExclamation = 0x21,
67
68 ValueQuotedString = 0x22,
69
70 CharNumber,
71 CharDollar,
72 CharPerCent,
73 CharAmpersand,
74 CharSingleQuote,
75 CharOpenParenthesis,
76 CharCloseParenthesis,
77 CharAsterix,
78 CharPlus,
79 CharComma,
80 CharHyphen,
81 CharDot,
82 CharSlash,
83 Char0,
84 Char1,
85 Char2,
86 Char3,
87 Char4,
88 Char5,
89 Char6,
90 Char7,
91 Char8,
92 Char9,
93 CharColon,
94 CharSemiColon,
95 CharLess,
96 CharEquals,
97 CharGreater,
98 CharQuestionMark,
99 CharAt,
100
101 CharUpperA = 65,
103 CharUpperB,
104 CharUpperC,
105 CharUpperD,
106 CharUpperE,
107 CharUpperF,
108 CharUpperG,
109 CharUpperH,
110 CharUpperI,
111 CharUpperJ,
112 CharUpperK,
113 CharUpperL,
114 CharUpperM,
115 CharUpperN,
116 CharUpperO,
117 CharUpperP,
118 CharUpperQ,
119 CharUpperR,
120 CharUpperS,
121 CharUpperT,
122 CharUpperU,
123 CharUpperV,
124 CharUpperW,
125 CharUpperX,
126 CharUpperY,
127 CharUpperZ,
128
129 CharLowerA = 97,
130 CharLowerB,
131 CharLowerC,
132 CharLowerD,
133 CharLowerE,
134 CharLowerF,
135 CharLowerG,
136 CharLowerH,
137 CharLowerI,
138 CharLowerJ,
139 CharLowerK,
140 CharLowerL,
141 CharLowerM,
142 CharLowerN,
143 CharLowerO,
144 CharLowerP,
145 CharLowerQ,
146 CharLowerR,
147 CharLowerS,
148 CharLowerT,
149 CharLowerU,
150 CharLowerV,
151 CharLowerW,
152 CharLowerX,
153 CharLowerY,
154 CharLowerZ,
155
156 Pipe = 0x7C,
157
158 Unused7d = 0x7D,
159 Unused7e = 0x7E,
160 Unused7f = 0x7F,
161
162 After = 0x80,
163 Auto,
164 Border,
165 Call,
166 Cat,
167 Chain,
168 Clear,
169 Clg,
170 Closein,
171 Closeout,
172 Cls,
173 Cont,
174 Data,
175 Def,
176 Defint,
177 Defreal,
178 Defstr,
179 Deg,
180 Delete,
181 Dim,
182 Draw,
183 Drawr,
184 Edit,
185 Else,
186 End,
187 Ent,
188 Env,
189 Erase,
190 Error,
191 Every,
192 For,
193 Gosub,
194 Goto,
195 If,
196 Ink,
197 Input,
198 Key,
199 Let,
200 Line,
201 List,
202 Load,
203 Locate,
204 Memory,
205 Merge,
206 MidDollar,
207 Mode,
208 Move,
209 Mover,
210 Next,
211 New,
212 On,
213 OnBreak,
214 OnErrorGoto,
215 Sq,
216 Openin,
217 Openout,
218 Origin,
219 Out,
220 Paper,
221 Pen,
222 Plot,
223 Plotr,
224 Poke,
225 Print,
226 SymbolQuote,
227 Rad,
228 Randomize,
229 Read,
230 Release,
231 Rem,
232 Renum,
233 Restore,
234 Resume,
235 Return,
236 Run,
237 Save,
238 Sound,
239 Speed,
240 Stop,
241 Symbol,
242 Tag,
243 Tagoff,
244 Troff,
245 Tron,
246 Wait,
247 Wend,
248 While,
249 Width,
250 Window,
251 Write,
252 Zone,
253 Di,
254 Ei,
255 Fill,
256 Graphics,
257 Mask,
258 Frame,
259 Cursor,
260 UnusedE2,
261 Erl,
262 Fn,
263 Spc,
264 Step,
265 Swap,
266 UnusedE8,
267 UnusedE9,
268 Tab,
269 Then,
270 To,
271 Using,
272 GreaterThan,
273 Equal,
274 GreaterOrEqual,
275 LessThan,
276 NotEqual,
277 LessThanOrEqual,
278 Addition,
279 SubstractionOrUnaryMinus,
280 Multiplication,
281 Division,
282 Power,
283 IntegerDivision,
284 And,
285 Mod,
286 Or,
287 Xor,
288 AdditionalTokenMarker
289}
290
291impl From<char> for BasicTokenNoPrefix {
292 fn from(c: char) -> Self {
293 match c {
294 ' ' => BasicTokenNoPrefix::CharSpace,
296 'A' => BasicTokenNoPrefix::CharUpperA,
297 'B' => BasicTokenNoPrefix::CharUpperB,
298 'C' => BasicTokenNoPrefix::CharUpperC,
299 'D' => BasicTokenNoPrefix::CharUpperD,
300 'E' => BasicTokenNoPrefix::CharUpperE,
301 'F' => BasicTokenNoPrefix::CharUpperF,
302 'G' => BasicTokenNoPrefix::CharUpperG,
303 'H' => BasicTokenNoPrefix::CharUpperH,
304 'I' => BasicTokenNoPrefix::CharUpperI,
305 'J' => BasicTokenNoPrefix::CharUpperJ,
306 'K' => BasicTokenNoPrefix::CharUpperK,
307 'L' => BasicTokenNoPrefix::CharUpperL,
308 'M' => BasicTokenNoPrefix::CharUpperM,
309 'N' => BasicTokenNoPrefix::CharUpperN,
310 'O' => BasicTokenNoPrefix::CharUpperO,
311 'P' => BasicTokenNoPrefix::CharUpperP,
312 'Q' => BasicTokenNoPrefix::CharUpperQ,
313 'R' => BasicTokenNoPrefix::CharUpperR,
314 'S' => BasicTokenNoPrefix::CharUpperS,
315 'T' => BasicTokenNoPrefix::CharUpperT,
316 'U' => BasicTokenNoPrefix::CharUpperU,
317 'V' => BasicTokenNoPrefix::CharUpperV,
318 'W' => BasicTokenNoPrefix::CharUpperW,
319 'X' => BasicTokenNoPrefix::CharUpperX,
320 'Y' => BasicTokenNoPrefix::CharUpperY,
321 'Z' => BasicTokenNoPrefix::CharUpperZ,
322 'a' => BasicTokenNoPrefix::CharLowerA,
323 'b' => BasicTokenNoPrefix::CharLowerB,
324 'c' => BasicTokenNoPrefix::CharLowerC,
325 'd' => BasicTokenNoPrefix::CharLowerD,
326 'e' => BasicTokenNoPrefix::CharLowerE,
327 'f' => BasicTokenNoPrefix::CharLowerF,
328 'g' => BasicTokenNoPrefix::CharLowerG,
329 'h' => BasicTokenNoPrefix::CharLowerH,
330 'i' => BasicTokenNoPrefix::CharLowerI,
331 'j' => BasicTokenNoPrefix::CharLowerJ,
332 'k' => BasicTokenNoPrefix::CharLowerK,
333 'l' => BasicTokenNoPrefix::CharLowerL,
334 'm' => BasicTokenNoPrefix::CharLowerM,
335 'n' => BasicTokenNoPrefix::CharLowerN,
336 'o' => BasicTokenNoPrefix::CharLowerO,
337 'p' => BasicTokenNoPrefix::CharLowerP,
338 'q' => BasicTokenNoPrefix::CharLowerQ,
339 'r' => BasicTokenNoPrefix::CharLowerR,
340 's' => BasicTokenNoPrefix::CharLowerS,
341 't' => BasicTokenNoPrefix::CharLowerT,
342 'u' => BasicTokenNoPrefix::CharLowerU,
343 'v' => BasicTokenNoPrefix::CharLowerV,
344 'w' => BasicTokenNoPrefix::CharLowerW,
345 'x' => BasicTokenNoPrefix::CharLowerX,
346 'y' => BasicTokenNoPrefix::CharLowerY,
347 'z' => BasicTokenNoPrefix::CharLowerZ,
348
349 '#' => BasicTokenNoPrefix::CharNumber,
350 '$' => BasicTokenNoPrefix::CharDollar,
351 '%' => BasicTokenNoPrefix::CharPerCent,
352 '&' => BasicTokenNoPrefix::CharAmpersand,
353 '\'' => BasicTokenNoPrefix::CharSingleQuote,
354 '(' => BasicTokenNoPrefix::CharOpenParenthesis,
355 ')' => BasicTokenNoPrefix::CharCloseParenthesis,
356 '*' => BasicTokenNoPrefix::CharAsterix,
357 '+' => BasicTokenNoPrefix::CharPlus,
358 ',' => BasicTokenNoPrefix::CharComma,
359 '_' => BasicTokenNoPrefix::CharHyphen,
360 '.' => BasicTokenNoPrefix::CharDot,
361 '/' => BasicTokenNoPrefix::CharSlash,
362 '0' => BasicTokenNoPrefix::Char0,
363 '1' => BasicTokenNoPrefix::Char1,
364 '2' => BasicTokenNoPrefix::Char2,
365 '3' => BasicTokenNoPrefix::Char3,
366 '4' => BasicTokenNoPrefix::Char4,
367 '5' => BasicTokenNoPrefix::Char5,
368 '6' => BasicTokenNoPrefix::Char6,
369 '7' => BasicTokenNoPrefix::Char7,
370 '8' => BasicTokenNoPrefix::Char8,
371 '9' => BasicTokenNoPrefix::Char9,
372 ':' => BasicTokenNoPrefix::CharColon,
373 ';' => BasicTokenNoPrefix::CharSemiColon,
374 '<' => BasicTokenNoPrefix::CharLess,
375 '=' => BasicTokenNoPrefix::CharEquals,
376 '>' => BasicTokenNoPrefix::CharGreater,
377 '?' => BasicTokenNoPrefix::CharQuestionMark,
378 '@' => BasicTokenNoPrefix::CharAt,
379
380 '\t' => BasicTokenNoPrefix::CharTab,
381
382 _ => unimplemented!("'{}'", c)
383 }
384 }
385}
386
387impl fmt::Display for BasicTokenNoPrefix {
388 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
389 match self {
390 Self::Call => write!(f, "CALL"),
391 Self::For => write!(f, "FOR"),
392 Self::Load => write!(f, "LOAD"),
393 Self::Memory => write!(f, "MEMORY"),
394 Self::Print => write!(f, "PRINT"),
395 Self::Rem => write!(f, "REM"),
396
397 Self::SymbolQuote => write!(f, "'"),
398 Self::StatementSeparator => write!(f, ":"),
399
400 Self::EndOfTokenisedLine => Ok(()),
401
402 _ => {
403 let c = (*self as u8) as char;
404 match c {
405 ' '..='z' => write!(f, "{c}"),
406
407 _ => unimplemented!("{:?}", self)
408 }
409 }
410 }
411 }
412}
413
414impl BasicTokenNoPrefix {
415 pub fn value(self) -> u8 {
417 self.into()
418 }
419}
420
421impl TryFrom<u8> for BasicTokenPrefixed {
422 type Error = String;
423
424 fn try_from(value: u8) -> Result<Self, String> {
425 match value {
426 0x1E..0x40 | 0x50..0x71 | 0x80.. => Err(format!("{value} is invalid")),
427 _ => Ok(unsafe { std::mem::transmute(value) })
428 }
429 }
430}
431
432impl From<BasicTokenPrefixed> for u8 {
433 fn from(val: BasicTokenPrefixed) -> Self {
434 val as u8
435 }
436}
437
438#[derive(Copy, Clone, PartialEq, Debug)]
439#[repr(u8)]
440#[allow(missing_docs)]
441pub enum BasicTokenPrefixed {
442 Abs = 0,
443 Asc,
444 Atn,
445 ChrDollar,
446 Cint,
447 Cos,
448 Creal,
449 Exp,
450 Fix,
451 Fre,
452 Inkey,
453 Inp,
454 Int,
455 Joy,
456 Len,
457 Log,
458 Log10,
459 LowerDollar,
460 Peek,
461 Remain,
462 Sign,
463 Sin,
464 SpaceDollar,
465 Sq,
466 Sqr,
467 StrDollar,
468 Tan,
469 Unt,
470 UpperDollar,
471 Val = 0x1D,
472
473 Eof = 0x40,
474 Err,
475 Himem,
476 InkeyDollar,
477 Pi,
478 Rnd,
479 Time,
480 Xpos,
481 Ypos,
482 Derr = 0x49,
483
484 BinDollar = 0x71,
485 DecDollar,
486 HexDollar,
487 Instr,
488 LeftDollar,
489 Max,
490 Min,
491 Pos,
492 RightDollar,
493 Round,
494 StringDollar,
495 Test,
496 Teststr,
497 CopycharDollar,
498 Vpos = 0x7F
499}
500
501impl fmt::Display for BasicTokenPrefixed {
502 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
503 let tag = match self {
504 Self::Abs => "ABS",
505 _ => unimplemented!("{}", self)
506 };
507 write!(f, "{tag}")
508 }
509}
510
511impl BasicTokenPrefixed {
518 pub fn value(self) -> u8 {
520 self.into()
521 }
522}
523
524#[derive(Debug, Clone, PartialEq)]
525pub enum BasicValue {
527 Integer(u8, u8),
529 Float(u8, u8, u8, u8, u8),
531 String(String)
533}
534
535#[allow(missing_docs)]
536impl BasicValue {
537 pub fn new_integer(word: i16) -> Self {
538 let word: u16 = unsafe { i16::cast_unsigned(word) };
539 BasicValue::Integer((word % 256) as u8, (word / 256) as u8)
540 }
541
542 pub fn new_integer_by_bytes(low: u8, high: u8) -> Self {
543 BasicValue::Integer(low, high)
544 }
545
546 pub fn new_string(_value: &str) -> Self {
547 unimplemented!()
548 }
549
550 pub fn new_float(_value: i32) -> Self {
551 unimplemented!()
552 }
553
554 pub fn as_bytes(&self) -> Vec<u8> {
555 match self {
556 Self::Integer(low, high) => vec![*low, *high],
557 _ => unimplemented!()
558 }
559 }
560
561 pub fn as_integer(&self) -> Option<u16> {
563 match self {
564 Self::Integer(low, high) => Some(u16::from(*low) + 256 * u16::from(*high)),
565 _ => None
566 }
567 }
568
569 pub fn int_hexdecimal_representation(&self) -> Option<String> {
570 self.as_integer().map(|i| format!("&{i:X}"))
571 }
572
573 pub fn int_decimal_representation(&self) -> Option<String> {
574 self.as_integer().map(|i| format!("{i}"))
575 }
576}
577
578#[derive(Debug, Clone, PartialEq)]
580pub enum BasicToken {
581 SimpleToken(BasicTokenNoPrefix),
583 PrefixedToken(BasicTokenPrefixed),
585 Rsx(String),
587 Variable(String, BasicValue),
589 Constant(BasicTokenNoPrefix, BasicValue),
591 Comment(BasicTokenNoPrefix, Vec<u8>)
593}
594
595impl fmt::Display for BasicToken {
596 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
597 match self {
598 BasicToken::SimpleToken(tok) => {
599 write!(f, "{tok}")?;
600 },
601 BasicToken::PrefixedToken(tok) => {
602 write!(f, "{tok}")?;
603 },
604 BasicToken::Comment(tok, comment) => {
605 write!(f, "{tok}")?;
606 write!(f, "{},", String::from_utf8(comment.to_vec()).unwrap())?;
607 },
608 BasicToken::Constant(kind, constant) => {
609 let repr = match kind {
610 BasicTokenNoPrefix::ValueIntegerHexadecimal16bits => {
611 constant.int_hexdecimal_representation().unwrap()
612 },
613 BasicTokenNoPrefix::ValueIntegerDecimal16bits => {
614 constant.int_decimal_representation().unwrap()
615 },
616 _ => unimplemented!("{:?}", kind)
617 };
618 write!(f, "{repr}")?;
619 },
620 _ => unimplemented!("{:?}", self)
621 }
622
623 Ok(())
624 }
625}
626
627#[allow(missing_docs)]
628impl BasicToken {
629 pub fn as_bytes(&self) -> Vec<u8> {
630 match self {
631 BasicToken::SimpleToken(tok) => vec![tok.value()],
632
633 BasicToken::PrefixedToken(tok) => {
634 vec![
635 BasicTokenNoPrefix::AdditionalTokenMarker.value(),
636 tok.value(),
637 ]
638 },
639
640 BasicToken::Rsx(_name) => {
641 let encoded_name = self.rsx_encoded_name().unwrap();
642 let mut data = vec![BasicTokenNoPrefix::Pipe.value(), encoded_name.len() as u8];
643 data.extend_from_slice(&encoded_name);
644 data
645 },
646
647 BasicToken::Constant(kind, constant) => {
648 let mut data = vec![kind.value()];
649 data.extend_from_slice(&constant.as_bytes());
650 data
651 },
652
653 BasicToken::Comment(comment_type, comment) => {
654 let mut data = vec![comment_type.value()];
655 data.extend_from_slice(comment);
656 data
657 },
658
659 _ => unimplemented!()
660 }
661 }
662
663 pub fn rsx_encoded_name(&self) -> Option<Vec<u8>> {
665 match self {
666 BasicToken::Rsx(name) => Some(Self::encode_string(name)),
667 _ => None
668 }
669 }
670
671 pub fn variable_encoded_name(&self) -> Option<Vec<u8>> {
672 match self {
673 BasicToken::Variable(name, _) => Some(Self::encode_string(name)),
674 _ => None
675 }
676 }
677
678 fn encode_string(name: &str) -> Vec<u8> {
680 let mut copy = name.as_bytes().to_vec();
681 copy.pop(); if let Some(c) = copy.last_mut() {
683 *c += 0b1000_0000; }
685 copy
686 }
687}
688
689#[cfg(test)]
690mod test {
691 use std::convert::TryInto;
692
693 use crate::tokens::*;
694
695 #[test]
696 fn test_conversion() {
697 assert_eq!(BasicTokenNoPrefix::Pipe.value(), 0x7C);
698 assert_eq!(BasicTokenNoPrefix::After.value(), 0x80);
699
700 assert_eq!(BasicTokenNoPrefix::Goto.value(), 0xA0);
701
702 assert_eq!(BasicTokenNoPrefix::SymbolQuote.value(), 0xC0);
703
704 assert_eq!(BasicTokenNoPrefix::Frame.value(), 0xE0);
705
706 assert_eq!(BasicTokenNoPrefix::GreaterOrEqual.value(), 0xF0);
707
708 assert_eq!(BasicTokenNoPrefix::Division.value(), 0xF7);
709
710 let token: BasicTokenNoPrefix = 0xF7.try_into().unwrap();
711 assert_eq!(token, BasicTokenNoPrefix::Division);
712 }
713}