1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
mod anomalies;
pub(crate) mod emitter;
mod instruction;
pub(crate) mod scanner;
mod span;
mod token;
pub(crate) mod tokenizer;
pub(crate) mod walker;

pub use anomalies::{Error, Warning};
pub(crate) use instruction::{Instruction, InstructionKind};
pub(crate) use span::{Location, Span, Spanned, Spanning};
pub(crate) use token::{Identifier, Token};

/// Assembles an Uxn binary from a string representing an Uxntal program.
///
/// - In case the program is valid, returns an `Ok((Vec<u8>, Vec<Warning>))` &mdash; the binary
///   represented as a sequence of bytes in a `Vec`, along with any [`Warning`]s that have been
///   reported during the assembly.
/// - In case the program is invalid, i.e. it contains errors, returns an
///   `Err((Vec<Error>, Vec<Warning>))`, which contains all [`Error`]s in the program, along with
///   any [`Warning`]s that may have also been generated. The `Vec` containing the errors is always
///   non-empty.
///
/// # Example
///
/// ```rust
/// let (binary, _) = ruxnasm::assemble("|0100 #02 #03 ADD").unwrap();
///
/// assert_eq!(binary, [0x01, 0x02, 0x01, 0x03, 0x18]);
/// ```
pub fn assemble(
    source: impl AsRef<str>,
) -> Result<(Vec<u8>, Vec<Warning>), (Vec<Error>, Vec<Warning>)> {
    let mut warnings = Vec::new();

    let words = match scanner::scan(source.as_ref()) {
        Ok((words, new_warnings)) => {
            warnings.extend(new_warnings);
            words
        }
        Err(error) => {
            return Err((vec![error], warnings));
        }
    };

    let (statements, definitions) = match walker::walk(words) {
        Ok((statements, definitions, new_warnings)) => {
            warnings.extend(new_warnings);
            (statements, definitions)
        }
        Err((errors, new_warnings)) => {
            warnings.extend(new_warnings);
            return Err((errors, warnings));
        }
    };

    // println!("statements: {:#?}", statements);
    // println!("labels: {:?}", definitions.labels.keys());
    // println!("sublabels: {:?}", definitions.sublabels.keys());

    match emitter::emit(statements, definitions) {
        Ok((binary, new_warnings)) => {
            warnings.extend(new_warnings);
            Ok((binary, warnings))
        }
        Err((errors, new_warnings)) => {
            warnings.extend(new_warnings);
            Err((errors, warnings))
        }
    }
}