cpclib_asm/parser/
orgams.rs

1use cpclib_common::smol_str::SmolStr;
2use cpclib_common::winnow::combinator::{alt, cut_err, delimited, not, opt, terminated};
3use cpclib_common::winnow::stream::{AsBStr, Stream, UpdateSlice};
4use cpclib_common::winnow::token::take_until;
5use cpclib_common::winnow::{ModalResult, Parser};
6use cpclib_tokens::{BinaryOperation, Expr};
7
8use super::{
9    InnerZ80Span, LocatedExpr, LocatedToken, LocatedTokenInner, Z80ParserError, inner_code,
10    parse_factor
11};
12use crate::preamble::{MayHaveSpan, located_expr, my_space0, one_instruction_inner_code};
13
14pub static STAND_ALONE_DIRECTIVE_ORGAMS: &[&[u8]] = &[
15    b"BANK",
16    b"BRK",
17    b"BUILDSNA",
18    b"BY",
19    b"BYTE",
20    b"DB",
21    b"DEFB",
22    b"DEFS",
23    b"ELSE", //  b"END",
24    b"ENT",
25    b"IMPORT",
26    b"ORG",
27    b"PRINT",
28    b"SKIP",
29    b"WORD"
30];
31
32pub static START_DIRECTIVE_ORGAMS: &[&[u8]] = &[b"IF", b"MACRO"];
33
34pub static END_DIRECTIVE_ORGAMS: &[&[u8]] = &[b"END", b"ENDM", b"]"];
35
36pub fn parse_orgams_fail(input: &mut InnerZ80Span) -> ModalResult<LocatedToken, Z80ParserError> {
37    let input_start = input.checkpoint();
38
39    "!!".parse_next(input)?;
40
41    let content = take_until(0.., "\n").parse_next(input)?;
42    let txt = String::from_utf8_lossy(content);
43    let exp = Expr::String(SmolStr::new(txt));
44    let fmtexp = cpclib_tokens::FormattedExpr::Raw(exp);
45    let token = LocatedTokenInner::Fail(Some(vec![fmtexp]));
46
47    let token = token.into_located_token_between(&input_start, *input);
48
49    Ok(token)
50}
51
52pub fn parse_orgams_repeat(input: &mut InnerZ80Span) -> ModalResult<LocatedToken, Z80ParserError> {
53    let input_start = input.checkpoint();
54
55    let amount = terminated(located_expr, (my_space0, "**", my_space0)).parse_next(input)?;
56
57    let bracket = opt('[').parse_next(input)?;
58    let listing = if bracket.is_some() {
59        my_space0.parse_next(input)?;
60        let listing = cut_err(inner_code.context("ORGAMS REPEAT: unable to parse inner code"))
61            .parse_next(input)?;
62        ']'.parse_next(input)?;
63        listing
64    }
65    else {
66        one_instruction_inner_code.parse_next(input)?
67    };
68
69    let token = LocatedTokenInner::Repeat(amount, listing, None, None, None);
70    let token = token.into_located_token_between(&input_start, *input);
71
72    Ok(token)
73}
74
75#[inline]
76pub fn parse_orgams_expression(
77    input: &mut InnerZ80Span
78) -> ModalResult<LocatedExpr, Z80ParserError> {
79    let mut factors = Vec::new();
80    let mut operators = Vec::new();
81
82    loop {
83        factors.push(parse_orgams_ordered_expression.parse_next(input)?);
84
85        if let Some(operator) =
86            opt(delimited(my_space0, parse_orgams_operator, my_space0)).parse_next(input)?
87        {
88            operators.push(operator);
89        }
90        else {
91            break;
92        }
93    }
94
95    factors.reverse();
96    operators.reverse();
97    let mut expr = factors.pop().unwrap();
98    while let Some(next) = factors.pop() {
99        let operator = operators.pop().unwrap();
100        let left = expr;
101        let right = next;
102
103        // span goes from left to right with operator between
104        let left_bytes = left.span().as_bstr();
105        let right_bytes = right.span().as_bstr();
106        let size = (unsafe { right_bytes.as_ptr().byte_offset_from(left_bytes.as_ptr()) })
107            .unsigned_abs()
108            + right_bytes.len();
109        let span = std::ptr::slice_from_raw_parts(left_bytes.as_ptr(), size);
110        let span = (*input).update_slice(unsafe { &*span });
111
112        expr = LocatedExpr::BinaryOperation(operator, Box::new(left), Box::new(right), span.into());
113    }
114
115    Ok(expr)
116}
117
118#[inline]
119pub fn parse_orgams_operator(
120    input: &mut InnerZ80Span
121) -> ModalResult<BinaryOperation, Z80ParserError> {
122    alt((
123        '+'.value(BinaryOperation::Add),
124        '-'.value(BinaryOperation::Sub),
125        '/'.value(BinaryOperation::Div),
126        ('*', not('*')).value(BinaryOperation::Mul),
127        "AND".value(BinaryOperation::BinaryAnd),
128        "OR".value(BinaryOperation::BinaryOr),
129        "MOD".value(BinaryOperation::Mod)
130    ))
131    .parse_next(input)
132}
133
134#[inline]
135pub fn parse_orgams_ordered_expression(
136    input: &mut InnerZ80Span
137) -> ModalResult<LocatedExpr, Z80ParserError> {
138    let mut factors = Vec::new();
139    let mut operators = Vec::new();
140
141    loop {
142        factors.push(parse_orgams_factor.parse_next(input)?);
143
144        if let Some(operator) = opt(parse_orgams_operator).parse_next(input)? {
145            operators.push(operator);
146        }
147        else {
148            break;
149        }
150    }
151
152    factors.reverse();
153    operators.reverse();
154    let mut expr = factors.pop().unwrap();
155    while let Some(next) = factors.pop() {
156        let operator = operators.pop().unwrap();
157        let left = expr;
158        let right = next;
159
160        // span goes from left to right with operator between
161        let left_bytes = left.span().as_bstr();
162        let right_bytes = right.span().as_bstr();
163        let size = (unsafe { right_bytes.as_ptr().byte_offset_from(left_bytes.as_ptr()) })
164            .unsigned_abs()
165            + right_bytes.len();
166        let span = std::ptr::slice_from_raw_parts(left_bytes.as_ptr(), size);
167        let span = (*input).update_slice(unsafe { &*span });
168
169        expr = LocatedExpr::BinaryOperation(operator, Box::new(left), Box::new(right), span.into());
170    }
171
172    Ok(expr)
173}
174
175#[inline]
176pub fn parse_orgams_factor(input: &mut InnerZ80Span) -> ModalResult<LocatedExpr, Z80ParserError> {
177    let before_bracket = input.checkpoint();
178    let bracket = opt(('[', my_space0)).parse_next(input)?;
179    let exp = if bracket.is_some() {
180        let exp = parse_orgams_expression.parse_next(input)?;
181        (my_space0, ']').parse_next(input)?;
182
183        // TODO properly setup the string (we lack parenthesis)
184        let span = exp.span().clone();
185        LocatedExpr::Paren(Box::new(exp), span)
186    }
187    else {
188        parse_factor(input)?
189    };
190    Ok(exp)
191}
192
193#[cfg(test)]
194mod test {
195    use std::ops::Deref;
196
197    use cpclib_common::winnow::ModalParser;
198    use cpclib_common::winnow::error::{ErrMode, ParseError};
199
200    use crate::error::AssemblerError;
201    use crate::preamble::{
202        InnerZ80Span, ParserContext, ParserContextBuilder, ParserOptions, Z80ParserError, Z80Span,
203        parse_line_component, parse_orgams_expression, parse_orgams_factor,
204        parse_orgams_ordered_expression, parse_orgams_repeat
205    };
206
207    #[derive(Debug)]
208    struct TestResult<O: std::fmt::Debug> {
209        ctx: Box<ParserContext>,
210        span: Z80Span,
211        res: Result<O, ParseError<InnerZ80Span, Z80ParserError>>
212    }
213
214    impl<O: std::fmt::Debug> Deref for TestResult<O> {
215        type Target = Result<O, ParseError<InnerZ80Span, Z80ParserError>>;
216
217        fn deref(&self) -> &Self::Target {
218            &self.res
219        }
220    }
221
222    #[derive(Debug)]
223    struct TestResultRest<O: std::fmt::Debug> {
224        ctx: Box<ParserContext>,
225        span: Z80Span,
226        res: Result<O, ErrMode<Z80ParserError>>
227    }
228
229    impl<O: std::fmt::Debug> Deref for TestResultRest<O> {
230        type Target = Result<O, ErrMode<Z80ParserError>>;
231
232        fn deref(&self) -> &Self::Target {
233            &self.res
234        }
235    }
236
237    fn ctx_and_span(code: &'static str) -> (Box<ParserContext>, Z80Span) {
238        let mut options = ParserOptions::default();
239        options.set_flavor(cpclib_tokens::AssemblerFlavor::Orgams);
240        let ctx = Box::new(
241            ParserContextBuilder::default()
242                .set_context_name("ORGAMS_TEST")
243                .set_options(options)
244                .build(code)
245        );
246        let span = Z80Span::new_extra(code, ctx.deref());
247        (ctx, span)
248    }
249
250    fn parse_test<O, P: ModalParser<InnerZ80Span, O, Z80ParserError>>(
251        mut parser: P,
252        code: &'static str
253    ) -> TestResult<O>
254    where
255        O: std::fmt::Debug
256    {
257        let (ctx, span) = ctx_and_span(code);
258        let res = parser.parse(span.0);
259        if let Err(e) = &res {
260            let e = e.inner();
261            let e = AssemblerError::SyntaxError { error: e.clone() };
262            eprintln!("Parse error: {}", e);
263        }
264
265        TestResult { ctx, span, res }
266    }
267
268    #[test]
269    fn orgams_test_parse_macro_call() {
270        assert!(dbg!(parse_test(parse_line_component, "empty (void)")).is_ok());
271        assert!(dbg!(parse_test(parse_line_component, "empty(void)")).is_ok());
272        assert!(dbg!(parse_test(parse_line_component, "empty()")).is_ok());
273        assert!(dbg!(parse_test(parse_line_component, "empty ()")).is_ok());
274    }
275
276    // TODO check that the appropriate opcode is assembled
277    #[test]
278    fn orgams_test_parse_byte() {
279        assert!(dbg!(parse_test(parse_line_component, "byte 1")).is_ok());
280        assert!(dbg!(parse_test(parse_line_component, "db 2")).is_ok());
281        assert!(dbg!(parse_test(parse_line_component, "defb 3")).is_ok());
282        assert!(dbg!(parse_test(parse_line_component, "by 3")).is_ok());
283    }
284
285    #[test]
286    fn orgams_test_expr() {
287        assert!(dbg!(parse_test(parse_orgams_factor, "label")).is_ok());
288        assert!(dbg!(parse_test(parse_orgams_factor, "10")).is_ok());
289        assert!(dbg!(parse_test(parse_orgams_factor, "-$")).is_ok());
290
291        assert!(dbg!(parse_test(parse_orgams_ordered_expression, "label")).is_ok());
292        assert!(dbg!(parse_test(parse_orgams_ordered_expression, "10")).is_ok());
293
294        assert!(dbg!(parse_test(parse_orgams_ordered_expression, "label+10")).is_ok());
295        assert!(dbg!(parse_test(parse_orgams_ordered_expression, "label+10*5")).is_ok());
296
297        assert!(dbg!(parse_test(parse_orgams_expression, "1+3 -5 *2")).is_ok());
298        assert!(dbg!(parse_test(parse_orgams_expression, "30 + #*2")).is_ok());
299        assert!(dbg!(parse_test(parse_orgams_expression, "&100 + #*10")).is_ok());
300        assert!(dbg!(parse_test(parse_orgams_expression, "96 MOD [30 + #*2]")).is_ok());
301        assert!(dbg!(parse_test(parse_orgams_expression, "[r1 + r13*2]*2")).is_ok());
302
303        assert!(dbg!(parse_test(parse_orgams_expression, "SIN(10)")).is_ok());
304        assert!(dbg!(parse_test(parse_orgams_expression, "ABS(SIN(10))")).is_ok());
305    }
306
307    #[test]
308    fn orgams_test_repeat() {
309        assert!(dbg!(parse_test(parse_orgams_repeat, "5 ** inc l")).is_ok());
310
311        assert!(
312            dbg!(parse_test(
313                parse_orgams_repeat,
314                "256 ** BYTE ABS(SIN(#)/256)"
315            ))
316            .is_ok()
317        );
318    }
319}