cpclib_basic/
string_parser.rs

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};
9/// ! Locomotive basic parser routines.
10use 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
20/// Parse complete basic program"],
21pub 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
29/// Parse a line
30pub fn parse_basic_line<'src>(input: &mut &'src str) -> BasicLineResult<'src> {
31    // get the number
32    let line_number = dec_u16_inner
33        .context(StrContext::Label("Wrong line number"))
34        .parse_next(input)?;
35
36    // forget the first space
37    ' '.context(StrContext::Label("Missing space"))
38        .parse_next(input)?;
39
40    // get the tokens
41    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
59/// Parse any instruction.
60/// In opposite to BASIC editor, parameters are verified (i.e. generated BASIC is valid)
61pub 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
122/// Parse a comment"],
123pub 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
202/// Parse a comma optionally surrounded by space
203pub 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
217/// Parse the Args SPC or TAB of a print expression
218pub 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
240/// Parse using argument of a print expression
241pub 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, // TODO add filtering because this string is special
248                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    // TODO check that it is valid
312
313    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
321/// Parse a single expression of a print
322pub 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
341/// Parse a list of expressions for print
342pub 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
369/// Parse a complete and valid print expression
370pub fn parse_print<'src>(input: &mut &'src str) -> BasicSeveralTokensResult<'src> {
371    // print keyword
372    let _ = Caseless("PRINT").parse_next(input)?;
373
374    // space after keyword
375    let mut tokens = vec![BasicToken::SimpleToken(BasicTokenNoPrefix::Print)];
376    let mut space = parse_space0.parse_next(input)?;
377    tokens.append(&mut space);
378
379    // canal and space
380    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    // list of expressions
390    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    // TODO implement the optional arguments list
410
411    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    // TODO implement the optional arguments list
441
442    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
466/// TODO add the missing chars
467// pub fn parse_char<'src>(input:&mut &'src str) -> BasicOneTokenResult<'src>{
468// map(
469// alt((
470// alt((
471// map(char(':'), |_| BasicTokenNoPrefix::StatementSeparator),
472// map(char(' '), |_| BasicTokenNoPrefix::CharSpace),
473// map(char('A'), |_| BasicTokenNoPrefix::CharUpperA),
474// map(char('B'), |_| BasicTokenNoPrefix::CharUpperB),
475// map(char('C'), |_| BasicTokenNoPrefix::CharUpperC),
476// map(char('D'), |_| BasicTokenNoPrefix::CharUpperD),
477// map(char('E'), |_| BasicTokenNoPrefix::CharUpperE),
478// map(char('F'), |_| BasicTokenNoPrefix::CharUpperF),
479// map(char('G'), |_| BasicTokenNoPrefix::CharUpperG),
480// map(char('H'), |_| BasicTokenNoPrefix::CharUpperH),
481// map(char('I'), |_| BasicTokenNoPrefix::CharUpperI),
482// map(char('J'), |_| BasicTokenNoPrefix::CharUpperJ),
483// map(char('K'), |_| BasicTokenNoPrefix::CharUpperK),
484// map(char('L'), |_| BasicTokenNoPrefix::CharUpperL),
485// map(char('M'), |_| BasicTokenNoPrefix::CharUpperM),
486// map(char('N'), |_| BasicTokenNoPrefix::CharUpperN),
487// map(char('O'), |_| BasicTokenNoPrefix::CharUpperO),
488// map(char('P'), |_| BasicTokenNoPrefix::CharUpperP),
489// map(char('Q'), |_| BasicTokenNoPrefix::CharUpperQ),
490// map(char('R'), |_| BasicTokenNoPrefix::CharUpperR)
491// )),
492// alt((
493// map(char('S'), |_| BasicTokenNoPrefix::CharUpperS),
494// map(char('T'), |_| BasicTokenNoPrefix::CharUpperT),
495// map(char('U'), |_| BasicTokenNoPrefix::CharUpperU),
496// map(char('V'), |_| BasicTokenNoPrefix::CharUpperV),
497// map(char('W'), |_| BasicTokenNoPrefix::CharUpperW),
498// map(char('X'), |_| BasicTokenNoPrefix::CharUpperX),
499// map(char('Y'), |_| BasicTokenNoPrefix::CharUpperY),
500// map(char('Z'), |_| BasicTokenNoPrefix::CharUpperZ)
501// )),
502// alt((
503// map(char('a'), |_| BasicTokenNoPrefix::CharLowerA),
504// map(char('b'), |_| BasicTokenNoPrefix::CharLowerB),
505// map(char('c'), |_| BasicTokenNoPrefix::CharLowerC),
506// map(char('d'), |_| BasicTokenNoPrefix::CharLowerD),
507// map(char('e'), |_| BasicTokenNoPrefix::CharLowerE),
508// map(char('f'), |_| BasicTokenNoPrefix::CharLowerF),
509// map(char('g'), |_| BasicTokenNoPrefix::CharLowerG),
510// map(char('h'), |_| BasicTokenNoPrefix::CharLowerH),
511// map(char('i'), |_| BasicTokenNoPrefix::CharLowerI),
512// map(char('j'), |_| BasicTokenNoPrefix::CharLowerJ),
513// map(char('k'), |_| BasicTokenNoPrefix::CharLowerK),
514// map(char('l'), |_| BasicTokenNoPrefix::CharLowerL),
515// map(char('m'), |_| BasicTokenNoPrefix::CharLowerM),
516// map(char('n'), |_| BasicTokenNoPrefix::CharLowerN),
517// map(char('o'), |_| BasicTokenNoPrefix::CharLowerO)
518// )),
519// alt((
520// map(char('p'), |_| BasicTokenNoPrefix::CharLowerP),
521// map(char('q'), |_| BasicTokenNoPrefix::CharLowerQ),
522// map(char('r'), |_| BasicTokenNoPrefix::CharLowerR),
523// map(char('s'), |_| BasicTokenNoPrefix::CharLowerS),
524// map(char('t'), |_| BasicTokenNoPrefix::CharLowerT),
525// map(char('u'), |_| BasicTokenNoPrefix::CharLowerU),
526// map(char('v'), |_| BasicTokenNoPrefix::CharLowerV),
527// map(char('w'), |_| BasicTokenNoPrefix::CharLowerW),
528// map(char('x'), |_| BasicTokenNoPrefix::CharLowerX),
529// map(char('y'), |_| BasicTokenNoPrefix::CharLowerY),
530// map(char('z'), |_| BasicTokenNoPrefix::CharLowerZ)
531// ))
532// )),
533// |token| BasicToken::SimpleToken(token)
534// )(input)
535// }
536/// Parse the instructions that do not need a prefix byte
537/// TODO Add all the other instructions"],
538
539/// Parse a basic value
540pub 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
562/// TODO check that some generated functions do not generate strings even if they consume numbers
563pub fn parse_numeric_expression<'code>(
564    constraint: NumericExpressionConstraint
565) -> impl Fn(&mut &'code str) -> BasicSeveralTokensResult<'code> {
566    // XXX Functions must be parsed first
567    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
653/// works with float on the amstrad cpc
654fn 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
726// pub fn parse_abs<'src>(input:&mut  &'src str) -> BasicSeveralTokensResult<'src>{
727// parse_any_numeric_function(
728// "ABS",
729// BasicToken::PrefixedToken(BasicTokenPrefixed::Abs)
730// )(input)
731// }
732
733macro_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
765// Generate all the functions that consume a numerical expression
766generate_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
794// implementation stolen to https://github.com/EdouardBERGE/rasm/blob/master/rasm.c#L2295
795pub 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        // nb is >=1
811        mask = 0x80000000;
812
813        // search for the first (from the left) bit to 1
814        while (deci & mask) == 0 {
815            mask /= 2;
816        }
817        // count the number of ContextErroraining bits
818        while mask > 0 {
819            exp += 1;
820            mask /= 2;
821        }
822        // build the mantissa part of the decimal value
823        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        // <1
837        if nb == 0.0 {
838            exp = -128;
839        }
840        else {
841            mantissa = (nb * 4294967296.0 + 0.5) as _; // as v is ALWAYS <1.0 we never reach the 32 bits maximum
842            if (mantissa & 0xFF00000000) != 0 {
843                mantissa = 0xFFFFFFFF;
844            }
845
846            mask = 0x80000000;
847            // find first significant bit of fraction part
848            while (mantissa & mask) == 0 {
849                mask /= 2;
850                exp -= 1;
851            }
852
853            mantissa = (nb * 2.0f64.powi(32 - exp) + 0.5) as _; // as v is ALWAYS <1.0 we never reach the 32 bits maximum
854            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        // generate the mantissa bytes
869        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        // generate the exponent
890        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        // Generate the sign bit
901        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
933/// Parse an hexadecimal value
934pub 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
950/// TODO: add binary number
951pub 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/// XXX stolen to the asm parser
964#[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/// XXX stolen to the asm parser
981#[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}