pub mod token;
pub mod lexer;
pub mod ast;
pub mod parser;
pub mod typecheck;
pub mod codegen;
pub mod loader;
pub fn compile(source: &str) -> Result<Vec<u8>, CompileError> {
let tokens = lexer::lex(source)?;
let module = parser::parse(&tokens)?;
let typed = typecheck::check(&module)?;
let wasm = codegen::emit(&typed)?;
Ok(wasm)
}
#[derive(Debug, Clone)]
pub struct CompileError {
pub message: String,
pub span: Option<Span>,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Span {
pub start: usize,
pub end: usize,
}
impl std::fmt::Display for CompileError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if let Some(span) = self.span {
write!(f, "[{}..{}] {}", span.start, span.end, self.message)
} else {
write!(f, "{}", self.message)
}
}
}
impl std::error::Error for CompileError {}
impl CompileError {
pub fn new(message: impl Into<String>) -> Self {
Self { message: message.into(), span: None }
}
pub fn at(message: impl Into<String>, span: Span) -> Self {
Self { message: message.into(), span: Some(span) }
}
}
impl From<String> for CompileError {
fn from(s: String) -> Self { Self::new(s) }
}
#[cfg(test)]
mod tests {
use super::compile;
#[test]
fn const_resolves_and_is_order_independent() {
assert!(compile(
"fn frame(t: i32) { host::display::clear(W); host::display::present(); } const W: i32 = 256;"
)
.is_ok());
assert!(compile(
"const A: i32 = 2; const B: i32 = A * 3; fn frame(t: i32) { host::display::clear(B); host::display::present(); }"
)
.is_ok());
assert!(compile(
"fn frame(t: i32) { host::display::clear(NOPE); host::display::present(); }"
)
.is_err());
}
#[test]
fn casts_between_numbers() {
assert!(compile(
"fn frame(t: i32) { let x = t as f64; let y = x as i32; host::display::clear(y + (3.7 as i32)); host::display::present(); }"
)
.is_ok());
}
#[test]
fn arrays_literal_and_index() {
assert!(compile(
"fn frame(t: i32) { let pal = [16711680, 65280, 255]; host::display::clear(pal[t % 3]); host::display::present(); }"
)
.is_ok());
assert!(compile(
"fn frame(t: i32) { let x = 5; host::display::clear(x[0]); host::display::present(); }"
)
.is_err());
assert!(compile(
"fn frame(t: i32) { let a = [1, 2, 3]; a[0] = 9; host::display::present(); }"
)
.is_err());
}
}