use std::mem;
use crate::common::{
number::split_number,
span::{Span, Spanned},
lambda::{Captured, Lambda},
opcode::Opcode,
data::Data,
};
use crate::compiler::{
sst::{UniqueSymbol, Scope, SST, SSTPattern},
syntax::Syntax,
};
use crate::core::{
ffi_core,
ffi::FFI,
};
pub fn gen(sst: (Spanned<SST>, Scope)) -> Result<Lambda, Syntax> {
return gen_with_ffi(sst, ffi_core());
}
pub fn gen_with_ffi(sst: (Spanned<SST>, Scope), ffi: FFI) -> Result<Lambda, Syntax> {
let mut compiler = Compiler::base(ffi, sst.1);
compiler.walk(&sst.0)?;
return Ok(compiler.lambda);
}
pub struct Compiler {
enclosing: Option<Box<Compiler>>,
lambda: Lambda,
ffi: FFI,
ffi_names: Vec<String>,
scope: Scope,
}
impl Compiler {
pub fn base(ffi: FFI, scope: Scope) -> Compiler {
Compiler {
enclosing: None,
lambda: Lambda::empty(),
ffi,
ffi_names: vec![],
scope,
}
}
pub fn enter_scope(&mut self, scope: Scope) {
let ffi = mem::replace(&mut self.ffi, FFI::new());
let nested = Compiler::base(ffi, scope);
let enclosing = mem::replace(self, nested);
self.enclosing = Some(Box::new(enclosing));
}
pub fn exit_scope(&mut self) -> Compiler {
let ffi = mem::replace(&mut self.ffi, FFI::new());
let enclosing = mem::replace(&mut self.enclosing, None);
let nested = match enclosing {
Some(compiler) => mem::replace(self, *compiler),
None => unreachable!("Can not go back past root copiler"),
};
self.ffi = ffi;
return nested;
}
pub fn walk(&mut self, sst: &Spanned<SST>) -> Result<(), Syntax> {
self.lambda.decls = self.scope.locals.len();
self.lambda.emit_span(&sst.span);
return match sst.item.clone() {
SST::Data(data) => Ok(self.data(data)),
SST::Symbol(unique) => Ok(self.symbol(unique)),
SST::Block(block) => self.block(block),
SST::Label(name, expression) => self.label(name, *expression),
SST::Tuple(tuple) => self.tuple(tuple),
SST::FFI { name, expression } => self.ffi(name, *expression, sst.span.clone()),
SST::Assign { pattern, expression } => self.assign(*pattern, *expression),
SST::Lambda { pattern, expression, scope } => self.lambda(*pattern, *expression, scope),
SST::Call { fun, arg } => self.call(*fun, *arg),
};
}
pub fn symbol(&mut self, unique_symbol: UniqueSymbol) {
let index = if let Some(i) = self.scope.local_index(unique_symbol) {
self.lambda.emit(Opcode::Load); i
} else if let Some(i) = self.scope.nonlocal_index(unique_symbol) {
self.lambda.emit(Opcode::LoadCap); i
} else {
todo!();
};
self.lambda.emit_bytes(&mut split_number(index));
}
pub fn data(&mut self, data: Data) {
self.lambda.emit(Opcode::Con);
let mut split = split_number(self.lambda.index_data(data));
self.lambda.emit_bytes(&mut split);
}
pub fn block(&mut self, children: Vec<Spanned<SST>>) -> Result<(), Syntax> {
if children.is_empty() {
self.data(Data::Unit);
return Ok(());
}
for child in children {
self.walk(&child)?;
self.lambda.emit(Opcode::Del);
}
self.lambda.demit();
Ok(())
}
pub fn print(&mut self, expression: Spanned<SST>) -> Result<(), Syntax> {
self.walk(&expression)?;
self.lambda.emit(Opcode::Print);
Ok(())
}
pub fn label(&mut self, name: String, expression: Spanned<SST>) -> Result<(), Syntax> {
self.walk(&expression)?;
self.data(Data::Kind(name));
self.lambda.emit(Opcode::Label);
Ok(())
}
pub fn tuple(&mut self, tuple: Vec<Spanned<SST>>) -> Result<(), Syntax> {
let length = tuple.len();
for item in tuple.into_iter() {
self.walk(&item)?;
}
self.lambda.emit(Opcode::Tuple);
self.lambda.emit_bytes(&mut split_number(length));
Ok(())
}
pub fn ffi(&mut self, name: String, expression: Spanned<SST>, span: Span) -> Result<(), Syntax> {
self.walk(&expression)?;
let function = self.ffi.get(&name)
.map_err(|s| Syntax::error(&s, &span))?;
let index = match self.ffi_names.iter().position(|n| n == &name) {
Some(p) => p,
None => {
self.ffi_names.push(name);
self.lambda.add_ffi(function)
},
};
self.lambda.emit_span(&span);
self.lambda.emit(Opcode::FFICall);
self.lambda.emit_bytes(&mut split_number(index));
Ok(())
}
pub fn resolve_assign(&mut self, unique_symbol: UniqueSymbol) {
let index = if let Some(i) = self.scope.local_index(unique_symbol) {
self.lambda.emit(Opcode::Save); i
} else if let Some(i) = self.scope.nonlocal_index(unique_symbol) {
self.lambda.emit(Opcode::SaveCap); i
} else {
todo!()
};
self.lambda.emit_bytes(&mut split_number(index));
}
pub fn destructure(&mut self, pattern: Spanned<SSTPattern>, redeclare: bool) {
self.lambda.emit_span(&pattern.span);
match pattern.item {
SSTPattern::Symbol(unique_symbol) => {
self.resolve_assign(unique_symbol);
},
SSTPattern::Data(expected) => {
self.data(expected);
self.lambda.emit(Opcode::UnData);
}
SSTPattern::Label(name, pattern) => {
self.data(Data::Kind(name));
self.lambda.emit(Opcode::UnLabel);
self.destructure(*pattern, redeclare);
}
SSTPattern::Tuple(tuple) => {
for (index, sub_pattern) in tuple.into_iter().enumerate() {
self.lambda.emit(Opcode::UnTuple);
self.lambda.emit_bytes(&mut split_number(index));
self.destructure(sub_pattern, redeclare);
}
self.lambda.emit(Opcode::Del);
},
}
}
pub fn assign(
&mut self,
pattern: Spanned<SSTPattern>,
expression: Spanned<SST>
) -> Result<(), Syntax> {
self.walk(&expression)?;
self.destructure(pattern, false);
self.data(Data::Unit);
Ok(())
}
pub fn lambda(
&mut self,
pattern: Spanned<SSTPattern>,
expression: Spanned<SST>,
scope: Scope,
) -> Result<(), Syntax> {
let mut captures = vec![];
for nonlocal in scope.nonlocals.iter() {
let captured = if self.scope.is_local(*nonlocal) {
let index = self.scope.local_index(*nonlocal).unwrap();
self.lambda.emit(Opcode::Capture);
self.lambda.emit_bytes(&mut split_number(index));
Captured::Local(index)
} else {
Captured::Nonlocal(self.scope.nonlocal_index(*nonlocal).unwrap())
};
captures.push(captured);
}
self.enter_scope(scope);
{
self.lambda.captures = captures;
self.destructure(pattern, true);
self.walk(&expression)?;
self.lambda.emit(Opcode::Return);
self.lambda.emit_bytes(&mut split_number(self.scope.locals.len()));
}
let lambda = self.exit_scope().lambda;
let lambda_index = self.lambda.index_data(Data::Lambda(Box::new(lambda)));
self.lambda.emit(Opcode::Closure);
self.lambda.emit_bytes(&mut split_number(lambda_index));
Ok(())
}
pub fn call(&mut self, fun: Spanned<SST>, arg: Spanned<SST>) -> Result<(), Syntax> {
self.walk(&arg)?;
self.walk(&fun)?;
self.lambda.emit_span(&Span::combine(&fun.span, &arg.span));
self.lambda.emit(Opcode::Call);
Ok(())
}
}
#[cfg(test)]
mod test {
use super::*;
use crate::compiler::{
lex::lex,
parse::parse,
desugar::desugar,
hoist::hoist,
};
use crate::common::source::Source;
#[test]
fn constants() {
let source = Source::source("heck = true; lol = 0.0; lmao = false; eyy = \"GOod MoRNiNg, SiR\"");
let lambda = gen(hoist(desugar(parse(lex(source).unwrap()).unwrap()).unwrap()).unwrap()).unwrap();
let result = vec![
Data::Boolean(true),
Data::Unit,
Data::Real(0.0),
Data::Boolean(false),
Data::String("GOod MoRNiNg, SiR".to_string()),
];
assert_eq!(lambda.constants, result);
}
#[test]
fn bytecode() {
let source = Source::source("heck = true; lol = heck; lmao = false");
let lambda = gen(hoist(desugar(parse(lex(source).unwrap()).unwrap()).unwrap()).unwrap()).unwrap();
let result = vec![
(Opcode::Con as u8), 128, (Opcode::Save as u8), 128,
(Opcode::Con as u8), 129, (Opcode::Del as u8),
(Opcode::Load as u8), 128, (Opcode::Save as u8), 129,
(Opcode::Con as u8), 129, (Opcode::Del as u8),
(Opcode::Con as u8), 130, (Opcode::Save as u8), 130,
(Opcode::Con as u8), 129,
];
assert_eq!(result, lambda.code);
}
}