use super::command::Command;
use super::command_parser::parse_command;
use super::error::InterfaceError;
use crate::prelude::StandardLibrary;
use crate::{infer_type, normalize, Context, Term};
pub struct Repl {
ctx: Context,
}
impl Repl {
pub fn new() -> Self {
let mut ctx = Context::new();
StandardLibrary::register(&mut ctx);
Self { ctx }
}
pub fn execute(&mut self, input: &str) -> Result<String, InterfaceError> {
let cmd = parse_command(input)?;
match cmd {
Command::Definition { name, ty, body, is_hint } => {
let inferred_ty = infer_type(&self.ctx, &body)?;
let ty = ty.unwrap_or(inferred_ty);
self.ctx.add_definition(name.clone(), ty, body);
if is_hint {
self.ctx.add_hint(&name);
}
Ok(String::new()) }
Command::Check(term) => {
let ty = infer_type(&self.ctx, &term)?;
Ok(format!("{} : {}", term, ty))
}
Command::Eval(term) => {
let _ = infer_type(&self.ctx, &term)?;
let result = normalize(&self.ctx, &term);
Ok(format!("{}", result))
}
Command::Inductive {
name,
params,
sort,
constructors,
} => {
let poly_sort = build_polymorphic_sort(¶ms, sort);
self.ctx.add_inductive(&name, poly_sort);
for (ctor_name, ctor_ty) in constructors {
let poly_ctor_ty = build_polymorphic_constructor(¶ms, ctor_ty);
self.ctx.add_constructor(&ctor_name, &name, poly_ctor_ty);
}
Ok(String::new()) }
}
}
pub fn context(&self) -> &Context {
&self.ctx
}
pub fn context_mut(&mut self) -> &mut Context {
&mut self.ctx
}
}
impl Default for Repl {
fn default() -> Self {
Self::new()
}
}
fn build_polymorphic_sort(params: &[(String, Term)], base_sort: Term) -> Term {
params.iter().rev().fold(base_sort, |body, (name, ty)| {
Term::Pi {
param: name.clone(),
param_type: Box::new(ty.clone()),
body_type: Box::new(body),
}
})
}
fn build_polymorphic_constructor(params: &[(String, Term)], ctor_ty: Term) -> Term {
if params.is_empty() {
return ctor_ty;
}
let param_names: Vec<&str> = params.iter().map(|(n, _)| n.as_str()).collect();
let body = substitute_globals_with_vars(&ctor_ty, ¶m_names);
params.iter().rev().fold(body, |body, (name, ty)| {
Term::Pi {
param: name.clone(),
param_type: Box::new(ty.clone()),
body_type: Box::new(body),
}
})
}
fn substitute_globals_with_vars(term: &Term, param_names: &[&str]) -> Term {
match term {
Term::Global(n) if param_names.contains(&n.as_str()) => Term::Var(n.clone()),
Term::Global(n) => Term::Global(n.clone()),
Term::Var(n) => Term::Var(n.clone()),
Term::Sort(u) => Term::Sort(u.clone()),
Term::Lit(l) => Term::Lit(l.clone()),
Term::App(f, a) => Term::App(
Box::new(substitute_globals_with_vars(f, param_names)),
Box::new(substitute_globals_with_vars(a, param_names)),
),
Term::Lambda { param, param_type, body } => Term::Lambda {
param: param.clone(),
param_type: Box::new(substitute_globals_with_vars(param_type, param_names)),
body: Box::new(substitute_globals_with_vars(body, param_names)),
},
Term::Pi { param, param_type, body_type } => Term::Pi {
param: param.clone(),
param_type: Box::new(substitute_globals_with_vars(param_type, param_names)),
body_type: Box::new(substitute_globals_with_vars(body_type, param_names)),
},
Term::Fix { name, body } => Term::Fix {
name: name.clone(),
body: Box::new(substitute_globals_with_vars(body, param_names)),
},
Term::Match { discriminant, motive, cases } => Term::Match {
discriminant: Box::new(substitute_globals_with_vars(discriminant, param_names)),
motive: Box::new(substitute_globals_with_vars(motive, param_names)),
cases: cases
.iter()
.map(|c| substitute_globals_with_vars(c, param_names))
.collect(),
},
Term::Hole => Term::Hole, }
}