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"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 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 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 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 #[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}