use crate::{
env::{Global, Local, Var},
gc::Trace,
symbols::Symbol,
syntax::Span,
value::Value as RuntimeValue,
};
use std::{
collections::{HashMap, HashSet},
fmt,
};
mod analysis;
pub(crate) mod codegen;
mod compile;
mod reduce;
pub use compile::Compile;
#[derive(Clone, PartialEq)]
pub enum Value {
Var(Var),
Const(RuntimeValue),
}
impl Value {
fn to_local(&self) -> Option<Local> {
if let Self::Var(Var::Local(local)) = self {
Some(*local)
} else {
None
}
}
}
impl From<RuntimeValue> for Value {
fn from(v: RuntimeValue) -> Self {
Self::Const(v)
}
}
impl From<Var> for Value {
fn from(var: Var) -> Self {
Self::Var(var)
}
}
impl From<Local> for Value {
fn from(local: Local) -> Self {
Self::Var(Var::Local(local))
}
}
impl From<Global> for Value {
fn from(global: Global) -> Self {
Self::Var(Var::Global(global))
}
}
impl fmt::Debug for Value {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Var(var) => var.fmt(f),
Self::Const(val) => val.fmt(f),
}
}
}
#[derive(Copy, Clone, Debug, Trace)]
pub enum PrimOp {
Set,
AllocCell,
Cons,
List,
Add,
Sub,
Mul,
Div,
Equal,
Greater,
GreaterEqual,
Lesser,
LesserEqual,
GetFrame,
SetContinuationMark,
Matches,
ExpandTemplate,
ErrorNoPatternsMatch,
}
#[derive(Debug, Clone)]
pub struct LambdaArgs {
args: Vec<Local>,
variadic: bool,
continuation: Option<Local>,
}
impl LambdaArgs {
pub fn new(args: Vec<Local>, variadic: bool, continuation: Option<Local>) -> Self {
Self {
args,
variadic,
continuation,
}
}
fn iter_mut(&mut self) -> impl Iterator<Item = &mut Local> {
self.args.iter_mut().chain(self.continuation.as_mut())
}
fn iter(&self) -> impl Iterator<Item = &Local> {
self.args.iter().chain(self.continuation.as_ref())
}
fn num_required(&self) -> usize {
self.args.len().saturating_sub(self.variadic as usize)
}
}
#[derive(Debug, Clone)]
pub enum Cps {
PrimOp(PrimOp, Vec<Value>, Local, Box<Cps>),
App(Value, Vec<Value>),
If(Value, Box<Cps>, Box<Cps>),
Lambda {
args: LambdaArgs,
body: Box<Cps>,
val: Local,
cexp: Box<Cps>,
span: Option<Span>,
},
Halt(Value),
}
impl Cps {
fn substitute(
&mut self,
substitutions: &HashMap<Local, Value>,
uses_cache: &mut HashMap<Local, HashMap<Local, usize>>,
) {
match self {
Self::PrimOp(_, args, _, cexp) => {
substitute_values(args, substitutions);
cexp.substitute(substitutions, uses_cache);
}
Self::App(value, values) => {
substitute_value(value, substitutions);
substitute_values(values, substitutions);
}
Self::If(cond, success, failure) => {
substitute_value(cond, substitutions);
success.substitute(substitutions, uses_cache);
failure.substitute(substitutions, uses_cache);
}
Self::Lambda {
body, cexp, val, ..
} => {
body.substitute(substitutions, uses_cache);
cexp.substitute(substitutions, uses_cache);
uses_cache.remove(val);
}
Self::Halt(value) => {
substitute_value(value, substitutions);
}
}
}
}
fn substitute_value(value: &mut Value, substitutions: &HashMap<Local, Value>) {
if let Some(local) = value.to_local()
&& let Some(substitution) = substitutions.get(&local)
{
*value = substitution.clone();
}
}
fn substitute_values(values: &mut [Value], substitutions: &HashMap<Local, Value>) {
values
.iter_mut()
.for_each(|value| substitute_value(value, substitutions))
}