#![allow(dead_code)]
#![allow(unused_variables)]
#![allow(unused_parens)]
#![allow(unused_imports)]
#![allow(unused_mut)]
#![allow(non_snake_case)]
#![allow(non_camel_case_types)]
#![allow(non_upper_case_globals)]
extern crate fixedstr;
extern crate rustlr;
use crate::untyped::Term::*;
use crate::typed::*;
use fixedstr::str16;
use rustlr::{unbox, LBox, LexSource, RawToken, StrTokenizer, TerminalToken, Tokenizer};
use std::collections::{HashMap, HashSet};
use std::mem::swap;
const lowerlam: &'static str = "\u{03bb}"; const LAM: &'static str = "lambda ";
const TypedFix:str16 = str16::const_make("FIX");
#[derive(Debug, Clone)]
pub enum Term {
Typeexp(Lstype),
Var(str16),
TypedVar(str16,Lstype),
Const(i64),
Abs(str16, LBox<Term>),
TypedAbs(str16,Lstype,LBox<Term>),
App(LBox<Term>, LBox<Term>),
Def(bool, str16, LBox<Term>), Weak(LBox<Term>), CBV(LBox<Term>), Seq(Vec<LBox<Term>>), Nothing,
}
impl Default for Term {
fn default() -> Self {
Nothing
}
}
impl Term {
pub fn is_fixpt(&self) -> bool {
match self {
Var(x) if x==&TypedFix => true,
_ => false
}
}
pub fn format(&self, lam: &str) -> String {
match self {
Var(x) => format!("{}", x),
Const(n) => format!("{}", n),
App(a, b) => {
let mut a2 = a.format(lam);
if let Abs(_, _) = &**a {
a2 = format!("({})", a2);
}
let mut bs = b.format(lam);
if let App(_, _) = &**b {
bs = format!("({})", bs);
} else if let Abs(_, _) = &**b {
bs = format!("({})", bs);
}
format!("{} {}", a2, bs)
}
Abs(x, a) => {
let a2 = a.format(lam);
let mut an = format!("{}{}", lam, x);
if let Abs(_, _) = &**a {
if lam != lowerlam {
an.push(' ');
}
} else {
an.push('.');
}
an.push_str(&a2);
an
}
x => format!("RAW({:?})", x),
} }
}
fn isfree(v: &str16, t: &Term) -> bool {
match t {
Var(y) => v == y,
App(a, b) => isfree(v, a) || isfree(v, b),
Abs(y, a) if v != y => isfree(v, a),
_ => false, } }
pub struct BetaReducer {
cx: u16, trace: u8,
typed: bool,
lamsym: &'static str,
pub symtab: SymbolTable,
pub defs: HashMap<str16,Term>, }
impl BetaReducer {
pub fn new() -> BetaReducer {
BetaReducer {
cx: 0, trace: 0, typed:false, lamsym:lowerlam,
symtab:SymbolTable::default(),
defs: HashMap::new(),
}
}
pub fn setlambda(&mut self, s:&'static str) {
self.lamsym = s;
}
pub fn set_trace(&mut self, t:u8) {
self.trace = t;
}
pub fn settyped(&mut self, b:bool) {
self.typed = b;
}
pub fn newvar(&mut self, x: &str16) -> str16 {
self.cx += 1;
let xs = format!("{}{}", x, self.cx);
return str16::from(&xs);
}
pub fn alpha(&mut self, amap: &mut HashMap<str16, str16>, t: &mut Term, N: &Term) {
match t {
Var(x) => {
amap.get(x).map(|y| {
if y != x {
let mut y2 = y.clone();
swap(x, &mut y2);
}
}); }
App(a, b) => {
self.alpha(amap, a, N);
self.alpha(amap, b, N);
}
Abs(x, a) => {
let current = amap.get(x);
match current {
None => {
let mut x2 = *x;
while isfree(&x2, N) {
x2 = self.newvar(x)
}
let mut amap2 = amap.clone(); amap2.insert(*x, x2);
if x != &x2 {
if self.trace > 0 {
println!(" < alpha conversion of {} to {} >", x, &x2);
}
swap(x, &mut x2);
}
self.alpha(&mut amap2, a, N);
}
Some(y) => {
let mut y2 = y.clone();
swap(x, &mut y2);
self.alpha(amap, a, N);
}
} } _ => {} } }
fn subst(&mut self, M: &mut Term, x: &str16, N: &Term) {
match M {
Var(y) if y == x => {
let mut N2 = N.clone();
swap(M, &mut N2);
}
App(a, b) => {
self.subst(a, x, N);
self.subst(b, x, N);
}
Abs(y, a) if x != y => {
let mut alphamap = HashMap::new();
self.alpha(&mut alphamap, M, N); if let Abs(y2, a2) = M {
self.subst(a2, x, N);
}
}
_ => {}
} }
pub fn beta1(&mut self, t: &mut Term) -> bool {
match t {
App(A, B) => {
while let Var(id) = &mut **A {
if let Some(iddef) = self.defs.get(id) {
let mut def2 = iddef.clone();
swap(&mut **A, &mut def2);
} else {
break;
}
} if let Abs(x, C) = &mut **A {
self.subst(C, x, B);
let mut C2 = C.clone();
swap(t, &mut C2);
true
}
else {
self.beta1(A) || self.beta1(B)
}
} Abs(x, B) => self.beta1(B),
_ => false,
} }
pub fn reduce_to_norm(&mut self, t: &mut Term) {
if self.trace > 0 {
println!("{}", t.format(self.lamsym));
}
let mut reducible = true;
while reducible {
if self.trace > 0 && expand(t,&self.defs) {
println!("= {}", t.format(self.lamsym));
}
reducible = self.beta1(t);
if reducible && self.trace > 0 {
println!(" => {}", t.format(self.lamsym));
}
}
}
pub fn weak_beta(&mut self, t: &Term) {
if self.trace > 0 {
println!("weak {}", t.format(self.lamsym));
}
let mut t2 = t.clone();
while expand(&mut t2,&self.defs) {
if self.trace > 0 {
println!("= {}", t2.format(self.lamsym));
}
}
while self.weak_beta1(&mut t2) {
if self.trace > 0 {
println!(" => {}", t2.format(self.lamsym));
}
}
} fn weak_beta1(&mut self, t: &mut Term) -> bool {
match t {
App(a, b) => {
if let Abs(x, body) = &**a {
self.weak_beta1(b) || self.beta1(t)
}
else {
self.weak_beta1(a)
}
}
_ => false,
} } }
pub fn getvar(t: &Term) -> str16 {
if let Var(x) = t {
*x
} else {
str16::default()
}
}
fn expand(t: &mut Term, defs: &HashMap<str16, Term>) -> bool {
match t {
Var(x) => {
if let Some(xdef) = defs.get(x) {
let ref mut xdef2 = xdef.clone();
swap(t, xdef2);
true
} else {
false
}
} App(a, b) => expand(a, defs) || expand(b, defs),
Abs(x, a) => {
if let Some(xdef) = defs.get(x) {
false
}
else {expand(a, defs)}
}
_ => false,
} }
pub fn eval_prog(prog: &Vec<LBox<Term>>, reducer:&mut BetaReducer) {
reducer.cx = 0; for line in prog {
reducer.symtab.reset_index();
match &**line {
Def(weak, x, xdef) => {
if reducer.typed {
let stype;
if x==&TypedFix {
stype = Lstype::fixpttype();
}
else {
stype = xdef.type_infer(reducer);
}
if stype.format().contains("UNTYPABLE") {
println!("TYPE INFERENCE FOR <{}> FAILED : {}\nDEFINITION OF {} NOT ACCEPTED",xdef.format(reducer.lamsym), stype.format(),x);
continue;
} else {
let statictype = Lstype::PI(Box::new(stype));
println!("THE INFERRED TYPE OF {} IS: {}",x,statictype.format());
reducer.symtab.add_def(*x,statictype);
}
} let mut xdef2 = unbox!(xdef).clone(); if *weak {
reducer.trace = 0;
reducer.cx = 0;
reducer.reduce_to_norm(&mut xdef2);
}
reducer.defs.insert(*x, xdef2);
}
Weak(t) => {
if reducer.typed {
let statictype;
if t.is_fixpt() {
statictype = Lstype::fixpttype();
}
else {
statictype = t.type_infer(reducer); }
if statictype.format().contains("UNTYPABLE") {
println!("TYPE INFERENCE FOR <{}> FAILED : {}\nEVALUATION CANCELED",t.format(reducer.lamsym), statictype.format());
continue;
} else {
println!("THE INFERRED TYPE OF {} IS {}",t.format(reducer.lamsym),statictype.format());
}
} reducer.trace = 1;
reducer.cx = 0;
reducer.weak_beta(t);
println!();
}
t => {
if reducer.typed {
let statictype;
if t.is_fixpt() {
statictype = Lstype::fixpttype();
}
else {
statictype = t.type_infer(reducer); }
if statictype.format().contains("UNTYPABLE") {
println!("TYPE INFERENCE FOR <{}> FAILED : {}\nEVALUATION CANCELED",t.format(reducer.lamsym), statictype.format());
continue;
} else {
println!("THE INFERRED TYPE OF <{}> IS {} ",t.format(reducer.lamsym),statictype.format());
}
}
reducer.trace = 1;
reducer.cx = 0;
let ref mut t2 = t.clone();
reducer.reduce_to_norm(t2);
println!();
}
} } }