1use cpclib_common::itertools::Itertools;
2use cpclib_common::winnow::ascii::{Caseless, line_ending};
3use cpclib_common::winnow::combinator::{
4 alt, cut_err, eof, not, opt, preceded, repeat, terminated
5};
6use cpclib_common::winnow::error::{ContextError, ParserError, StrContext};
7use cpclib_common::winnow::stream::AsChar;
8use cpclib_common::winnow::token::{one_of, take_while};
9use cpclib_common::winnow::{ModalParser, *};
11use paste::paste;
12
13use crate::tokens::*;
14use crate::{BasicError, BasicLine, BasicProgram};
15
16type BasicSeveralTokensResult<'src> = ModalResult<Vec<BasicToken>, ContextError<StrContext>>;
17type BasicOneTokenResult<'src> = ModalResult<BasicToken, ContextError<StrContext>>;
18type BasicLineResult<'src> = ModalResult<BasicLine, ContextError<StrContext>>;
19
20pub fn parse_basic_program(
22 input: &mut &str
23) -> ModalResult<BasicProgram, ContextError<StrContext>> {
24 repeat(0.., parse_basic_line)
25 .map(BasicProgram::new)
26 .parse_next(input)
27}
28
29pub fn parse_basic_line<'src>(input: &mut &'src str) -> BasicLineResult<'src> {
31 let line_number = dec_u16_inner
33 .context(StrContext::Label("Wrong line number"))
34 .parse_next(input)?;
35
36 ' '.context(StrContext::Label("Missing space"))
38 .parse_next(input)?;
39
40 let tokens = repeat(0.., (parse_instruction, alt((eof, line_ending, ":"))))
42 .fold(Vec::new, |mut acc: Vec<_>, (mut item, next)| {
43 acc.append(&mut item);
44 if !next.is_empty() {
45 let char = next.chars().next().unwrap();
46 match char {
47 ':' => acc.push(BasicToken::SimpleToken(BasicTokenNoPrefix::CharColon)),
48 '\n' | '\r' => {},
49 _ => panic!("char '{char}' is unhandled")
50 }
51 }
52 acc
53 })
54 .parse_next(input)?;
55
56 Ok(BasicLine::new(line_number, &tokens))
57}
58
59pub fn parse_instruction<'src>(input: &mut &'src str) -> BasicSeveralTokensResult<'src> {
62 let mut res = parse_space0(input)?;
63
64 let mut instruction = alt((
65 alt((parse_rem,)).map(|i| vec![i]),
66 parse_call,
67 parse_input,
68 parse_print,
69 parse_assign
70 ))
71 .context(StrContext::Label("Unable to parse an instruction"))
72 .parse_next(input)?;
73
74 res.append(&mut instruction);
75
76 let mut extra_space = parse_space0.parse_next(input)?;
77 res.append(&mut extra_space);
78
79 Ok(res)
80}
81
82pub fn parse_assign<'src>(input: &mut &'src str) -> BasicSeveralTokensResult<'src> {
83 enum Kind {
84 Float,
85 Int,
86 String
87 };
88 let var = alt((
89 parse_string_variable.map(|v| (Kind::String, v)),
90 parse_integer_variable.map(|v| (Kind::Int, v)),
91 parse_float_variable.map(|v| (Kind::Float, v))
92 ))
93 .parse_next(input)?;
94
95 let mut space = ((parse_space0, '=', parse_space0)).parse_next(input)?;
96
97 let mut val = match var.0 {
98 Kind::Float | Kind::Int => {
99 cut_err(
100 parse_numeric_expression(NumericExpressionConstraint::None)
101 .context(StrContext::Label("Numeric expression expected"))
102 )
103 .parse_next(input)?
104 },
105 Kind::String => {
106 cut_err(
107 parse_string_expression.context(StrContext::Label("String expression expected"))
108 )
109 .parse_next(input)?
110 },
111 };
112
113 let mut res = var.1;
114 res.append(&mut space.0);
115 res.push(BasicToken::SimpleToken(space.1.into()));
116 res.append(&mut space.2);
117 res.append(&mut val);
118
119 Ok(res)
120}
121
122pub fn parse_rem<'src>(input: &mut &'src str) -> BasicOneTokenResult<'src> {
124 let sym = alt((
125 Caseless("REM").value(BasicTokenNoPrefix::Rem),
126 '\''.value(BasicTokenNoPrefix::SymbolQuote)
127 ))
128 .parse_next(input)?;
129
130 let list = take_while(0.., |ch| ch != '\n').parse_next(input)?;
131
132 Ok(BasicToken::Comment(sym, list.as_bytes().to_vec()))
133}
134
135pub fn parse_space<'src>(input: &mut &'src str) -> BasicOneTokenResult<'src> {
136 one_of([' ', '\t'])
137 .map(|c: char| BasicToken::SimpleToken(c.into()))
138 .parse_next(input)
139}
140
141pub fn parse_space0<'src>(input: &mut &'src str) -> BasicSeveralTokensResult<'src> {
142 repeat(0.., parse_space).parse_next(input)
143}
144pub fn parse_space1<'src>(input: &mut &'src str) -> BasicSeveralTokensResult<'src> {
145 repeat(1.., parse_space).parse_next(input)
146}
147
148pub fn parse_char<'src>(input: &mut &'src str) -> BasicOneTokenResult<'src> {
149 one_of(|c: char| {
150 "#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~".chars().any(|c2| c2==c)
151 })
152 .map(|c: char| BasicToken::SimpleToken(c.into()))
153 .parse_next(input)
154}
155
156pub fn parse_quote<'src>(input: &mut &'src str) -> BasicOneTokenResult<'src> {
157 '"'.value(BasicToken::SimpleToken(
158 BasicTokenNoPrefix::ValueQuotedString
159 ))
160 .parse_next(input)
161}
162
163pub fn parse_canal<'src>(input: &mut &'src str) -> BasicSeveralTokensResult<'src> {
164 (
165 '#'.value(BasicToken::SimpleToken('#'.into())),
166 one_of('0'..='7').map(|c| {
167 BasicToken::SimpleToken(match c {
168 '0' => BasicTokenNoPrefix::ConstantNumber0,
169 '1' => BasicTokenNoPrefix::ConstantNumber1,
170 '2' => BasicTokenNoPrefix::ConstantNumber2,
171 '3' => BasicTokenNoPrefix::ConstantNumber3,
172 '4' => BasicTokenNoPrefix::ConstantNumber4,
173 '5' => BasicTokenNoPrefix::ConstantNumber5,
174 '6' => BasicTokenNoPrefix::ConstantNumber6,
175 '7' => BasicTokenNoPrefix::ConstantNumber7,
176 _ => unreachable!()
177 })
178 })
179 )
180 .map(|(a, b)| vec![a, b])
181 .parse_next(input)
182}
183
184pub fn parse_quoted_string<'src>(input: &mut &'src str) -> BasicSeveralTokensResult<'src> {
185 let start = parse_quote.parse_next(input)?;
186 let mut content = repeat(0.., alt((parse_char, parse_space)))
187 .fold(Vec::new, |mut acc, new| {
188 acc.push(new);
189 acc
190 })
191 .parse_next(input)?;
192 let stop =
193 cut_err(parse_quote.context(StrContext::Label("Unclosed string"))).parse_next(input)?;
194
195 let mut res = vec![start];
196 res.append(&mut content);
197 res.push(stop);
198
199 Ok(res)
200}
201
202pub fn parse_comma<'src>(input: &mut &'src str) -> BasicSeveralTokensResult<'src> {
204 let mut data = (
205 parse_space0,
206 ','.map(|c: char| BasicToken::SimpleToken(c.into())),
207 parse_space0
208 )
209 .parse_next(input)?;
210
211 data.0.push(data.1);
212 data.0.append(&mut data.2);
213
214 Ok(data.0)
215}
216
217pub fn parse_print_arg_spc_or_tab<'src>(input: &mut &'src str) -> BasicSeveralTokensResult<'src> {
219 let (kind, open, param, close, mut space) = (
220 alt((Caseless("SPC"), Caseless("TAB"))),
221 '(',
222 parse_decimal_value_16bits,
223 ')',
224 parse_space0
225 )
226 .parse_next(input)?;
227
228 let mut tokens = kind
229 .chars()
230 .map(|c| BasicToken::SimpleToken(c.to_ascii_uppercase().into()))
231 .collect_vec();
232 tokens.push(BasicToken::SimpleToken(open.into()));
233 tokens.push(param);
234 tokens.push(BasicToken::SimpleToken(close.into()));
235 tokens.append(&mut space);
236
237 Ok(tokens)
238}
239
240pub fn parse_print_arg_using<'src>(input: &mut &'src str) -> BasicSeveralTokensResult<'src> {
242 let (using, mut space_a, mut format, mut space_b, sep, mut space_c) = (
243 Caseless("USING"),
244 parse_space0,
245 cut_err(
246 alt((
247 parse_quoted_string, parse_string_variable
249 ))
250 .context(StrContext::Label("FORMAT expected"))
251 ),
252 parse_space0,
253 cut_err(one_of([',', ';']).context(StrContext::Label("; or , expected"))),
254 parse_space0
255 )
256 .parse_next(input)?;
257
258 let mut tokens = using
259 .chars()
260 .map(|c| BasicToken::SimpleToken(c.to_ascii_uppercase().into()))
261 .collect_vec();
262 tokens.append(&mut space_a);
263 tokens.append(&mut format);
264 tokens.append(&mut space_b);
265 tokens.push(BasicToken::SimpleToken(sep.into()));
266 tokens.append(&mut space_c);
267
268 Ok(tokens)
269}
270
271pub fn parse_variable<'src>(input: &mut &'src str) -> BasicSeveralTokensResult<'src> {
272 alt((parse_string_variable, parse_integer_variable)).parse_next(input)
273}
274
275pub fn parse_string_variable<'src>(input: &mut &'src str) -> BasicSeveralTokensResult<'src> {
276 let name = terminated(parse_base_variable_name, '$').parse_next(input)?;
277
278 let mut tokens = name;
279 tokens.push(BasicToken::SimpleToken('$'.into()));
280
281 Ok(tokens)
282}
283
284pub fn parse_integer_variable<'src>(input: &mut &'src str) -> BasicSeveralTokensResult<'src> {
285 let name = terminated(parse_base_variable_name, '%').parse_next(input)?;
286
287 let mut tokens = name;
288 tokens.push(BasicToken::SimpleToken('%'.into()));
289
290 Ok(tokens)
291}
292
293pub fn parse_float_variable<'src>(input: &mut &'src str) -> BasicSeveralTokensResult<'src> {
294 let name = (parse_base_variable_name, opt('!')).parse_next(input)?;
295
296 let mut tokens = name.0;
297 if name.1.is_some() {
298 tokens.push(BasicToken::SimpleToken('!'.into()));
299 }
300
301 Ok(tokens)
302}
303
304pub fn parse_base_variable_name<'src>(input: &mut &'src str) -> BasicSeveralTokensResult<'src> {
305 let first = one_of(('a'..='z', 'A'..='Z')).parse_next(input)?;
306
307 let next =
308 opt(take_while(0.., ('a'..='z', 'A'..='Z', '0'..='9')).verify(|s: &str| s.len() < 39))
309 .parse_next(input)?;
310
311 let mut tokens = vec![BasicToken::SimpleToken(first.into())];
314 if let Some(next) = next {
315 tokens.extend(next.chars().map(|c| BasicToken::SimpleToken(c.into())));
316 }
317
318 Ok(tokens)
319}
320
321pub fn parse_print_expression<'src>(input: &mut &'src str) -> BasicSeveralTokensResult<'src> {
323 let (prefix, mut expr) = (
324 opt(alt((parse_print_arg_spc_or_tab, parse_print_arg_using))),
325 alt((
326 parse_quoted_string,
327 parse_variable,
328 parse_basic_value.map(|v| vec![v]),
329 parse_numeric_expression(NumericExpressionConstraint::None)
330 ))
331 .context(StrContext::Label("Missing expression to print"))
332 )
333 .parse_next(input)?;
334
335 let mut tokens = prefix.unwrap_or_default();
336 tokens.append(&mut expr);
337
338 Ok(tokens)
339}
340
341pub fn parse_print_stream_expression<'src>(
343 input: &mut &'src str
344) -> BasicSeveralTokensResult<'src> {
345 let mut first = parse_print_expression.parse_next(input)?;
346
347 let mut next: Vec<Vec<BasicToken>> = repeat(
348 0..,
349 (one_of([';', ',']), parse_space0, parse_print_expression).map(
350 |(sep, mut space_a, mut expr)| {
351 let mut inner = Vec::with_capacity(1 + space_a.len() + expr.len());
352 inner.push(BasicToken::SimpleToken(sep.into()));
353 inner.append(&mut space_a);
354 inner.append(&mut expr);
355
356 inner
357 }
358 )
359 )
360 .parse_next(input)?;
361
362 for other in &mut next {
363 first.append(other);
364 }
365
366 Ok(first)
367}
368
369pub fn parse_print<'src>(input: &mut &'src str) -> BasicSeveralTokensResult<'src> {
371 let _ = Caseless("PRINT").parse_next(input)?;
373
374 let mut tokens = vec![BasicToken::SimpleToken(BasicTokenNoPrefix::Print)];
376 let mut space = parse_space0.parse_next(input)?;
377 tokens.append(&mut space);
378
379 let canal = opt(parse_canal).parse_next(input)?;
381
382 if let Some(mut canal) = canal {
383 tokens.append(&mut canal);
384
385 let mut comma = parse_comma.parse_next(input)?;
386 tokens.append(&mut comma);
387 }
388
389 let exprs = opt(parse_print_stream_expression).parse_next(input)?;
391 if let Some(mut exprs) = exprs {
392 tokens.append(&mut exprs);
393 }
394
395 Ok(tokens)
396}
397
398pub fn parse_call<'src>(input: &mut &'src str) -> BasicSeveralTokensResult<'src> {
399 let (_, mut space_a, mut address) = (
400 Caseless("CALL"),
401 parse_space1,
402 cut_err(
403 parse_numeric_expression(NumericExpressionConstraint::Integer)
404 .context(StrContext::Label("Address expected"))
405 )
406 )
407 .parse_next(input)?;
408
409 let mut res = vec![BasicToken::SimpleToken(BasicTokenNoPrefix::Call)];
412 res.append(&mut space_a);
413 res.append(&mut address);
414
415 Ok(res)
416}
417
418pub fn parse_input<'src>(input: &mut &'src str) -> BasicSeveralTokensResult<'src> {
419 let (_, mut space_a, canal, mut space_b, sep, mut space_c, string, args): (
420 _,
421 _,
422 _,
423 _,
424 _,
425 _,
426 _,
427 Vec<_>
428 ) = (
429 Caseless("INPUT"),
430 parse_space1,
431 opt(parse_canal),
432 parse_space0,
433 opt(';'),
434 parse_space0,
435 opt(parse_quoted_string),
436 repeat(1.., (parse_space0, ';', parse_space0, parse_variable))
437 )
438 .parse_next(input)?;
439
440 let mut res = vec![BasicToken::SimpleToken(BasicTokenNoPrefix::Input)];
443 res.append(&mut space_a);
444 if let Some(mut canal) = canal {
445 res.append(&mut canal)
446 };
447 res.append(&mut space_b);
448 if let Some(sep) = sep {
449 res.push(BasicToken::SimpleToken(sep.into()))
450 };
451 res.append(&mut space_c);
452 if let Some(mut string) = string {
453 res.append(&mut string)
454 };
455
456 for mut arg in args.into_iter() {
457 res.append(&mut arg.0);
458 res.push(BasicToken::SimpleToken(arg.1.into()));
459 res.append(&mut arg.2);
460 res.append(&mut arg.3);
461 }
462
463 Ok(res)
464}
465
466pub fn parse_basic_value<'src>(input: &mut &'src str) -> BasicOneTokenResult<'src> {
541 alt((parse_floating_point, parse_integer_value_16bits)).parse_next(input)
542}
543
544pub fn parse_string_expression<'src>(input: &mut &'src str) -> BasicSeveralTokensResult<'src> {
545 alt((
546 parse_quoted_string,
547 parse_chr_dollar,
548 parse_lower_dollar,
549 parse_upper_dollar,
550 parse_space_dollar,
551 parse_str_dollar
552 ))
553 .parse_next(input)
554}
555
556#[derive(Copy, Clone, PartialEq, Eq)]
557pub enum NumericExpressionConstraint {
558 None,
559 Integer
560}
561
562pub fn parse_numeric_expression<'code>(
564 constraint: NumericExpressionConstraint
565) -> impl Fn(&mut &'code str) -> BasicSeveralTokensResult<'code> {
566 move |input: &mut &'code str| {
568 match constraint {
569 NumericExpressionConstraint::None => {
570 alt((
571 parse_asc,
572 parse_val,
573 parse_len,
574 parse_all_generated_numeric_functions_any,
575 parse_all_generated_numeric_functions_int,
576 parse_basic_value.map(|v| vec![v]),
577 parse_integer_variable,
578 parse_float_variable
579 ))
580 .parse_next(input)
581 },
582 NumericExpressionConstraint::Integer => {
583 alt((
584 parse_asc,
585 parse_val,
586 parse_len,
587 parse_all_generated_numeric_functions_int,
588 parse_integer_value_16bits.map(|v| vec![v]),
589 parse_integer_variable
590 ))
591 .parse_next(input)
592 },
593 }
594 }
595}
596
597fn parse_any_string_function<'code>(
598 name: &'static str,
599 code: BasicToken
600) -> impl Fn(&mut &'code str) -> BasicSeveralTokensResult<'code> {
601 move |input: &mut &'code str| -> BasicSeveralTokensResult<'code> {
602 let (code, mut space_a, open, mut expr, close) = (
603 Caseless(name).map(|_| code.clone()),
604 parse_space0,
605 '(',
606 cut_err(parse_string_expression.context(StrContext::Label("Wrong parameter"))),
607 cut_err(')'.context(StrContext::Label("Missing ')'")))
608 )
609 .parse_next(input)?;
610
611 let mut res = Vec::new();
612 res.push(code);
613 res.append(&mut space_a);
614 res.push(BasicToken::SimpleToken(BasicTokenNoPrefix::from(open)));
615 res.append(&mut expr);
616 res.push(BasicToken::SimpleToken(BasicTokenNoPrefix::from(close)));
617
618 Ok(res)
619 }
620}
621
622macro_rules! generate_string_functions {
623 (
624 $($name:ident: $code:expr_2021),+
625
626 )=> {
627 $(paste! {
628 pub fn [<parse_ $name:lower>]<'src>(input:&mut &'src str) -> BasicSeveralTokensResult<'src>{
629 parse_any_string_function(
630 stringify!($name),
631 $code,
632 ).parse_next(input)
633 }
634 })+
635
636 pub fn parse_all_generated_string_functions<'src>(input:&mut &'src str) -> BasicSeveralTokensResult<'src>{
637 alt((
638 $(
639 paste!{[<parse_ $name:lower>]},
640 )+
641 )).parse_next(input)
642 }
643
644};
645}
646
647generate_string_functions! {
648 ASC: BasicToken::PrefixedToken(BasicTokenPrefixed::Asc),
649 LEN: BasicToken::PrefixedToken(BasicTokenPrefixed::Len),
650 VAL: BasicToken::PrefixedToken(BasicTokenPrefixed::Val)
651}
652
653fn parse_chr_dollar<'src>(input: &mut &'src str) -> BasicSeveralTokensResult<'src> {
655 parse_any_numeric_function(
656 "CHR$",
657 BasicToken::PrefixedToken(BasicTokenPrefixed::ChrDollar),
658 NumericExpressionConstraint::None
659 )
660 .parse_next(input)
661}
662
663fn parse_space_dollar<'src>(input: &mut &'src str) -> BasicSeveralTokensResult<'src> {
664 parse_any_numeric_function(
665 "SPACE$",
666 BasicToken::PrefixedToken(BasicTokenPrefixed::SpaceDollar),
667 NumericExpressionConstraint::None
668 )
669 .parse_next(input)
670}
671
672fn parse_str_dollar<'src>(input: &mut &'src str) -> BasicSeveralTokensResult<'src> {
673 parse_any_numeric_function(
674 "STR$",
675 BasicToken::PrefixedToken(BasicTokenPrefixed::StrDollar),
676 NumericExpressionConstraint::None
677 )
678 .parse_next(input)
679}
680
681fn parse_lower_dollar<'src>(input: &mut &'src str) -> BasicSeveralTokensResult<'src> {
682 parse_any_string_function(
683 "LOWER$",
684 BasicToken::PrefixedToken(BasicTokenPrefixed::LowerDollar)
685 )
686 .parse_next(input)
687}
688
689fn parse_upper_dollar<'src>(input: &mut &'src str) -> BasicSeveralTokensResult<'src> {
690 parse_any_string_function(
691 "UPPER$",
692 BasicToken::PrefixedToken(BasicTokenPrefixed::UpperDollar)
693 )
694 .parse_next(input)
695}
696
697fn parse_any_numeric_function<'code>(
698 name: &'static str,
699 code: BasicToken,
700 constraint: NumericExpressionConstraint
701) -> impl Fn(&mut &'code str) -> BasicSeveralTokensResult<'code> {
702 move |input: &mut &'code str| -> BasicSeveralTokensResult<'code> {
703 let (code, mut space_a, open, mut expr, close) = (
704 Caseless(name).map(|_| code.clone()),
705 parse_space0,
706 '(',
707 cut_err(
708 parse_numeric_expression(constraint).context(StrContext::Label("Wrong parameter"))
709 )
710 .context(StrContext::Label("Wrong parameter")),
711 cut_err(')'.context(StrContext::Label("Missing ')'")))
712 )
713 .parse_next(input)?;
714
715 let mut res = Vec::new();
716 res.push(code);
717 res.append(&mut space_a);
718 res.push(BasicToken::SimpleToken(BasicTokenNoPrefix::from(open)));
719 res.append(&mut expr);
720 res.push(BasicToken::SimpleToken(BasicTokenNoPrefix::from(close)));
721
722 Ok(res)
723 }
724}
725
726macro_rules! generate_numeric_functions {
734 ( $(
735 $const:ty | $kind:ident => {
736 $($name:ident: $code:expr_2021),+
737 }
738 )+
739
740 )=> {$(
741 $(paste! {
742 pub fn [<parse_ $name:lower>]<'src>(input: &mut &'src str) -> BasicSeveralTokensResult<'src> {
743 parse_any_numeric_function(
744 stringify!($name),
745 $code,
746 $const
747 ).parse_next(input)
748 }
749 })+
750
751
752 paste! {
753 pub fn [<parse_all_generated_numeric_functions_ $kind >]<'src>(input: &mut &'src str) -> BasicSeveralTokensResult<'src> {
754 alt((
755 $(
756 paste!{[<parse_ $name:lower>]},
757 )+
758 )).parse_next(input)
759 }
760 }
761 )+
762};
763}
764
765generate_numeric_functions! {
767
768 NumericExpressionConstraint::None | any => {
769 ABS: BasicToken::PrefixedToken(BasicTokenPrefixed::Abs),
770 ATN: BasicToken::PrefixedToken(BasicTokenPrefixed::Atn),
771 CINT: BasicToken::PrefixedToken(BasicTokenPrefixed::Cint),
772 COS: BasicToken::PrefixedToken(BasicTokenPrefixed::Cos),
773 CREAL: BasicToken::PrefixedToken(BasicTokenPrefixed::Creal),
774 EXP: BasicToken::PrefixedToken(BasicTokenPrefixed::Exp),
775 FIX: BasicToken::PrefixedToken(BasicTokenPrefixed::Fix),
776 INP: BasicToken::PrefixedToken(BasicTokenPrefixed::Inp),
777 INT: BasicToken::PrefixedToken(BasicTokenPrefixed::Int),
778 LOG: BasicToken::PrefixedToken(BasicTokenPrefixed::Log),
779 PEEK: BasicToken::PrefixedToken(BasicTokenPrefixed::Peek),
780 SGN: BasicToken::PrefixedToken(BasicTokenPrefixed::Sign),
781 SIN: BasicToken::PrefixedToken(BasicTokenPrefixed::Sin),
782 SQ: BasicToken::PrefixedToken(BasicTokenPrefixed::Sq),
783 SQR: BasicToken::PrefixedToken(BasicTokenPrefixed::Sqr),
784 TAN: BasicToken::PrefixedToken(BasicTokenPrefixed::Tan),
785 UNT: BasicToken::PrefixedToken(BasicTokenPrefixed::Unt)
786 }
787
788 NumericExpressionConstraint::Integer | int => {
789 INKEY: BasicToken::PrefixedToken(BasicTokenPrefixed::Inkey),
790 JOY: BasicToken::PrefixedToken(BasicTokenPrefixed::Joy)
791 }
792}
793
794pub fn f32_to_amstrad_float(nb: f64) -> Result<[u8; 5], BasicError> {
796 let mut bits = [false; 32];
797 let mut res = [0; 5];
798
799 let (is_pos, nb) = if nb >= 0f64 { (true, nb) } else { (false, -nb) };
800
801 let deci = nb.trunc() as u64;
802 let _fract = nb.fract();
803
804 let mut bitpos = 0;
805 let mut exp: i32 = 0;
806 let mut mantissa: u64 = 0;
807 let mut mask: u64 = 0x80000000;
808
809 if deci >= 1 {
810 mask = 0x80000000;
812
813 while (deci & mask) == 0 {
815 mask /= 2;
816 }
817 while mask > 0 {
819 exp += 1;
820 mask /= 2;
821 }
822 mantissa = (nb * 2f64.powi(32 - exp) + 0.5) as _;
824 if (mantissa & 0xFF00000000) != 0 {
825 mantissa = 0xFFFFFFFF
826 };
827
828 mask = 0x80000000;
829 while mask != 0 {
830 bits[bitpos] = (mantissa & mask) != 0;
831 bitpos += 1;
832 mask /= 2;
833 }
834 }
835 else {
836 if nb == 0.0 {
838 exp = -128;
839 }
840 else {
841 mantissa = (nb * 4294967296.0 + 0.5) as _; if (mantissa & 0xFF00000000) != 0 {
843 mantissa = 0xFFFFFFFF;
844 }
845
846 mask = 0x80000000;
847 while (mantissa & mask) == 0 {
849 mask /= 2;
850 exp -= 1;
851 }
852
853 mantissa = (nb * 2.0f64.powi(32 - exp) + 0.5) as _; if (mantissa & 0xFF00000000) != 0 {
855 mantissa = 0xFFFFFFFF;
856 }
857
858 mask = 0x80000000;
859 while mask != 0 {
860 bits[bitpos] = (mantissa & mask) != 0;
861 bitpos += 1;
862 mask /= 2;
863 }
864 }
865 }
866
867 {
868 let mut ib: usize = 3;
870 let mut ibb: u8 = 0x80;
871 for j in 0..bitpos {
872 if bits[j] {
873 res[ib] |= ibb;
874 }
875 ibb /= 2;
876 if ibb == 0 {
877 ibb = 0x80;
878 if ib != 0 {
879 ib -= 1
880 }
881 else {
882 debug_assert!(j == bitpos - 1);
883 };
884 }
885 }
886 }
887
888 {
889 exp += 128;
891 if !(0..=255).contains(&exp) {
892 return Err(BasicError::ExponentOverflow);
893 }
894 else {
895 res[4] = exp as _;
896 }
897 }
898
899 {
900 if is_pos {
902 res[3] &= 0x7F;
903 }
904 else {
905 res[3] |= 0x80;
906 }
907 }
908
909 Ok(res)
910}
911
912pub fn parse_floating_point<'src>(input: &mut &'src str) -> BasicOneTokenResult<'src> {
913 let nb = (opt('-'), dec_u16_inner, '.', dec_u16_inner)
914 .recognize()
915 .map(|nb| f32_to_amstrad_float(nb.parse::<f64>().unwrap()))
916 .verify(|res| res.is_ok())
917 .context(StrContext::Label("Unable to parse float"))
918 .parse_next(input)?;
919
920 let bytes = nb.unwrap();
921 let res = BasicToken::Constant(
922 BasicTokenNoPrefix::ValueFloatingPoint,
923 BasicValue::Float(bytes[0], bytes[1], bytes[2], bytes[3], bytes[4])
924 );
925
926 Ok(res)
927}
928
929pub fn parse_integer_value_16bits<'src>(input: &mut &'src str) -> BasicOneTokenResult<'src> {
930 alt((parse_decimal_value_16bits, parse_hexadecimal_value_16bits)).parse_next(input)
931}
932
933pub fn parse_hexadecimal_value_16bits<'src>(input: &mut &'src str) -> BasicOneTokenResult<'src> {
935 (
936 opt('-'),
937 preceded(alt((Caseless("&h"), "&")), hex_u16_inner)
938 )
939 .map(|(neg, val)| {
940 let val = val as i16;
941
942 BasicToken::Constant(
943 BasicTokenNoPrefix::ValueIntegerHexadecimal16bits,
944 BasicValue::new_integer(if neg.is_some() { -val } else { val })
945 )
946 })
947 .parse_next(input)
948}
949
950pub fn parse_decimal_value_16bits<'src>(input: &mut &'src str) -> BasicOneTokenResult<'src> {
952 (opt('-'), terminated(dec_u16_inner, not('.')))
953 .map(|(neg, val)| {
954 let val = val as i16;
955 BasicToken::Constant(
956 BasicTokenNoPrefix::ValueIntegerDecimal16bits,
957 BasicValue::new_integer(if neg.is_some() { -val } else { val })
958 )
959 })
960 .parse_next(input)
961}
962
963#[inline]
965pub fn hex_u16_inner(input: &mut &str) -> ModalResult<u16, ContextError> {
966 take_while(1..=4, AsChar::is_hex_digit)
967 .map(|parsed: &str| {
968 let mut res = 0_u32;
969 for digit in parsed.chars() {
970 let value = digit.to_digit(16).unwrap_or(0);
971 res = value + (res * 16);
972 }
973 res
974 })
975 .verify(|res| *res < u32::from(u16::max_value()))
976 .map(|res| res as u16)
977 .parse_next(input)
978}
979
980#[inline]
982pub fn dec_u16_inner(input: &mut &str) -> ModalResult<u16, ContextError> {
983 take_while(1.., '0'..='9')
984 .verify(|parsed: &str| parsed.len() <= 5)
985 .map(|parsed: &str| {
986 let mut res = 0_u32;
987 for e in parsed.chars() {
988 let digit = e;
989 let value = digit.to_digit(10).unwrap_or(0);
990 res = value + (res * 10);
991 }
992 res
993 })
994 .verify(|nb| *nb < u32::from(u16::max_value()))
995 .map(|nb| nb as u16)
996 .parse_next(input)
997}
998
999pub fn test_parse<'code, P: ModalParser<&'code str, Vec<BasicToken>, ContextError>>(
1000 mut parser: P,
1001 code: &'code str
1002) -> BasicLine {
1003 let tokens = dbg!(parser.parse(code)).expect("Parse issue");
1004
1005 BasicLine {
1006 line_number: 10,
1007 tokens,
1008 forced_length: None
1009 }
1010}
1011
1012pub fn test_parse1<'code, P: ModalParser<&'code str, BasicToken, ContextError>>(
1013 mut parser: P,
1014 code: &'code str
1015) -> BasicLine {
1016 let tokens = dbg!(parser.parse(code)).expect("Parse issue");
1017
1018 BasicLine {
1019 line_number: 10,
1020 tokens: vec![tokens],
1021 forced_length: None
1022 }
1023}
1024
1025pub fn test_parse_and_compare<'code, P: ModalParser<&'code str, Vec<BasicToken>, ContextError>>(
1026 parser: P,
1027 code: &'code str,
1028 bytes: &[u8]
1029) {
1030 let prog = test_parse(parser, code);
1031 assert_eq!(bytes, prog.tokens_as_bytes().as_slice())
1032}
1033
1034#[cfg(test)]
1035mod test {
1036 use crate::string_parser::*;
1037
1038 #[test]
1039 fn check_number() {
1040 assert!(dbg!(dec_u16_inner(&mut "10")).is_ok());
1041
1042 assert!(dbg!(parse_floating_point(&mut "67.98")).is_ok());
1043 assert!(dbg!(parse_floating_point(&mut "-67.98")).is_ok());
1044
1045 match hex_u16_inner(&mut "1234") {
1046 Ok(value) => {
1047 println!("{:x}", &value);
1048 assert_eq!(0x1234, value);
1049 },
1050 Err(e) => {
1051 panic!("{:?}", e);
1052 }
1053 }
1054
1055 match parse_hexadecimal_value_16bits(&mut "&1234") {
1056 Ok(value) => {
1057 println!("{:?}", &value);
1058 let bytes = value.as_bytes();
1059 assert_eq!(
1060 bytes[0],
1061 BasicTokenNoPrefix::ValueIntegerHexadecimal16bits as u8
1062 );
1063 assert_eq!(bytes[1], 0x34);
1064 assert_eq!(bytes[2], 0x12);
1065 },
1066 Err(e) => {
1067 panic!("{:?}", e);
1068 }
1069 }
1070 }
1071
1072 fn check_line_tokenisation(code: &str) -> BasicLine {
1073 let res = parse_basic_line.parse(code);
1074 match res {
1075 Ok(line) => {
1076 println!("{:?}", &line);
1077 line
1078 },
1079 Err(e) => {
1080 panic!("{:?}", e);
1081 }
1082 }
1083 }
1084
1085 fn check_token_tokenisation(code: &str) {
1086 let res = parse_instruction.parse(code);
1087 match res {
1088 Ok(line) => {
1089 println!("{} => {:?}", code, &line);
1090 },
1091 Err(e) => {
1092 panic!("{:?}", e);
1093 }
1094 }
1095 }
1096
1097 #[test]
1098 fn test_lines() {
1099 check_line_tokenisation("10 call &0\n");
1100 check_line_tokenisation("10 call &0 \n");
1101 check_line_tokenisation("10 call &0: call &0\n");
1102 }
1103
1104 #[test]
1105 fn test_comment() {
1106 check_line_tokenisation("10 REM fldsfksjfksjkg");
1107 check_line_tokenisation("10 ' fldsfksjfksjkg");
1108
1109 let _line = check_line_tokenisation("10 REM fldsfksjfksjkg:CALL\n");
1110 }
1111
1112 fn check_expression(code: &str) {
1113 let res = parse_numeric_expression(NumericExpressionConstraint::None).parse(code);
1114 match res {
1115 Ok(line) => {
1116 println!("{} => {:?}", code, &line);
1117 },
1118 Err(e) => {
1119 panic!("{:?}", e);
1120 }
1121 }
1122 }
1123
1124 fn check_print_expression(code: &str) {
1125 let res = parse_print_expression.parse(code);
1126 match res {
1127 Ok(line) => {
1128 println!("{} => {:?}", code, &line);
1129 },
1130 Err(e) => {
1131 panic!("{:?}", e);
1132 }
1133 }
1134 }
1135
1136 #[test]
1137 fn test_expression() {
1138 let exprs = ["ATN(1)", "ABS(-67.98)"];
1139
1140 for exp in exprs.into_iter() {
1141 check_expression(exp);
1142 check_print_expression(exp);
1143 }
1144 }
1145}