1use std::borrow::Borrow;
2use std::collections::HashMap;
3use std::fmt::Debug;
4use std::ops::Deref;
5use std::sync::{LazyLock, RwLock};
6
7use cpclib_common::itertools::Itertools;
8use cpclib_tokens::{
9 CrunchType, Expr, ExprResult, ListingElement, TestKindElement, ToSimpleToken, Token
10};
11
12use super::list::{
13 list_argsort, list_get, list_len, list_push, list_sort, list_sublist, string_from_list,
14 string_new, string_push
15};
16use super::matrix::{
17 matrix_col, matrix_get, matrix_height, matrix_row, matrix_set_col, matrix_set_row, matrix_width
18};
19use super::processed_token::ProcessedToken;
20use super::{Env, file};
21use crate::assembler::list::{list_new, list_set};
22use crate::assembler::matrix::{matrix_new, matrix_set};
23use crate::error::{AssemblerError, ExpressionError};
24use crate::implementation::expression::ExprEvaluationExt;
25use crate::list::list_extend;
26use crate::preamble::{LocatedExpr, LocatedToken, LocatedTokenInner, MayHaveSpan, ParsingState};
27use crate::section::*;
28use crate::{Cruncher, Visited};
29
30pub trait ReturnExpr {
32 type Expr: ExprEvaluationExt;
33 fn return_expr(&self) -> Option<&Self::Expr>;
34}
35
36impl ReturnExpr for Token {
37 type Expr = Expr;
38
39 fn return_expr(&self) -> Option<&Self::Expr> {
40 match self {
41 Token::Return(exp) => Some(exp),
42 _ => None
43 }
44 }
45}
46
47impl ReturnExpr for LocatedToken {
48 type Expr = LocatedExpr;
49
50 fn return_expr(&self) -> Option<&Self::Expr> {
51 match self.deref() {
52 LocatedTokenInner::Return(e) => Some(e),
53 _ => None
54 }
55 }
56}
57
58#[derive(Debug)]
59pub struct AnyFunction<'token, T: ListingElement + Visited + ToSimpleToken + Sync + MayHaveSpan>
60where
61 <T as cpclib_tokens::ListingElement>::Expr: ExprEvaluationExt,
62 <<T as cpclib_tokens::ListingElement>::TestKind as TestKindElement>::Expr: ExprEvaluationExt,
63 ProcessedToken<'token, T>: FunctionBuilder
64{
65 name: String,
66 args: Vec<String>,
67 inner: RwLock<Vec<ProcessedToken<'token, T>>>
68}
69
70impl<'token, T: ListingElement + Visited + ToSimpleToken + Sync + MayHaveSpan> Clone
71 for AnyFunction<'token, T>
72where
73 <T as cpclib_tokens::ListingElement>::Expr: ExprEvaluationExt,
74 <<T as cpclib_tokens::ListingElement>::TestKind as TestKindElement>::Expr: ExprEvaluationExt,
75 ProcessedToken<'token, T>: FunctionBuilder
76{
77 fn clone(&self) -> Self {
78 Self {
79 name: self.name.clone(),
80 args: self.args.clone(),
81 inner: todo!()
82 }
83 }
84}
85
86impl<'token, T: ListingElement + Visited + ToSimpleToken + Sync + MayHaveSpan> PartialEq
87 for AnyFunction<'token, T>
88where
89 <T as cpclib_tokens::ListingElement>::Expr: ExprEvaluationExt,
90 <<T as cpclib_tokens::ListingElement>::TestKind as TestKindElement>::Expr: ExprEvaluationExt,
91 ProcessedToken<'token, T>: FunctionBuilder
92{
93 fn eq(&self, other: &Self) -> bool {
94 self.name == other.name && self.args == other.args
95 }
96}
97
98impl<'token, T: ListingElement + Visited + ToSimpleToken + Sync + MayHaveSpan> Eq
99 for AnyFunction<'token, T>
100where
101 <T as cpclib_tokens::ListingElement>::Expr: ExprEvaluationExt,
102 <<T as cpclib_tokens::ListingElement>::TestKind as TestKindElement>::Expr: ExprEvaluationExt,
103 ProcessedToken<'token, T>: FunctionBuilder
104{
105}
106
107impl<'token, T: ListingElement + Visited + ToSimpleToken + Sync + MayHaveSpan>
108 AnyFunction<'token, T>
109where
110 <T as cpclib_tokens::ListingElement>::Expr: ExprEvaluationExt,
111 <<T as cpclib_tokens::ListingElement>::TestKind as TestKindElement>::Expr: ExprEvaluationExt,
112 ProcessedToken<'token, T>: FunctionBuilder
113{
114 fn new<S1: AsRef<str>, S2: Borrow<str>>(
115 name: S1,
116 args: &[S2],
117 inner: Vec<ProcessedToken<'token, T>>
118 ) -> Self {
119 AnyFunction {
120 name: name.as_ref().to_owned(),
121 args: args.iter().map(|s| s.borrow().into()).collect_vec(),
122 inner: inner.into()
123 }
124 }
125}
126
127impl<'token, T: ListingElement + Visited + ToSimpleToken + Sync + ReturnExpr + MayHaveSpan>
128 AnyFunction<'token, T>
129where
130 <T as cpclib_tokens::ListingElement>::Expr: ExprEvaluationExt,
131 <<T as cpclib_tokens::ListingElement>::TestKind as TestKindElement>::Expr: ExprEvaluationExt,
132 ProcessedToken<'token, T>: FunctionBuilder + Clone
133{
134 pub fn eval(
135 &self,
136 init_env: &Env,
137 params: &[ExprResult]
138 ) -> Result<ExprResult, AssemblerError> {
139 if self.args.len() != params.len() {
140 return Err(AssemblerError::FunctionWithWrongNumberOfArguments(
141 self.name.clone(),
142 self.args.len(),
143 params.len()
144 ));
145 }
146 let mut env = init_env.clone();
150
151 for param in self.args.iter().zip(params.iter()) {
153 env.add_function_parameter_to_symbols_table(
155 format!("{{{}}}", param.0),
156 param.1.clone()
157 )
158 .unwrap();
159 }
160
161 let inner = self.inner.read().unwrap();
162 let mut inner = inner.iter().cloned().collect_vec(); for token in inner.iter_mut() {
164 token
165 .visited(&mut env)
166 .map_err(|e| AssemblerError::FunctionError(self.name.clone(), Box::new(e)))?;
167
168 if env.return_value.is_some() {
169 let extra_print = &env.active_page_info().print_commands()
170 [init_env.active_page_info().print_commands().len()..];
171 let extra_assert = &env.active_page_info().failed_assert_commands()
172 [init_env.active_page_info().failed_assert_commands().len()..];
173
174 init_env
175 .extra_print_from_function
176 .write()
177 .unwrap()
178 .extend_from_slice(extra_print);
179 init_env
180 .extra_failed_assert_from_function
181 .write()
182 .unwrap()
183 .extend_from_slice(extra_assert);
184
185 return Ok(env.return_value.take().unwrap());
186 }
187 }
188
189 Err(AssemblerError::FunctionWithoutReturn(self.name.clone()))
190 }
191}
192
193#[derive(Debug, Clone, PartialEq, Eq)]
194pub enum Function {
195 Located(AnyFunction<'static, LocatedToken>), Standard(AnyFunction<'static, Token>),
197 HardCoded(HardCodedFunction)
198}
199
200static HARD_CODED_FUNCTIONS: LazyLock<HashMap<&'static str, Function>> = LazyLock::new(|| {
201 velcro::hash_map! {
202 "mode0_byte_to_pen_at": Function::HardCoded(HardCodedFunction::Mode0ByteToPenAt),
203 "mode1_byte_to_pen_at": Function::HardCoded(HardCodedFunction::Mode1ByteToPenAt),
204 "mode2_byte_to_pen_at": Function::HardCoded(HardCodedFunction::Mode2ByteToPenAt),
205
206 "pen_at_mode0_byte": Function::HardCoded(HardCodedFunction::PenAtToMode0Byte),
207 "pen_at_mode1_byte":Function::HardCoded(HardCodedFunction::PenAtToMode1Byte),
208 "pen_at_mode2_byte": Function::HardCoded(HardCodedFunction::PenAtToMode2Byte),
209 "pens_to_mode0_byte": Function::HardCoded(HardCodedFunction::PensToMode0Byte),
210 "pens_to_mode1_byte": Function::HardCoded(HardCodedFunction::PensToMode1Byte),
211 "pens_to_mode2_byte": Function::HardCoded(HardCodedFunction::PensToMode2Byte),
212
213 "list_new": Function::HardCoded(HardCodedFunction::ListNew),
214 "list_get": Function::HardCoded(HardCodedFunction::ListGet),
215 "list_set": Function::HardCoded(HardCodedFunction::ListSet),
216 "list_len": Function::HardCoded(HardCodedFunction::ListLen),
217 "list_sublist": Function::HardCoded(HardCodedFunction::ListSublist),
218 "list_sort": Function::HardCoded(HardCodedFunction::ListSort),
219 "list_argsort": Function::HardCoded(HardCodedFunction::ListArgsort),
220 "list_push": Function::HardCoded(HardCodedFunction::ListPush),
221 "list_extend": Function::HardCoded(HardCodedFunction::ListExtend),
222
223 "string_new": Function::HardCoded(HardCodedFunction::StringNew),
224 "string_push": Function::HardCoded(HardCodedFunction::StringPush),
225 "string_concat": Function::HardCoded(HardCodedFunction::StringConcat),
226 "string_from_list": Function::HardCoded(HardCodedFunction::StringFromList),
227 "string_len": Function::HardCoded(HardCodedFunction::ListLen),
228
229
230 "assemble": Function::HardCoded(HardCodedFunction::Assemble),
231
232 "matrix_new": Function::HardCoded(HardCodedFunction::MatrixNew),
233 "matrix_set": Function::HardCoded(HardCodedFunction::MatrixSet),
234 "matrix_get": Function::HardCoded(HardCodedFunction::MatrixGet),
235 "matrix_col": Function::HardCoded(HardCodedFunction::MatrixCol),
236 "matrix_row": Function::HardCoded(HardCodedFunction::MatrixRow),
237 "matrix_set_row": Function::HardCoded(HardCodedFunction::MatrixSetRow),
238 "matrix_set_col": Function::HardCoded(HardCodedFunction::MatrixSetCol),
239 "matrix_width": Function::HardCoded(HardCodedFunction::MatrixWidth),
240 "matrix_height": Function::HardCoded(HardCodedFunction::MatrixHeight),
241
242 "load": Function::HardCoded(HardCodedFunction::Load),
243
244 "section_start": Function::HardCoded(HardCodedFunction::SectionStart),
245 "section_stop": Function::HardCoded(HardCodedFunction::SectionStop),
246 "section_length": Function::HardCoded(HardCodedFunction::SectionLength),
247 "section_used": Function::HardCoded(HardCodedFunction::SectionUsed),
248 "section_mmr": Function::HardCoded(HardCodedFunction::SectionMmr),
249
250 "binary_transform": Function::HardCoded(HardCodedFunction::BinaryTransform)
251 }
252});
253
254#[derive(Debug, Clone, PartialEq, Eq)]
255pub enum HardCodedFunction {
256 Mode0ByteToPenAt,
257 Mode1ByteToPenAt,
258 Mode2ByteToPenAt,
259
260 PenAtToMode0Byte,
261 PenAtToMode1Byte,
262 PenAtToMode2Byte,
263
264 PensToMode0Byte,
265 PensToMode1Byte,
266 PensToMode2Byte,
267
268 ListNew,
269 ListSet,
270 ListGet,
271 ListSublist,
272 ListLen,
273 ListPush,
274 ListExtend,
275 ListSort,
276 ListArgsort,
277
278 MatrixNew,
279 MatrixSet,
280 MatrixGet,
281 MatrixCol,
282 MatrixRow,
283 MatrixSetRow,
284 MatrixSetCol,
285 MatrixWidth,
286 MatrixHeight,
287
288 SectionStart,
289 SectionStop,
290 SectionLength,
291 SectionUsed,
292 SectionMmr,
293
294 StringNew,
295 StringPush,
296 StringConcat,
297 StringFromList,
298
299 Load,
300 Assemble,
301
302 BinaryTransform
303}
304
305impl HardCodedFunction {
306 pub fn nb_expected_params(&self) -> Option<usize> {
307 match self {
308 HardCodedFunction::Mode0ByteToPenAt => Some(2),
309 HardCodedFunction::Mode1ByteToPenAt => Some(2),
310 HardCodedFunction::Mode2ByteToPenAt => Some(2),
311
312 HardCodedFunction::PenAtToMode0Byte => Some(2),
313 HardCodedFunction::PenAtToMode1Byte => Some(2),
314 HardCodedFunction::PenAtToMode2Byte => Some(2),
315
316 HardCodedFunction::PensToMode0Byte => Some(2),
317 HardCodedFunction::PensToMode1Byte => Some(4),
318 HardCodedFunction::PensToMode2Byte => Some(8),
319
320 HardCodedFunction::ListNew => Some(2),
321 HardCodedFunction::ListSet => Some(3),
322 HardCodedFunction::ListGet => Some(2),
323 HardCodedFunction::ListSublist => Some(3),
324 HardCodedFunction::ListLen => Some(1),
325 HardCodedFunction::ListSort => Some(1),
326 HardCodedFunction::ListArgsort => Some(1),
327 HardCodedFunction::ListPush => Some(2),
328
329 HardCodedFunction::StringNew => Some(2),
330 HardCodedFunction::StringPush => Some(2),
331 HardCodedFunction::StringFromList => Some(1),
332 HardCodedFunction::StringConcat => None,
333
334 HardCodedFunction::Assemble => Some(1),
335
336 HardCodedFunction::MatrixNew => Some(3),
337 HardCodedFunction::MatrixSet => Some(4),
338 HardCodedFunction::MatrixCol => Some(2),
339 HardCodedFunction::MatrixRow => Some(2),
340 HardCodedFunction::MatrixGet => Some(3),
341 HardCodedFunction::MatrixSetRow => Some(3),
342 HardCodedFunction::MatrixSetCol => Some(3),
343
344 HardCodedFunction::MatrixWidth => Some(1),
345 HardCodedFunction::MatrixHeight => Some(1),
346
347 HardCodedFunction::Load => Some(1),
348
349 HardCodedFunction::SectionStart => Some(1),
350 HardCodedFunction::SectionStop => Some(1),
351 HardCodedFunction::SectionLength => Some(1),
352 HardCodedFunction::SectionUsed => Some(1),
353 HardCodedFunction::SectionMmr => Some(1),
354
355 HardCodedFunction::BinaryTransform => Some(2),
356 HardCodedFunction::ListExtend => Some(2)
357 }
358 }
359
360 pub fn by_name(name: &str) -> Option<&Function> {
361 HARD_CODED_FUNCTIONS.get(name.to_lowercase().as_str())
362 }
363
364 pub fn name(&self) -> &str {
365 HARD_CODED_FUNCTIONS
366 .iter()
367 .find_map(|(k, v)| {
368 match v {
369 Function::HardCoded(v) => {
370 if v == self {
371 Some(k)
372 }
373 else {
374 None
375 }
376 },
377 _ => None
378 }
379 })
380 .unwrap() }
382
383 pub fn eval(&self, env: &Env, params: &[ExprResult]) -> Result<ExprResult, AssemblerError> {
384 if let Some(nb) = self.nb_expected_params() {
385 if nb != params.len() {
386 return Err(AssemblerError::FunctionWithWrongNumberOfArguments(
387 self.name().into(),
388 nb,
389 params.len()
390 ));
391 }
392 }
393
394 match self {
395 HardCodedFunction::Mode0ByteToPenAt => {
396 Ok(
397 cpclib_image::pixels::mode0::byte_to_pens(params[0].int()? as _)
398 [params[1].int()? as usize % 2]
399 .number()
400 .into()
401 )
402 },
403 HardCodedFunction::Mode1ByteToPenAt => {
404 Ok(
405 cpclib_image::pixels::mode1::byte_to_pens(params[0].int()? as _)
406 [params[1].int()? as usize % 4]
407 .number()
408 .into()
409 )
410 },
411 HardCodedFunction::Mode2ByteToPenAt => {
412 Ok(
413 cpclib_image::pixels::mode2::byte_to_pens(params[0].int()? as _)
414 [params[1].int()? as usize % 8]
415 .number()
416 .into()
417 )
418 },
419
420 HardCodedFunction::PenAtToMode0Byte => {
421 Ok(cpclib_image::pixels::mode0::pen_to_pixel_byte(
422 (params[0].int()? as u8 % 16).into(),
423 (params[1].int()? as u8 % 2).into()
424 )
425 .into())
426 },
427 HardCodedFunction::PenAtToMode1Byte => {
428 Ok(cpclib_image::pixels::mode1::pen_to_pixel_byte(
429 (params[0].int()? as u8 % 4).into(),
430 params[1].int()? as u8 % 4
431 )
432 .into())
433 },
434
435 HardCodedFunction::PenAtToMode2Byte => {
436 Ok(cpclib_image::pixels::mode2::pen_to_pixel_byte(
437 (params[0].int()? as u8 % 2).into(),
438 (params[1].int()? as u8 % 8).into()
439 )
440 .into())
441 },
442
443 HardCodedFunction::PensToMode0Byte => {
444 Ok(cpclib_image::pixels::mode0::pens_to_byte(
445 params[0].int()?.into(),
446 params[1].int()?.into()
447 )
448 .into())
449 },
450 HardCodedFunction::PensToMode1Byte => {
451 Ok(cpclib_image::pixels::mode1::pens_to_byte(
452 params[0].int()?.into(),
453 params[1].int()?.into(),
454 params[2].int()?.into(),
455 params[3].int()?.into()
456 )
457 .into())
458 },
459 HardCodedFunction::PensToMode2Byte => {
460 Ok(cpclib_image::pixels::mode2::pens_to_byte(
461 params[0].int()?.into(),
462 params[1].int()?.into(),
463 params[2].int()?.into(),
464 params[3].int()?.into(),
465 params[4].int()?.into(),
466 params[5].int()?.into(),
467 params[6].int()?.into(),
468 params[7].int()?.into()
469 )
470 .into())
471 },
472 HardCodedFunction::ListNew => Ok(list_new(params[0].int()? as _, params[1].clone())),
473 HardCodedFunction::ListSet => {
474 list_set(params[0].clone(), params[1].int()? as _, params[2].clone())
475 },
476 HardCodedFunction::ListGet => list_get(¶ms[0], params[1].int()? as _),
477 HardCodedFunction::ListPush => list_push(params[0].clone(), params[1].clone()),
478 HardCodedFunction::ListExtend => list_extend(params[0].clone(), params[1].clone()),
479
480 HardCodedFunction::StringNew => string_new(params[0].int()? as _, params[1].clone()),
481 HardCodedFunction::ListLen => list_len(¶ms[0]),
482 HardCodedFunction::ListSublist => {
483 list_sublist(¶ms[0], params[1].int()? as _, params[2].int()? as _)
484 },
485
486 HardCodedFunction::StringPush => string_push(params[0].clone(), params[1].clone()),
487
488 HardCodedFunction::StringFromList => string_from_list(params[0].clone()),
489
490 HardCodedFunction::Assemble => assemble(params[0].clone(), env),
491 HardCodedFunction::StringConcat => {
492 let mut base = params[0].clone();
493 for i in 1..params.len() {
494 base = string_push(base, params[i].clone())?
495 }
496 Ok(base)
497 },
498 HardCodedFunction::ListSort => list_sort(params[0].clone()),
499 HardCodedFunction::ListArgsort => list_argsort(¶ms[0]),
500
501 HardCodedFunction::MatrixNew => {
502 Ok(matrix_new(
503 params[0].int()? as _,
504 params[1].int()? as _,
505 params[2].clone()
506 ))
507 },
508 HardCodedFunction::MatrixSet => {
509 matrix_set(
510 params[0].clone(),
511 params[1].int()? as _,
512 params[2].int()? as _,
513 params[3].clone()
514 )
515 },
516 HardCodedFunction::MatrixGet => {
517 matrix_get(¶ms[0], params[1].int()? as _, params[2].int()? as _)
518 },
519 HardCodedFunction::MatrixCol => matrix_col(¶ms[0], params[1].int()? as _),
520 HardCodedFunction::MatrixRow => matrix_row(¶ms[0], params[1].int()? as _),
521 HardCodedFunction::MatrixSetRow => {
522 matrix_set_row(params[0].clone(), params[1].int()? as _, ¶ms[2])
523 },
524
525 HardCodedFunction::MatrixSetCol => {
526 matrix_set_col(params[0].clone(), params[1].int()? as _, ¶ms[2])
527 },
528 HardCodedFunction::MatrixWidth => matrix_width(¶ms[0]),
529 HardCodedFunction::MatrixHeight => matrix_height(¶ms[0]),
530
531 HardCodedFunction::Load => {
532 let fname = params[0].string()?;
533 let (data, _) = file::load_file((fname, env), env.options().parse_options())?;
534 let data = Vec::from(data);
535 Ok(ExprResult::from(data.as_slice()))
536 },
537
538 HardCodedFunction::SectionStart => section_start(params[0].string()?, env),
539 HardCodedFunction::SectionStop => section_stop(params[0].string()?, env),
540 HardCodedFunction::SectionLength => section_length(params[0].string()?, env),
541 HardCodedFunction::SectionUsed => section_used(params[0].string()?, env),
542 HardCodedFunction::SectionMmr => section_mmr(params[0].string()?, env),
543
544 HardCodedFunction::BinaryTransform => {
545 let crunch_type = params[1].string()?;
546 let crunch_type = match crunch_type.to_uppercase().as_bytes() {
547 #[cfg(not(target_arch = "wasm32"))]
548 b"LZEXO" => CrunchType::LZEXO,
549 #[cfg(not(target_arch = "wasm32"))]
550 b"LZ4" => CrunchType::LZ4,
551 b"LZ48" => CrunchType::LZ48,
552 b"LZ49" => CrunchType::LZ49,
553 #[cfg(not(target_arch = "wasm32"))]
554 b"LZSHRINKLER" => CrunchType::Shrinkler,
555 b"LZX7" => CrunchType::LZX7,
556 #[cfg(not(target_arch = "wasm32"))]
557 b"LZX0" => CrunchType::LZX0,
558 #[cfg(not(target_arch = "wasm32"))]
559 b"LZAPU" => CrunchType::LZAPU,
560 _ => {
561 return Err(AssemblerError::AssemblingError {
562 msg: format!("{crunch_type} is not a valid crunch")
563 });
564 }
565 };
566
567 let data = params[0]
568 .list_content()
569 .iter()
570 .map(|item| item.int().map(|v| v as u8))
571 .collect::<Result<Vec<u8>, _>>()?;
572
573 let data = crunch_type.crunch(&data)?;
574 let data = ExprResult::from(data.as_slice());
575 Ok(data)
576 }
577 }
578 }
579}
580
581impl Function {
582 pub unsafe fn new_located<S1: AsRef<str>, S2: Borrow<str>>(
584 name: &S1,
585 args: &[S2],
586 inner: Vec<ProcessedToken<'_, LocatedToken>>
587 ) -> Result<Self, AssemblerError> {
588 unsafe {
589 if inner.is_empty() {
590 return Err(AssemblerError::FunctionWithEmptyBody(
591 name.as_ref().to_owned()
592 ));
593 }
594
595 let inner = std::mem::transmute(inner);
596
597 Ok(Function::Located(AnyFunction::new(name, args, inner)))
598 }
599 }
600
601 pub unsafe fn new_standard<S1: AsRef<str>, S2: Borrow<str>>(
602 name: &S1,
603 args: &[S2],
604 inner: Vec<ProcessedToken<'_, Token>>
605 ) -> Result<Self, AssemblerError> {
606 unsafe {
607 if inner.is_empty() {
608 return Err(AssemblerError::FunctionWithEmptyBody(
609 name.as_ref().to_owned()
610 ));
611 }
612
613 let inner = std::mem::transmute(inner);
614
615 Ok(Function::Standard(AnyFunction::new(name, args, inner)))
616 }
617 }
618
619 pub fn eval(&self, env: &Env, params: &[ExprResult]) -> Result<ExprResult, AssemblerError> {
622 match self {
623 Self::Located(f) => f.eval(env, params),
624 Self::Standard(f) => f.eval(env, params),
625 Self::HardCoded(f) => f.eval(env, params)
626 }
627 }
628}
629
630pub trait FunctionBuilder {
631 unsafe fn new<S1: AsRef<str>, S2: Borrow<str>>(
632 name: &S1,
633 args: &[S2],
634 inner: Vec<Self>
635 ) -> Result<Function, AssemblerError>
636 where
637 Self: Sized;
638}
639
640impl FunctionBuilder for ProcessedToken<'_, LocatedToken> {
641 unsafe fn new<S1: AsRef<str>, S2: Borrow<str>>(
642 name: &S1,
643 args: &[S2],
644 inner: Vec<Self>
645 ) -> Result<Function, AssemblerError>
646 where
647 Self: Sized
648 {
649 unsafe { Function::new_located(name, args, inner) }
650 }
651}
652
653impl FunctionBuilder for ProcessedToken<'_, Token> {
654 unsafe fn new<S1: AsRef<str>, S2: Borrow<str>>(
655 name: &S1,
656 args: &[S2],
657 inner: Vec<Self>
658 ) -> Result<Function, AssemblerError>
659 where
660 Self: Sized
661 {
662 unsafe { Function::new_standard(name, args, inner) }
663 }
664}
665
666pub fn assemble(code: ExprResult, base_env: &Env) -> Result<ExprResult, AssemblerError> {
670 let code = match code {
671 ExprResult::String(code) => code,
672 _ => {
673 return Err(AssemblerError::ExpressionError(ExpressionError::OwnError(
674 Box::new(AssemblerError::AssemblingError {
675 msg: "Wrong type. String expected".to_owned()
676 })
677 )));
678 }
679 };
680
681 let builder = base_env
682 .options()
683 .clone()
684 .context_builder()
685 .set_state(ParsingState::GeneratedLimited)
686 .set_context_name("Generated source");
687
688 let tokens = crate::parse_z80_with_context_builder(code, builder)?;
689
690 let mut env = Env::new(base_env.options().clone());
691 env.symbols = base_env.symbols().clone();
692 env.start_new_pass();
693 env.visit_page_or_bank::<Expr>(None)?; env.visit_listing(&tokens)?;
695 let bank_info = env.free_banks.pages.pop().unwrap();
696 match &bank_info.1.startadr {
697 Some(startadr) => {
698 let bytes = bank_info.0[*startadr as _..=bank_info.1.maxadr as _]
699 .iter()
700 .map(|b| ExprResult::from(*b))
701 .collect_vec();
702 Ok(ExprResult::List(bytes))
703 },
704 None => Ok(ExprResult::List(Default::default()))
705 }
706}