[
  {
    "path": ".gitattributes",
    "content": "*\ttext=auto"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "content": "---\nname: Bug report\nabout: Create a report to help us improve\ntitle: ''\nlabels: bug\nassignees: ''\n\n---\n\n**Describe the bug**\nA clear and concise description of what the bug is.\n\n**To Reproduce**\nSteps to reproduce the behavior:\n1. Go to '...'\n2. Click on '....'\n3. Scroll down to '....'\n4. See error\n\n**Expected behavior**\nA clear and concise description of what you expected to happen.\n\n**Screenshots**\nIf applicable, add screenshots to help explain your problem.\n\n**Additional context**\nAdd any other context about the problem here.\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.md",
    "content": "---\nname: Feature request\nabout: Suggest an idea for this project\ntitle: ''\nlabels: enhancement\nassignees: ''\n\n---\n\n**Is your feature request related to a problem? Please describe.**\nA clear and concise description of what the problem is. Ex. I'm always frustrated when [...]\n\n**Describe the solution you'd like**\nA clear and concise description of what you want to happen.\n\n**Describe alternatives you've considered**\nA clear and concise description of any alternative solutions or features you've considered.\n\n**Additional context**\nAdd any other context or screenshots about the feature request here.\n"
  },
  {
    "path": ".github/workflows/rust.yml",
    "content": "name: Rust\n\non: [push, pull_request]\n\njobs:\n  build:\n\n    runs-on: ubuntu-latest\n\n    steps:\n    - uses: actions/checkout@v1\n    - name: Build\n      run: cargo build --verbose\n    - name: Run tests\n      run: |\n        cargo test --verbose\n        cargo run --bin system_f ./06_system_f/test.sf\n"
  },
  {
    "path": ".gitignore",
    "content": "/target\n**/*.rs.bk\n.vscode/"
  },
  {
    "path": ".rustfmt.toml",
    "content": "wrap_comments = true\nmax_width = 120"
  },
  {
    "path": ".travis.yml",
    "content": "language: rust\nrust:\n  - stable\n  - nightly\nmatrix:\n  allow_failures:\n    - rust: nightly\nscript:\n  - cargo build --verbose --all\n  - cargo test --lib\nnotifications:\n  email: false\n"
  },
  {
    "path": "01_arith/Cargo.toml",
    "content": "[package]\nname = \"arith\"\nversion = \"0.1.0\"\nauthors = [\"Michael Lazear <lazear@scripps.edu>\"]\nedition = \"2018\"\n\n[dependencies]\nutil = { path = \"../util\" }"
  },
  {
    "path": "01_arith/src/lexer.rs",
    "content": "use util::span::{Location, Span, Spanned};\n\nuse std::char;\nuse std::iter::Peekable;\nuse std::str::Chars;\n\n#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]\npub enum Token {\n    Int(u32),\n    Succ,\n    Pred,\n    If,\n    Then,\n    Else,\n    True,\n    False,\n    IsZero,\n\n    Semicolon,\n    LParen,\n    RParen,\n\n    Invalid,\n}\n\n#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]\npub struct TokenSpan {\n    pub kind: Token,\n    pub span: Span,\n}\n\nimpl std::ops::Deref for TokenSpan {\n    type Target = Token;\n    fn deref(&self) -> &Self::Target {\n        &self.kind\n    }\n}\n\n#[derive(Clone)]\npub struct Lexer<'s> {\n    input: Peekable<Chars<'s>>,\n    current: Location,\n}\n\nimpl<'s> Lexer<'s> {\n    pub fn new(input: Chars<'s>) -> Lexer<'s> {\n        Lexer {\n            input: input.peekable(),\n            current: Location {\n                line: 0,\n                col: 0,\n                abs: 0,\n            },\n        }\n    }\n\n    fn peek(&mut self) -> Option<char> {\n        self.input.peek().cloned()\n    }\n\n    /// Consume the next [`char`] and advance internal source position\n    fn consume(&mut self) -> Option<char> {\n        match self.input.next() {\n            Some('\\n') => {\n                self.current.line += 1;\n                self.current.col = 0;\n                self.current.abs += 1;\n                Some('\\n')\n            }\n            Some(ch) => {\n                self.current.col += 1;\n                self.current.abs += 1;\n                Some(ch)\n            }\n            None => None,\n        }\n    }\n\n    fn consume_while<F: Fn(char) -> bool>(&mut self, pred: F) -> Spanned<String> {\n        let mut s = String::new();\n        let start = self.current;\n        while let Some(n) = self.peek() {\n            if pred(n) {\n                match self.consume() {\n                    Some(ch) => s.push(ch),\n                    None => break,\n                }\n            } else {\n                break;\n            }\n        }\n        Spanned::new(Span::new(start, self.current), s)\n    }\n\n    /// Eat whitespace\n    fn consume_delimiter(&mut self) {\n        let _ = self.consume_while(char::is_whitespace);\n    }\n\n    fn number(&mut self) -> Option<TokenSpan> {\n        let Spanned { data, span } = self.consume_while(char::is_numeric);\n        let kind = Token::Int(data.parse::<u32>().expect(\"only numeric chars\"));\n        Some(TokenSpan { kind, span })\n    }\n\n    fn keyword(&mut self) -> Option<TokenSpan> {\n        let Spanned { data, span } = self.consume_while(|ch| ch.is_ascii_alphanumeric());\n        let kind = match data.as_ref() {\n            \"if\" => Token::If,\n            \"then\" => Token::Then,\n            \"else\" => Token::Else,\n            \"true\" => Token::True,\n            \"false\" => Token::False,\n            \"succ\" => Token::Succ,\n            \"pred\" => Token::Pred,\n            \"iszero\" => Token::IsZero,\n            \"zero\" => Token::Int(0),\n            _ => Token::Invalid,\n        };\n        Some(TokenSpan { kind, span })\n    }\n\n    fn eat(&mut self, ch: char, token: Token) -> Option<TokenSpan> {\n        let loc = self.current;\n        let n = self.consume()?;\n        let kind = if n == ch { token } else { Token::Invalid };\n        Some(TokenSpan {\n            span: Span::new(loc, self.current),\n            kind,\n        })\n    }\n\n    fn lex(&mut self) -> Option<TokenSpan> {\n        self.consume_delimiter();\n        match self.peek()? {\n            x if x.is_ascii_alphabetic() => self.keyword(),\n            x if x.is_numeric() => self.number(),\n            '(' => self.eat('(', Token::LParen),\n            ')' => self.eat(')', Token::RParen),\n            ';' => self.eat(';', Token::Semicolon),\n            _ => self.eat(' ', Token::Invalid),\n        }\n    }\n}\n\nimpl<'s> Iterator for Lexer<'s> {\n    type Item = TokenSpan;\n    fn next(&mut self) -> Option<Self::Item> {\n        self.lex()\n    }\n}\n\n#[cfg(test)]\nmod test {\n    use super::*;\n    use Token::*;\n    #[test]\n    fn valid() {\n        let input = \"succ(succ(succ(0)))\";\n        let expected = vec![Succ, LParen, Succ, LParen, Succ, LParen, Int(0), RParen, RParen, RParen];\n        let output = Lexer::new(input.chars())\n            .into_iter()\n            .map(|t| t.kind)\n            .collect::<Vec<Token>>();\n        assert_eq!(expected, output);\n    }\n\n    #[test]\n    fn invalid() {\n        let input = \"succ(succ(succ(xyz)))\";\n        let expected = vec![\n            Succ, LParen, Succ, LParen, Succ, LParen, Invalid, RParen, RParen, RParen,\n        ];\n        let output = Lexer::new(input.chars())\n            .into_iter()\n            .map(|t| t.kind)\n            .collect::<Vec<Token>>();\n        assert_eq!(expected, output);\n    }\n}\n"
  },
  {
    "path": "01_arith/src/main.rs",
    "content": "mod lexer;\nmod parser;\nuse parser::{Parser, Term};\n\n#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]\npub enum RuntimeError {\n    NoRuleApplies,\n}\n\nimpl Term {\n    pub fn is_numeric(&self) -> bool {\n        match self {\n            Term::TmZero => true,\n            Term::TmSucc(t) => t.is_numeric(),\n            _ => false,\n        }\n    }\n\n    pub fn is_normal(&self) -> bool {\n        match self {\n            Term::TmZero | Term::TmTrue | Term::TmFalse => true,\n            _ => false,\n        }\n    }\n}\n\npub fn eval1(t: Term) -> Result<Term, RuntimeError> {\n    use Term::*;\n    let res = match t {\n        TmIf(cond, csq, alt) => match *cond {\n            TmFalse => *alt,\n            TmTrue => *csq,\n            _ => TmIf(Box::new(eval1(*cond)?), csq, alt),\n        },\n        TmSucc(term) => TmSucc(Box::new(eval1(*term)?)),\n        TmPred(term) => match *term {\n            TmZero => TmZero,\n            TmSucc(nv) => {\n                if nv.is_numeric() {\n                    *nv\n                } else {\n                    return Err(RuntimeError::NoRuleApplies);\n                }\n            }\n            _ => TmPred(Box::new(eval1(*term)?)),\n        },\n        TmIsZero(term) => match *term {\n            TmZero => TmTrue,\n            TmSucc(nv) => {\n                if nv.is_numeric() {\n                    TmFalse\n                } else {\n                    return Err(RuntimeError::NoRuleApplies);\n                }\n            }\n            _ => TmIsZero(Box::new(eval1(*term)?)),\n        },\n        _ => return Err(RuntimeError::NoRuleApplies),\n    };\n    Ok(res)\n}\n\npub fn eval(t: Term) -> Term {\n    let mut r = t;\n    while let Ok(tprime) = eval1(r.clone()) {\n        r = tprime;\n        if r.is_normal() {\n            break;\n        }\n    }\n    r\n}\n\nfn main() {\n    println!(\"λ\");\n    let input = \"if iszero(succ(zero)) then false else succ(4)\";\n    let mut p = Parser::new(input);\n    while let Some(tm) = p.parse_term() {\n        print!(\"{:?} ==> \", tm);\n        println!(\"{:?}\", eval(tm));\n    }\n\n    let diag = p.diagnostic();\n    if diag.error_count() > 0 {\n        println!(\"\\n{} error(s) detected while parsing!\", diag.error_count());\n        println!(\"{}\", diag.emit());\n    }\n}\n"
  },
  {
    "path": "01_arith/src/parser.rs",
    "content": "use crate::lexer::{Lexer, Token};\nuse std::iter::Peekable;\nuse util::diagnostic::Diagnostic;\nuse util::span::Span;\n\n#[derive(Clone, Debug, PartialEq, PartialOrd)]\npub enum Term {\n    TmTrue,\n    TmFalse,\n    TmIf(Box<Term>, Box<Term>, Box<Term>),\n    TmZero,\n    TmSucc(Box<Term>),\n    TmPred(Box<Term>),\n    TmIsZero(Box<Term>),\n}\n\npub struct Parser<'s> {\n    diagnostic: Diagnostic<'s>,\n    /// [`Lexer`] impls [`Iterator`] over [`TokenSpan`],\n    /// so we can just directly wrap it in a [`Peekable`]\n    lexer: Peekable<Lexer<'s>>,\n    span: Span,\n}\n\nimpl<'s> Parser<'s> {\n    /// Create a new [`Parser`] for the input `&str`\n    pub fn new(input: &'s str) -> Parser<'s> {\n        Parser {\n            diagnostic: Diagnostic::new(input),\n            lexer: Lexer::new(input.chars()).peekable(),\n            span: Span::default(),\n        }\n    }\n\n    fn consume(&mut self) -> Option<Token> {\n        let ts = self.lexer.next()?;\n        self.span = ts.span;\n        Some(ts.kind)\n    }\n\n    fn expect(&mut self, token: Token) -> Option<Token> {\n        match self.consume()? {\n            t if t == token => Some(t),\n            _ => None,\n        }\n    }\n\n    fn parse_paren(&mut self) -> Option<Term> {\n        let e = self.parse_term();\n        self.expect(Token::RParen);\n        e\n    }\n\n    fn parse_if(&mut self) -> Option<Term> {\n        let cond = self.parse_term()?;\n        let _ = self.expect(Token::Then)?;\n        let csq = self.parse_term()?;\n        let _ = self.expect(Token::Else)?;\n        let alt = self.parse_term()?;\n        Some(Term::TmIf(Box::new(cond), Box::new(csq), Box::new(alt)))\n    }\n\n    pub fn parse_term(&mut self) -> Option<Term> {\n        let kind = match self.consume()? {\n            Token::False => Term::TmFalse,\n            Token::True => Term::TmTrue,\n            Token::Succ => Term::TmSucc(Box::new(self.parse_term()?)),\n            Token::Pred => Term::TmPred(Box::new(self.parse_term()?)),\n            Token::IsZero => Term::TmIsZero(Box::new(self.parse_term()?)),\n            Token::If => return self.parse_if(),\n            Token::LParen => return self.parse_paren(),\n            Token::Semicolon => return self.parse_term(),\n            Token::Int(x) => baptize(x),\n            Token::Then | Token::Else | Token::RParen => {\n                self.diagnostic.push(\"Out of place token\", self.span);\n                return self.parse_term();\n            }\n            Token::Invalid => {\n                self.diagnostic.push(\"Invalid token\", self.span);\n                return self.parse_term();\n            }\n        };\n        Some(kind)\n    }\n\n    pub fn diagnostic(self) -> Diagnostic<'s> {\n        self.diagnostic\n    }\n}\n\n/// Convert from natural number to church encoding\nfn baptize(int: u32) -> Term {\n    let mut num = Term::TmZero;\n    for _ in 0..int {\n        num = Term::TmSucc(Box::new(num));\n    }\n    num\n}\n"
  },
  {
    "path": "02_lambda/Cargo.toml",
    "content": "[package]\nname = \"lambda\"\nversion = \"0.1.0\"\nauthors = [\"Michael Lazear <lazear@scripps.edu>\"]\nedition = \"2018\"\n\n[dependencies]\nutil = { path = \"../util\" }"
  },
  {
    "path": "02_lambda/src/context.rs",
    "content": "use std::collections::VecDeque;\n\n#[derive(Clone, Debug, Default)]\npub struct Context {\n    inner: VecDeque<String>,\n}\n\nimpl Context {\n    pub fn bind(&mut self, hint: String) -> (Context, usize) {\n        if self.inner.contains(&hint) {\n            self.bind(format!(\"{}'\", hint))\n        } else {\n            let mut ctx = self.clone();\n            let idx = ctx.size();\n            ctx.inner.push_front(hint);\n            (ctx, idx)\n        }\n    }\n\n    pub fn lookup(&self, key: String) -> Option<usize> {\n        for (idx, s) in self.inner.iter().enumerate() {\n            if key == *s {\n                return Some(idx);\n            }\n        }\n        None\n    }\n\n    pub fn size(&self) -> usize {\n        self.inner.len()\n    }\n}\n"
  },
  {
    "path": "02_lambda/src/lexer.rs",
    "content": "use util::span::{Location, Span, Spanned};\n\nuse std::char;\nuse std::iter::Peekable;\nuse std::str::Chars;\n\n#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]\npub enum Token {\n    Var(char),\n    LParen,\n    RParen,\n    Lambda,\n    Dot,\n    Invalid,\n}\n\n#[derive(Clone)]\npub struct Lexer<'s> {\n    input: Peekable<Chars<'s>>,\n    current: Location,\n}\n\nimpl<'s> Lexer<'s> {\n    pub fn new(input: Chars<'s>) -> Lexer<'s> {\n        Lexer {\n            input: input.peekable(),\n            current: Location {\n                line: 0,\n                col: 0,\n                abs: 0,\n            },\n        }\n    }\n\n    fn peek(&mut self) -> Option<char> {\n        self.input.peek().copied()\n    }\n\n    /// Consume the next [`char`] and advance internal source position\n    fn consume(&mut self) -> Option<char> {\n        match self.input.next() {\n            Some('\\n') => {\n                self.current.line += 1;\n                self.current.col = 0;\n                self.current.abs += 1;\n                Some('\\n')\n            }\n            Some(ch) => {\n                self.current.col += 1;\n                self.current.abs += 1;\n                Some(ch)\n            }\n            None => None,\n        }\n    }\n\n    fn consume_while<F: Fn(char) -> bool>(&mut self, pred: F) -> Spanned<String> {\n        let mut s = String::new();\n        let start = self.current;\n        while let Some(n) = self.peek() {\n            if pred(n) {\n                match self.consume() {\n                    Some(ch) => s.push(ch),\n                    None => break,\n                }\n            } else {\n                break;\n            }\n        }\n        Spanned::new(Span::new(start, self.current), s)\n    }\n\n    /// Eat whitespace\n    fn consume_delimiter(&mut self) {\n        let _ = self.consume_while(char::is_whitespace);\n    }\n\n    fn eat(&mut self, ch: char, token: Token) -> Option<Spanned<Token>> {\n        let loc = self.current;\n        let n = self.consume()?;\n        let kind = if n == ch { token } else { Token::Invalid };\n        Some(Spanned::new(Span::new(loc, self.current), kind))\n    }\n\n    fn lex(&mut self) -> Option<Spanned<Token>> {\n        self.consume_delimiter();\n        match self.peek()? {\n            '(' => self.eat('(', Token::LParen),\n            ')' => self.eat(')', Token::RParen),\n            'λ' => self.eat('λ', Token::Lambda),\n            '.' => self.eat('.', Token::Dot),\n            ch => self.eat(ch, Token::Var(ch)),\n        }\n    }\n}\n\nimpl<'s> Iterator for Lexer<'s> {\n    type Item = Spanned<Token>;\n    fn next(&mut self) -> Option<Self::Item> {\n        self.lex()\n    }\n}\n"
  },
  {
    "path": "02_lambda/src/main.rs",
    "content": "mod context;\nmod lexer;\nmod parser;\nuse parser::Parser;\n\nuse context::Context;\nuse parser::{RcTerm, Term};\n\nfn shift1(d: isize, c: isize, tm: RcTerm) -> RcTerm {\n    match &tm as &Term {\n        Term::TmVar(sp, x) => {\n            if *x as isize >= c {\n                Term::TmVar(*sp, *x + d as usize).into()\n            } else {\n                Term::TmVar(*sp, *x).into()\n            }\n        }\n        Term::TmAbs(sp, x) => Term::TmAbs(*sp, shift1(d, c + 1, x.clone())).into(),\n        Term::TmApp(sp, a, b) => Term::TmApp(*sp, shift1(d, c, a.clone()), shift1(d, c, b.clone())).into(),\n    }\n}\n\nfn shift(d: isize, tm: RcTerm) -> RcTerm {\n    shift1(d, 0, tm)\n}\n\nfn subst_walk(j: isize, s: RcTerm, c: isize, t: RcTerm) -> RcTerm {\n    match &t as &Term {\n        Term::TmVar(_, x) => {\n            if *x as isize == j + c {\n                shift(c, s)\n            } else {\n                t\n            }\n        }\n        Term::TmAbs(sp, tm) => Term::TmAbs(*sp, subst_walk(j, s, c + 1, tm.clone())).into(),\n        Term::TmApp(sp, lhs, rhs) => Term::TmApp(\n            *sp,\n            subst_walk(j, s.clone(), c, lhs.clone()),\n            subst_walk(j, s, c, rhs.clone()),\n        )\n        .into(),\n    }\n}\n\nfn subst(j: isize, s: RcTerm, tm: RcTerm) -> RcTerm {\n    subst_walk(j, s, 0, tm)\n}\n\nfn term_subst_top(s: RcTerm, tm: RcTerm) -> RcTerm {\n    shift(-1, subst(0, shift(1, s), tm))\n}\n\nfn isval(_ctx: &Context, tm: RcTerm) -> bool {\n    match &tm as &Term {\n        Term::TmAbs(_, _) => true,\n        _ => false,\n    }\n}\n\nfn eval1(ctx: &Context, tm: RcTerm) -> RcTerm {\n    match &tm as &Term {\n        Term::TmApp(_, t, v) if isval(ctx, v.clone()) => {\n            if let Term::TmAbs(_, t2) = &t as &Term {\n                term_subst_top(v.clone(), t2.clone())\n            } else {\n                panic!(\"No rule applies!\")\n            }\n        }\n        Term::TmApp(sp, v, t) if isval(ctx, v.clone()) => {\n            let t_prime = eval1(ctx, t.clone());\n            Term::TmApp(*sp, v.clone(), t_prime).into()\n        }\n        Term::TmApp(sp, t1, t2) => {\n            let t_prime = eval1(ctx, t1.clone());\n            Term::TmApp(*sp, t_prime, t2.clone()).into()\n        }\n        _ => panic!(\"No rule applies!\"),\n    }\n}\n\nfn main() {\n    // let input = \"(λ x. x x) (λ x. x x) λ x. λ y. y λ x. λ x. x\";\n    //\n    let input = \"(λ x. (λ y. y) x) (λ x. x)\";\n    let mut p = Parser::new(input);\n    while let Some(tm) = p.parse_term() {\n        println!(\"{:?}\", tm);\n        dbg!(eval1(p.ctx(), tm));\n        // dbg!(term_subst_top(Term::TmVar(Span::default(), 0).into(), tm));\n    }\n\n    dbg!(p.ctx());\n\n    let diag = p.diagnostic();\n    if diag.error_count() > 0 {\n        println!(\"\\n{} error(s) detected while parsing!\", diag.error_count());\n        println!(\"{}\", diag.emit());\n    }\n}\n"
  },
  {
    "path": "02_lambda/src/parser.rs",
    "content": "use crate::context::Context;\nuse crate::lexer::{Lexer, Token};\nuse std::iter::Peekable;\nuse std::ops::Deref;\nuse std::rc::Rc;\nuse util::diagnostic::Diagnostic;\nuse util::span::*;\n\n#[derive(Clone, PartialEq, PartialOrd)]\npub struct RcTerm(pub Rc<Term>);\n\nimpl From<Term> for RcTerm {\n    fn from(term: Term) -> RcTerm {\n        RcTerm(Rc::new(term))\n    }\n}\n\nimpl std::fmt::Debug for RcTerm {\n    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {\n        write!(f, \"{:?}\", self.0)\n    }\n}\n\nimpl std::fmt::Debug for Term {\n    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {\n        match self {\n            Term::TmVar(_, v) => write!(f, \"{}\", v),\n            Term::TmAbs(_, tm) => write!(f, \"λ.{:?}\", tm),\n            Term::TmApp(_, t, b) => write!(f, \"{:?} {:?}\", t, b),\n        }\n    }\n}\n\nimpl Deref for RcTerm {\n    type Target = Term;\n    fn deref(&self) -> &Self::Target {\n        &self.0\n    }\n}\n\n#[derive(Clone, PartialEq, PartialOrd)]\npub enum Term {\n    TmVar(Span, usize),\n    TmAbs(Span, RcTerm),\n    TmApp(Span, RcTerm, RcTerm),\n}\n\npub struct Parser<'s> {\n    ctx: Context,\n    diagnostic: Diagnostic<'s>,\n    /// [`Lexer`] impls [`Iterator`] over [`TokenSpan`],\n    /// so we can just directly wrap it in a [`Peekable`]\n    lexer: Peekable<Lexer<'s>>,\n    span: Span,\n}\n\nimpl<'s> Parser<'s> {\n    /// Create a new [`Parser`] for the input `&str`\n    pub fn new(input: &'s str) -> Parser<'s> {\n        Parser {\n            ctx: Context::default(),\n            diagnostic: Diagnostic::new(input),\n            lexer: Lexer::new(input.chars()).peekable(),\n            span: Span::default(),\n        }\n    }\n\n    fn consume(&mut self) -> Option<Spanned<Token>> {\n        let ts = self.lexer.next()?;\n        self.span = ts.span;\n        Some(ts)\n    }\n\n    fn expect(&mut self, token: Token) -> Option<Spanned<Token>> {\n        let spanned = self.consume()?;\n        match spanned.data {\n            t if t == token => Some(spanned),\n            t => {\n                self.diagnostic\n                    .push(format!(\"Expected token {:?}, found {:?}\", token, t), spanned.span);\n                None\n            }\n        }\n    }\n\n    fn peek(&mut self) -> Option<Token> {\n        self.lexer.peek().map(|s| s.data)\n    }\n\n    fn lambda(&mut self) -> Option<RcTerm> {\n        let start = self.expect(Token::Lambda)?.span;\n\n        let var = self.consume()?;\n\n        // Bind variable into a new context before parsing the body\n        // of the lambda abstraction\n        let prev_ctx = self.ctx.clone();\n        let (ctx, _) = match var.data {\n            Token::Var(ch) => {\n                let (ctx, idx) = self.ctx.bind(format!(\"{}\", ch));\n                (ctx, Term::TmVar(var.span, idx))\n            }\n            x => {\n                self.diagnostic\n                    .push(format!(\"Expected variable, found {:?}\", x), var.span);\n                return None;\n            }\n        };\n\n        self.ctx = ctx;\n\n        let _ = self.expect(Token::Dot)?;\n        let body = self.term()?;\n        let end = self.span;\n\n        // Return to previous context\n        self.ctx = prev_ctx;\n        Some(Term::TmAbs(start + end, body).into())\n    }\n\n    fn term(&mut self) -> Option<RcTerm> {\n        match self.peek()? {\n            Token::Lambda => self.lambda(),\n            _ => self.application(),\n        }\n    }\n\n    /// Parse an application of form:\n    /// application = atom application' | atom\n    /// application' = atom application' | empty\n    fn application(&mut self) -> Option<RcTerm> {\n        let mut lhs = self.atom()?;\n        let span = self.span;\n        while let Some(rhs) = self.atom() {\n            lhs = Term::TmApp(span + self.span, lhs, rhs).into();\n        }\n        Some(lhs)\n    }\n\n    /// Parse an atomic term\n    /// LPAREN term RPAREN | var\n    fn atom(&mut self) -> Option<RcTerm> {\n        match self.peek()? {\n            Token::LParen => {\n                self.expect(Token::LParen)?;\n                let term = self.term()?;\n                self.expect(Token::RParen)?;\n                Some(term)\n            }\n            Token::Var(ch) => {\n                let sp = self.consume()?.span;\n                match self.ctx.lookup(format!(\"{}\", ch)) {\n                    Some(idx) => Some(Term::TmVar(sp, idx).into()),\n                    None => {\n                        self.diagnostic.push(format!(\"Unbound variable {}\", ch), sp);\n                        None\n                    }\n                }\n            }\n\n            _ => None,\n        }\n    }\n\n    pub fn parse_term(&mut self) -> Option<RcTerm> {\n        self.term()\n    }\n\n    pub fn ctx(&self) -> &Context {\n        &self.ctx\n    }\n\n    pub fn diagnostic(self) -> Diagnostic<'s> {\n        self.diagnostic\n    }\n}\n"
  },
  {
    "path": "03_typedarith/Cargo.toml",
    "content": "[package]\nname = \"typedarith\"\nversion = \"0.1.0\"\nauthors = [\"Michael Lazear <lazear@scripps.edu>\"]\nedition = \"2018\"\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nutil = { path = \"../util\" }"
  },
  {
    "path": "03_typedarith/src/ast.rs",
    "content": "use std::ops::Deref;\nuse std::rc::Rc;\n\n#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]\npub enum Type {\n    Nat,\n    Bool,\n}\n\n#[derive(Clone, Debug, PartialEq, PartialOrd)]\npub enum Term {\n    TmTrue,\n    TmFalse,\n    TmIf(RcTerm, RcTerm, RcTerm),\n    TmZero,\n    TmSucc(RcTerm),\n    TmPred(RcTerm),\n    TmIsZero(RcTerm),\n}\n\n#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]\npub enum TyError {\n    TypingError,\n}\n\npub fn typing(tm: RcTerm) -> Result<Type, TyError> {\n    match &tm as &Term {\n        Term::TmTrue => Ok(Type::Bool),\n        Term::TmFalse => Ok(Type::Bool),\n        Term::TmZero => Ok(Type::Nat),\n        Term::TmSucc(t) => match typing(t.clone()) {\n            Ok(Type::Nat) => Ok(Type::Nat),\n            _ => Err(TyError::TypingError),\n        },\n        Term::TmPred(t) => match typing(t.clone()) {\n            Ok(Type::Nat) => Ok(Type::Nat),\n            _ => Err(TyError::TypingError),\n        },\n        Term::TmIsZero(t) => match typing(t.clone()) {\n            Ok(Type::Nat) => Ok(Type::Bool),\n            _ => Err(TyError::TypingError),\n        },\n        Term::TmIf(a, b, c) => match typing(a.clone()) {\n            Ok(Type::Bool) => {\n                let ty_b = typing(b.clone())?;\n                let ty_c = typing(c.clone())?;\n                if ty_b == ty_c {\n                    Ok(ty_b)\n                } else {\n                    Err(TyError::TypingError)\n                }\n            }\n            _ => Err(TyError::TypingError),\n        },\n    }\n}\n\n#[derive(Clone, PartialEq, PartialOrd)]\npub struct RcTerm(pub Rc<Term>);\n\nimpl std::fmt::Debug for RcTerm {\n    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {\n        write!(f, \"{:?}\", self.0)\n    }\n}\n\nimpl From<Term> for RcTerm {\n    fn from(term: Term) -> RcTerm {\n        RcTerm(Rc::new(term))\n    }\n}\n\nimpl Deref for RcTerm {\n    type Target = Term;\n    fn deref(&self) -> &Self::Target {\n        &self.0\n    }\n}\n"
  },
  {
    "path": "03_typedarith/src/lexer.rs",
    "content": "use util::span::{Location, Span, Spanned};\n\nuse std::char;\nuse std::iter::Peekable;\nuse std::str::Chars;\n\n#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]\npub enum Token {\n    Int(u32),\n    Succ,\n    Pred,\n    If,\n    Then,\n    Else,\n    True,\n    False,\n    IsZero,\n    Semicolon,\n    LParen,\n    RParen,\n    Invalid,\n}\n\n#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]\npub struct TokenSpan {\n    pub kind: Token,\n    pub span: Span,\n}\n\nimpl std::ops::Deref for TokenSpan {\n    type Target = Token;\n    fn deref(&self) -> &Self::Target {\n        &self.kind\n    }\n}\n\n#[derive(Clone)]\npub struct Lexer<'s> {\n    input: Peekable<Chars<'s>>,\n    current: Location,\n}\n\nimpl<'s> Lexer<'s> {\n    pub fn new(input: Chars<'s>) -> Lexer<'s> {\n        Lexer {\n            input: input.peekable(),\n            current: Location {\n                line: 0,\n                col: 0,\n                abs: 0,\n            },\n        }\n    }\n\n    fn peek(&mut self) -> Option<char> {\n        self.input.peek().cloned()\n    }\n\n    /// Consume the next [`char`] and advance internal source position\n    fn consume(&mut self) -> Option<char> {\n        match self.input.next() {\n            Some('\\n') => {\n                self.current.line += 1;\n                self.current.col = 0;\n                self.current.abs += 1;\n                Some('\\n')\n            }\n            Some(ch) => {\n                self.current.col += 1;\n                self.current.abs += 1;\n                Some(ch)\n            }\n            None => None,\n        }\n    }\n\n    fn consume_while<F: Fn(char) -> bool>(&mut self, pred: F) -> Spanned<String> {\n        let mut s = String::new();\n        let start = self.current;\n        while let Some(n) = self.peek() {\n            if pred(n) {\n                match self.consume() {\n                    Some(ch) => s.push(ch),\n                    None => break,\n                }\n            } else {\n                break;\n            }\n        }\n        Spanned::new(Span::new(start, self.current), s)\n    }\n\n    /// Eat whitespace\n    fn consume_delimiter(&mut self) {\n        let _ = self.consume_while(char::is_whitespace);\n    }\n\n    fn number(&mut self) -> Option<TokenSpan> {\n        let Spanned { data, span } = self.consume_while(char::is_numeric);\n        let kind = Token::Int(data.parse::<u32>().expect(\"only numeric chars\"));\n        Some(TokenSpan { kind, span })\n    }\n\n    fn keyword(&mut self) -> Option<TokenSpan> {\n        let Spanned { data, span } = self.consume_while(|ch| ch.is_ascii_alphanumeric());\n        let kind = match data.as_ref() {\n            \"if\" => Token::If,\n            \"then\" => Token::Then,\n            \"else\" => Token::Else,\n            \"true\" => Token::True,\n            \"false\" => Token::False,\n            \"succ\" => Token::Succ,\n            \"pred\" => Token::Pred,\n            \"iszero\" => Token::IsZero,\n            \"zero\" => Token::Int(0),\n            _ => Token::Invalid,\n        };\n        Some(TokenSpan { kind, span })\n    }\n\n    fn eat(&mut self, ch: char, token: Token) -> Option<TokenSpan> {\n        let loc = self.current;\n        let n = self.consume()?;\n        let kind = if n == ch { token } else { Token::Invalid };\n        Some(TokenSpan {\n            span: Span::new(loc, self.current),\n            kind,\n        })\n    }\n\n    fn lex(&mut self) -> Option<TokenSpan> {\n        self.consume_delimiter();\n        match self.peek()? {\n            x if x.is_ascii_alphabetic() => self.keyword(),\n            x if x.is_numeric() => self.number(),\n            '(' => self.eat('(', Token::LParen),\n            ')' => self.eat(')', Token::RParen),\n            ';' => self.eat(';', Token::Semicolon),\n            _ => self.eat(' ', Token::Invalid),\n        }\n    }\n}\n\nimpl<'s> Iterator for Lexer<'s> {\n    type Item = TokenSpan;\n    fn next(&mut self) -> Option<Self::Item> {\n        self.lex()\n    }\n}\n\n#[cfg(test)]\nmod test {\n    use super::*;\n    use Token::*;\n    #[test]\n    fn valid() {\n        let input = \"succ(succ(succ(0)))\";\n        let expected = vec![Succ, LParen, Succ, LParen, Succ, LParen, Int(0), RParen, RParen, RParen];\n        let output = Lexer::new(input.chars())\n            .into_iter()\n            .map(|t| t.kind)\n            .collect::<Vec<Token>>();\n        assert_eq!(expected, output);\n    }\n\n    #[test]\n    fn invalid() {\n        let input = \"succ(succ(succ(xyz)))\";\n        let expected = vec![\n            Succ, LParen, Succ, LParen, Succ, LParen, Invalid, RParen, RParen, RParen,\n        ];\n        let output = Lexer::new(input.chars())\n            .into_iter()\n            .map(|t| t.kind)\n            .collect::<Vec<Token>>();\n        assert_eq!(expected, output);\n    }\n}\n"
  },
  {
    "path": "03_typedarith/src/main.rs",
    "content": "mod ast;\nmod lexer;\nmod parser;\nuse ast::*;\nuse parser::Parser;\n\nfn main() {\n    let input = \"if iszero(succ(zero)) then pred(0) else succ(4)\";\n    let mut p = Parser::new(input);\n    while let Some(tm) = p.parse_term() {\n        print!(\"{:?} ==> \", tm);\n        println!(\"{:?}\", typing(tm));\n    }\n\n    let diag = p.diagnostic();\n    if diag.error_count() > 0 {\n        println!(\"\\n{} error(s) detected while parsing!\", diag.error_count());\n        println!(\"{}\", diag.emit());\n    }\n}\n"
  },
  {
    "path": "03_typedarith/src/parser.rs",
    "content": "use crate::ast::{RcTerm, Term};\nuse crate::lexer::{Lexer, Token};\nuse std::iter::Peekable;\nuse util::diagnostic::Diagnostic;\nuse util::span::Span;\n\npub struct Parser<'s> {\n    diagnostic: Diagnostic<'s>,\n    /// [`Lexer`] impls [`Iterator`] over [`TokenSpan`],\n    /// so we can just directly wrap it in a [`Peekable`]\n    lexer: Peekable<Lexer<'s>>,\n    span: Span,\n}\n\nimpl<'s> Parser<'s> {\n    /// Create a new [`Parser`] for the input `&str`\n    pub fn new(input: &'s str) -> Parser<'s> {\n        Parser {\n            diagnostic: Diagnostic::new(input),\n            lexer: Lexer::new(input.chars()).peekable(),\n            span: Span::default(),\n        }\n    }\n\n    fn consume(&mut self) -> Option<Token> {\n        let ts = self.lexer.next()?;\n        self.span = ts.span;\n        Some(ts.kind)\n    }\n\n    fn expect(&mut self, token: Token) -> Option<Token> {\n        match self.consume()? {\n            t if t == token => Some(t),\n            _ => None,\n        }\n    }\n\n    fn parse_paren(&mut self) -> Option<RcTerm> {\n        let e = self.parse_term();\n        self.expect(Token::RParen);\n        e\n    }\n\n    fn parse_if(&mut self) -> Option<RcTerm> {\n        let cond = self.parse_term()?;\n        let _ = self.expect(Token::Then)?;\n        let csq = self.parse_term()?;\n        let _ = self.expect(Token::Else)?;\n        let alt = self.parse_term()?;\n        Some(Term::TmIf(cond, csq, alt).into())\n    }\n\n    pub fn parse_term(&mut self) -> Option<RcTerm> {\n        let kind = match self.consume()? {\n            Token::False => Term::TmFalse,\n            Token::True => Term::TmTrue,\n            Token::Succ => Term::TmSucc(self.parse_term()?),\n            Token::Pred => Term::TmPred(self.parse_term()?),\n            Token::IsZero => Term::TmIsZero(self.parse_term()?),\n            Token::If => return self.parse_if(),\n            Token::LParen => return self.parse_paren(),\n            Token::Semicolon => return self.parse_term(),\n            Token::Int(x) => baptize(x),\n            Token::Then | Token::Else | Token::RParen => {\n                self.diagnostic.push(\"Out of place token\", self.span);\n                return self.parse_term();\n            }\n            Token::Invalid => {\n                self.diagnostic.push(\"Invalid token\", self.span);\n                return self.parse_term();\n            }\n        };\n        Some(kind.into())\n    }\n\n    pub fn diagnostic(self) -> Diagnostic<'s> {\n        self.diagnostic\n    }\n}\n\n/// Convert from natural number to church encoding\nfn baptize(int: u32) -> Term {\n    let mut num = Term::TmZero;\n    for _ in 0..int {\n        num = Term::TmSucc(num.into());\n    }\n    num\n}\n"
  },
  {
    "path": "04_stlc/.gitignore",
    "content": "/target\n**/*.rs.bk\n.vscode/"
  },
  {
    "path": "04_stlc/Cargo.toml",
    "content": "[package]\nname = \"stlc\"\nversion = \"0.1.0\"\nauthors = [\"Michael Lazear <lazear@scripps.edu>\"]\nedition = \"2018\"\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nutil = { path = \"../util\" }"
  },
  {
    "path": "04_stlc/src/eval.rs",
    "content": "use super::term::*;\nuse super::typing::Context;\nuse super::visitor::{Direction, MutVisitor, Shifting, Substitution};\n\n#[derive(Debug)]\npub enum Error {\n    NoRuleApplies,\n}\n\n#[inline]\nfn subst(mut val: Term, body: &mut Term) {\n    Shifting::new(Direction::Up).visit_term(&mut val);\n    Substitution::new(val).visit_term(body);\n    Shifting::new(Direction::Down).visit_term(body);\n}\n\nfn value(ctx: &Context, term: &Term) -> bool {\n    match term {\n        Term::Unit | Term::True | Term::False | Term::Abs(_, _) | Term::Zero => true,\n        Term::Succ(t) | Term::Pred(t) | Term::IsZero(t) => value(ctx, t),\n        Term::Record(fields) => {\n            for field in fields {\n                if !value(ctx, &field.term) {\n                    return false;\n                }\n            }\n            true\n        }\n        _ => false,\n    }\n}\n\nfn eval1(ctx: &Context, term: Term) -> Result<Box<Term>, Error> {\n    match term {\n        Term::App(t1, t2) => {\n            if value(ctx, &t2) {\n                match *t1 {\n                    Term::Abs(_, mut abs) => {\n                        subst(*t2, abs.as_mut());\n                        Ok(abs)\n                    }\n                    _ => {\n                        let t_prime = eval1(ctx, *t1)?;\n                        Ok(Term::App(t_prime, t2).into())\n                    }\n                }\n            } else if value(ctx, &t1) {\n                let t_prime = eval1(ctx, *t2)?;\n                Ok(Term::App(t1.clone(), t_prime).into())\n            } else {\n                let t_prime = eval1(ctx, *t1)?;\n                Ok(Term::App(t_prime, t2.clone()).into())\n            }\n        }\n        Term::If(guard, csq, alt) => match &*guard {\n            Term::True => Ok(csq),\n            Term::False => Ok(alt),\n            _ => {\n                let t_prime = eval1(ctx, *guard)?;\n                Ok(Term::If(t_prime, csq, alt).into())\n            }\n        },\n        Term::Let(bind, mut body) => {\n            if value(ctx, &bind) {\n                subst(*bind, body.as_mut());\n                Ok(body)\n            } else {\n                let t = eval1(ctx, *bind)?;\n                Ok(Term::Let(t, body).into())\n            }\n        }\n        Term::Succ(t) => {\n            let t_prime = eval1(ctx, *t)?;\n            Ok(Term::Succ(t_prime).into())\n        }\n\n        Term::Pred(t) => match t.as_ref() {\n            Term::Zero => Ok(t.clone()),\n            Term::Succ(n) => Ok(n.clone()),\n            _ => Ok(Term::Pred(eval1(ctx, *t)?).into()),\n        },\n\n        Term::IsZero(t) => match t.as_ref() {\n            Term::Zero => Ok(Term::True.into()),\n            Term::Succ(_) => Ok(Term::False.into()),\n            _ => Ok(Term::IsZero(eval1(ctx, *t)?).into()),\n        },\n\n        Term::Projection(rec, proj) => {\n            if value(ctx, &rec) {\n                match rec.as_ref() {\n                    Term::Record(rec) => crate::term::record_access(rec, &proj).ok_or(Error::NoRuleApplies),\n                    _ => Ok(Term::Projection(eval1(ctx, *rec)?, proj).into()),\n                }\n            } else {\n                Ok(Term::Projection(eval1(ctx, *rec)?, proj).into())\n            }\n        }\n\n        _ => Err(Error::NoRuleApplies),\n    }\n}\n\npub fn eval(ctx: &Context, term: Term) -> Result<Term, Error> {\n    let mut tp = term;\n    loop {\n        println!(\"  -> {}\", &tp);\n        match eval1(ctx, tp.clone()) {\n            Ok(r) => tp = *r,\n            Err(e) => {\n                return Ok(tp);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "04_stlc/src/lexer.rs",
    "content": "use util::span::{Location, Span};\n\nuse std::char;\nuse std::iter::Peekable;\nuse std::str::Chars;\n\n#[derive(Clone, Debug, PartialEq, PartialOrd)]\npub enum TokenKind {\n    Ident(String),\n    Nat(u32),\n    TyNat,\n    TyBool,\n    TyArrow,\n    TyUnit,\n    TypeDecl,\n    Unit,\n    True,\n    False,\n    Lambda,\n    Succ,\n    Pred,\n    If,\n    Then,\n    Else,\n    Let,\n    In,\n    IsZero,\n    Semicolon,\n    Colon,\n    Comma,\n    Proj,\n    LParen,\n    RParen,\n    LBrace,\n    RBrace,\n    Equals,\n    Bar,\n    Invalid(char),\n    Eof,\n}\n\n#[derive(Clone, Debug, PartialEq, PartialOrd)]\npub struct Token {\n    pub kind: TokenKind,\n    pub span: Span,\n}\n\nimpl Token {\n    pub const fn new(kind: TokenKind, span: Span) -> Token {\n        Token { kind, span }\n    }\n}\n\n#[derive(Clone)]\npub struct Lexer<'s> {\n    input: Peekable<Chars<'s>>,\n    current: Location,\n}\n\nimpl<'s> Lexer<'s> {\n    pub fn new(input: Chars<'s>) -> Lexer<'s> {\n        Lexer {\n            input: input.peekable(),\n            current: Location {\n                line: 0,\n                col: 0,\n                abs: 0,\n            },\n        }\n    }\n\n    /// Peek at the next [`char`] in the input stream\n    fn peek(&mut self) -> Option<char> {\n        self.input.peek().cloned()\n    }\n\n    /// Consume the next [`char`] and advance internal source position\n    fn consume(&mut self) -> Option<char> {\n        match self.input.next() {\n            Some('\\n') => {\n                self.current.line += 1;\n                self.current.col = 0;\n                self.current.abs += 1;\n                Some('\\n')\n            }\n            Some(ch) => {\n                self.current.col += 1;\n                self.current.abs += 1;\n                Some(ch)\n            }\n            None => None,\n        }\n    }\n\n    /// Consume characters from the input stream while pred(peek()) is true,\n    /// collecting the characters into a string.\n    fn consume_while<F: Fn(char) -> bool>(&mut self, pred: F) -> (String, Span) {\n        let mut s = String::new();\n        let start = self.current;\n        while let Some(n) = self.peek() {\n            if pred(n) {\n                match self.consume() {\n                    Some(ch) => s.push(ch),\n                    None => break,\n                }\n            } else {\n                break;\n            }\n        }\n        (s, Span::new(start, self.current))\n    }\n\n    /// Eat whitespace\n    fn consume_delimiter(&mut self) {\n        let _ = self.consume_while(char::is_whitespace);\n    }\n\n    /// Lex a natural number\n    fn number(&mut self) -> Token {\n        // Since we peeked at least one numeric char, we should always\n        // have a string containing at least 1 single digit, as such\n        // it is safe to call unwrap() on str::parse<u32>\n        let (data, span) = self.consume_while(char::is_numeric);\n        let n = data.parse::<u32>().unwrap();\n        Token::new(TokenKind::Nat(n), span)\n    }\n\n    /// Lex a reserved keyword or an identifier\n    fn keyword(&mut self) -> Token {\n        let (data, span) = self.consume_while(|ch| ch.is_ascii_alphanumeric());\n        let kind = match data.as_ref() {\n            \"if\" => TokenKind::If,\n            \"then\" => TokenKind::Then,\n            \"else\" => TokenKind::Else,\n            \"true\" => TokenKind::True,\n            \"false\" => TokenKind::False,\n            \"succ\" => TokenKind::Succ,\n            \"pred\" => TokenKind::Pred,\n            \"iszero\" => TokenKind::IsZero,\n            \"zero\" => TokenKind::Nat(0),\n            \"Bool\" => TokenKind::TyBool,\n            \"Nat\" => TokenKind::TyNat,\n            \"Unit\" => TokenKind::TyUnit,\n            \"unit\" => TokenKind::Unit,\n            \"let\" => TokenKind::Let,\n            \"in\" => TokenKind::In,\n            \"type\" => TokenKind::TypeDecl,\n            _ => TokenKind::Ident(data),\n        };\n        Token::new(kind, span)\n    }\n\n    /// Consume the next input character, expecting to match `ch`.\n    /// Return a [`TokenKind::Invalid`] if the next character does not match,\n    /// or the argument `kind` if it does\n    fn eat(&mut self, ch: char, kind: TokenKind) -> Token {\n        let loc = self.current;\n        // Lexer::eat() should only be called internally after calling peek()\n        // so we know that it's safe to unwrap the result of Lexer::consume()\n        let n = self.consume().unwrap();\n        let kind = if n == ch { kind } else { TokenKind::Invalid(n) };\n        Token::new(kind, Span::new(loc, self.current))\n    }\n\n    /// Return the next lexeme in the input as a [`Token`]\n    pub fn lex(&mut self) -> Token {\n        self.consume_delimiter();\n        let next = match self.peek() {\n            Some(ch) => ch,\n            None => return Token::new(TokenKind::Eof, Span::dummy()),\n        };\n        match next {\n            x if x.is_ascii_alphabetic() => self.keyword(),\n            x if x.is_numeric() => self.number(),\n            '(' => self.eat('(', TokenKind::LParen),\n            ')' => self.eat(')', TokenKind::RParen),\n            ';' => self.eat(';', TokenKind::Semicolon),\n            ':' => self.eat(':', TokenKind::Colon),\n            ',' => self.eat(',', TokenKind::Comma),\n            '{' => self.eat('{', TokenKind::LBrace),\n            '}' => self.eat('}', TokenKind::RBrace),\n            '\\\\' => self.eat('\\\\', TokenKind::Lambda),\n            'λ' => self.eat('λ', TokenKind::Lambda),\n            '.' => self.eat('.', TokenKind::Proj),\n            '=' => self.eat('=', TokenKind::Equals),\n            '|' => self.eat('|', TokenKind::Bar),\n            '-' => {\n                self.consume();\n                self.eat('>', TokenKind::TyArrow)\n            }\n            ch => self.eat(' ', TokenKind::Invalid(ch)),\n        }\n    }\n}\n\nimpl<'s> Iterator for Lexer<'s> {\n    type Item = Token;\n    fn next(&mut self) -> Option<Self::Item> {\n        match self.lex() {\n            Token {\n                kind: TokenKind::Eof, ..\n            } => None,\n            tok => Some(tok),\n        }\n    }\n}\n\n#[cfg(test)]\nmod test {\n    use super::*;\n    use TokenKind::*;\n    #[test]\n    fn valid() {\n        let input = \"succ(succ(succ(0)))\";\n        let expected = vec![Succ, LParen, Succ, LParen, Succ, LParen, Nat(0), RParen, RParen, RParen];\n        let output = Lexer::new(input.chars())\n            .into_iter()\n            .map(|t| t.kind)\n            .collect::<Vec<TokenKind>>();\n        assert_eq!(expected, output);\n    }\n\n    #[test]\n    fn invalid() {\n        let input = \"succ(succ(succ(xyz)))\";\n        let expected = vec![\n            Succ,\n            LParen,\n            Succ,\n            LParen,\n            Succ,\n            LParen,\n            Ident(\"xyz\".into()),\n            RParen,\n            RParen,\n            RParen,\n        ];\n        let output = Lexer::new(input.chars())\n            .into_iter()\n            .map(|t| t.kind)\n            .collect::<Vec<TokenKind>>();\n        assert_eq!(expected, output);\n    }\n}\n"
  },
  {
    "path": "04_stlc/src/main.rs",
    "content": "#![allow(unused_variables)]\nmod eval;\nmod lexer;\nmod parser;\nmod term;\nmod typing;\nmod visitor;\n\nuse term::Term;\nuse typing::{Context, Type};\n\nfn ev(ctx: &mut Context, term: Term) -> Result<Term, eval::Error> {\n    let ty = match ctx.type_of(&term) {\n        Ok(ty) => ty,\n        Err(err) => {\n            println!(\"Mistyped term {} => {:?}\", term, err);\n            return Err(eval::Error::NoRuleApplies);\n        }\n    };\n    let r = eval::eval(&ctx, term)?;\n\n    // This is safe by our typing inference/induction rules\n    // any well typed term t (checked previously) that evaluates to\n    // a term t' [ t -> t' ] is also well typed\n    //\n    // Furthermore,  Γ t:T, t ->* t' => t':T\n    let ty_ = ctx.type_of(&r);\n    // assert_eq!(ty_, ty);\n    println!(\"===> {} -- {:?}\\n\", r, ty_);\n\n    Ok(r)\n}\n\nfn parse(ctx: &mut Context, input: &str) {\n    let mut p = parser::Parser::new(input);\n    while let Some(tok) = p.parse_term() {\n        let _ = ev(ctx, *tok);\n    }\n\n    let diag = p.diagnostic();\n    if diag.error_count() > 0 {\n        println!(\"\\n{} error(s) detected while parsing!\", diag.error_count());\n        println!(\"{}\", diag.emit());\n    }\n}\n\nfn main() {\n    let mut root: Context = Context::default();\n    // parse(\n    //     &mut root,\n    //     \"let not = (\\\\x: Bool. if x then false else true) in\n    //      let x = not false in\n    //      let y = not x in\n    //      if y then succ 0 else succ succ 0\",\n    // );\n\n    parse(&mut root, \"let x = (\\\\y: Nat. y) in x\");\n\n    parse(&mut root, \"(\\\\x: Nat. (\\\\y: Nat. iszero x)) (succ 0) 0\");\n\n    parse(\n        &mut root,\n        \"(\\\\x: {a: Bool, b: Bool, c: Nat}. x.b) {a: true, b: false, c: 0}\",\n    );\n\n    // parse(&mut root, \"let not = \\\\x: Bool. if x then false else true in {a:\n    // 0, b: \\\\x: Bool. not x, c: unit}.b \"); parse(&mut root, \"type Struct\n    // = {valid: Bool, number: Nat}\"); parse(&mut root, \"(\\\\x: Struct.\n    // x.number) {valid: true, number: succ 0}\"); parse(\n    //     &mut root,\n    //     \"(\\\\x: Struct. x.number) {valid: false, number: succ 0}\",\n    // )\n    // dbg!(root);\n}\n"
  },
  {
    "path": "04_stlc/src/parser.rs",
    "content": "use crate::lexer::{Lexer, Token, TokenKind};\nuse crate::term::{Field, Term};\nuse crate::typing::{Record, RecordField, Type};\nuse std::collections::VecDeque;\nuse std::iter::Peekable;\nuse util::diagnostic::Diagnostic;\nuse util::span::*;\n\n#[derive(Clone, Debug, Default)]\npub struct DeBruijnIndexer {\n    inner: VecDeque<String>,\n}\n\nimpl DeBruijnIndexer {\n    pub fn push(&mut self, hint: String) -> usize {\n        if self.inner.contains(&hint) {\n            self.push(format!(\"{}'\", hint))\n        } else {\n            let idx = self.inner.len();\n            self.inner.push_front(hint);\n            idx\n        }\n    }\n\n    pub fn pop(&mut self) {\n        self.inner.pop_front();\n    }\n\n    pub fn lookup(&self, key: &str) -> Option<usize> {\n        for (idx, s) in self.inner.iter().enumerate() {\n            if key == s {\n                return Some(idx);\n            }\n        }\n        None\n    }\n}\n\npub struct Parser<'s> {\n    ctx: DeBruijnIndexer,\n    diagnostic: Diagnostic<'s>,\n    /// [`Lexer`] impls [`Iterator`] over [`TokenSpan`],\n    /// so we can just directly wrap it in a [`Peekable`]\n    lexer: Peekable<Lexer<'s>>,\n    span: Span,\n}\n\nimpl<'s> Parser<'s> {\n    /// Create a new [`Parser`] for the input `&str`\n    pub fn new(input: &'s str) -> Parser<'s> {\n        Parser {\n            ctx: DeBruijnIndexer::default(),\n            diagnostic: Diagnostic::new(input),\n            lexer: Lexer::new(input.chars()).peekable(),\n            span: Span::dummy(),\n        }\n    }\n\n    fn consume(&mut self) -> Option<Token> {\n        let ts = self.lexer.next()?;\n        self.span = ts.span;\n        Some(ts)\n    }\n\n    fn expect(&mut self, kind: TokenKind) -> Option<Token> {\n        let tk = self.consume()?;\n        match &tk.kind {\n            t if t == &kind => Some(tk),\n            _ => {\n                self.diagnostic\n                    .push(format!(\"Expected token {:?}, found {:?}\", kind, tk.kind), tk.span);\n                None\n            }\n        }\n    }\n\n    fn expect_term(&mut self) -> Option<Box<Term>> {\n        match self.term() {\n            Some(term) => Some(term),\n            None => {\n                let sp = self.peek_span();\n                self.diagnostic.push(\"Expected term\".to_string(), sp);\n                None\n            }\n        }\n    }\n\n    fn peek(&mut self) -> Option<TokenKind> {\n        self.lexer.peek().map(|tk| tk.kind.clone())\n    }\n\n    fn peek_span(&mut self) -> Span {\n        self.lexer.peek().map(|s| s.span).unwrap_or(self.span)\n    }\n\n    fn lambda(&mut self) -> Option<Box<Term>> {\n        let start = self.expect(TokenKind::Lambda)?;\n\n        // Bind variable into a new context before parsing the body\n        let var = self.ident()?;\n        self.ctx.push(var);\n\n        let _ = self.expect(TokenKind::Colon)?;\n        let ty = self.ty()?;\n        let _ = self.expect(TokenKind::Proj)?;\n        let body = self.term()?;\n\n        // Return to previous context\n        self.ctx.pop();\n        Some(Term::Abs(ty, body).into())\n    }\n\n    fn let_expr(&mut self) -> Option<Box<Term>> {\n        let start = self.expect(TokenKind::Let)?;\n        let var = self.ident()?;\n        self.ctx.push(var);\n        let _ = self.expect(TokenKind::Equals)?;\n        let bind = self.expect_term()?;\n        let _ = self.expect(TokenKind::In)?;\n        let body = self.expect_term()?;\n        self.ctx.pop();\n        Some(Term::Let(bind, body).into())\n    }\n\n    fn ty_record_field(&mut self) -> Option<RecordField> {\n        let ident = self.ident()?;\n        self.expect(TokenKind::Colon)?;\n        let ty = self.ty()?;\n        Some(RecordField {\n            ident,\n            ty: Box::new(ty),\n        })\n    }\n\n    fn ty_atom(&mut self) -> Option<Type> {\n        match &self.peek()? {\n            TokenKind::TyBool => {\n                self.consume()?;\n                Some(Type::Bool)\n            }\n            TokenKind::TyNat => {\n                self.consume()?;\n                Some(Type::Nat)\n            }\n            TokenKind::TyUnit => {\n                self.consume()?;\n                Some(Type::Unit)\n            }\n            TokenKind::LBrace => {\n                self.consume()?;\n                let mut fields = vec![self.ty_record_field()?];\n                while let Some(TokenKind::Comma) = self.peek() {\n                    self.expect(TokenKind::Comma)?;\n                    fields.push(self.ty_record_field()?);\n                }\n                self.expect(TokenKind::RBrace)?;\n                Some(Type::Record(Record {\n                    // span,\n                    ident: String::new(),\n                    fields,\n                }))\n            }\n            TokenKind::LParen => {\n                self.consume()?;\n                let r = self.ty()?;\n                self.expect(TokenKind::RParen)?;\n                Some(r)\n            }\n            _ => None,\n        }\n    }\n\n    fn ty(&mut self) -> Option<Type> {\n        let span = self.span;\n        let mut lhs = match self.ty_atom() {\n            Some(ty) => ty,\n            None => {\n                let sp = self.peek_span();\n                self.diagnostic.push(\"Expected type\".to_string(), sp);\n                return None;\n            }\n        };\n\n        if let Some(TokenKind::TyArrow) = self.peek() {\n            self.consume()?;\n        }\n        while let Some(rhs) = self.ty_atom() {\n            lhs = Type::Arrow(Box::new(lhs), Box::new(rhs));\n            if let Some(TokenKind::TyArrow) = self.peek() {\n                self.consume()?;\n            } else {\n                break;\n            }\n        }\n        Some(lhs)\n    }\n\n    /// Parse an application of form:\n    /// application = atom application' | atom\n    /// application' = atom application' | empty\n    fn application(&mut self) -> Option<Box<Term>> {\n        let mut lhs = self.atom()?;\n        let span = self.span;\n        while let Some(rhs) = self.atom() {\n            lhs = Term::App(lhs, rhs).into();\n        }\n\n        if let Some(TokenKind::Proj) = self.peek() {\n            self.expect(TokenKind::Proj)?;\n            let accessor = self.ident()?;\n            lhs = Term::Projection(lhs, accessor.into()).into();\n        }\n        Some(lhs)\n    }\n\n    fn ident(&mut self) -> Option<String> {\n        let Token { kind, span } = self.consume()?;\n        match kind {\n            TokenKind::Ident(s) => Some(s),\n            _ => {\n                self.diagnostic\n                    .push(format!(\"Expected identifier, found {:?}\", kind), span);\n                None\n            }\n        }\n    }\n\n    fn record_field(&mut self) -> Option<Field> {\n        let span = self.span;\n        let ident = self.ident()?;\n        self.expect(TokenKind::Colon)?;\n        let term = self.expect_term()?;\n\n        Some(Field {\n            span: span + self.span,\n            ident,\n            term,\n        })\n    }\n\n    fn record(&mut self) -> Option<Box<Term>> {\n        let mut fields = vec![self.record_field()?];\n        let span = self.span;\n        while let Some(TokenKind::Comma) = self.peek() {\n            self.expect(TokenKind::Comma)?;\n            fields.push(self.record_field()?);\n        }\n        Some(Term::Record(fields).into())\n    }\n\n    fn if_expr(&mut self) -> Option<Box<Term>> {\n        let _ = self.expect(TokenKind::If)?;\n        let guard = self.expect_term()?;\n        let _ = self.expect(TokenKind::Then)?;\n        let csq = self.expect_term()?;\n        let _ = self.expect(TokenKind::Else)?;\n        let alt = self.expect_term()?;\n        Some(Term::If(guard, csq, alt).into())\n    }\n\n    /// Parse an atomic term\n    /// LPAREN term RPAREN | var\n    fn atom(&mut self) -> Option<Box<Term>> {\n        match self.peek()? {\n            TokenKind::True => {\n                self.expect(TokenKind::True)?;\n                Some(Term::True.into())\n            }\n            TokenKind::False => {\n                self.expect(TokenKind::False)?;\n                Some(Term::False.into())\n            }\n            TokenKind::If => self.if_expr(),\n            TokenKind::Let => self.let_expr(),\n            TokenKind::Nat(i) => {\n                self.consume()?;\n                Some(Term::Zero.into())\n            }\n            TokenKind::Succ => {\n                self.expect(TokenKind::Succ)?;\n                Some(Term::Succ(self.term()?).into())\n            }\n            TokenKind::Pred => {\n                self.expect(TokenKind::Pred)?;\n                Some(Term::Pred(self.term()?).into())\n            }\n            TokenKind::IsZero => {\n                self.expect(TokenKind::IsZero)?;\n                Some(Term::IsZero(self.term()?).into())\n            }\n            TokenKind::LParen => {\n                self.expect(TokenKind::LParen)?;\n                let term = self.term()?;\n                self.expect(TokenKind::RParen)?;\n                Some(term)\n            }\n            TokenKind::LBrace => {\n                self.expect(TokenKind::LBrace)?;\n                let term = self.record()?;\n                self.expect(TokenKind::RBrace)?;\n                Some(term)\n            }\n            TokenKind::Unit => {\n                self.expect(TokenKind::Unit)?;\n                Some(Term::Unit.into())\n            }\n            TokenKind::Lambda => self.lambda(),\n            TokenKind::Ident(s) => {\n                let sp = self.consume()?.span;\n                match self.ctx.lookup(&s) {\n                    Some(idx) => Some(Term::Var(idx).into()),\n                    None => {\n                        self.diagnostic.push(format!(\"Unbound variable {}\", s), sp);\n                        None\n                    }\n                }\n            }\n            _ => None,\n        }\n    }\n\n    fn term(&mut self) -> Option<Box<Term>> {\n        match self.peek()? {\n            // TokenKind::Lambda => self.lambda(),\n            _ => self.application(),\n        }\n    }\n\n    pub fn parse_term(&mut self) -> Option<Box<Term>> {\n        self.term()\n    }\n\n    pub fn diagnostic(self) -> Diagnostic<'s> {\n        self.diagnostic\n    }\n}\n"
  },
  {
    "path": "04_stlc/src/term.rs",
    "content": "use crate::typing::Type;\nuse std::fmt;\nuse util::span::Span;\n\n#[derive(Clone, Debug, PartialEq, PartialOrd)]\npub struct Field {\n    pub span: Span,\n    pub ident: String,\n    pub term: Box<Term>,\n}\n\n// pub enum Item {\n//     Variant(VariantDecl),\n//     Record(RecordDecl)\n// }\n\n#[derive(Clone, Debug, PartialEq, PartialOrd)]\npub enum Term {\n    Unit,\n    True,\n    False,\n    Zero,\n    Succ(Box<Term>),\n    Pred(Box<Term>),\n    IsZero(Box<Term>),\n    // DeBrujin index\n    Var(usize),\n    // Type of bound variable, and body of abstraction\n    Abs(Type, Box<Term>),\n    // Application (t1 t2)\n    App(Box<Term>, Box<Term>),\n    If(Box<Term>, Box<Term>, Box<Term>),\n    Let(Box<Term>, Box<Term>),\n    Record(Vec<Field>),\n    Projection(Box<Term>, Box<String>),\n}\n\npub fn record_access(fields: &[Field], projection: &str) -> Option<Box<Term>> {\n    for f in fields {\n        if f.ident == projection {\n            return Some(f.term.clone());\n        }\n    }\n    None\n}\n\nimpl fmt::Display for Term {\n    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n        match self {\n            Term::Unit => write!(f, \"unit\"),\n            Term::True => write!(f, \"true\"),\n            Term::False => write!(f, \"false\"),\n            Term::Zero => write!(f, \"Z\"),\n            Term::Succ(t) => write!(f, \"S({})\", t),\n            Term::Pred(t) => write!(f, \"P({})\", t),\n            Term::IsZero(t) => write!(f, \"IsZero({})\", t),\n            Term::Var(idx) => write!(f, \"#{}\", idx),\n            Term::Abs(ty, body) => write!(f, \"λ_:{:?}. {}\", ty, body),\n            Term::App(t1, t2) => write!(f, \"({}) {}\", t1, t2),\n            Term::If(a, b, c) => write!(f, \"if {} then {} else {}\", a, b, c),\n            Term::Let(bind, body) => write!(f, \"let x={} in {}\", bind, body),\n            Term::Record(rec) => write!(\n                f,\n                \"{{{}}}\",\n                rec.iter()\n                    .map(|x| format!(\"{}:{}\", x.ident, x.term))\n                    .collect::<Vec<String>>()\n                    .join(\",\")\n            ),\n            Term::Projection(rec, idx) => write!(f, \"{}.{}\", rec, idx),\n        }\n    }\n}\n"
  },
  {
    "path": "04_stlc/src/typing.rs",
    "content": "use crate::term::Term;\nuse std::fmt;\n\n#[derive(Clone, PartialEq, PartialOrd)]\npub enum Type {\n    Unit,\n    Bool,\n    Nat,\n    Arrow(Box<Type>, Box<Type>),\n    Record(Record),\n}\n\n#[derive(Clone, PartialEq, PartialOrd)]\npub struct Record {\n    // pub span: Span,\n    pub ident: String,\n    pub fields: Vec<RecordField>,\n}\n\n#[derive(Clone, PartialEq, PartialOrd)]\npub struct RecordField {\n    // pub span: Span,\n    pub ident: String,\n    pub ty: Box<Type>,\n}\n\nimpl fmt::Debug for Type {\n    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n        match self {\n            Type::Unit => write!(f, \"Unit\"),\n            Type::Bool => write!(f, \"Bool\"),\n            Type::Nat => write!(f, \"Nat\"),\n            Type::Arrow(a, b) => write!(f, \"({:?}->{:?})\", a, b),\n            Type::Record(r) => write!(\n                f,\n                \"{} {{{}}}\",\n                r.ident,\n                r.fields\n                    .iter()\n                    .map(|x| format!(\"{}:{:?}\", x.ident, x.ty))\n                    .collect::<Vec<String>>()\n                    .join(\",\")\n            ),\n        }\n    }\n}\n\n#[derive(Clone, Debug, PartialEq, PartialOrd)]\npub enum TypeError {\n    Guard,\n    ArmMismatch,\n    ParameterMismatch,\n    UnknownVariable(usize),\n    ExpectedArrow,\n    InvalidProjection,\n    NotRecordType,\n}\n\n#[derive(Clone, Debug, Default)]\n/// A typing context, Γ\n///\n/// Much simpler than the binding list suggested in the book, and used\n/// in the other directories, but this should be more efficient, and\n/// a vec is really overkill here\npub struct Context<'a> {\n    parent: Option<&'a Context<'a>>,\n    ty: Option<Type>,\n}\n\nimpl<'a> Context<'a> {\n    pub fn add(&self, ty: Type) -> Context {\n        if self.ty.is_none() {\n            Context {\n                parent: None,\n                ty: Some(ty),\n            }\n        } else {\n            Context {\n                parent: Some(self),\n                ty: Some(ty),\n            }\n        }\n    }\n\n    pub fn get(&self, idx: usize) -> Option<&Type> {\n        if idx == 0 {\n            self.ty.as_ref()\n        } else if let Some(ctx) = self.parent {\n            ctx.get(idx - 1)\n        } else {\n            None\n        }\n    }\n\n    pub fn type_of(&self, term: &Term) -> Result<Type, TypeError> {\n        use Term::*;\n        match term {\n            Unit => Ok(Type::Unit),\n            True => Ok(Type::Bool),\n            False => Ok(Type::Bool),\n            Zero => Ok(Type::Nat),\n            Record(fields) => {\n                let fields: Vec<RecordField> = fields\n                    .iter()\n                    .map(|f| {\n                        self.type_of(&f.term).map(|ty| {\n                            RecordField {\n                                // span: f.span,\n                                ident: f.ident.clone(),\n                                ty: Box::new(ty),\n                            }\n                        })\n                    })\n                    .collect::<Result<Vec<RecordField>, TypeError>>()?;\n\n                Ok(Type::Record(crate::typing::Record {\n                    // span: Span::dummy(),\n                    ident: String::new(),\n                    fields,\n                }))\n            }\n            Projection(r, proj) => match self.type_of(r)? {\n                Type::Record(self::Record { fields, .. }) => {\n                    for f in &fields {\n                        if &f.ident == proj.as_ref() {\n                            return Ok(*f.ty.clone());\n                        }\n                    }\n                    Err(TypeError::InvalidProjection)\n                }\n                _ => Err(TypeError::NotRecordType),\n            },\n            IsZero(t) => {\n                if let Ok(Type::Nat) = self.type_of(t) {\n                    Ok(Type::Bool)\n                } else {\n                    Err(TypeError::ParameterMismatch)\n                }\n            }\n            Succ(t) | Pred(t) => {\n                if let Ok(Type::Nat) = self.type_of(t) {\n                    Ok(Type::Nat)\n                } else {\n                    Err(TypeError::ParameterMismatch)\n                }\n            }\n            If(guard, csq, alt) => {\n                if let Ok(Type::Bool) = self.type_of(guard) {\n                    let ty1 = self.type_of(csq)?;\n                    let ty2 = self.type_of(alt)?;\n                    if ty1 == ty2 {\n                        Ok(ty2)\n                    } else {\n                        Err(TypeError::ArmMismatch)\n                    }\n                } else {\n                    Err(TypeError::Guard)\n                }\n            }\n            Let(bind, body) => {\n                let ty = self.type_of(bind)?;\n                let ctx = self.add(ty);\n                ctx.type_of(body)\n            }\n            Var(s) => match self.get(*s) {\n                Some(ty) => Ok(ty.clone()),\n                _ => Err(TypeError::UnknownVariable(*s)),\n            },\n            Abs(ty, body) => {\n                let ctx = self.add(ty.clone());\n                let ty_body = ctx.type_of(body)?;\n                Ok(Type::Arrow(Box::new(ty.clone()), Box::new(ty_body)))\n            }\n            App(t1, t2) => {\n                let ty1 = self.type_of(t1)?;\n                let ty2 = self.type_of(t2)?;\n                match ty1 {\n                    Type::Arrow(ty11, ty12) => {\n                        if *ty11 == ty2 {\n                            Ok(*ty12)\n                        } else {\n                            Err(TypeError::ParameterMismatch)\n                        }\n                    }\n                    _ => Err(TypeError::ExpectedArrow),\n                }\n            }\n        }\n    }\n}\n\n// impl<'a> Visitor for Context<'a> {\n//     fn visit_var(&mut self, var: usize) {\n//         self.get(var)\n//             .cloned()\n//             .ok_or(TypeError::UnknownVariable(var))\n//     }\n\n//     fn visit_abs(&mut self, ty: Type, body: &Term) {\n//         let ty = match ty {\n//             Type::Var(name) => self\n//                 .types\n//                 .borrow()\n//                 .get(&name)\n//                 .cloned()\n//                 .ok_or(TypeError::Undefined(name))?,\n//             x => x,\n//         };\n//         let mut ctx = self.add(ty.clone());\n//         let ty_body: Result<Type, TypeError> = body.accept(&mut ctx);\n//         Ok(Type::Arrow(Box::new(ty), Box::new(ty_body?)))\n//     }\n\n//     fn visit_app(&mut self, t1: &Term, t2: &Term) {\n//         let ty1 = t1.accept(self)?;\n//         let ty2 = t2.accept(self)?;\n//         match ty1 {\n//             Type::Arrow(ty11, ty12) => {\n//                 if *ty11 == ty2 {\n//                     Ok(*ty12)\n//                 } else {\n//                     Err(TypeError::ParameterMismatch)\n//                 }\n//             }\n//             _ => Err(TypeError::ExpectedArrow),\n//         }\n//     }\n\n//     fn visit_if(\n//         &mut self,\n//         guard: &Term,\n//         csq: &Term,\n//         alt: &Term,\n//     ) {\n//         if let Ok(Type::Bool) = guard.accept(self) {\n//             let ty1 = csq.accept(self)?;\n//             let ty2 = alt.accept(self)?;\n//             if ty1 == ty2 {\n//                 Ok(ty2)\n//             } else {\n//                 Err(TypeError::ArmMismatch)\n//             }\n//         } else {\n//             Err(TypeError::Guard)\n//         }\n//     }\n\n//     fn visit_let(&mut self, bind: &Term, body: &Term) {\n//         // Dirty hack or correct behavior?\n//         //\n//         // We definitely need to correct var indices or how the context is\n//         // working so that let binders can access names defined in an\n//         // enclosing let-bound scope\n//         let ty = bind\n//             // .accept(&mut Shifting::new(Direction::Down))\n//             .accept(self)?;\n//         let mut ctx = self.add(ty);\n//         body.accept(&mut ctx)\n//     }\n\n//     fn visit_succ(&mut self, t: &Term) {\n//         Ok(Type::Nat)\n//     }\n\n//     fn visit_pred(&mut self, t: &Term) {\n//         Ok(Type::Nat)\n//     }\n\n//     fn visit_iszero(&mut self, t: &Term) {\n//         Ok(Type::Bool)\n//     }\n\n//     fn visit_const(&mut self, c: &Term) {\n//         match c.as_ref() {\n//             Term::Unit => Ok(Type::Unit),\n//             Term::Zero => Ok(Type::Nat),\n//             Term::True | Term::False => Ok(Type::Bool),\n//             _ => unreachable!(),\n//         }\n//     }\n\n//     fn visit_record(&mut self, rec: &[RecordField]) {\n//         let tys = rec\n//             .iter()\n//             .map(|f| f.data.accept(self).map(|ty| (f.label.clone(), ty)))\n//             .collect::<Result<Vec<(Rc<String>, Type)>, TypeError>>()?;\n//         Ok(Type::Record(tys))\n//     }\n\n//     fn visit_proj(&mut self, c: &Term, proj: Rc<String>) {\n//         match c.accept(self)? {\n//             Type::Record(fields) => {\n//                 for f in &fields {\n//                     if f.0 == proj {\n//                         return Ok(f.1.clone());\n//                     }\n//                 }\n//                 Err(TypeError::InvalidProjection)\n//             }\n//             _ => Err(TypeError::NotRecordType),\n//         }\n//     }\n\n//     fn visit_typedecl(&mut self, name: Rc<String>, ty: &Type) {\n//         self.bind(name.to_string(), ty.clone());\n//         Ok(Type::Unit)\n//     }\n// }\n"
  },
  {
    "path": "04_stlc/src/visitor.rs",
    "content": "use super::*;\nuse crate::term::{Field, Term};\nuse std::default::Default;\n\npub trait Visitor: Sized {\n    fn visit_var(&mut self, var: usize);\n    fn visit_abs(&mut self, ty: Type, body: &Term);\n    fn visit_app(&mut self, t1: &Term, t2: &Term);\n    fn visit_if(&mut self, guard: &Term, csq: &Term, alt: &Term);\n    fn visit_let(&mut self, bind: &Term, body: &Term);\n    fn visit_succ(&mut self, t: &Term);\n    fn visit_pred(&mut self, t: &Term);\n    fn visit_iszero(&mut self, t: &Term);\n    fn visit_const(&mut self, c: &Term);\n    fn visit_record(&mut self, c: &[Field]);\n    fn visit_proj(&mut self, c: &Term, proj: &str);\n    fn visit_typedecl(&mut self, name: &str, ty: &Type);\n}\n\npub trait MutVisitor: Sized {\n    fn visit_var(&mut self, var: &mut Term) {}\n\n    fn visit_abs(&mut self, ty: &mut Type, body: &mut Term) {\n        self.visit_term(body);\n    }\n    fn visit_app(&mut self, t1: &mut Term, t2: &mut Term) {\n        self.visit_term(t1);\n        self.visit_term(t2);\n    }\n    fn visit_if(&mut self, guard: &mut Term, csq: &mut Term, alt: &mut Term) {\n        self.visit_term(guard);\n        self.visit_term(csq);\n        self.visit_term(alt);\n    }\n    fn visit_let(&mut self, bind: &mut Term, body: &mut Term) {\n        self.visit_term(bind);\n        self.visit_term(body);\n    }\n    fn visit_succ(&mut self, t: &mut Term) {\n        self.visit_term(t);\n    }\n    fn visit_pred(&mut self, t: &mut Term) {\n        self.visit_term(t);\n    }\n    fn visit_iszero(&mut self, t: &mut Term) {\n        self.visit_term(t);\n    }\n    fn visit_const(&mut self, t: &mut Term) {}\n    fn visit_record(&mut self, c: &mut [Field]) {\n        for t in c {\n            self.visit_term(t.term.as_mut());\n        }\n    }\n    fn visit_proj(&mut self, t: &mut Term, proj: &mut String) {\n        self.visit_term(t);\n    }\n    fn visit_typedecl(&mut self, name: &mut String, ty: &mut Type) {}\n\n    fn visit_term(&mut self, term: &mut Term) {\n        walk_mut_term(self, term);\n    }\n}\n\nfn walk_mut_term<V: MutVisitor>(visitor: &mut V, var: &mut Term) {\n    match var {\n        Term::Unit | Term::True | Term::False | Term::Zero => visitor.visit_const(var),\n        Term::Succ(t) => visitor.visit_succ(t),\n        Term::Pred(t) => visitor.visit_pred(t),\n        Term::IsZero(t) => visitor.visit_iszero(t),\n        Term::Var(_) => visitor.visit_var(var),\n        Term::Abs(ty, body) => visitor.visit_abs(ty, body),\n        Term::App(t1, t2) => visitor.visit_app(t1, t2),\n        Term::If(a, b, c) => visitor.visit_if(a, b, c),\n        Term::Let(bind, body) => visitor.visit_let(bind, body),\n        Term::Record(rec) => visitor.visit_record(rec),\n        Term::Projection(rec, idx) => visitor.visit_proj(rec, idx),\n    }\n}\n\n#[derive(Copy, Clone, Debug)]\npub enum Direction {\n    Up,\n    Down,\n}\n\n#[derive(Copy, Clone, Debug)]\npub struct Shifting {\n    pub cutoff: usize,\n    pub direction: Direction,\n}\n\nimpl Default for Shifting {\n    fn default() -> Self {\n        Shifting {\n            cutoff: 0,\n            direction: Direction::Up,\n        }\n    }\n}\n\nimpl Shifting {\n    pub fn new(direction: Direction) -> Self {\n        Shifting { cutoff: 0, direction }\n    }\n}\n\nimpl MutVisitor for Shifting {\n    fn visit_var(&mut self, var: &mut Term) {\n        let n = match var {\n            Term::Var(n) => n,\n            _ => unreachable!(),\n        };\n\n        if *n >= self.cutoff {\n            // NB: Substracting 1 from the usize here is safe, as long as\n            // a shift Down is only called *after* a shift/substitute cycle\n            match self.direction {\n                Direction::Up => *n += 1,\n                Direction::Down => *n -= 1,\n            }\n        }\n    }\n\n    fn visit_abs(&mut self, ty_: &mut Type, body: &mut Term) {\n        self.cutoff += 1;\n        self.visit_term(body);\n        self.cutoff -= 1;\n    }\n\n    fn visit_let(&mut self, bind: &mut Term, body: &mut Term) {\n        self.cutoff += 1;\n        self.visit_term(bind);\n        self.visit_term(body);\n        self.cutoff -= 1;\n    }\n}\n\n#[derive(Debug)]\npub struct Substitution {\n    pub cutoff: usize,\n    pub term: Term,\n}\n\nimpl Substitution {\n    pub fn new(term: Term) -> Substitution {\n        Substitution { cutoff: 0, term }\n    }\n}\n\nimpl MutVisitor for Substitution {\n    fn visit_var(&mut self, var: &mut Term) {\n        match var {\n            Term::Var(n) if *n >= self.cutoff => {\n                *var = self.term.clone();\n            }\n            _ => unreachable!(),\n        }\n    }\n\n    fn visit_abs(&mut self, ty_: &mut Type, body: &mut Term) {\n        self.cutoff += 1;\n        walk_mut_term(self, body);\n        self.cutoff -= 1;\n    }\n\n    fn visit_let(&mut self, bind: &mut Term, body: &mut Term) {\n        self.cutoff += 1;\n        walk_mut_term(self, bind);\n        walk_mut_term(self, body);\n        self.cutoff -= 1;\n    }\n}\n"
  },
  {
    "path": "05_recon/Cargo.toml",
    "content": "[package]\nname = \"recon\"\nversion = \"0.1.0\"\nauthors = [\"Michael Lazear <lazear@scripps.edu>\"]\nedition = \"2018\"\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nutil = { path = \"../util\" }"
  },
  {
    "path": "05_recon/src/disjoint.rs",
    "content": "//! A disjoint set using the union-find algorithm with path-compression\n\nuse std::cell::Cell;\nuse std::cmp::Ordering;\nuse std::collections::HashMap;\n\nstruct SetElement<T> {\n    data: Option<T>,\n    rank: Cell<u32>,\n    parent: Cell<usize>,\n}\n\npub struct DisjointSet<T> {\n    elements: Vec<SetElement<T>>,\n    components: Cell<usize>,\n}\n\nimpl<T> Default for DisjointSet<T> {\n    fn default() -> Self {\n        DisjointSet {\n            elements: Vec::new(),\n            components: Cell::new(0),\n        }\n    }\n}\n\n#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Eq, Hash)]\npub struct Element(usize);\n\npub enum Choice {\n    Left,\n    Right,\n}\n\nimpl<T> DisjointSet<T> {\n    pub fn new() -> DisjointSet<T> {\n        DisjointSet {\n            elements: Vec::new(),\n            components: Cell::new(0),\n        }\n    }\n\n    pub fn singleton(&mut self, data: T) -> Element {\n        let n = self.elements.len();\n        let elem = SetElement {\n            data: Some(data),\n            rank: Cell::new(0),\n            parent: Cell::new(n),\n        };\n        self.elements.push(elem);\n        self.components.replace(self.components.get() + 1);\n        Element(n)\n    }\n\n    fn find_set(&self, id: usize) -> usize {\n        // locate parent set\n        let mut ptr = id;\n        while ptr != self.elements[ptr].parent.get() {\n            ptr = self.elements[ptr].parent.get();\n        }\n\n        // id is the representative element, return\n        if ptr == id {\n            return id;\n        }\n\n        // perform path compression\n        let parent = ptr;\n        ptr = id;\n        while ptr != self.elements[ptr].parent.get() {\n            ptr = self.elements[ptr].parent.replace(parent);\n        }\n        parent\n    }\n\n    pub fn find_repr(&self, element: Element) -> Element {\n        Element(self.find_set(element.0))\n    }\n\n    pub fn data(&self, element: Element) -> Option<&T> {\n        self.elements[element.0].data.as_ref()\n    }\n\n    pub fn find(&self, element: Element) -> &T {\n        // Invariant that the representative element is always \"Some\"\n        self.elements[self.find_set(element.0)]\n            .data\n            .as_ref()\n            .expect(\"Invariant violated\")\n    }\n\n    pub fn union<F: Fn(T, T) -> T>(&mut self, f: F, a: Element, b: Element) {\n        let pa = self.find_set(a.0);\n        let pb = self.find_set(b.0);\n\n        if pa == pb {\n            return;\n        }\n\n        // Move data out first to appease borrowck\n        let a_data = self.elements[pa].data.take().expect(\"Invariant violated\");\n        let b_data = self.elements[pb].data.take().expect(\"Invariant violated\");\n\n        self.components.replace(self.components.get() - 1);\n        match self.elements[pa].rank.cmp(&self.elements[pb].rank) {\n            Ordering::Equal => {\n                self.elements[pa].data = Some(f(a_data, b_data));\n                self.elements[pb].parent.replace(pa);\n                self.elements[pa].rank.replace(self.elements[pa].rank.get() + 1);\n            }\n            Ordering::Less => {\n                self.elements[pb].data = Some(f(a_data, b_data));\n                self.elements[pa].parent.replace(pb);\n                self.elements[pb].rank.replace(self.elements[pb].rank.get() + 1);\n            }\n            Ordering::Greater => {\n                self.elements[pa].data = Some(f(a_data, b_data));\n                self.elements[pb].parent.replace(pa);\n                self.elements[pa].rank.replace(self.elements[pa].rank.get() + 1);\n            }\n        }\n    }\n\n    pub fn partition(&self) -> Vec<&T> {\n        let mut v = HashSet::new();\n\n        for idx in 0..self.elements.len() {\n            v.insert(self.find_set(idx));\n        }\n        v.into_iter()\n            .map(|idx| self.elements[idx].data.as_ref().unwrap())\n            .collect()\n    }\n}\n\nuse super::*;\ntype Variable = Element;\n\n#[derive(Debug, Clone)]\npub enum Unification {\n    Unknown(TypeVar),\n    Constr(Tycon, Vec<Variable>),\n}\n\nimpl Unification {\n    fn is_var(&self) -> bool {\n        match self {\n            Self::Unknown(_) => true,\n            _ => false,\n        }\n    }\n}\n\n#[derive(Debug, Default)]\npub struct Unifier {\n    set: disjoint::DisjointSet<Unification>,\n    map: HashMap<Type, Variable>,\n}\n\nimpl Unifier {\n    pub fn new() -> Unifier {\n        Unifier {\n            set: DisjointSet::new(),\n            map: HashMap::default(),\n        }\n    }\n\n    pub fn occurs_check(&self, v: TypeVar, u: &Unification) -> bool {\n        match u {\n            Unification::Unknown(x) => *x == v,\n            Unification::Constr(_, vars) => vars.iter().any(|x| self.occurs_check(v, self.set.find(*x))),\n        }\n    }\n\n    pub fn decode(&self, uni: &Unification) -> Type {\n        match uni {\n            Unification::Unknown(x) => Type::Var(*x),\n            Unification::Constr(tc, vars) => {\n                Type::Con(*tc, vars.into_iter().map(|v| self.decode(self.set.find(*v))).collect())\n            }\n        }\n    }\n\n    pub fn intern(&mut self, ty: Type) -> Variable {\n        if let Some(v) = self.map.get(&ty) {\n            return *v;\n        }\n\n        let v = match &ty {\n            Type::Var(x) => self.set.singleton(Unification::Unknown(*x)),\n            Type::Con(tc, vars) => {\n                let vars = vars.into_iter().cloned().map(|v| self.intern(v)).collect();\n                self.set.singleton(Unification::Constr(*tc, vars))\n            }\n        };\n        self.map.insert(ty, v);\n\n        v\n    }\n\n    fn var_bind(&mut self, v: TypeVar, v_: Variable, u: &Unification, u_: Variable) -> Result<(), String> {\n        if self.occurs_check(v, u) {\n            return Err(format!(\"Failed occurs check {:?} {:?}\", v, u));\n        }\n        self.set.union(\n            |a, b| match (a, b) {\n                (a @ Unification::Constr(_, _), _) => a,\n                (_, b) => b,\n            },\n            u_,\n            v_,\n        );\n        Ok(())\n    }\n\n    pub fn subst(&self) -> HashMap<TypeVar, Type> {\n        let mut map = HashMap::new();\n        for (ty, var) in &self.map {\n            match ty {\n                Type::Var(x) => {\n                    map.insert(*x, self.decode(self.set.find(*var)));\n                }\n                _ => {}\n            }\n        }\n\n        map\n    }\n\n    pub fn unify(&mut self, a_: Variable, b_: Variable) -> Result<(), String> {\n        if a_ == b_ {\n            return Ok(());\n        }\n        if a_ == self.set.find_repr(b_) || b_ == self.set.find_repr(a_) {\n            return Ok(());\n        }\n        let a = self.set.find(a_).clone();\n        let b = self.set.find(b_).clone();\n        use Unification::*;\n        match (a, b) {\n            (Unknown(a), b) => self.var_bind(a, a_, &b, b_),\n            (a, Unknown(b)) => self.var_bind(b, b_, &a, a_),\n            (Constr(a, a_vars), Constr(b, b_vars)) => {\n                if a != b {\n                    return Err(format!(\"Can't unify constructors {:?} and {:?}\", a, b));\n                }\n                if a_vars.len() != b_vars.len() {\n                    return Err(format!(\"Can't unify argument lists {:?} and {:?}\", a_vars, b_vars));\n                }\n                for (c, d) in a_vars.into_iter().zip(b_vars) {\n                    self.set.union(\n                        |a, b| match (a, b) {\n                            (a @ Unification::Constr(_, _), _) => a,\n                            (_, b) => b,\n                        },\n                        c,\n                        d,\n                    );\n                }\n                Ok(())\n            }\n        }\n    }\n}\n\npub fn solve<I: Iterator<Item = (Type, Type)>>(iter: I) -> Result<HashMap<TypeVar, Type>, String> {\n    let mut un = Unifier::new();\n\n    for (a, b) in iter {\n        let a = un.intern(a);\n        let b = un.intern(b);\n        un.unify(a, b)?;\n    }\n    let mut map = HashMap::new();\n    for (ty, var) in &un.map {\n        match ty {\n            Type::Var(x) => {\n                map.insert(*x, un.decode(un.set.find(*var)));\n            }\n            _ => {}\n        }\n    }\n\n    Ok(map)\n}\n\nimpl<T: std::fmt::Debug> std::fmt::Debug for DisjointSet<T> {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        let part = self.partition();\n        writeln!(f, \"{{\")?;\n        for values in part {\n            write!(f, \"\\t{:?}\\n\", values)?;\n        }\n        writeln!(f, \"}}\")\n    }\n}\n"
  },
  {
    "path": "05_recon/src/main.rs",
    "content": "use std::collections::{HashMap, HashSet};\npub mod disjoint;\npub mod mutation;\npub mod naive;\npub mod parser;\npub mod types;\n\nuse types::*;\n\n#[derive(Debug)]\npub enum Term {\n    Unit,\n    Bool(bool),\n    Int(usize),\n    Var(usize, String),\n    Abs(Box<Term>),\n    App(Box<Term>, Box<Term>),\n    Let(Box<Term>, Box<Term>),\n    If(Box<Term>, Box<Term>, Box<Term>),\n}\n\n#[derive(Debug)]\npub enum TypedTerm {\n    Unit,\n    Bool(bool),\n    Int(usize),\n    Var(usize, String),\n    Abs(Box<SystemF>),\n    App(Box<SystemF>, Box<SystemF>),\n    Let(Box<SystemF>, Box<SystemF>),\n    If(Box<SystemF>, Box<SystemF>, Box<SystemF>),\n}\n\n#[derive(Debug)]\npub struct SystemF<T = Type> {\n    expr: TypedTerm,\n    ty: T,\n}\n\npub enum Constraint {\n    Eq(Type, Type),\n    Inst(Type, Scheme),\n    Gen(Type, Vec<TypeVar>, Type),\n}\n\n#[derive(Default, Debug)]\nstruct Elaborator {\n    exist: TypeVar,\n    context: Vec<Scheme>,\n    constraints: Vec<(Type, Type)>,\n\n    uni: disjoint::Unifier,\n}\n\nimpl SystemF {\n    fn new(expr: TypedTerm, ty: Type) -> SystemF {\n        SystemF { expr, ty }\n    }\n\n    fn de(self) -> (TypedTerm, Type) {\n        (self.expr, self.ty)\n    }\n}\n\nimpl Elaborator {\n    fn fresh(&mut self) -> TypeVar {\n        let ex = self.exist;\n        self.exist.0 += 1;\n        ex\n    }\n\n    fn ftv(&self) -> HashSet<TypeVar> {\n        let mut set = HashSet::new();\n        for s in &self.context {\n            set.extend(s.ftv());\n        }\n        set\n    }\n\n    fn get_scheme(&self, index: usize) -> Option<&Scheme> {\n        for (idx, scheme) in self.context.iter().rev().enumerate() {\n            if idx == index {\n                return Some(scheme);\n            }\n        }\n        None\n    }\n\n    fn generalize(&mut self, ty: Type) -> Scheme {\n        let set: HashSet<TypeVar> = ty.ftv().difference(&self.ftv()).copied().collect();\n\n        if set.is_empty() {\n            Scheme::Mono(ty)\n        } else {\n            Scheme::Poly(set.into_iter().collect(), ty)\n        }\n    }\n\n    fn instantiate(&mut self, scheme: Scheme) -> Type {\n        match scheme {\n            Scheme::Mono(ty) => ty,\n            Scheme::Poly(vars, ty) => {\n                let freshv: Vec<TypeVar> = (0..vars.len()).map(|_| self.fresh()).collect();\n                let map = vars\n                    .into_iter()\n                    .zip(freshv.iter())\n                    .map(|(v, f)| (v, Type::Var(*f)))\n                    .collect::<HashMap<TypeVar, Type>>();\n                ty.apply(&map)\n            }\n        }\n    }\n\n    fn push(&mut self, ty: (Type, Type)) {\n        let a = self.uni.intern(ty.0);\n        let b = self.uni.intern(ty.1);\n        self.uni.unify(a, b).unwrap();\n    }\n\n    fn elaborate(&mut self, term: &Term) -> SystemF {\n        // dbg!(term);\n        match term {\n            Term::Unit => SystemF::new(TypedTerm::Unit, Type::Con(T_UNIT, vec![])),\n            Term::Bool(b) => SystemF::new(TypedTerm::Bool(*b), Type::Con(T_BOOL, vec![])),\n            Term::Int(i) => SystemF::new(TypedTerm::Int(*i), Type::Con(T_INT, vec![])),\n            // x has type T iff T is an instance of the type scheme associated with x\n            Term::Var(x, s) => {\n                let scheme = self.get_scheme(*x).cloned().expect(\"Unbound variable!\");\n                let ty = self.instantiate(scheme.clone());\n                SystemF::new(TypedTerm::Var(*x, s.clone()), ty)\n            }\n\n            Term::Abs(body) => {\n                let arg = self.fresh();\n\n                self.context.push(Scheme::Mono(Type::Var(arg)));\n                let (body, ty) = self.elaborate(body).de();\n                self.context.pop();\n                let arrow = Type::arrow(Type::Var(arg), ty.clone());\n                SystemF::new(TypedTerm::Abs(Box::new(SystemF::new(body, ty))), arrow)\n            }\n            // t1 t2 has type T iff for some X2, t1 has type X2 -> T and t2 has type X2\n            Term::App(t1, t2) => {\n                let (t1, ty1) = self.elaborate(t1).de();\n                let (t2, ty2) = self.elaborate(t2).de();\n\n                let v = self.fresh();\n                self.push((ty1.clone(), Type::arrow(ty2.clone(), Type::Var(v))));\n\n                SystemF::new(\n                    TypedTerm::App(Box::new(SystemF::new(t1, ty1)), Box::new(SystemF::new(t2, ty2))),\n                    Type::Var(v),\n                )\n            }\n            Term::Let(t1, t2) => {\n                let (t1, ty1) = self.elaborate(t1).de();\n\n                // let sub = disjoint::solve(self.constraints.drain(..)).unwrap();\n                // for (a, b) in self.constraints.drain(..) {\n                //     let a = self.uni.intern(a);\n                //     let b = self.uni.intern(b);\n                //     self.uni.unify(a, b).unwrap();\n                // }\n\n                let sub = self.uni.subst();\n                self.context = self.context.drain(..).map(|sch| sch.apply(&sub)).collect();\n                let scheme = self.generalize(ty1.clone().apply(&sub));\n\n                self.context.push(scheme);\n                let (t2, ty2) = self.elaborate(t2).de();\n                self.context.pop();\n                SystemF::new(\n                    TypedTerm::Let(Box::new(SystemF::new(t1, ty1)), Box::new(SystemF::new(t2, ty2.clone()))),\n                    ty2,\n                )\n            }\n            Term::If(t1, t2, t3) => {\n                let (t1, ty1) = self.elaborate(t1).de();\n                let (t2, ty2) = self.elaborate(t2).de();\n                let (t3, ty3) = self.elaborate(t3).de();\n\n                let fresh = self.fresh();\n                self.push((ty1.clone(), Type::bool()));\n                self.push((ty2.clone(), Type::Var(fresh)));\n                self.push((ty3.clone(), Type::Var(fresh)));\n\n                SystemF::new(\n                    TypedTerm::If(\n                        Box::new(SystemF::new(t1, ty1)),\n                        Box::new(SystemF::new(t2, ty2)),\n                        Box::new(SystemF::new(t3, ty3)),\n                    ),\n                    Type::Var(fresh),\n                )\n            }\n        }\n    }\n}\n\nimpl TypedTerm {\n    fn subst(self, s: &HashMap<TypeVar, Type>) -> TypedTerm {\n        use TypedTerm::*;\n        match self {\n            Abs(a) => Abs(Box::new(a.subst(s))),\n            App(a, b) => App(Box::new(a.subst(s)), Box::new(b.subst(s))),\n            Let(a, b) => Let(Box::new(a.subst(s)), Box::new(b.subst(s))),\n            If(a, b, c) => If(Box::new(a.subst(s)), Box::new(b.subst(s)), Box::new(c.subst(s))),\n            x => x,\n        }\n    }\n}\n\nimpl SystemF {\n    fn subst(self, s: &HashMap<TypeVar, Type>) -> SystemF {\n        SystemF {\n            expr: self.expr.subst(s),\n            ty: self.ty.apply(s),\n        }\n    }\n}\n\nfn main() {\n    use std::io::prelude::*;\n    use std::time::{Duration, Instant};\n\n    let input = \"fn m. let y = m in let x = y true in x\";\n    let input = \"\n    let id = fn x. x in \n        let g = id id in \n        let f = id true in \n        let h = (id id) 1 in \n        let j = id 10 in \n        g f\";\n    let tm = parser::Parser::new(input).parse_term().unwrap();\n\n    let start = Instant::now();\n    let mut gen = mutation::Elaborator::default();\n    let tm = gen.elaborate(&tm);\n    // let sub = gen.uni.subst();\n    // let sub =  disjoint.solve(gen.constraints);\n    // let sub = disjoint::solve(gen.constraints.into_iter());\n    let end1 = start.elapsed().as_micros();\n    println!(\"{:?} {:?}\", end1, tm);\n\n    loop {\n        let mut buffer = String::new();\n        print!(\"repl: \");\n        std::io::stdout().flush().unwrap();\n        std::io::stdin().read_to_string(&mut buffer).unwrap();\n        // let mut gen = Elaborator::default();\n        match parser::Parser::new(&buffer).parse_term() {\n            Some(tm) => {\n                // let (tm, ty) = gen.elaborate(&tm).de();\n\n                let mut e = mutation::Elaborator::default();\n                dbg!(e.elaborate(&tm));\n\n                // let mut sub = HashMap::new();\n                // println!(\"{:?}\", gen.constraints);\n                // for (a, b) in &gen.constraints {\n                //     let tmp = unify(a.clone().apply(&sub), b.clone().apply(&sub)).unwrap();\n                //     sub = compose(tmp, sub);\n                // }\n                // let sub =  disjoint::solve(gen.constraints.clone());\n                // println!(\"{:?}\", sub);\n                // println!(\"tm {:#?} :{:?}\", tm, ty);\n\n                // println!(\"tm {:#?} :{:?}\", tm.subst(&sub), ty.apply(&sub));\n\n                // dbg!(sub);\n            }\n            None => println!(\"parse error!\"),\n        }\n    }\n}\n"
  },
  {
    "path": "05_recon/src/mutation/mod.rs",
    "content": "use super::{Term, T_ARROW, T_BOOL, T_INT, T_UNIT};\nuse std::collections::{HashMap, HashSet, VecDeque};\nuse std::rc::Rc;\n\nmod write_once;\nuse write_once::WriteOnce;\n\n#[derive(Debug, Clone, PartialEq)]\npub struct TypeVar {\n    exist: usize,\n    data: Rc<WriteOnce<Type>>,\n}\n\n#[derive(Debug, Clone, PartialEq)]\npub enum Type {\n    Var(TypeVar),\n    Con(super::Tycon, Vec<Type>),\n}\n\n#[derive(Debug, Clone)]\npub enum Scheme {\n    Mono(Type),\n    Poly(Vec<usize>, Type),\n}\n\n#[derive(Debug)]\npub enum TypedTerm {\n    Unit,\n    Bool(bool),\n    Int(usize),\n    Var(usize, String),\n    Abs(Box<SystemF>),\n    App(Box<SystemF>, Box<SystemF>),\n    Let(Box<SystemF>, Box<SystemF>),\n    If(Box<SystemF>, Box<SystemF>, Box<SystemF>),\n}\n\n#[derive(Debug)]\npub struct SystemF {\n    expr: TypedTerm,\n    ty: Type,\n}\n\nimpl SystemF {\n    fn new(expr: TypedTerm, ty: Type) -> SystemF {\n        SystemF { expr, ty }\n    }\n}\n\nimpl Type {\n    fn ftv(&self, rank: usize) -> HashSet<usize> {\n        let mut set = HashSet::new();\n        let mut queue = VecDeque::new();\n        queue.push_back(self);\n\n        while let Some(ty) = queue.pop_front() {\n            match ty {\n                Type::Var(x) => match x.data.get() {\n                    None => {\n                        if x.data.get_rank() > rank {\n                            set.insert(x.exist);\n                        }\n                    }\n                    Some(link) => {\n                        queue.push_back(link);\n                    }\n                },\n                Type::Con(_, tys) => {\n                    for ty in tys {\n                        queue.push_back(ty);\n                    }\n                }\n            }\n        }\n        set\n    }\n\n    fn apply(self, map: &HashMap<usize, Type>) -> Type {\n        match self {\n            Type::Var(x) => match x.data.get() {\n                Some(ty) => ty.clone().apply(map),\n                None => map.get(&x.exist).cloned().unwrap_or(Type::Var(x)),\n            },\n            Type::Con(tc, vars) => Type::Con(tc, vars.into_iter().map(|ty| ty.apply(map)).collect()),\n        }\n    }\n}\n\nimpl Type {\n    pub fn arrow(a: Type, b: Type) -> Type {\n        Type::Con(T_ARROW, vec![a, b])\n    }\n\n    pub fn bool() -> Type {\n        Type::Con(T_BOOL, vec![])\n    }\n\n    pub fn de_arrow(&self) -> (&Type, &Type) {\n        match self {\n            Type::Con(T_ARROW, v) => (&v[0], &v[1]),\n            _ => panic!(\"Not arrow type! {:?}\", self),\n        }\n    }\n}\n\npub fn occurs_check(v: &TypeVar, ty: &Type) -> bool {\n    match ty {\n        Type::Var(x) => {\n            if let Some(info) = x.data.get() {\n                occurs_check(v, &info)\n            } else {\n                let min_rank = x.data.get_rank().min(v.data.get_rank());\n                if min_rank != x.data.get_rank() {\n                    println!(\"promoting type var {:?} {}->{}\", x, x.data.get_rank(), min_rank);\n                    x.data.set_rank(min_rank);\n                }\n\n                x.exist == v.exist\n            }\n        }\n        Type::Con(_, vars) => vars.iter().any(|x| occurs_check(v, x)),\n    }\n}\n\nfn var_bind(v: &TypeVar, ty: &Type) -> Result<(), String> {\n    if occurs_check(&v, ty) {\n        return Err(format!(\"Failed occurs check {:?} {:?}\", v, ty));\n    }\n\n    v.data.set(ty.clone()).unwrap();\n    Ok(())\n}\n\nfn unify_type(a: &Type, b: &Type) -> Result<(), String> {\n    match (a, b) {\n        (Type::Var(a), b) => match a.data.get() {\n            Some(ty) => unify_type(ty, b),\n            None => var_bind(a, b),\n        },\n        (a, Type::Var(b)) => match b.data.get() {\n            Some(ty) => unify_type(a, ty),\n            None => var_bind(b, a),\n        },\n        (Type::Con(a, a_args), Type::Con(b, b_args)) => {\n            if a != b {\n                return Err(format!(\"Can't unify constructors {:?} and {:?}\", a, b));\n            }\n            if a_args.len() != b_args.len() {\n                return Err(format!(\"Can't unify argument lists {:?} and {:?}\", a_args, b_args));\n            }\n            for (c, d) in a_args.into_iter().zip(b_args) {\n                unify_type(c, d)?;\n            }\n            Ok(())\n        }\n    }\n}\n\n#[derive(Default, Debug)]\npub struct Elaborator {\n    exist: usize,\n    rank: usize,\n    context: Vec<Scheme>,\n}\n\nimpl Elaborator {\n    fn fresh(&mut self) -> TypeVar {\n        let ex = self.exist;\n        self.exist += 1;\n        TypeVar {\n            exist: ex,\n            data: Rc::new(WriteOnce::with_rank(self.rank)),\n        }\n    }\n\n    fn get_scheme(&self, index: usize) -> Option<&Scheme> {\n        for (idx, scheme) in self.context.iter().rev().enumerate() {\n            if idx == index {\n                return Some(scheme);\n            }\n        }\n        None\n    }\n\n    fn generalize(&mut self, ty: Type) -> Scheme {\n        let set: HashSet<usize> = ty.ftv(self.rank);\n\n        if set.is_empty() {\n            Scheme::Mono(ty)\n        } else {\n            Scheme::Poly(set.into_iter().collect(), ty)\n        }\n    }\n\n    fn instantiate(&mut self, scheme: Scheme) -> Type {\n        match scheme {\n            Scheme::Mono(ty) => ty,\n            Scheme::Poly(vars, ty) => {\n                let map = vars\n                    .into_iter()\n                    .map(|v| (v, Type::Var(self.fresh())))\n                    .collect::<HashMap<usize, Type>>();\n                ty.apply(&map)\n            }\n        }\n    }\n\n    pub fn elaborate(&mut self, term: &Term) -> SystemF {\n        match term {\n            Term::Unit => SystemF::new(TypedTerm::Unit, Type::Con(T_UNIT, vec![])),\n            Term::Bool(b) => SystemF::new(TypedTerm::Bool(*b), Type::Con(T_BOOL, vec![])),\n            Term::Int(i) => SystemF::new(TypedTerm::Int(*i), Type::Con(T_INT, vec![])),\n\n            Term::Var(x, s) => {\n                let scheme = self.get_scheme(*x).cloned().expect(\"Unbound variable!\");\n                let ty = self.instantiate(scheme.clone());\n                SystemF::new(TypedTerm::Var(*x, s.clone()), ty)\n            }\n            Term::Abs(body) => {\n                let arg = self.fresh();\n\n                self.context.push(Scheme::Mono(Type::Var(arg.clone())));\n                let body = self.elaborate(body);\n                self.context.pop();\n                let arrow = Type::arrow(Type::Var(arg), body.ty.clone());\n                SystemF::new(TypedTerm::Abs(Box::new(body)), arrow)\n            }\n            Term::App(t1, t2) => {\n                let t1 = self.elaborate(t1);\n                let t2 = self.elaborate(t2);\n\n                let v = self.fresh();\n\n                unify_type(&t1.ty, &Type::arrow(t2.ty.clone(), Type::Var(v.clone()))).unwrap();\n\n                SystemF::new(TypedTerm::App(Box::new(t1), Box::new(t2)), Type::Var(v))\n            }\n            Term::Let(t1, t2) => {\n                self.rank += 1;\n                let t1 = self.elaborate(t1);\n                self.rank -= 1;\n\n                let scheme = self.generalize(t1.ty.clone());\n\n                self.context.push(scheme);\n                let t2 = self.elaborate(t2);\n                self.context.pop();\n                let ty = t2.ty.clone();\n                SystemF::new(TypedTerm::Let(Box::new(t1), Box::new(t2)), ty)\n            }\n            Term::If(t1, t2, t3) => {\n                let t1 = self.elaborate(t1);\n                let t2 = self.elaborate(t2);\n                let t3 = self.elaborate(t3);\n\n                unify_type(&t1.ty, &Type::bool()).unwrap();\n                unify_type(&t2.ty, &t3.ty).unwrap();\n\n                let ty = t2.ty.clone();\n                SystemF::new(TypedTerm::If(Box::new(t1), Box::new(t2), Box::new(t3)), ty)\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "05_recon/src/mutation/write_once.rs",
    "content": "use std::cell::{Cell, UnsafeCell};\nuse std::rc::Rc;\nuse std::sync::atomic::{AtomicBool, Ordering};\n\npub struct WriteOnce<T> {\n    inner: UnsafeCell<Option<T>>,\n    rank: Cell<usize>,\n    init: AtomicBool,\n}\n\npub type WriteOnceCell<T> = Rc<WriteOnce<T>>;\n\nimpl<T> Default for WriteOnce<T> {\n    fn default() -> Self {\n        WriteOnce {\n            inner: UnsafeCell::new(None),\n            rank: Cell::new(0),\n            init: false.into(),\n        }\n    }\n}\n\nimpl<T: PartialEq> PartialEq for WriteOnce<T> {\n    fn eq(&self, other: &Self) -> bool {\n        self.get() == other.get()\n    }\n}\n\nimpl<T: std::fmt::Debug> std::fmt::Debug for WriteOnce<T> {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        write!(f, \"{:?}#{}\", self.get(), self.get_rank())\n    }\n}\n\nimpl<T> WriteOnce<T> {\n    pub fn with_rank(rank: usize) -> Self {\n        WriteOnce {\n            inner: UnsafeCell::new(None),\n            rank: Cell::new(rank),\n            init: false.into(),\n        }\n    }\n\n    pub fn set(&self, data: T) -> Result<(), T> {\n        if !self.init.compare_and_swap(false, true, Ordering::Acquire) {\n            unsafe {\n                let ptr = &mut *self.inner.get();\n                *ptr = Some(data);\n            }\n            Ok(())\n        } else {\n            Err(data)\n        }\n    }\n\n    pub fn get(&self) -> Option<&T> {\n        if !self.init.compare_and_swap(false, false, Ordering::Release) {\n            None\n        } else {\n            unsafe { &*self.inner.get() }.as_ref()\n        }\n    }\n\n    pub fn set_rank(&self, rank: usize) {\n        self.rank.set(rank)\n    }\n\n    pub fn get_rank(&self) -> usize {\n        self.rank.get()\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    #[test]\n    fn smoke() {\n        let cell = WriteOnce::default();\n        assert_eq!(cell.get(), None);\n        assert_eq!(cell.set(10), Ok(()));\n        assert_eq!(cell.set(12), Err(12));\n        assert_eq!(cell.get(), Some(&10));\n    }\n\n    #[test]\n    fn smoke_shared() {\n        let cell = Rc::new(WriteOnce::default());\n        let rc1 = cell.clone();\n        let rc2 = cell.clone();\n\n        assert_eq!(rc2.get(), None);\n        rc1.set(12).unwrap();\n        assert_eq!(rc2.get(), Some(&12));\n        assert_eq!(rc2.set(10), Err(10));\n    }\n}\n"
  },
  {
    "path": "05_recon/src/naive.rs",
    "content": "use super::*;\n\nfn var_bind(var: TypeVar, ty: Type) -> Result<HashMap<TypeVar, Type>, String> {\n    if ty.occurs(var) {\n        return Err(format!(\"Fails occurs check! {:?} {:?}\", var, ty));\n    }\n    let mut sub = HashMap::new();\n    match ty {\n        Type::Var(x) if x == var => {}\n        _ => {\n            sub.insert(var, ty);\n        }\n    }\n    Ok(sub)\n}\n\npub fn unify(a: Type, b: Type) -> Result<HashMap<TypeVar, Type>, String> {\n    // println!(\"{:?} {:?}\", a, b);\n    match (a, b) {\n        (Type::Con(a, a_args), Type::Con(b, b_args)) => {\n            if a_args.len() == b_args.len() && a == b {\n                solve(a_args.into_iter().zip(b_args.into_iter()))\n            } else {\n                Err(format!(\n                    \"Can't unify types: {:?} {:?}\",\n                    Type::Con(a, a_args),\n                    Type::Con(b, b_args)\n                ))\n            }\n        }\n        (Type::Var(tv), b) => var_bind(tv, b),\n        (a, Type::Var(tv)) => var_bind(tv, a),\n    }\n}\n\npub fn solve<I: Iterator<Item = (Type, Type)>>(iter: I) -> Result<HashMap<TypeVar, Type>, String> {\n    let mut sub = HashMap::new();\n    for (a, b) in iter {\n        let tmp = unify(a.clone().apply(&sub), b.clone().apply(&sub))?;\n        sub = compose(tmp, sub);\n    }\n    Ok(sub)\n}\n"
  },
  {
    "path": "05_recon/src/parser.rs",
    "content": "use super::Term;\nuse std::char;\nuse std::collections::VecDeque;\nuse std::iter::Peekable;\nuse std::str::Chars;\nuse util::span::{Location, Span};\n\n#[derive(Clone, Debug, PartialEq, PartialOrd)]\npub enum TokenKind {\n    Ident(String),\n    Int(u32),\n    Unit,\n    Lambda,\n    Let,\n    Equals,\n    In,\n    Dot,\n    If,\n    Then,\n    Else,\n    True,\n    False,\n    LParen,\n    RParen,\n    Invalid(char),\n    Eof,\n}\n\n#[derive(Clone, Debug, PartialEq, PartialOrd)]\npub struct Token {\n    pub kind: TokenKind,\n    pub span: Span,\n}\n\nimpl Token {\n    pub const fn new(kind: TokenKind, span: Span) -> Token {\n        Token { kind, span }\n    }\n}\n\n#[derive(Clone)]\npub struct Lexer<'s> {\n    input: Peekable<Chars<'s>>,\n    current: Location,\n}\n\nimpl<'s> Lexer<'s> {\n    pub fn new(input: Chars<'s>) -> Lexer<'s> {\n        Lexer {\n            input: input.peekable(),\n            current: Location {\n                line: 0,\n                col: 0,\n                abs: 0,\n            },\n        }\n    }\n\n    /// Peek at the next [`char`] in the input stream\n    fn peek(&mut self) -> Option<char> {\n        self.input.peek().cloned()\n    }\n\n    /// Consume the next [`char`] and advance internal source position\n    fn consume(&mut self) -> Option<char> {\n        match self.input.next() {\n            Some('\\n') => {\n                self.current.line += 1;\n                self.current.col = 0;\n                self.current.abs += 1;\n                Some('\\n')\n            }\n            Some(ch) => {\n                self.current.col += 1;\n                self.current.abs += 1;\n                Some(ch)\n            }\n            None => None,\n        }\n    }\n\n    /// Consume characters from the input stream while pred(peek()) is true,\n    /// collecting the characters into a string.\n    fn consume_while<F: Fn(char) -> bool>(&mut self, pred: F) -> (String, Span) {\n        let mut s = String::new();\n        let start = self.current;\n        while let Some(n) = self.peek() {\n            if pred(n) {\n                match self.consume() {\n                    Some(ch) => s.push(ch),\n                    None => break,\n                }\n            } else {\n                break;\n            }\n        }\n        (s, Span::new(start, self.current))\n    }\n\n    /// Eat whitespace\n    fn consume_delimiter(&mut self) {\n        let _ = self.consume_while(char::is_whitespace);\n    }\n\n    /// Lex a natural number\n    fn number(&mut self) -> Token {\n        // Since we peeked at least one numeric char, we should always\n        // have a string containing at least 1 single digit, as such\n        // it is safe to call unwrap() on str::parse<u32>\n        let (data, span) = self.consume_while(char::is_numeric);\n        let n = data.parse::<u32>().unwrap();\n        Token::new(TokenKind::Int(n), span)\n    }\n\n    /// Lex a reserved keyword or an identifier\n    fn keyword(&mut self) -> Token {\n        let (data, span) = self.consume_while(|ch: char| ch.is_ascii_alphanumeric());\n        let kind = match data.as_ref() {\n            \"unit\" => TokenKind::Unit,\n            \"let\" => TokenKind::Let,\n            \"in\" => TokenKind::In,\n            \"fn\" => TokenKind::Lambda,\n            \"if\" => TokenKind::If,\n            \"then\" => TokenKind::Then,\n            \"else\" => TokenKind::Else,\n            \"true\" => TokenKind::True,\n            \"false\" => TokenKind::False,\n            _ => TokenKind::Ident(data),\n        };\n        Token::new(kind, span)\n    }\n\n    /// Consume the next input character, expecting to match `ch`.\n    /// Return a [`TokenKind::Invalid`] if the next character does not match,\n    /// or the argument `kind` if it does\n    fn eat(&mut self, ch: char, kind: TokenKind) -> Token {\n        let loc = self.current;\n        // Lexer::eat() should only be called internally after calling peek()\n        // so we know that it's safe to unwrap the result of Lexer::consume()\n        let n = self.consume().unwrap();\n        let kind = if n == ch { kind } else { TokenKind::Invalid(n) };\n        Token::new(kind, Span::new(loc, self.current))\n    }\n\n    /// Return the next lexeme in the input as a [`Token`]\n    pub fn lex(&mut self) -> Token {\n        self.consume_delimiter();\n        let next = match self.peek() {\n            Some(ch) => ch,\n            None => return Token::new(TokenKind::Eof, Span::dummy()),\n        };\n        match next {\n            x if x.is_ascii_alphabetic() => self.keyword(),\n            x if x.is_numeric() => self.number(),\n            '(' => self.eat('(', TokenKind::LParen),\n            ')' => self.eat(')', TokenKind::RParen),\n            '\\\\' => self.eat('\\\\', TokenKind::Lambda),\n            'λ' => self.eat('λ', TokenKind::Lambda),\n            '.' => self.eat('.', TokenKind::Dot),\n            '=' => self.eat('=', TokenKind::Equals),\n            ch => self.eat(' ', TokenKind::Invalid(ch)),\n        }\n    }\n}\n\nimpl<'s> Iterator for Lexer<'s> {\n    type Item = Token;\n    fn next(&mut self) -> Option<Self::Item> {\n        match self.lex() {\n            Token {\n                kind: TokenKind::Eof, ..\n            } => None,\n            tok => Some(tok),\n        }\n    }\n}\n\n#[derive(Clone, Debug, Default)]\npub struct DeBruijnIndexer {\n    inner: VecDeque<String>,\n}\n\nimpl DeBruijnIndexer {\n    pub fn push(&mut self, hint: String) -> usize {\n        if self.inner.contains(&hint) {\n            self.push(format!(\"{}'\", hint))\n        } else {\n            let idx = self.inner.len();\n            self.inner.push_front(hint);\n            idx\n        }\n    }\n\n    pub fn pop(&mut self) {\n        self.inner.pop_front();\n    }\n\n    pub fn lookup(&self, key: &str) -> Option<usize> {\n        for (idx, s) in self.inner.iter().enumerate() {\n            if key == s {\n                return Some(idx);\n            }\n        }\n        None\n    }\n}\n\npub struct Parser<'s> {\n    ctx: DeBruijnIndexer,\n    /// [`Lexer`] impls [`Iterator`] over [`TokenSpan`],\n    /// so we can just directly wrap it in a [`Peekable`]\n    lexer: Peekable<Lexer<'s>>,\n    span: Span,\n}\n\nimpl<'s> Parser<'s> {\n    /// Create a new [`Parser`] for the input `&str`\n    pub fn new(input: &'s str) -> Parser<'s> {\n        Parser {\n            ctx: DeBruijnIndexer::default(),\n            lexer: Lexer::new(input.chars()).peekable(),\n            span: Span::dummy(),\n        }\n    }\n\n    fn consume(&mut self) -> Option<Token> {\n        let ts = self.lexer.next()?;\n        self.span = ts.span;\n        Some(ts)\n    }\n\n    fn expect(&mut self, kind: TokenKind) -> Option<Token> {\n        let tk = self.consume()?;\n        match &tk.kind {\n            t if t == &kind => Some(tk),\n            _ => {\n                eprintln!(\"Expected token {:?}, found {:?}\", kind, tk.kind);\n                None\n            }\n        }\n    }\n\n    fn expect_term(&mut self) -> Option<Box<Term>> {\n        match self.term() {\n            Some(term) => Some(term),\n            None => {\n                let sp = self.peek_span();\n                eprintln!(\"Expected term  at {:?}\", sp);\n                None\n            }\n        }\n    }\n\n    fn peek(&mut self) -> Option<TokenKind> {\n        self.lexer.peek().map(|tk| tk.kind.clone())\n    }\n\n    fn peek_span(&mut self) -> Span {\n        self.lexer.peek().map(|s| s.span).unwrap_or(self.span)\n    }\n\n    fn lambda(&mut self) -> Option<Box<Term>> {\n        let start = self.expect(TokenKind::Lambda)?;\n\n        // Bind variable into a new context before parsing the body\n        let var = self.ident()?;\n        self.ctx.push(var);\n        let _ = self.expect(TokenKind::Dot)?;\n        let body = self.term()?;\n\n        // Return to previous context\n        self.ctx.pop();\n        Some(Term::Abs(body).into())\n    }\n\n    fn let_expr(&mut self) -> Option<Box<Term>> {\n        let start = self.expect(TokenKind::Let)?;\n        let var = self.ident()?;\n\n        let _ = self.expect(TokenKind::Equals)?;\n        let bind = self.expect_term()?;\n        self.ctx.push(var);\n        let _ = self.expect(TokenKind::In)?;\n        let body = self.expect_term()?;\n        self.ctx.pop();\n        Some(Term::Let(bind, body).into())\n    }\n\n    /// Parse an application of form:\n    /// application = atom application' | atom\n    /// application' = atom application' | empty\n    fn application(&mut self) -> Option<Box<Term>> {\n        let mut lhs = self.atom()?;\n        let span = self.span;\n        while let Some(rhs) = self.atom() {\n            lhs = Term::App(lhs, rhs).into();\n        }\n        Some(lhs)\n    }\n\n    fn ident(&mut self) -> Option<String> {\n        let Token { kind, span } = self.consume()?;\n        match kind {\n            TokenKind::Ident(s) => Some(s),\n            _ => {\n                eprintln!(\"Expected identifier, found {:?}\", kind);\n                None\n            }\n        }\n    }\n\n    fn if_expr(&mut self) -> Option<Box<Term>> {\n        let _ = self.expect(TokenKind::If)?;\n        let guard = self.expect_term()?;\n        let _ = self.expect(TokenKind::Then)?;\n        let csq = self.expect_term()?;\n        let _ = self.expect(TokenKind::Else)?;\n        let alt = self.expect_term()?;\n        Some(Term::If(guard, csq, alt).into())\n    }\n\n    /// Parse an atomic term\n    /// LPAREN term RPAREN | var\n    fn atom(&mut self) -> Option<Box<Term>> {\n        match self.peek()? {\n            TokenKind::Let => self.let_expr(),\n            TokenKind::Int(i) => {\n                self.consume()?;\n                Some(Term::Int(i as usize).into())\n            }\n            TokenKind::True => {\n                self.consume();\n                Some(Term::Bool(true).into())\n            }\n            TokenKind::False => {\n                self.consume();\n                Some(Term::Bool(false).into())\n            }\n            TokenKind::LParen => {\n                self.expect(TokenKind::LParen)?;\n                let term = self.term()?;\n                self.expect(TokenKind::RParen)?;\n                Some(term)\n            }\n            TokenKind::Unit => {\n                self.expect(TokenKind::Unit)?;\n                Some(Term::Unit.into())\n            }\n            TokenKind::If => self.if_expr(),\n            TokenKind::Lambda => self.lambda(),\n            TokenKind::Ident(s) => {\n                let sp = self.consume()?.span;\n                match self.ctx.lookup(&s) {\n                    Some(idx) => Some(Term::Var(idx, s).into()),\n                    None => {\n                        eprintln!(\"Unbound variable {}\", s);\n                        None\n                    }\n                }\n            }\n            _ => None,\n        }\n    }\n\n    fn term(&mut self) -> Option<Box<Term>> {\n        match self.peek()? {\n            // TokenKind::Lambda => self.lambda(),\n            _ => self.application(),\n        }\n    }\n\n    pub fn parse_term(&mut self) -> Option<Box<Term>> {\n        self.term()\n    }\n}\n"
  },
  {
    "path": "05_recon/src/types.rs",
    "content": "use std::collections::{HashMap, HashSet, VecDeque};\n\n#[derive(Copy, Clone, Default, PartialEq, PartialOrd, Eq, Hash)]\npub struct TypeVar(pub u32, pub u32);\n\n#[derive(Copy, Clone, PartialEq, PartialOrd, Eq, Hash)]\npub struct Tycon {\n    id: usize,\n    arity: usize,\n}\n\n#[derive(Clone, PartialEq, PartialOrd, Eq, Hash)]\npub enum Type {\n    Var(TypeVar),\n    Con(Tycon, Vec<Type>),\n}\n\n#[derive(Debug, Clone)]\npub enum Scheme {\n    Mono(Type),\n    Poly(Vec<TypeVar>, Type),\n}\n\npub trait Substitution {\n    fn ftv(&self) -> HashSet<TypeVar>;\n    fn apply(self, s: &HashMap<TypeVar, Type>) -> Self;\n}\n\nimpl Substitution for Type {\n    fn ftv(&self) -> HashSet<TypeVar> {\n        let mut set = HashSet::new();\n        let mut queue = VecDeque::new();\n        queue.push_back(self);\n\n        while let Some(ty) = queue.pop_front() {\n            match ty {\n                Type::Var(x) => {\n                    set.insert(*x);\n                }\n                Type::Con(_, tys) => {\n                    for ty in tys {\n                        queue.push_back(ty);\n                    }\n                }\n            }\n        }\n        set\n    }\n\n    fn apply(self, map: &HashMap<TypeVar, Type>) -> Type {\n        match self {\n            Type::Var(x) => map.get(&x).cloned().unwrap_or(Type::Var(x)),\n            Type::Con(tc, vars) => Type::Con(tc, vars.into_iter().map(|ty| ty.apply(map)).collect()),\n        }\n    }\n}\n\nimpl Type {\n    pub fn arrow(a: Type, b: Type) -> Type {\n        Type::Con(T_ARROW, vec![a, b])\n    }\n\n    pub fn bool() -> Type {\n        Type::Con(T_BOOL, vec![])\n    }\n\n    pub fn occurs(&self, exist: TypeVar) -> bool {\n        match self {\n            Type::Var(x) => *x == exist,\n            Type::Con(_, tys) => tys.iter().any(|ty| ty.occurs(exist)),\n        }\n    }\n\n    pub fn de_arrow(&self) -> (&Type, &Type) {\n        match self {\n            Type::Con(T_ARROW, v) => (&v[0], &v[1]),\n            _ => panic!(\"Not arrow type! {:?}\", self),\n        }\n    }\n}\n\npub fn compose(s1: HashMap<TypeVar, Type>, s2: HashMap<TypeVar, Type>) -> HashMap<TypeVar, Type> {\n    let mut s2 = s2\n        .into_iter()\n        .map(|(k, v)| (k, v.apply(&s1)))\n        .collect::<HashMap<TypeVar, Type>>();\n    for (k, v) in s1 {\n        if !s2.contains_key(&k) {\n            s2.insert(k, v);\n        }\n    }\n    s2\n}\n\nimpl Substitution for Scheme {\n    fn ftv(&self) -> HashSet<TypeVar> {\n        match self {\n            Scheme::Mono(ty) => ty.ftv(),\n            Scheme::Poly(vars, ty) => ty.ftv(),\n        }\n    }\n\n    fn apply(self, map: &HashMap<TypeVar, Type>) -> Scheme {\n        match self {\n            Scheme::Mono(ty) => Scheme::Mono(ty.apply(map)),\n            Scheme::Poly(vars, ty) => {\n                let mut map: HashMap<TypeVar, Type> = map.clone();\n                for v in &vars {\n                    map.remove(v);\n                }\n                Scheme::Poly(vars, ty.apply(&map))\n            }\n        }\n    }\n}\n\npub const T_ARROW: Tycon = Tycon { id: 0, arity: 2 };\npub const T_INT: Tycon = Tycon { id: 1, arity: 0 };\npub const T_UNIT: Tycon = Tycon { id: 2, arity: 0 };\npub const T_BOOL: Tycon = Tycon { id: 3, arity: 0 };\n\nimpl std::fmt::Debug for Tycon {\n    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {\n        match self.id {\n            0 => write!(f, \"->\"),\n            1 => write!(f, \"int\"),\n            2 => write!(f, \"unit\"),\n            3 => write!(f, \"bool\"),\n            _ => write!(f, \"??\"),\n        }\n    }\n}\n\nfn fresh_name(x: u32) -> String {\n    let last = ((x % 26) as u8 + 'a' as u8) as char;\n    (0..x / 26)\n        .map(|_| 'z')\n        .chain(std::iter::once(last))\n        .collect::<String>()\n}\n\nimpl std::fmt::Debug for TypeVar {\n    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {\n        f.write_str(&fresh_name(self.0))\n    }\n}\n\nimpl std::fmt::Debug for Type {\n    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {\n        match self {\n            Type::Var(x) => write!(f, \"{:?}\", x),\n            Type::Con(T_ARROW, tys) => write!(f, \"({:?} -> {:?})\", tys[0], tys[1]),\n            Type::Con(tc, _) => write!(f, \"{:?}\", tc,),\n        }\n    }\n}\n"
  },
  {
    "path": "06_system_f/Cargo.toml",
    "content": "[package]\nname = \"system_f\"\nversion = \"0.1.0\"\nauthors = [\"Michael Lazear <lazear@scripps.edu>\"]\nedition = \"2018\"\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nutil = { path = \"../util\" }"
  },
  {
    "path": "06_system_f/README.md",
    "content": "# System F\n\nAn extension of the simply typed lambda calculus with parametric polymorphism"
  },
  {
    "path": "06_system_f/src/diagnostics.rs",
    "content": "use util::span::Span;\n#[derive(Debug, Copy, Clone)]\npub enum Level {\n    Warn,\n    Error,\n}\n\n#[derive(Debug, Clone)]\npub struct Annotation {\n    pub span: Span,\n    pub info: String,\n}\n\n#[derive(Debug, Clone)]\npub struct Diagnostic {\n    pub level: Level,\n    pub primary: Annotation,\n    pub info: Vec<String>,\n    pub other: Vec<Annotation>,\n}\n\nimpl Annotation {\n    pub fn new<S: Into<String>>(span: Span, message: S) -> Annotation {\n        Annotation {\n            span,\n            info: message.into(),\n        }\n    }\n}\n\nimpl Diagnostic {\n    pub fn error<S: Into<String>>(span: Span, message: S) -> Diagnostic {\n        Diagnostic {\n            level: Level::Error,\n            primary: Annotation::new(span, message),\n            other: Vec::new(),\n            info: Vec::new(),\n        }\n    }\n\n    pub fn warn<S: Into<String>>(span: Span, message: S) -> Diagnostic {\n        Diagnostic {\n            level: Level::Warn,\n            primary: Annotation::new(span, message),\n            other: Vec::new(),\n            info: Vec::new(),\n        }\n    }\n\n    pub fn message<S: Into<String>>(mut self, span: Span, message: S) -> Diagnostic {\n        self.other.push(Annotation::new(span, message));\n        self\n    }\n\n    pub fn info<S: Into<String>>(mut self, info: S) -> Diagnostic {\n        self.info.push(info.into());\n        self\n    }\n\n    pub fn lines(&self) -> std::ops::Range<u32> {\n        let mut range = std::ops::Range {\n            start: self.primary.span.start.line,\n            end: self.primary.span.end.line + 1,\n        };\n\n        for addl in &self.other {\n            if addl.span.start.line < range.start {\n                range.start = addl.span.start.line;\n            }\n            if addl.span.end.line + 1 > range.end {\n                range.end = addl.span.end.line + 1;\n            }\n        }\n        range\n    }\n}\n"
  },
  {
    "path": "06_system_f/src/eval.rs",
    "content": "use crate::patterns::Pattern;\nuse crate::terms::visit::{Shift, Subst, TyTermSubst};\nuse crate::terms::{Kind, Literal, Primitive, Term};\nuse crate::types::{Context, Type};\nuse crate::visit::MutTermVisitor;\n\npub struct Eval<'ctx> {\n    _context: &'ctx Context,\n}\n\nimpl<'ctx> Eval<'ctx> {\n    pub fn with_context(_context: &Context) -> Eval<'_> {\n        Eval { _context }\n    }\n\n    fn normal_form(&self, term: &Term) -> bool {\n        match &term.kind {\n            Kind::Lit(_) => true,\n            Kind::Abs(_, _) => true,\n            Kind::TyAbs(_) => true,\n            Kind::Primitive(_) => true,\n            Kind::Injection(_, tm, _) => self.normal_form(tm),\n            Kind::Product(fields) => fields.iter().all(|f| self.normal_form(f)),\n            Kind::Fold(_, tm) => self.normal_form(tm),\n            Kind::Pack(_, tm, _) => self.normal_form(tm),\n            // Kind::Unpack(pack, tm) => self.normal_form(tm),\n            _ => false,\n        }\n    }\n\n    fn eval_primitive(&self, p: Primitive, term: Term) -> Option<Term> {\n        fn map<F: Fn(u32) -> u32>(f: F, mut term: Term) -> Option<Term> {\n            match &term.kind {\n                Kind::Lit(Literal::Nat(n)) => {\n                    term.kind = Kind::Lit(Literal::Nat(f(*n)));\n                    Some(term)\n                }\n                _ => None,\n            }\n        }\n\n        match p {\n            Primitive::Succ => map(|l| l + 1, term),\n            Primitive::Pred => map(|l| l.saturating_sub(1), term),\n            Primitive::IsZero => match &term.kind {\n                Kind::Lit(Literal::Nat(0)) => Some(Term::new(Kind::Lit(Literal::Bool(true)), term.span)),\n                _ => Some(Term::new(Kind::Lit(Literal::Bool(false)), term.span)),\n            },\n        }\n    }\n\n    pub fn small_step(&self, term: Term) -> Option<Term> {\n        if self.normal_form(&term) {\n            return None;\n        }\n        match term.kind {\n            Kind::App(t1, t2) => {\n                if self.normal_form(&t2) {\n                    match t1.kind {\n                        Kind::Abs(_, mut abs) => {\n                            term_subst(*t2, abs.as_mut());\n                            Some(*abs)\n                        }\n                        Kind::Primitive(p) => self.eval_primitive(p, *t2),\n                        _ => {\n                            let t = self.small_step(*t1)?;\n                            Some(Term::new(Kind::App(Box::new(t), t2), term.span))\n                        }\n                    }\n                } else if self.normal_form(&t1) {\n                    // t1 is in normal form, but t2 is not, so we will\n                    // carry out the reducton t2 -> t2', and return\n                    // App(t1, t2')\n                    let t = self.small_step(*t2)?;\n                    Some(Term::new(Kind::App(t1, Box::new(t)), term.span))\n                } else {\n                    // Neither t1 nor t2 are in normal form, we reduce t1 first\n                    let t = self.small_step(*t1)?;\n                    Some(Term::new(Kind::App(Box::new(t), t2), term.span))\n                }\n            }\n            Kind::Let(pat, bind, mut body) => {\n                if self.normal_form(&bind) {\n                    // term_subst(*bind, &mut body);\n                    self.case_subst(&pat, &bind, body.as_mut());\n                    Some(*body)\n                } else {\n                    let t = self.small_step(*bind)?;\n                    Some(Term::new(Kind::Let(pat, Box::new(t), body), term.span))\n                }\n            }\n            Kind::TyApp(tm, ty) => match tm.kind {\n                Kind::TyAbs(mut tm2) => {\n                    type_subst(*ty, &mut tm2);\n                    Some(*tm2)\n                }\n                _ => {\n                    let t_prime = self.small_step(*tm)?;\n                    Some(Term::new(Kind::TyApp(Box::new(t_prime), ty), term.span))\n                }\n            },\n            Kind::Injection(label, tm, ty) => {\n                let t_prime = self.small_step(*tm)?;\n                Some(Term::new(Kind::Injection(label, Box::new(t_prime), ty), term.span))\n            }\n            Kind::Projection(tm, idx) => {\n                if self.normal_form(&tm) {\n                    match tm.kind {\n                        // Typechecker ensures that idx is in bounds\n                        Kind::Product(terms) => terms.get(idx).cloned(),\n                        _ => None,\n                    }\n                } else {\n                    let t_prime = self.small_step(*tm)?;\n                    Some(Term::new(Kind::Projection(Box::new(t_prime), idx), term.span))\n                }\n            }\n            Kind::Product(terms) => {\n                let mut v = Vec::with_capacity(terms.len());\n                for term in terms {\n                    if self.normal_form(&term) {\n                        v.push(term);\n                    } else {\n                        v.push(self.small_step(term)?);\n                    }\n                }\n                Some(Term::new(Kind::Product(v), term.span))\n            }\n            Kind::Fix(tm) => {\n                if !self.normal_form(&tm) {\n                    let t_prime = self.small_step(*tm)?;\n                    return Some(Term::new(Kind::Fix(Box::new(t_prime)), term.span));\n                }\n\n                let x = Term::new(Kind::Fix(tm.clone()), term.span);\n                match tm.kind {\n                    Kind::Abs(_, mut body) => {\n                        term_subst(x, &mut body);\n                        Some(*body)\n                    }\n                    _ => None,\n                }\n            }\n            Kind::Case(expr, arms) => {\n                if !self.normal_form(&expr) {\n                    let t_prime = self.small_step(*expr)?;\n                    return Some(Term::new(Kind::Case(Box::new(t_prime), arms), term.span));\n                }\n\n                for mut arm in arms {\n                    if arm.pat.matches(&expr) {\n                        self.case_subst(&arm.pat, &expr, arm.term.as_mut());\n                        return Some(*arm.term);\n                    }\n                }\n\n                None\n            }\n            Kind::Fold(ty, tm) => {\n                if !self.normal_form(&tm) {\n                    let t_prime = self.small_step(*tm)?;\n                    Some(Term::new(Kind::Fold(ty, Box::new(t_prime)), term.span))\n                } else {\n                    None\n                }\n            }\n\n            Kind::Unfold(ty, tm) => {\n                if !self.normal_form(&tm) {\n                    let t_prime = self.small_step(*tm)?;\n                    return Some(Term::new(Kind::Unfold(ty, Box::new(t_prime)), term.span));\n                }\n\n                match tm.kind {\n                    Kind::Fold(ty2, inner) => Some(*inner),\n                    _ => None,\n                }\n            }\n            Kind::Pack(wit, evidence, sig) => {\n                if !self.normal_form(&evidence) {\n                    let t_prime = self.small_step(*evidence)?;\n                    return Some(Term::new(Kind::Pack(wit, Box::new(t_prime), sig), term.span));\n                }\n                None\n            }\n            Kind::Unpack(package, mut body) => match package.kind {\n                Kind::Pack(wit, evidence, sig) => {\n                    term_subst(*evidence, &mut body);\n                    type_subst(*wit, &mut body);\n                    Some(*body)\n                }\n                _ => {\n                    if !self.normal_form(&package) {\n                        let t_prime = self.small_step(*package)?;\n                        return Some(Term::new(Kind::Unpack(Box::new(t_prime), body), term.span));\n                    }\n                    None\n                }\n            },\n\n            _ => None,\n        }\n    }\n\n    fn case_subst(&self, pat: &Pattern, expr: &Term, term: &mut Term) {\n        use Pattern::*;\n        match pat {\n            Any => {}\n            Literal(_) => {}\n            Variable(_) => {\n                term_subst(expr.clone(), term);\n            }\n            Product(v) => {\n                if let Kind::Product(terms) = &expr.kind {\n                    let mut idx = 0;\n                    for tm in terms.iter() {\n                        self.case_subst(&v[idx], tm, term);\n                        idx += 1;\n                    }\n                } else {\n                    panic!(\"wrong type!\")\n                }\n            }\n            Constructor(label, v) => {\n                if let Kind::Injection(label_, tm, _) = &expr.kind {\n                    if label == label_ {\n                        self.case_subst(&v, &tm, term);\n                    }\n                } else {\n                    panic!(\"wrong type!\")\n                }\n            }\n        }\n    }\n}\n\nfn term_subst(mut s: Term, t: &mut Term) {\n    Shift::new(1).visit(&mut s);\n    Subst::new(s).visit(t);\n    Shift::new(-1).visit(t);\n}\n\nfn type_subst(s: Type, t: &mut Term) {\n    TyTermSubst::new(s).visit(t);\n    Shift::new(-1).visit(t);\n}\n\n#[cfg(test)]\nmod test {\n    use super::*;\n    use util::span::Span;\n\n    #[test]\n    fn literal() {\n        let ctx = crate::types::Context::default();\n        let eval = Eval::with_context(&ctx);\n        assert_eq!(eval.small_step(lit!(false)), None);\n    }\n\n    #[test]\n    fn application() {\n        let ctx = crate::types::Context::default();\n        let eval = Eval::with_context(&ctx);\n        let tm = app!(abs!(Type::Nat, app!(prim!(Primitive::Succ), var!(0))), nat!(1));\n\n        let t1 = eval.small_step(tm);\n        assert_eq!(t1, Some(app!(prim!(Primitive::Succ), nat!(1))));\n        let t2 = eval.small_step(t1.unwrap());\n        assert_eq!(t2, Some(nat!(2)));\n        let t3 = eval.small_step(t2.unwrap());\n        assert_eq!(t3, None);\n    }\n\n    #[test]\n    fn type_application() {\n        let ctx = crate::types::Context::default();\n        let eval = Eval::with_context(&ctx);\n        let tm = tyapp!(\n            tyabs!(abs!(Type::Var(0), app!(prim!(Primitive::Succ), var!(0)))),\n            Type::Nat\n        );\n\n        let t1 = eval.small_step(tm);\n        assert_eq!(t1, Some(abs!(Type::Nat, app!(prim!(Primitive::Succ), var!(0)))));\n        let t2 = eval.small_step(t1.unwrap());\n        assert_eq!(t2, None);\n    }\n\n    #[test]\n    fn projection() {\n        let ctx = crate::types::Context::default();\n        let eval = Eval::with_context(&ctx);\n        let product = Term::new(Kind::Product(vec![nat!(5), nat!(6), nat!(29)]), Span::zero());\n        let projection = Term::new(Kind::Projection(Box::new(product), 2), Span::zero());\n        let term = app!(prim!(Primitive::Succ), projection);\n\n        let t1 = eval.small_step(term);\n        assert_eq!(t1, Some(app!(prim!(Primitive::Succ), nat!(29))));\n        let t2 = eval.small_step(t1.unwrap());\n        assert_eq!(t2, Some(nat!(30)));\n        let t3 = eval.small_step(t2.unwrap());\n        assert_eq!(t3, None);\n    }\n}\n"
  },
  {
    "path": "06_system_f/src/macros.rs",
    "content": "//! Macros to make writing tests easier\n\n/// Boolean term\nmacro_rules! lit {\n    ($x:expr) => {\n        crate::terms::Term::new(\n            crate::terms::Kind::Lit(crate::terms::Literal::Bool($x)),\n            util::span::Span::dummy(),\n        )\n    };\n}\n\n/// Integer term\nmacro_rules! nat {\n    ($x:expr) => {\n        crate::terms::Term::new(\n            crate::terms::Kind::Lit(crate::terms::Literal::Nat($x)),\n            util::span::Span::dummy(),\n        )\n    };\n}\n\n/// TmVar term\nmacro_rules! var {\n    ($x:expr) => {\n        crate::terms::Term::new(crate::terms::Kind::Var($x), util::span::Span::dummy())\n    };\n}\n\n/// Application term\nmacro_rules! app {\n    ($t1:expr, $t2:expr) => {\n        crate::terms::Term::new(\n            crate::terms::Kind::App(Box::new($t1), Box::new($t2)),\n            util::span::Span::dummy(),\n        )\n    };\n}\n\n/// Lambda abstraction term\nmacro_rules! abs {\n    ($ty:expr, $t:expr) => {\n        crate::terms::Term::new(\n            crate::terms::Kind::Abs(Box::new($ty), Box::new($t)),\n            util::span::Span::dummy(),\n        )\n    };\n}\n\n/// Type application term\nmacro_rules! tyapp {\n    ($t1:expr, $t2:expr) => {\n        crate::terms::Term::new(\n            crate::terms::Kind::TyApp(Box::new($t1), Box::new($t2)),\n            util::span::Span::dummy(),\n        )\n    };\n}\n\n/// Type abstraction term\nmacro_rules! tyabs {\n    ( $t:expr) => {\n        crate::terms::Term::new(crate::terms::Kind::TyAbs(Box::new($t)), util::span::Span::dummy())\n    };\n}\n\n/// Primitive term\nmacro_rules! prim {\n    ($t:expr) => {\n        crate::terms::Term::new(crate::terms::Kind::Primitive($t), util::span::Span::dummy())\n    };\n}\n\nmacro_rules! inj {\n    ($label:expr, $t:expr, $ty:expr) => {\n        crate::terms::Term::new(\n            crate::terms::Kind::Injection($label.to_string(), Box::new($t), Box::new($ty)),\n            util::span::Span::dummy(),\n        )\n    };\n}\n\n/// Product term\nmacro_rules! tuple {\n    ($($ex:expr),+) => { crate::terms::Term::new(crate::terms::Kind::Product(vec![$($ex),+]),\n    util::span::Span::dummy()) }\n}\n\n/// Type arrow\nmacro_rules! arrow {\n    ($ty1:expr, $ty2:expr) => {\n        crate::types::Type::Arrow(Box::new($ty1), Box::new($ty2))\n    };\n}\n\n/// Boolean pattern\nmacro_rules! boolean {\n    ($ex:expr) => {\n        crate::patterns::Pattern::Literal(crate::terms::Literal::Bool($ex))\n    };\n}\n\n/// Numeric pattern\nmacro_rules! num {\n    ($ex:expr) => {\n        crate::patterns::Pattern::Literal(crate::terms::Literal::Nat($ex))\n    };\n}\n\n/// Product pattern\nmacro_rules! prod {\n    ($($ex:expr),+) => { crate::patterns::Pattern::Product(vec![$($ex),+]) }\n}\n\n/// Constructor pattern\nmacro_rules! con {\n    ($label:expr, $ex:expr) => {\n        crate::patterns::Pattern::Constructor($label.to_string(), Box::new($ex))\n    };\n}\n\n/// Variant type\nmacro_rules! variant {\n    ($label:expr, $ty:expr) => {\n        crate::types::Variant {\n            label: $label.to_string(),\n            ty: $ty,\n        }\n    };\n}\n"
  },
  {
    "path": "06_system_f/src/main.rs",
    "content": "#![allow(unused_variables, unused_macros)]\n#[macro_use]\npub mod macros;\npub mod diagnostics;\npub mod eval;\npub mod patterns;\npub mod syntax;\npub mod terms;\npub mod types;\npub mod visit;\n\nuse diagnostics::*;\nuse std::env;\nuse std::io::{Read, Write};\nuse syntax::parser::{self, Parser};\nuse terms::{visit::InjRewriter, Term};\nuse types::{Type, Variant};\nuse visit::MutTermVisitor;\n\nfn test_variant() -> Type {\n    Type::Variant(vec![\n        Variant {\n            label: \"A\".into(),\n            ty: Type::Unit,\n        },\n        Variant {\n            label: \"B\".into(),\n            ty: Type::Nat,\n        },\n        Variant {\n            label: \"C\".into(),\n            ty: Type::Nat,\n        },\n    ])\n}\n\npub fn code_format(src: &str, diag: Diagnostic) {\n    // let lines = diag.ot\n    //     .iter()\n    //     .map(|(_, sp)| sp.start.line)\n    //     .collect::<std::collections::HashSet<_>>();\n    let srcl = src.lines().collect::<Vec<&str>>();\n\n    let mut msgs = diag.other.clone();\n    msgs.insert(0, diag.primary.clone());\n\n    for line in diag.lines() {\n        println!(\"| {} {}\", line + 1, &srcl[line as usize]);\n        for anno in &msgs {\n            if anno.span.start.line != line {\n                continue;\n            }\n            let empty = (0..anno.span.start.col + 3).map(|_| ' ').collect::<String>();\n            let tilde = (1..anno.span.end.col.saturating_sub(anno.span.start.col))\n                .map(|_| '~')\n                .collect::<String>();\n            println!(\"{}^{}^ --- {}\", empty, tilde, anno.info);\n        }\n    }\n}\n\nfn eval(ctx: &mut types::Context, mut term: Term, verbose: bool) -> Result<Term, Diagnostic> {\n    ctx.de_alias(&mut term);\n    InjRewriter.visit(&mut term);\n    let ty = ctx.type_check(&term)?;\n    println!(\"  -: {:?}\", ty);\n\n    let ev = eval::Eval::with_context(ctx);\n    let mut t = term;\n    let fin = loop {\n        if let Some(res) = ev.small_step(t.clone()) {\n            t = res;\n        } else {\n            break t;\n        }\n        if verbose {\n            println!(\"---> {}\", t);\n        }\n    };\n    println!(\"===> {}\", fin);\n    let fty = ctx.type_check(&fin)?;\n    if fty != ty {\n        panic!(\n            \"Type of term after evaluation is different than before!\\n1 {:?}\\n2 {:?}\",\n            ty, fty\n        );\n    }\n    Ok(fin)\n}\n\nfn parse_and_eval(ctx: &mut types::Context, input: &str, verbose: bool) -> bool {\n    let mut p = Parser::new(input);\n    loop {\n        let term = match p.parse() {\n            Ok(term) => term,\n            Err(parser::Error {\n                kind: parser::ErrorKind::Eof,\n                ..\n            }) => break,\n            Err(e) => {\n                dbg!(e);\n                break;\n            }\n        };\n        if let Err(diag) = eval(ctx, term, verbose) {\n            code_format(input, diag);\n            return false;\n        }\n    }\n    let diag = p.diagnostic();\n    if diag.error_count() > 0 {\n        println!(\"Parsing {}\", diag.emit());\n        false\n    } else {\n        true\n    }\n}\n\nfn nat_list() -> Type {\n    Type::Rec(Box::new(Type::Variant(vec![\n        variant!(\"Nil\", Type::Unit),\n        variant!(\"Cons\", Type::Product(vec![Type::Nat, Type::Var(0)])),\n    ])))\n}\n\nfn nat_list2() -> Type {\n    Type::Variant(vec![\n        variant!(\"Nil\", Type::Unit),\n        variant!(\"Cons\", Type::Product(vec![Type::Nat, Type::Var(0)])),\n    ])\n}\n\nfn main() {\n    let mut ctx = types::Context::default();\n\n    ctx.alias(\"Var\".into(), test_variant());\n    ctx.alias(\"NatList\".into(), nat_list());\n    ctx.alias(\"NB\".into(), nat_list2());\n\n    let args = env::args();\n    if args.len() > 1 {\n        for f in args.skip(1) {\n            println!(\"reading {}\", f);\n            let file = std::fs::read_to_string(&f).unwrap();\n            if !parse_and_eval(&mut ctx, &file, false) {\n                panic!(\"test failed! {}\", f);\n            }\n        }\n        return;\n    }\n\n    loop {\n        let mut buffer = String::new();\n        print!(\"repl: \");\n        std::io::stdout().flush().unwrap();\n        std::io::stdin().read_to_string(&mut buffer).unwrap();\n\n        parse_and_eval(&mut ctx, &buffer, true);\n    }\n}\n"
  },
  {
    "path": "06_system_f/src/patterns/mod.rs",
    "content": "use crate::terms::{Kind, Literal, Term};\nuse crate::types::{variant_field, Type};\nuse crate::visit::PatternVisitor;\nuse util::span::Span;\n\n/// Patterns for case and let expressions\n#[derive(Clone, Debug, PartialEq, PartialOrd, Eq, Hash)]\npub enum Pattern {\n    /// Wildcard pattern, this always matches\n    Any,\n    /// Constant pattern\n    Literal(Literal),\n    /// Variable binding pattern, this always matches\n    Variable(String),\n    /// Tuple of pattern bindings\n    Product(Vec<Pattern>),\n    /// Algebraic datatype constructor, along with binding pattern\n    Constructor(String, Box<Pattern>),\n}\n\n#[derive(Clone, Debug, Default)]\npub struct PatVarStack {\n    pub inner: Vec<String>,\n}\n\nimpl PatVarStack {\n    pub fn collect(pat: &mut Pattern) -> Vec<String> {\n        let mut p = Self::default();\n        p.visit_pattern(pat);\n        p.inner\n    }\n}\n\nimpl PatternVisitor for PatVarStack {\n    fn visit_variable(&mut self, var: &String) {\n        self.inner.push(var.clone());\n    }\n}\n\n/// Visitor that simply counts the number of binders (variables) within a\n/// pattern\npub struct PatternCount(usize);\n\nimpl PatternCount {\n    pub fn collect(pat: &mut Pattern) -> usize {\n        let mut p = PatternCount(0);\n        p.visit_pattern(pat);\n        p.0\n    }\n}\n\nimpl PatternVisitor for PatternCount {\n    fn visit_variable(&mut self, var: &String) {\n        self.0 += 1;\n    }\n}\n\nimpl Pattern {\n    /// Does this pattern match the given [`Term`]?\n    pub fn matches(&self, term: &Term) -> bool {\n        match self {\n            Pattern::Any => return true,\n            Pattern::Variable(_) => return true,\n            Pattern::Literal(l) => {\n                if let Kind::Lit(l2) = &term.kind {\n                    return l == l2;\n                }\n            }\n            Pattern::Product(vec) => {\n                if let Kind::Product(terms) = &term.kind {\n                    return vec.iter().zip(terms).all(|(p, t)| p.matches(t));\n                }\n            }\n            Pattern::Constructor(label, inner) => {\n                if let Kind::Injection(label_, tm, _) = &term.kind {\n                    if label == label_ {\n                        return inner.matches(&tm);\n                    }\n                }\n            }\n        }\n        false\n    }\n}\n\n/// Helper struct to traverse a [`Pattern`] and bind variables\n/// to the typing context as needed.\n///\n/// It is the caller's responsibiliy to track stack growth and pop off\n/// types after calling this function\npub struct PatTyStack<'ty> {\n    pub ty: &'ty Type,\n    pub inner: Vec<&'ty Type>,\n}\n\nimpl<'ty> PatTyStack<'ty> {\n    pub fn collect(ty: &'ty Type, pat: &Pattern) -> Vec<&'ty Type> {\n        let mut p = PatTyStack {\n            ty,\n            inner: Vec::with_capacity(16),\n        };\n        p.visit_pattern(pat);\n        p.inner\n    }\n}\n\nimpl<'ty> PatternVisitor for PatTyStack<'_> {\n    fn visit_product(&mut self, pats: &Vec<Pattern>) {\n        if let Type::Product(tys) = self.ty {\n            let ty = self.ty;\n            for (ty, pat) in tys.iter().zip(pats.iter()) {\n                self.ty = ty;\n                self.visit_pattern(pat);\n            }\n            self.ty = ty;\n        }\n    }\n\n    fn visit_constructor(&mut self, label: &String, pat: &Pattern) {\n        if let Type::Variant(vs) = self.ty {\n            let ty = self.ty;\n            self.ty = variant_field(&vs, label, Span::zero()).unwrap();\n            self.visit_pattern(pat);\n            self.ty = ty;\n        }\n    }\n\n    fn visit_pattern(&mut self, pattern: &Pattern) {\n        match pattern {\n            Pattern::Any | Pattern::Literal(_) => {}\n            Pattern::Variable(_) => self.inner.push(self.ty),\n            Pattern::Constructor(label, pat) => self.visit_constructor(label, pat),\n            Pattern::Product(pats) => self.visit_product(pats),\n        }\n    }\n}\n\n#[cfg(test)]\nmod test {\n    use super::*;\n    #[test]\n    fn pattern_count() {\n        let mut pat = Pattern::Variable(String::new());\n        assert_eq!(PatternCount::collect(&mut pat), 1);\n    }\n\n    #[test]\n    fn pattern_ty_stack() {\n        let mut pat = Pattern::Variable(String::new());\n        let ty = Type::Nat;\n        assert_eq!(PatTyStack::collect(&ty, &mut pat), vec![&ty]);\n    }\n\n    #[test]\n    fn pattern_var_stack() {\n        let mut pat = Pattern::Variable(\"x\".into());\n        assert_eq!(PatVarStack::collect(&mut pat), vec![String::from(\"x\")]);\n    }\n}\n"
  },
  {
    "path": "06_system_f/src/syntax/lexer.rs",
    "content": "use super::{Token, TokenKind};\nuse std::char;\nuse std::iter::Peekable;\nuse std::str::Chars;\nuse util::span::{Location, Span};\n\n#[derive(Clone)]\npub struct Lexer<'s> {\n    input: Peekable<Chars<'s>>,\n    current: Location,\n}\n\nimpl<'s> Lexer<'s> {\n    pub fn new(input: Chars<'s>) -> Lexer<'s> {\n        Lexer {\n            input: input.peekable(),\n            current: Location {\n                line: 0,\n                col: 0,\n                abs: 0,\n            },\n        }\n    }\n\n    /// Peek at the next [`char`] in the input stream\n    fn peek(&mut self) -> Option<char> {\n        self.input.peek().cloned()\n    }\n\n    /// Consume the next [`char`] and advance internal source position\n    fn consume(&mut self) -> Option<char> {\n        match self.input.next() {\n            Some('\\n') => {\n                self.current.line += 1;\n                self.current.col = 0;\n                self.current.abs += 1;\n                Some('\\n')\n            }\n            Some(ch) => {\n                self.current.col += 1;\n                self.current.abs += 1;\n                Some(ch)\n            }\n            None => None,\n        }\n    }\n\n    /// Consume characters from the input stream while pred(peek()) is true,\n    /// collecting the characters into a string.\n    fn consume_while<F: Fn(char) -> bool>(&mut self, pred: F) -> (String, Span) {\n        let mut s = String::new();\n        let start = self.current;\n        while let Some(n) = self.peek() {\n            if pred(n) {\n                match self.consume() {\n                    Some(ch) => s.push(ch),\n                    None => break,\n                }\n            } else {\n                break;\n            }\n        }\n        (s, Span::new(start, self.current))\n    }\n\n    /// Eat whitespace\n    fn consume_delimiter(&mut self) {\n        let _ = self.consume_while(char::is_whitespace);\n    }\n\n    /// Lex a natural number\n    fn number(&mut self) -> Token {\n        // Since we peeked at least one numeric char, we should always\n        // have a string containing at least 1 single digit, as such\n        // it is safe to call unwrap() on str::parse<u32>\n        let (data, span) = self.consume_while(char::is_numeric);\n        let n = data.parse::<u32>().unwrap();\n        Token::new(TokenKind::Nat(n), span)\n    }\n\n    /// Lex a reserved keyword or an identifier\n    fn keyword(&mut self) -> Token {\n        let (data, span) = self.consume_while(|ch| ch.is_ascii_alphanumeric());\n        let kind = match data.as_ref() {\n            \"if\" => TokenKind::If,\n            \"then\" => TokenKind::Then,\n            \"else\" => TokenKind::Else,\n            \"true\" => TokenKind::True,\n            \"false\" => TokenKind::False,\n            \"succ\" => TokenKind::Succ,\n            \"pred\" => TokenKind::Pred,\n            \"iszero\" => TokenKind::IsZero,\n            \"zero\" => TokenKind::Nat(0),\n            \"Bool\" => TokenKind::TyBool,\n            \"Nat\" => TokenKind::TyNat,\n            \"Unit\" => TokenKind::TyUnit,\n            \"unit\" => TokenKind::Unit,\n            \"let\" => TokenKind::Let,\n            \"in\" => TokenKind::In,\n            \"fix\" => TokenKind::Fix,\n            \"case\" => TokenKind::Case,\n            \"of\" => TokenKind::Of,\n            \"fold\" => TokenKind::Fold,\n            \"unfold\" => TokenKind::Unfold,\n            \"rec\" => TokenKind::Rec,\n            \"lambda\" => TokenKind::Lambda,\n            \"forall\" => TokenKind::Forall,\n            \"exists\" => TokenKind::Exists,\n            \"pack\" => TokenKind::Pack,\n            \"unpack\" => TokenKind::Unpack,\n            \"as\" => TokenKind::As,\n\n            _ => {\n                if data.starts_with(|ch: char| ch.is_ascii_uppercase()) {\n                    TokenKind::Uppercase(data)\n                } else {\n                    TokenKind::Lowercase(data)\n                }\n            }\n        };\n        Token::new(kind, span)\n    }\n\n    /// Consume the next input character, expecting to match `ch`.\n    /// Return a [`TokenKind::Invalid`] if the next character does not match,\n    /// or the argument `kind` if it does\n    fn eat(&mut self, ch: char, kind: TokenKind) -> Token {\n        let loc = self.current;\n        // Lexer::eat() should only be called internally after calling peek()\n        // so we know that it's safe to unwrap the result of Lexer::consume()\n        let n = self.consume().unwrap();\n        let kind = if n == ch { kind } else { TokenKind::Invalid(n) };\n        Token::new(kind, Span::new(loc, self.current))\n    }\n\n    /// Return the next lexeme in the input as a [`Token`]\n    pub fn lex(&mut self) -> Token {\n        self.consume_delimiter();\n        let next = match self.peek() {\n            Some(ch) => ch,\n            None => return Token::new(TokenKind::Eof, Span::new(self.current, self.current)),\n        };\n        match next {\n            x if x.is_ascii_alphabetic() => self.keyword(),\n            x if x.is_numeric() => self.number(),\n            '(' => self.eat('(', TokenKind::LParen),\n            ')' => self.eat(')', TokenKind::RParen),\n            ';' => self.eat(';', TokenKind::Semicolon),\n            ':' => self.eat(':', TokenKind::Colon),\n            ',' => self.eat(',', TokenKind::Comma),\n            '{' => self.eat('{', TokenKind::LBrace),\n            '}' => self.eat('}', TokenKind::RBrace),\n            '[' => self.eat('[', TokenKind::LSquare),\n            ']' => self.eat(']', TokenKind::RSquare),\n            '\\\\' => self.eat('\\\\', TokenKind::Lambda),\n            'λ' => self.eat('λ', TokenKind::Lambda),\n            '∀' => self.eat('∀', TokenKind::Forall),\n            '∃' => self.eat('∃', TokenKind::Exists),\n            '.' => self.eat('.', TokenKind::Proj),\n            '=' => self.eat('=', TokenKind::Equals),\n            '|' => self.eat('|', TokenKind::Bar),\n            '_' => self.eat('_', TokenKind::Wildcard),\n            '>' => self.eat('>', TokenKind::Gt),\n            '-' => {\n                self.consume();\n                self.eat('>', TokenKind::TyArrow)\n            }\n            ch => self.eat(' ', TokenKind::Invalid(ch)),\n        }\n    }\n}\n\nimpl<'s> Iterator for Lexer<'s> {\n    type Item = Token;\n    fn next(&mut self) -> Option<Self::Item> {\n        match self.lex() {\n            Token {\n                kind: TokenKind::Eof, ..\n            } => None,\n            tok => Some(tok),\n        }\n    }\n}\n\n#[cfg(test)]\nmod test {\n    use super::*;\n    use TokenKind::*;\n    #[test]\n    fn nested() {\n        let input = \"succ(succ(succ(0)))\";\n        let expected = vec![Succ, LParen, Succ, LParen, Succ, LParen, Nat(0), RParen, RParen, RParen];\n        let output = Lexer::new(input.chars())\n            .into_iter()\n            .map(|t| t.kind)\n            .collect::<Vec<TokenKind>>();\n        assert_eq!(expected, output);\n    }\n\n    #[test]\n    fn case() {\n        let input = \"case x of | A _ => true | B x => (\\\\y: Nat. x)\";\n        let expected = vec![\n            Case,\n            Lowercase(\"x\".into()),\n            Of,\n            Bar,\n            Uppercase(\"A\".into()),\n            Wildcard,\n            Equals,\n            Gt,\n            True,\n            Bar,\n            Uppercase(\"B\".into()),\n            Lowercase(\"x\".into()),\n            Equals,\n            Gt,\n            LParen,\n            Lambda,\n            Lowercase(\"y\".into()),\n            Colon,\n            TyNat,\n            Proj,\n            Lowercase(\"x\".into()),\n            RParen,\n        ];\n        let output = Lexer::new(input.chars())\n            .into_iter()\n            .map(|t| t.kind)\n            .collect::<Vec<TokenKind>>();\n        assert_eq!(expected, output);\n    }\n}\n"
  },
  {
    "path": "06_system_f/src/syntax/mod.rs",
    "content": "//! Lexical analysis and recursive descent parser for System F\npub mod lexer;\npub mod parser;\nuse util::span::Span;\n\n#[derive(Clone, Debug, PartialEq, PartialOrd)]\npub enum TokenKind {\n    Uppercase(String),\n    Lowercase(String),\n    Nat(u32),\n    TyNat,\n    TyBool,\n    TyArrow,\n    TyUnit,\n    Unit,\n    True,\n    False,\n    Lambda,\n    Forall,\n    Exists,\n    As,\n    Pack,\n    Unpack,\n    Succ,\n    Pred,\n    If,\n    Then,\n    Else,\n    Let,\n    In,\n    IsZero,\n    Semicolon,\n    Colon,\n    Comma,\n    Proj,\n    LParen,\n    RParen,\n    LBrace,\n    RBrace,\n    LSquare,\n    RSquare,\n    Equals,\n    Bar,\n    Wildcard,\n    Gt,\n    Case,\n    Of,\n    Fix,\n    Fold,\n    Unfold,\n    Rec,\n    Invalid(char),\n    Dummy,\n    Eof,\n}\n\n#[derive(Clone, Debug, PartialEq, PartialOrd)]\npub struct Token {\n    pub kind: TokenKind,\n    pub span: Span,\n}\n\nimpl Token {\n    pub const fn dummy() -> Token {\n        Token {\n            kind: TokenKind::Dummy,\n            span: Span::zero(),\n        }\n    }\n\n    pub const fn new(kind: TokenKind, span: Span) -> Token {\n        Token { kind, span }\n    }\n}\n"
  },
  {
    "path": "06_system_f/src/syntax/parser.rs",
    "content": "use super::lexer::Lexer;\nuse super::{Token, TokenKind};\n\nuse std::collections::VecDeque;\nuse util::diagnostic::Diagnostic;\nuse util::span::*;\n\nuse crate::patterns::{PatVarStack, Pattern};\nuse crate::terms::*;\nuse crate::types::*;\n\n#[derive(Clone, Debug, Default)]\npub struct DeBruijnIndexer {\n    inner: VecDeque<String>,\n}\n\nimpl DeBruijnIndexer {\n    pub fn push(&mut self, hint: String) -> usize {\n        let idx = self.inner.len();\n        self.inner.push_front(hint);\n        idx\n    }\n\n    pub fn pop(&mut self) {\n        self.inner.pop_front();\n    }\n\n    pub fn lookup(&self, key: &str) -> Option<usize> {\n        for (idx, s) in self.inner.iter().enumerate() {\n            if key == s {\n                return Some(idx);\n            }\n        }\n        None\n    }\n\n    pub fn len(&self) -> usize {\n        self.inner.len()\n    }\n}\n\npub struct Parser<'s> {\n    tmvar: DeBruijnIndexer,\n    tyvar: DeBruijnIndexer,\n    diagnostic: Diagnostic<'s>,\n    lexer: Lexer<'s>,\n    span: Span,\n    token: Token,\n}\n\n#[derive(Clone, Debug)]\npub struct Error {\n    pub span: Span,\n    pub tok: Token,\n    pub kind: ErrorKind,\n}\n\n#[derive(Clone, Debug)]\npub enum ErrorKind {\n    ExpectedAtom,\n    ExpectedIdent,\n    ExpectedType,\n    ExpectedPattern,\n    ExpectedToken(TokenKind),\n    UnboundTypeVar,\n    Unknown,\n    Eof,\n}\nimpl<'s> Parser<'s> {\n    /// Create a new [`Parser`] for the input `&str`\n    pub fn new(input: &'s str) -> Parser<'s> {\n        let mut p = Parser {\n            tmvar: DeBruijnIndexer::default(),\n            tyvar: DeBruijnIndexer::default(),\n            diagnostic: Diagnostic::new(input),\n            lexer: Lexer::new(input.chars()),\n            span: Span::default(),\n            token: Token::dummy(),\n        };\n        p.bump();\n        p\n    }\n\n    pub fn diagnostic(self) -> Diagnostic<'s> {\n        self.diagnostic\n    }\n}\n\nimpl<'s> Parser<'s> {\n    /// Kleene Plus combinator\n    fn once_or_more<T, F>(&mut self, func: F, delimiter: TokenKind) -> Result<Vec<T>, Error>\n    where\n        F: Fn(&mut Parser) -> Result<T, Error>,\n    {\n        let mut v = vec![func(self)?];\n        while self.bump_if(&delimiter) {\n            v.push(func(self)?);\n        }\n        Ok(v)\n    }\n\n    /// Expect combinator\n    /// Combinator that must return Ok or a message will be pushed to\n    /// diagnostic. This method should only be called after a token has\n    /// already been bumped.\n    fn once<T, F>(&mut self, func: F, message: &str) -> Result<T, Error>\n    where\n        F: Fn(&mut Parser) -> Result<T, Error>,\n    {\n        match func(self) {\n            Ok(t) => Ok(t),\n            Err(e) => {\n                self.diagnostic.push(message, self.span);\n                Err(e)\n            }\n        }\n    }\n}\n\nimpl<'s> Parser<'s> {\n    fn error<T>(&self, kind: ErrorKind) -> Result<T, Error> {\n        Err(Error {\n            span: self.token.span,\n            tok: self.token.clone(),\n            kind,\n        })\n    }\n\n    fn bump(&mut self) -> TokenKind {\n        let prev = std::mem::replace(&mut self.token, self.lexer.lex());\n        self.span = prev.span;\n        prev.kind\n    }\n\n    fn bump_if(&mut self, kind: &TokenKind) -> bool {\n        if &self.token.kind == kind {\n            self.bump();\n            true\n        } else {\n            false\n        }\n    }\n\n    fn expect(&mut self, kind: TokenKind) -> Result<(), Error> {\n        if self.token.kind == kind {\n            self.bump();\n            Ok(())\n        } else {\n            self.diagnostic.push(\n                format!(\"expected token {:?}, found {:?}\", kind, self.token.kind),\n                self.span,\n            );\n            self.error(ErrorKind::ExpectedToken(kind))\n        }\n    }\n\n    fn kind(&self) -> &TokenKind {\n        &self.token.kind\n    }\n\n    fn ty_variant(&mut self) -> Result<Variant, Error> {\n        let label = self.uppercase_id()?;\n        let ty = match self.ty() {\n            Ok(ty) => ty,\n            _ => Type::Unit,\n        };\n\n        Ok(Variant { label, ty })\n    }\n\n    fn ty_app(&mut self) -> Result<Type, Error> {\n        if !self.bump_if(&TokenKind::LSquare) {\n            return self.error(ErrorKind::ExpectedToken(TokenKind::LSquare));\n        }\n        let ty = self.ty()?;\n        self.expect(TokenKind::RSquare)?;\n        Ok(ty)\n    }\n\n    fn ty_atom(&mut self) -> Result<Type, Error> {\n        match self.kind() {\n            TokenKind::TyBool => {\n                self.bump();\n                Ok(Type::Bool)\n            }\n            TokenKind::TyNat => {\n                self.bump();\n                Ok(Type::Nat)\n            }\n            TokenKind::TyUnit => {\n                self.bump();\n                Ok(Type::Unit)\n            }\n            TokenKind::LParen => {\n                self.bump();\n                let r = self.ty()?;\n                self.expect(TokenKind::RParen)?;\n                Ok(r)\n            }\n            TokenKind::Forall => {\n                self.bump();\n                Ok(Type::Universal(Box::new(self.ty()?)))\n            }\n            TokenKind::Exists => {\n                self.bump();\n                let tvar = self.uppercase_id()?;\n                self.expect(TokenKind::Proj)?;\n                self.tyvar.push(tvar);\n                let xs = Type::Existential(Box::new(self.ty()?));\n                self.tyvar.pop();\n                Ok(xs)\n            }\n            TokenKind::Uppercase(_) => {\n                let ty = self.uppercase_id()?;\n                match self.tyvar.lookup(&ty) {\n                    Some(idx) => Ok(Type::Var(idx)),\n                    None => Ok(Type::Alias(ty)),\n                }\n            }\n            TokenKind::LBrace => {\n                self.bump();\n                let fields = self.once_or_more(|p| p.ty_variant(), TokenKind::Bar)?;\n                self.expect(TokenKind::RBrace)?;\n                Ok(Type::Variant(fields))\n            }\n            _ => self.error(ErrorKind::ExpectedType),\n        }\n    }\n\n    fn ty_tuple(&mut self) -> Result<Type, Error> {\n        if self.bump_if(&TokenKind::LParen) {\n            let mut v = self.once_or_more(|p| p.ty(), TokenKind::Comma)?;\n            self.expect(TokenKind::RParen)?;\n\n            if v.len() > 1 {\n                Ok(Type::Product(v))\n            } else {\n                Ok(v.remove(0))\n            }\n        } else {\n            self.ty_atom()\n        }\n    }\n\n    pub fn ty(&mut self) -> Result<Type, Error> {\n        if self.bump_if(&TokenKind::Rec) {\n            let name = self.uppercase_id()?;\n            self.expect(TokenKind::Equals)?;\n            self.tyvar.push(name);\n            let ty = self.ty()?;\n            self.tyvar.pop();\n            return Ok(Type::Rec(Box::new(ty)));\n        }\n\n        let mut lhs = self.ty_tuple()?;\n        if let TokenKind::TyArrow = self.kind() {\n            self.bump();\n            while let Ok(rhs) = self.ty() {\n                lhs = Type::Arrow(Box::new(lhs), Box::new(rhs));\n                if let TokenKind::TyArrow = self.kind() {\n                    self.bump();\n                } else {\n                    break;\n                }\n            }\n        }\n        Ok(lhs)\n    }\n\n    fn tyabs(&mut self) -> Result<Term, Error> {\n        let tyvar = self.uppercase_id()?;\n        let sp = self.span;\n        let ty = Box::new(Type::Var(self.tyvar.push(tyvar)));\n        let body = self.once(|p| p.parse(), \"abstraction body required\")?;\n        Ok(Term::new(Kind::TyAbs(Box::new(body)), sp + self.span))\n    }\n\n    fn tmabs(&mut self) -> Result<Term, Error> {\n        let tmvar = self.lowercase_id()?;\n        let sp = self.span;\n        self.tmvar.push(tmvar);\n\n        self.expect(TokenKind::Colon)?;\n        let ty = self.once(|p| p.ty(), \"type annotation required in abstraction\")?;\n        self.expect(TokenKind::Proj)?;\n        let body = self.once(|p| p.parse(), \"abstraction body required\")?;\n        self.tmvar.pop();\n        Ok(Term::new(Kind::Abs(Box::new(ty), Box::new(body)), sp + self.span))\n    }\n\n    fn fold(&mut self) -> Result<Term, Error> {\n        self.expect(TokenKind::Fold)?;\n        let sp = self.span;\n        let ty = self.once(|p| p.ty(), \"type annotation required after `fold`\")?;\n        let tm = self.once(|p| p.parse(), \"term required after `fold`\")?;\n        Ok(Term::new(Kind::Fold(Box::new(ty), Box::new(tm)), sp + self.span))\n    }\n\n    fn unfold(&mut self) -> Result<Term, Error> {\n        self.expect(TokenKind::Unfold)?;\n        let sp = self.span;\n        let ty = self.once(|p| p.ty(), \"type annotation required after `unfold`\")?;\n        let tm = self.once(|p| p.parse(), \"term required after `unfold`\")?;\n        Ok(Term::new(Kind::Unfold(Box::new(ty), Box::new(tm)), sp + self.span))\n    }\n\n    fn fix(&mut self) -> Result<Term, Error> {\n        let sp = self.span;\n        self.expect(TokenKind::Fix)?;\n        let t = self.parse()?;\n        Ok(Term::new(Kind::Fix(Box::new(t)), sp + self.span))\n    }\n\n    fn letexpr(&mut self) -> Result<Term, Error> {\n        let sp = self.span;\n        self.expect(TokenKind::Let)?;\n        let mut pat = self.once(|p| p.pattern(), \"missing pattern\")?;\n\n        self.expect(TokenKind::Equals)?;\n\n        let t1 = self.once(|p| p.parse(), \"let binder required\")?;\n        let len = self.tmvar.len();\n        for var in PatVarStack::collect(&mut pat).into_iter().rev() {\n            self.tmvar.push(var);\n        }\n        self.expect(TokenKind::In)?;\n        let t2 = self.once(|p| p.parse(), \"let body required\")?;\n        while self.tmvar.len() > len {\n            self.tmvar.pop();\n        }\n        Ok(Term::new(\n            Kind::Let(Box::new(pat), Box::new(t1), Box::new(t2)),\n            sp + self.span,\n        ))\n    }\n\n    fn lambda(&mut self) -> Result<Term, Error> {\n        self.expect(TokenKind::Lambda)?;\n        match self.kind() {\n            TokenKind::Uppercase(_) => self.tyabs(),\n            TokenKind::Lowercase(_) => self.tmabs(),\n            _ => {\n                self.diagnostic\n                    .push(\"expected identifier after lambda, found\".to_string(), self.span);\n                self.error(ErrorKind::ExpectedIdent)\n            }\n        }\n    }\n\n    fn paren(&mut self) -> Result<Term, Error> {\n        self.expect(TokenKind::LParen)?;\n        let span = self.span;\n        let mut n = self.once_or_more(|p| p.parse(), TokenKind::Comma)?;\n        self.expect(TokenKind::RParen)?;\n        if n.len() > 1 {\n            Ok(Term::new(Kind::Product(n), span + self.span))\n        } else {\n            // invariant, n.len() >= 1\n            Ok(n.remove(0))\n        }\n    }\n\n    fn uppercase_id(&mut self) -> Result<String, Error> {\n        match self.bump() {\n            TokenKind::Uppercase(s) => Ok(s),\n            tk => {\n                self.diagnostic\n                    .push(format!(\"expected uppercase identifier, found {:?}\", tk), self.span);\n                self.error(ErrorKind::ExpectedIdent)\n            }\n        }\n    }\n\n    fn lowercase_id(&mut self) -> Result<String, Error> {\n        match self.bump() {\n            TokenKind::Lowercase(s) => Ok(s),\n            tk => {\n                self.diagnostic\n                    .push(format!(\"expected lowercase identifier, found {:?}\", tk), self.span);\n                self.error(ErrorKind::ExpectedIdent)\n            }\n        }\n    }\n\n    fn literal(&mut self) -> Result<Term, Error> {\n        let lit = match self.bump() {\n            TokenKind::Nat(x) => Literal::Nat(x),\n            TokenKind::True => Literal::Bool(true),\n            TokenKind::False => Literal::Bool(false),\n            TokenKind::Unit => Literal::Unit,\n            _ => return self.error(ErrorKind::Unknown),\n        };\n        Ok(Term::new(Kind::Lit(lit), self.span))\n    }\n\n    fn primitive(&mut self) -> Result<Term, Error> {\n        let p = match self.bump() {\n            TokenKind::IsZero => Primitive::IsZero,\n            TokenKind::Succ => Primitive::Succ,\n            TokenKind::Pred => Primitive::Pred,\n            _ => return self.error(ErrorKind::Unknown),\n        };\n        Ok(Term::new(Kind::Primitive(p), self.span))\n    }\n\n    /// Important to note that this function can push variable names to the\n    /// de Bruijn naming context. Callers of this function are responsible for\n    /// making sure that the stack is balanced afterwards\n    fn pat_atom(&mut self) -> Result<Pattern, Error> {\n        match self.kind() {\n            TokenKind::LParen => self.pattern(),\n            TokenKind::Wildcard => {\n                self.bump();\n                Ok(Pattern::Any)\n            }\n            TokenKind::Uppercase(_) => {\n                let tycon = self.uppercase_id()?;\n                let inner = match self.pattern() {\n                    Ok(pat) => pat,\n                    _ => Pattern::Any,\n                };\n                Ok(Pattern::Constructor(tycon, Box::new(inner)))\n            }\n            TokenKind::Lowercase(_) => {\n                let var = self.lowercase_id()?;\n                // self.tmvar.push(var.clone());\n                Ok(Pattern::Variable(var))\n            }\n            TokenKind::True => {\n                self.bump();\n                Ok(Pattern::Literal(Literal::Bool(true)))\n            }\n            TokenKind::False => {\n                self.bump();\n                Ok(Pattern::Literal(Literal::Bool(false)))\n            }\n            TokenKind::Unit => {\n                self.bump();\n                Ok(Pattern::Literal(Literal::Unit))\n            }\n            TokenKind::Nat(n) => {\n                // O great borrowck, may this humble offering appease thee\n                let n = *n;\n                self.bump();\n                Ok(Pattern::Literal(Literal::Nat(n)))\n            }\n            _ => self.error(ErrorKind::ExpectedPattern),\n        }\n    }\n\n    fn pattern(&mut self) -> Result<Pattern, Error> {\n        match self.kind() {\n            TokenKind::LParen => {\n                self.bump();\n                let mut v = self.once_or_more(|p| p.pat_atom(), TokenKind::Comma)?;\n                self.expect(TokenKind::RParen)?;\n                if v.len() > 1 {\n                    Ok(Pattern::Product(v))\n                } else {\n                    // v must have length == 1, else we would have early returned\n                    assert_eq!(v.len(), 1);\n                    Ok(v.remove(0))\n                }\n            }\n            _ => self.pat_atom(),\n        }\n    }\n\n    fn case_arm(&mut self) -> Result<Arm, Error> {\n        // match self.kind() {\n        //     TokenKind::Bar => self.bump(),\n        //     _ => return self.error(ErrorKind::ExpectedToken(TokenKind::Bar)),\n        // };\n\n        // We don't track the length of the debruijn index in other methods,\n        // but we have a couple branches where variables might be bound,\n        // and this is pretty much the easiest way of doing it\n\n        let len = self.tmvar.len();\n        let mut span = self.span;\n\n        let mut pat = self.once(|p| p.pattern(), \"missing pattern\")?;\n\n        for var in PatVarStack::collect(&mut pat).into_iter().rev() {\n            self.tmvar.push(var);\n        }\n\n        self.expect(TokenKind::Equals)?;\n        self.expect(TokenKind::Gt)?;\n\n        let term = Box::new(self.once(|p| p.application(), \"missing case term\")?);\n\n        self.bump_if(&TokenKind::Comma);\n\n        // Unbind any variables from the parsing context\n        while self.tmvar.len() > len {\n            self.tmvar.pop();\n        }\n\n        span = span + self.span;\n\n        Ok(Arm { span, pat, term })\n    }\n\n    fn case(&mut self) -> Result<Term, Error> {\n        self.expect(TokenKind::Case)?;\n        let span = self.span;\n        let expr = self.once(|p| p.parse(), \"missing case expression\")?;\n        self.expect(TokenKind::Of)?;\n\n        self.bump_if(&TokenKind::Bar);\n        let arms = self.once_or_more(|p| p.case_arm(), TokenKind::Bar)?;\n\n        Ok(Term::new(Kind::Case(Box::new(expr), arms), span + self.span))\n    }\n\n    fn injection(&mut self) -> Result<Term, Error> {\n        let label = self.uppercase_id()?;\n        let sp = self.span;\n        let term = match self.parse() {\n            Ok(t) => t,\n            _ => Term::new(Kind::Lit(Literal::Unit), self.span),\n        };\n\n        self.expect(TokenKind::Of)?;\n        let ty = self.ty()?;\n        Ok(Term::new(\n            Kind::Injection(label, Box::new(term), Box::new(ty)),\n            sp + self.span,\n        ))\n    }\n\n    fn pack(&mut self) -> Result<Term, Error> {\n        self.expect(TokenKind::Pack)?;\n        let sp = self.span;\n        let witness = self.ty()?;\n        self.expect(TokenKind::Comma)?;\n        let evidence = self.parse()?;\n        self.expect(TokenKind::As)?;\n        let signature = self.ty()?;\n\n        Ok(Term::new(\n            Kind::Pack(Box::new(witness), Box::new(evidence), Box::new(signature)),\n            sp + self.span,\n        ))\n    }\n\n    fn unpack(&mut self) -> Result<Term, Error> {\n        self.expect(TokenKind::Unpack)?;\n        let sp = self.span;\n        let package = self.parse()?;\n        self.expect(TokenKind::As)?;\n\n        let tyvar = self.uppercase_id()?;\n        self.expect(TokenKind::Comma)?;\n        let name = self.lowercase_id()?;\n        self.tyvar.push(tyvar);\n        self.tmvar.push(name);\n        self.expect(TokenKind::In)?;\n        let expr = self.parse()?;\n        self.tmvar.pop();\n        self.tyvar.pop();\n        Ok(Term::new(\n            Kind::Unpack(Box::new(package), Box::new(expr)),\n            sp + self.span,\n        ))\n    }\n\n    fn atom(&mut self) -> Result<Term, Error> {\n        match self.kind() {\n            TokenKind::LParen => self.paren(),\n            TokenKind::Fix => self.fix(),\n            TokenKind::Fold => self.fold(),\n            TokenKind::Unfold => self.unfold(),\n            TokenKind::Pack => self.pack(),\n            TokenKind::Unpack => self.unpack(),\n            TokenKind::IsZero | TokenKind::Succ | TokenKind::Pred => self.primitive(),\n            TokenKind::Uppercase(_) => self.injection(),\n            TokenKind::Lowercase(s) => {\n                let var = self.lowercase_id()?;\n                match self.tmvar.lookup(&var) {\n                    Some(idx) => Ok(Term::new(Kind::Var(idx), self.span)),\n                    None => {\n                        self.diagnostic.push(format!(\"unbound variable {}\", var), self.span);\n                        self.error(ErrorKind::UnboundTypeVar)\n                    }\n                }\n            }\n            TokenKind::Nat(_) | TokenKind::True | TokenKind::False | TokenKind::Unit => self.literal(),\n            TokenKind::Eof => self.error(ErrorKind::Eof),\n            TokenKind::Semicolon => {\n                self.bump();\n                self.error(ErrorKind::ExpectedAtom)\n            }\n            _ => self.error(ErrorKind::ExpectedAtom),\n        }\n    }\n\n    /// Parse a term of form:\n    /// projection = atom `.` projection\n    /// projection = atom\n    fn projection(&mut self) -> Result<Term, Error> {\n        let atom = self.atom()?;\n        if self.bump_if(&TokenKind::Proj) {\n            let idx = match self.bump() {\n                TokenKind::Nat(idx) => idx,\n                _ => {\n                    self.diagnostic\n                        .push(format!(\"expected integer index after {}\", atom), self.span);\n                    return self.error(ErrorKind::ExpectedToken(TokenKind::Proj));\n                }\n            };\n            let sp = atom.span + self.span;\n            Ok(Term::new(Kind::Projection(Box::new(atom), idx as usize), sp))\n        } else {\n            Ok(atom)\n        }\n    }\n\n    /// Parse an application of form:\n    /// application = atom application' | atom\n    /// application' = atom application' | empty\n    fn application(&mut self) -> Result<Term, Error> {\n        let mut app = self.projection()?;\n\n        loop {\n            let sp = app.span;\n            if let Ok(ty) = self.ty_app() {\n                // Full type inference for System F is undecidable\n                // Additionally, even partial type reconstruction,\n                // where only type application types are erased is also\n                // undecidable, see TaPL 23.6.2, Boehm 1985, 1989\n                //\n                // Partial erasure rules:\n                // erasep(x) = x\n                // erasep(λx:T. t) = λx:T. erasep(t)\n                // erasep(t1 t2) = erasep(t1) erasep(t2)\n                // erasep(λX. t) = λX. erasep(t)\n                // erasep(t T) = erasep(t) []      <--- erasure of TyApp\n                app = Term::new(Kind::TyApp(Box::new(app), Box::new(ty)), sp + self.span);\n            } else if let Ok(term) = self.projection() {\n                app = Term::new(Kind::App(Box::new(app), Box::new(term)), sp + self.span);\n            } else {\n                break;\n            }\n        }\n        Ok(app)\n    }\n\n    pub fn parse(&mut self) -> Result<Term, Error> {\n        match self.kind() {\n            TokenKind::Case => self.case(),\n            TokenKind::Lambda => self.lambda(),\n            TokenKind::Let => self.letexpr(),\n            _ => self.application(),\n        }\n    }\n}\n"
  },
  {
    "path": "06_system_f/src/terms/mod.rs",
    "content": "//! Representation lambda calculus terms\nuse crate::patterns::Pattern;\nuse crate::types::Type;\nuse std::fmt;\nuse util::span::Span;\npub mod visit;\n\n#[derive(Clone, PartialEq, PartialOrd)]\npub struct Term {\n    pub span: Span,\n    pub kind: Kind,\n}\n\n/// Primitive functions supported by this implementation\n#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]\npub enum Primitive {\n    Succ,\n    Pred,\n    IsZero,\n}\n\n/// Abstract syntax of the parametric polymorphic lambda calculus\n#[derive(Clone, Debug, PartialEq, PartialOrd)]\npub enum Kind {\n    /// A literal value\n    Lit(Literal),\n    /// A bound variable, represented by it's de Bruijn index\n    Var(usize),\n    /// Fixpoint operator/Y combinator\n    Fix(Box<Term>),\n\n    Primitive(Primitive),\n\n    /// Injection into a sum type\n    /// fields: type constructor tag, term, and sum type\n    Injection(String, Box<Term>, Box<Type>),\n\n    /// Product type (tuple)\n    Product(Vec<Term>),\n    /// Projection into a term\n    Projection(Box<Term>, usize),\n\n    /// A case expr, with case arms\n    Case(Box<Term>, Vec<Arm>),\n\n    Let(Box<Pattern>, Box<Term>, Box<Term>),\n    /// A lambda abstraction\n    Abs(Box<Type>, Box<Term>),\n    /// Application of a term to another term\n    App(Box<Term>, Box<Term>),\n    /// Type abstraction\n    TyAbs(Box<Term>),\n    /// Type application\n    TyApp(Box<Term>, Box<Type>),\n\n    Fold(Box<Type>, Box<Term>),\n    Unfold(Box<Type>, Box<Term>),\n\n    /// Introduce an existential type\n    /// { *Ty1, Term } as {∃X.Ty}\n    /// essentially, concrete representation as interface\n    Pack(Box<Type>, Box<Term>, Box<Type>),\n    /// Unpack an existential type\n    /// open {∃X, bind} in body -- X is bound as a TyVar, and bind as Var(0)\n    /// Eliminate an existential type\n    Unpack(Box<Term>, Box<Term>),\n}\n\n/// Arm of a case expression\n#[derive(Clone, Debug, PartialEq, PartialOrd)]\npub struct Arm {\n    pub span: Span,\n    pub pat: Pattern,\n    pub term: Box<Term>,\n}\n\n/// Constant literal expression or pattern\n#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Eq, Hash)]\npub enum Literal {\n    Unit,\n    Bool(bool),\n    Nat(u32),\n}\n\nimpl Term {\n    pub fn new(kind: Kind, span: Span) -> Term {\n        Term { span, kind }\n    }\n\n    #[allow(dead_code)]\n    pub const fn unit() -> Term {\n        Term {\n            span: Span::dummy(),\n            kind: Kind::Lit(Literal::Unit),\n        }\n    }\n\n    #[allow(dead_code)]\n    #[inline]\n    pub fn span(&self) -> Span {\n        self.span\n    }\n\n    #[inline]\n    pub fn kind(&self) -> &Kind {\n        &self.kind\n    }\n}\n\nimpl fmt::Display for Literal {\n    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n        match self {\n            Literal::Nat(n) => write!(f, \"{}\", n),\n            Literal::Bool(b) => write!(f, \"{}\", b),\n            Literal::Unit => write!(f, \"unit\"),\n        }\n    }\n}\n\nimpl fmt::Display for Term {\n    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n        match &self.kind {\n            Kind::Lit(lit) => write!(f, \"{}\", lit),\n            Kind::Var(v) => write!(f, \"#{}\", v),\n            Kind::Abs(ty, term) => write!(f, \"(λ_:{:?}. {})\", ty, term),\n            Kind::Fix(term) => write!(f, \"Fix {:?}\", term),\n            Kind::Primitive(p) => write!(f, \"{:?}\", p),\n            Kind::Injection(label, tm, ty) => write!(f, \"{}({})\", label, tm),\n            Kind::Projection(term, idx) => write!(f, \"{}.{}\", term, idx),\n            Kind::Product(terms) => write!(\n                f,\n                \"({})\",\n                terms\n                    .iter()\n                    .map(|t| format!(\"{}\", t))\n                    .collect::<Vec<String>>()\n                    .join(\",\")\n            ),\n            Kind::Case(term, arms) => {\n                writeln!(f, \"case {} of\", term)?;\n                for arm in arms {\n                    writeln!(f, \"\\t| {:?} => {},\", arm.pat, arm.term)?;\n                }\n                write!(f, \"\")\n            }\n            Kind::Let(pat, t1, t2) => write!(f, \"let {:?} = {} in {}\", pat, t1, t2),\n            Kind::App(t1, t2) => write!(f, \"({} {})\", t1, t2),\n            Kind::TyAbs(term) => write!(f, \"(λTy {})\", term),\n            Kind::TyApp(term, ty) => write!(f, \"({} [{:?}])\", term, ty),\n            Kind::Fold(ty, term) => write!(f, \"fold [{:?}] {}\", ty, term),\n            Kind::Unfold(ty, term) => write!(f, \"unfold [{:?}] {}\", ty, term),\n            Kind::Pack(witness, body, sig) => write!(f, \"[|pack {{*{:?}, {}}} as {:?} |]\", witness, body, sig),\n            Kind::Unpack(m, n) => write!(f, \"unpack {} as {}\", m, n),\n        }\n    }\n}\n\nimpl fmt::Debug for Term {\n    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n        write!(f, \"{:?}\", self.kind)\n    }\n}\n\n#[cfg(test)]\nmod test {\n    use super::*;\n\n    #[test]\n    fn pattern_matches() {\n        let ty = Type::Variant(vec![\n            variant!(\"A\", Type::Nat),\n            variant!(\"B\", Type::Product(vec![Type::Nat, Type::Bool])),\n        ]);\n\n        let a_pats = vec![con!(\"A\", Pattern::Any), con!(\"A\", num!(9)), con!(\"A\", num!(10))];\n\n        let b_pats = vec![\n            con!(\"B\", Pattern::Any),\n            con!(\"B\", prod!(num!(1), boolean!(true))),\n            con!(\"B\", prod!(Pattern::Any, boolean!(false))),\n        ];\n\n        let res = [true, false, true];\n\n        let a = inj!(\"A\", nat!(10), ty.clone());\n        let b = inj!(\"B\", tuple!(nat!(1), lit!(false)), ty.clone());\n\n        for (pat, result) in a_pats.iter().zip(&res) {\n            assert_eq!(pat.matches(&a), *result);\n        }\n\n        for (pat, result) in b_pats.iter().zip(&res) {\n            assert_eq!(pat.matches(&b), *result, \"{:?}\", pat);\n        }\n    }\n}\n"
  },
  {
    "path": "06_system_f/src/terms/visit.rs",
    "content": "use crate::patterns::{Pattern, PatternCount};\nuse crate::terms::{Arm, Kind, Primitive, Term};\nuse crate::types::Type;\nuse crate::visit::{MutTermVisitor, MutTypeVisitor};\nuse util::span::Span;\n\npub struct Shift {\n    cutoff: usize,\n    shift: isize,\n}\n\nimpl Shift {\n    pub const fn new(shift: isize) -> Shift {\n        Shift { cutoff: 0, shift }\n    }\n}\n\nimpl MutTermVisitor for Shift {\n    fn visit_var(&mut self, sp: &mut Span, var: &mut usize) {\n        if *var >= self.cutoff {\n            *var = (*var as isize + self.shift) as usize;\n        }\n    }\n\n    fn visit_abs(&mut self, sp: &mut Span, ty: &mut Type, term: &mut Term) {\n        self.cutoff += 1;\n        self.visit(term);\n        self.cutoff -= 1;\n    }\n\n    fn visit_let(&mut self, sp: &mut Span, pat: &mut Pattern, t1: &mut Term, t2: &mut Term) {\n        self.visit(t1);\n        let c = PatternCount::collect(pat);\n        self.cutoff += c;\n        self.visit(t2);\n        self.cutoff -= c;\n    }\n\n    fn visit_case(&mut self, sp: &mut Span, term: &mut Term, arms: &mut Vec<Arm>) {\n        self.visit(term);\n        for arm in arms {\n            let c = PatternCount::collect(&mut arm.pat);\n            self.cutoff += c;\n            self.visit(&mut arm.term);\n            self.cutoff -= c;\n        }\n    }\n\n    fn visit_unpack(&mut self, _: &mut Span, package: &mut Term, term: &mut Term) {\n        self.visit(package);\n        self.cutoff += 1;\n        self.visit(term);\n        self.cutoff -= 1;\n    }\n}\n\npub struct Subst {\n    cutoff: usize,\n    term: Term,\n}\n\nimpl Subst {\n    pub fn new(term: Term) -> Subst {\n        Subst { cutoff: 0, term }\n    }\n}\n\nimpl MutTermVisitor for Subst {\n    fn visit_abs(&mut self, sp: &mut Span, ty: &mut Type, term: &mut Term) {\n        self.cutoff += 1;\n        self.visit(term);\n        self.cutoff -= 1;\n    }\n\n    fn visit_let(&mut self, sp: &mut Span, pat: &mut Pattern, t1: &mut Term, t2: &mut Term) {\n        self.visit(t1);\n        let c = PatternCount::collect(pat);\n        self.cutoff += c;\n        self.visit(t2);\n        self.cutoff -= c;\n    }\n\n    fn visit_case(&mut self, sp: &mut Span, term: &mut Term, arms: &mut Vec<Arm>) {\n        self.visit(term);\n        for arm in arms {\n            let c = PatternCount::collect(&mut arm.pat);\n            self.cutoff += c;\n            self.visit(&mut arm.term);\n            self.cutoff -= c;\n        }\n    }\n\n    fn visit_unpack(&mut self, _: &mut Span, package: &mut Term, term: &mut Term) {\n        self.visit(package);\n        self.cutoff += 1;\n        self.visit(term);\n        self.cutoff -= 1;\n    }\n\n    fn visit(&mut self, term: &mut Term) {\n        let sp = &mut term.span;\n        match &mut term.kind {\n            Kind::Var(v) if *v == self.cutoff => {\n                Shift::new(self.cutoff as isize).visit(&mut self.term);\n                *term = self.term.clone();\n            }\n            _ => self.walk(term),\n        }\n    }\n}\n\npub struct TyTermSubst {\n    cutoff: usize,\n    ty: Type,\n}\n\nimpl TyTermSubst {\n    pub fn new(ty: Type) -> TyTermSubst {\n        use crate::types::visit::*;\n        let mut ty = ty;\n        Shift::new(1).visit(&mut ty);\n        TyTermSubst { cutoff: 0, ty }\n    }\n\n    fn visit_ty(&mut self, ty: &mut Type) {\n        let mut s = crate::types::visit::Subst {\n            cutoff: self.cutoff,\n            ty: self.ty.clone(),\n        };\n        s.visit(ty);\n    }\n}\n\nimpl MutTermVisitor for TyTermSubst {\n    fn visit_abs(&mut self, sp: &mut Span, ty: &mut Type, term: &mut Term) {\n        // self.cutoff += 1;\n        self.visit_ty(ty);\n        self.visit(term);\n        // self.cutoff -= 1;\n    }\n\n    fn visit_tyapp(&mut self, sp: &mut Span, term: &mut Term, ty: &mut Type) {\n        self.visit_ty(ty);\n        self.visit(term);\n    }\n\n    fn visit_tyabs(&mut self, sp: &mut Span, term: &mut Term) {\n        self.cutoff += 1;\n        self.visit(term);\n        self.cutoff -= 1;\n    }\n\n    fn visit_fold(&mut self, sp: &mut Span, ty: &mut Type, term: &mut Term) {\n        self.visit_ty(ty);\n        self.visit(term);\n    }\n\n    fn visit_unfold(&mut self, sp: &mut Span, ty: &mut Type, term: &mut Term) {\n        self.visit_ty(ty);\n        self.visit(term);\n    }\n\n    fn visit_unpack(&mut self, _: &mut Span, package: &mut Term, term: &mut Term) {\n        self.visit(package);\n        self.cutoff += 1;\n        self.visit(term);\n        self.cutoff -= 1;\n    }\n\n    fn visit_pack(&mut self, _: &mut Span, wit: &mut Type, body: &mut Term, sig: &mut Type) {\n        self.visit_ty(wit);\n        self.visit(body);\n        self.visit_ty(sig);\n    }\n\n    fn visit_injection(&mut self, sp: &mut Span, label: &mut String, term: &mut Term, ty: &mut Type) {\n        self.visit_ty(ty);\n        self.visit(term);\n    }\n}\n\n/// Visitor for handling recursive variants automatically, by inserting a\n/// fold term\n///\n/// Transform an [`Injection`] term of form: `Label tm of Rec(u.T)` into\n/// `fold [u.T] Label tm of [X->u.T] T`\npub struct InjRewriter;\n\nimpl MutTermVisitor for InjRewriter {\n    fn visit(&mut self, term: &mut Term) {\n        match &mut term.kind {\n            Kind::Injection(label, val, ty) => {\n                match *ty.clone() {\n                    Type::Rec(inner) => {\n                        let ty_prime = crate::types::subst(*ty.clone(), *inner.clone());\n                        let rewrite_ty = Term::new(\n                            Kind::Injection(label.clone(), val.clone(), Box::new(ty_prime)),\n                            term.span,\n                        );\n\n                        *term = Term::new(Kind::Fold(ty.clone(), Box::new(rewrite_ty)), term.span);\n                    }\n                    _ => {}\n                }\n                self.walk(term);\n            }\n            _ => self.walk(term),\n        }\n    }\n}\n"
  },
  {
    "path": "06_system_f/src/types/mod.rs",
    "content": "//! Typechecking of the simply typed lambda calculus with parametric\n//! polymorphism\npub mod patterns;\npub mod visit;\nuse crate::diagnostics::*;\nuse crate::terms::{Kind, Literal, Primitive, Term};\nuse crate::visit::{MutTermVisitor, MutTypeVisitor};\nuse std::collections::{HashMap, VecDeque};\nuse std::fmt;\nuse util::span::Span;\nuse visit::{Shift, Subst};\n\n#[derive(Clone, PartialEq, PartialOrd, Eq, Hash)]\npub enum Type {\n    Unit,\n    Nat,\n    Bool,\n    Alias(String),\n    Var(usize),\n    Variant(Vec<Variant>),\n    Product(Vec<Type>),\n    Arrow(Box<Type>, Box<Type>),\n    Universal(Box<Type>),\n    Existential(Box<Type>),\n    Rec(Box<Type>),\n}\n\n#[derive(Clone, PartialEq, PartialOrd, Eq, Hash)]\npub struct Variant {\n    pub label: String,\n    pub ty: Type,\n}\n\n#[derive(Clone, Debug, PartialEq, PartialOrd)]\npub struct TypeError {\n    pub span: Span,\n    pub kind: TypeErrorKind,\n}\n\n#[derive(Clone, Debug, PartialEq, PartialOrd)]\npub enum TypeErrorKind {\n    ParameterMismatch(Box<Type>, Box<Type>, Span),\n\n    InvalidProjection,\n    NotArrow,\n    NotUniversal,\n    NotVariant,\n    NotProduct,\n    NotRec,\n    IncompatibleArms,\n    InvalidPattern,\n    NotExhaustive,\n    UnreachablePattern,\n    UnboundVariable(usize),\n}\n\n#[derive(Clone, Debug, Default, PartialEq)]\npub struct Context {\n    stack: VecDeque<Type>,\n    map: HashMap<String, Type>,\n}\n\nimpl Context {\n    fn push(&mut self, ty: Type) {\n        self.stack.push_front(ty);\n    }\n\n    fn pop(&mut self) {\n        self.stack.pop_front().expect(\"Context::pop() with empty type stack\");\n    }\n\n    fn find(&self, idx: usize) -> Option<&Type> {\n        self.stack.get(idx)\n    }\n\n    pub fn alias(&mut self, alias: String, ty: Type) {\n        self.map.insert(alias, ty);\n    }\n\n    fn aliaser(&self) -> Aliaser<'_> {\n        Aliaser { map: &self.map }\n    }\n\n    pub fn de_alias(&mut self, term: &mut Term) {\n        crate::visit::MutTermVisitor::visit(self, term)\n    }\n}\n\n/// Helper function for extracting type from a variant\npub fn variant_field<'vs>(var: &'vs [Variant], label: &str, span: Span) -> Result<&'vs Type, Diagnostic> {\n    for f in var {\n        if label == f.label {\n            return Ok(&f.ty);\n        }\n    }\n    Err(Diagnostic::error(\n        span,\n        format!(\"constructor {} doesn't appear in variant fields\", label),\n    ))\n\n    // Err(TypeError {\n    //     span,\n    //     kind: TypeErrorKind::NotVariant,\n    // })\n}\n\nimpl Context {\n    pub fn type_check(&mut self, term: &Term) -> Result<Type, Diagnostic> {\n        // dbg!(&self.stack);\n\n        // println!(\"{}\", term);\n        match term.kind() {\n            Kind::Lit(Literal::Unit) => Ok(Type::Unit),\n            Kind::Lit(Literal::Bool(_)) => Ok(Type::Bool),\n            Kind::Lit(Literal::Nat(_)) => Ok(Type::Nat),\n            Kind::Var(idx) => self\n                .find(*idx)\n                .cloned()\n                .ok_or_else(|| Diagnostic::error(term.span, format!(\"unbound variable {}\", idx))),\n\n            Kind::Abs(ty, t2) => {\n                self.push(*ty.clone());\n                let ty2 = self.type_check(t2)?;\n                // Shift::new(-1).visit(&mut ty2);\n                self.pop();\n                Ok(Type::Arrow(ty.clone(), Box::new(ty2)))\n            }\n            Kind::App(t1, t2) => {\n                let ty1 = self.type_check(t1)?;\n                let ty2 = self.type_check(t2)?;\n                match ty1 {\n                    Type::Arrow(ty11, ty12) => {\n                        if *ty11 == ty2 {\n                            Ok(*ty12)\n                        } else {\n                            let d = Diagnostic::error(term.span, \"Type mismatch in application\")\n                                .message(t1.span, format!(\"Abstraction requires type {:?}\", ty11))\n                                .message(t2.span, format!(\"Value has a type of {:?}\", ty2));\n                            Err(d)\n                        }\n                    }\n                    _ => Err(Diagnostic::error(term.span, \"Expected arrow type!\")\n                        .message(t1.span, format!(\"operator has type {:?}\", ty1))),\n                }\n            }\n            Kind::Fix(inner) => {\n                let ty = self.type_check(inner)?;\n                match ty {\n                    Type::Arrow(ty1, ty2) => {\n                        if ty1 == ty2 {\n                            Ok(*ty1)\n                        } else {\n                            let d = Diagnostic::error(term.span, \"Type mismatch in fix term\")\n                                .message(inner.span, format!(\"Abstraction requires type {:?}->{:?}\", ty1, ty1));\n                            Err(d)\n                        }\n                    }\n                    _ => Err(Diagnostic::error(term.span, \"Expected arrow type!\")\n                        .message(inner.span, format!(\"operator has type {:?}\", ty))),\n                }\n            }\n            Kind::Primitive(prim) => match prim {\n                Primitive::IsZero => Ok(Type::Arrow(Box::new(Type::Nat), Box::new(Type::Bool))),\n                _ => Ok(Type::Arrow(Box::new(Type::Nat), Box::new(Type::Nat))),\n            },\n            Kind::Injection(label, tm, ty) => match ty.as_ref() {\n                Type::Variant(fields) => {\n                    for f in fields {\n                        if label == &f.label {\n                            let ty_ = self.type_check(tm)?;\n                            if ty_ == f.ty {\n                                return Ok(*ty.clone());\n                            } else {\n                                let d = Diagnostic::error(term.span, \"Invalid associated type in variant\").message(\n                                    tm.span,\n                                    format!(\"variant {} requires type {:?}, but this is {:?}\", label, f.ty, ty_),\n                                );\n                                return Err(d);\n                            }\n                        }\n                    }\n                    Err(Diagnostic::error(\n                        term.span,\n                        format!(\n                            \"constructor {} does not belong to the variant {:?}\",\n                            label,\n                            fields\n                                .iter()\n                                .map(|f| f.label.clone())\n                                .collect::<Vec<String>>()\n                                .join(\" | \")\n                        ),\n                    ))\n                }\n                _ => Err(Diagnostic::error(\n                    term.span,\n                    format!(\"Cannot injection {} into non-variant type {:?}\", label, ty),\n                )),\n            },\n            Kind::Projection(term, idx) => match self.type_check(term)? {\n                Type::Product(types) => match types.get(*idx) {\n                    Some(ty) => Ok(ty.clone()),\n                    None => Err(Diagnostic::error(\n                        term.span,\n                        format!(\"{} is out of range for product of length {}\", idx, types.len()),\n                    )),\n                },\n                ty => Err(Diagnostic::error(\n                    term.span,\n                    format!(\"Cannot project on non-product type {:?}\", ty),\n                )),\n            },\n            Kind::Product(terms) => Ok(Type::Product(\n                terms.iter().map(|t| self.type_check(t)).collect::<Result<_, _>>()?,\n            )),\n            Kind::Let(pat, t1, t2) => {\n                let ty = self.type_check(t1)?;\n                if !self.pattern_type_eq(&pat, &ty) {\n                    return Err(Diagnostic::error(\n                        t1.span,\n                        format!(\"pattern does not match type of binder\"),\n                    ));\n                }\n\n                let height = self.stack.len();\n\n                let binds = crate::patterns::PatTyStack::collect(&ty, &pat);\n                for b in binds.into_iter().rev() {\n                    self.push(b.clone());\n                }\n\n                let y = self.type_check(t2);\n\n                while self.stack.len() > height {\n                    self.pop();\n                }\n\n                y\n            }\n            Kind::TyAbs(term) => {\n                self.stack.iter_mut().for_each(|ty| match ty {\n                    Type::Var(v) => *v += 1,\n                    _ => {}\n                });\n                let ty2 = self.type_check(term)?;\n                self.stack.iter_mut().for_each(|ty| match ty {\n                    Type::Var(v) => *v -= 1,\n                    _ => {}\n                });\n                Ok(Type::Universal(Box::new(ty2)))\n            }\n            Kind::TyApp(term, ty) => {\n                let mut ty = ty.clone();\n                let ty1 = self.type_check(term)?;\n                match ty1 {\n                    Type::Universal(mut ty12) => {\n                        Shift::new(1).visit(&mut ty);\n                        Subst::new(*ty).visit(&mut ty12);\n                        Shift::new(-1).visit(&mut ty12);\n                        Ok(*ty12)\n                    }\n                    _ => Err(Diagnostic::error(\n                        term.span,\n                        format!(\"Expected a universal type, not {:?}\", ty1),\n                    )),\n                }\n            }\n            // See src/types/patterns.rs for exhaustiveness and typechecking\n            // of case expressions\n            Kind::Case(expr, arms) => self.type_check_case(expr, arms),\n\n            Kind::Unfold(rec, tm) => match rec.as_ref() {\n                Type::Rec(inner) => {\n                    let ty_ = self.type_check(&tm)?;\n                    if ty_ == *rec.clone() {\n                        let s = subst(*rec.clone(), *inner.clone());\n                        Ok(s)\n                    } else {\n                        let d = Diagnostic::error(term.span, \"Type mismatch in unfold\")\n                            .message(term.span, format!(\"unfold requires type {:?}\", rec))\n                            .message(tm.span, format!(\"term has a type of {:?}\", ty_));\n                        Err(d)\n                    }\n                }\n                _ => Err(Diagnostic::error(\n                    term.span,\n                    format!(\"Expected a recursive type, not {:?}\", rec),\n                )),\n            },\n\n            Kind::Fold(rec, tm) => match rec.as_ref() {\n                Type::Rec(inner) => {\n                    let ty_ = self.type_check(&tm)?;\n                    let s = subst(*rec.clone(), *inner.clone());\n                    if ty_ == s {\n                        Ok(*rec.clone())\n                    } else {\n                        let d = Diagnostic::error(term.span, \"Type mismatch in fold\")\n                            .message(term.span, format!(\"unfold requires type {:?}\", s))\n                            .message(tm.span, format!(\"term has a type of {:?}\", ty_));\n                        Err(d)\n                    }\n                }\n                _ => Err(Diagnostic::error(\n                    term.span,\n                    format!(\"Expected a recursive type, not {:?}\", rec),\n                )),\n            },\n            Kind::Pack(witness, evidence, signature) => {\n                if let Type::Existential(exists) = signature.as_ref() {\n                    let sig_prime = subst(*witness.clone(), *exists.clone());\n                    let evidence_ty = self.type_check(evidence)?;\n                    if evidence_ty == sig_prime {\n                        Ok(*signature.clone())\n                    } else {\n                        let d = Diagnostic::error(term.span, \"Type mismatch in pack\")\n                            .message(term.span, format!(\"signature has type {:?}\", sig_prime))\n                            .message(evidence.span, format!(\"but term has a type {:?}\", evidence_ty));\n                        Err(d)\n                    }\n                } else {\n                    Err(Diagnostic::error(\n                        term.span,\n                        format!(\"Expected an existential type signature, not {:?}\", signature),\n                    ))\n                }\n            }\n            Kind::Unpack(package, body) => {\n                let p_ty = self.type_check(package)?;\n                if let Type::Existential(xst) = p_ty {\n                    self.push(*xst);\n                    let body_ty = self.type_check(body)?;\n                    self.pop();\n                    Ok(body_ty)\n                } else {\n                    Err(Diagnostic::error(\n                        package.span,\n                        format!(\"Expected an existential type signature, not {:?}\", p_ty),\n                    ))\n                }\n            }\n        }\n    }\n}\n\npub fn subst(mut s: Type, mut t: Type) -> Type {\n    Shift::new(1).visit(&mut s);\n    Subst::new(s).visit(&mut t);\n    Shift::new(-1).visit(&mut t);\n    t\n}\n\nstruct Aliaser<'ctx> {\n    map: &'ctx HashMap<String, Type>,\n}\n\nimpl<'ctx> MutTypeVisitor for Aliaser<'ctx> {\n    fn visit(&mut self, ty: &mut Type) {\n        match ty {\n            Type::Unit | Type::Bool | Type::Nat => {}\n            Type::Var(v) => {}\n            Type::Alias(v) => {\n                if let Some(aliased) = self.map.get(v) {\n                    *ty = aliased.clone();\n                }\n            }\n            Type::Variant(v) => self.visit_variant(v),\n            Type::Product(v) => self.visit_product(v),\n\n            Type::Arrow(ty1, ty2) => self.visit_arrow(ty1, ty2),\n            Type::Universal(ty) => self.visit_universal(ty),\n            Type::Existential(ty) => self.visit_existential(ty),\n            Type::Rec(ty) => self.visit_rec(ty),\n        }\n    }\n}\n\nimpl MutTermVisitor for Context {\n    fn visit_abs(&mut self, sp: &mut Span, ty: &mut Type, term: &mut Term) {\n        self.aliaser().visit(ty);\n        self.visit(term);\n    }\n\n    fn visit_tyapp(&mut self, sp: &mut Span, term: &mut Term, ty: &mut Type) {\n        self.aliaser().visit(ty);\n        self.visit(term);\n    }\n\n    fn visit_injection(&mut self, sp: &mut Span, label: &mut String, term: &mut Term, ty: &mut Type) {\n        self.aliaser().visit(ty);\n        self.visit(term);\n    }\n\n    fn visit_fold(&mut self, sp: &mut Span, ty: &mut Type, tm: &mut Term) {\n        self.aliaser().visit(ty);\n        self.visit(tm);\n    }\n\n    fn visit_unfold(&mut self, sp: &mut Span, ty: &mut Type, tm: &mut Term) {\n        self.aliaser().visit(ty);\n        self.visit(tm);\n    }\n}\n\nimpl fmt::Debug for Type {\n    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n        match self {\n            Type::Unit => write!(f, \"Unit\"),\n            Type::Bool => write!(f, \"Bool\"),\n            Type::Nat => write!(f, \"Nat\"),\n            Type::Var(v) => write!(f, \"TyVar({})\", v),\n            Type::Variant(v) => write!(\n                f,\n                \"{:?}\",\n                v.iter()\n                    .map(|x| format!(\"{}: {:?}\", x.label, x.ty))\n                    .collect::<Vec<String>>()\n                    .join(\" | \")\n            ),\n            Type::Product(v) => write!(\n                f,\n                \"({})\",\n                v.iter().map(|x| format!(\"{:?}\", x)).collect::<Vec<String>>().join(\",\")\n            ),\n            Type::Alias(s) => write!(f, \"{}\", s),\n            Type::Arrow(t1, t2) => write!(f, \"({:?}->{:?})\", t1, t2),\n            Type::Universal(ty) => write!(f, \"forall X.{:?}\", ty),\n            Type::Existential(ty) => write!(f, \"exists X.{:?}\", ty),\n            Type::Rec(ty) => write!(f, \"rec {:?}\", ty),\n        }\n    }\n}\n"
  },
  {
    "path": "06_system_f/src/types/patterns.rs",
    "content": "//! Naive, inefficient exhaustiveness checking for pattern matching\n//!\n//! Inspired somewhat by the docs for the Rust compiler (and linked paper), we\n//! create a \"usefulness\" predicate. We store current patterns in a row-wise\n//! [`Matrix`], and iterate through each row in the matrix every time we want\n//! to add a new pattern. If no existing rows completely overlap the new row,\n//! then we can determine that the new row is \"useful\", and add it.\n//!\n//! To check for exhaustiveness, we simply create a row of Wildcard matches,\n//! and see if it would be useful to add\n//!\n//! https://doc.rust-lang.org/nightly/nightly-rustc/src/rustc_mir/hair/pattern/_match.rs.html\n//! http://moscova.inria.fr/~maranget/papers/warn/index.html\n//!\n\nuse super::*;\nuse crate::diagnostics::*;\nuse crate::patterns::{PatTyStack, Pattern};\nuse crate::terms::*;\nuse std::collections::HashSet;\n\n/// Return true if `existing` covers `new`, i.e. if new is a useful pattern\n/// then `overlap` will return `false`\nfn overlap(existing: &Pattern, new: &Pattern) -> bool {\n    use Pattern::*;\n    match (existing, new) {\n        (Any, _) => true,\n        (Variable(_), _) => true,\n        (Constructor(l, a), Constructor(l2, b)) => {\n            if l == l2 {\n                overlap(a, b)\n            } else {\n                false\n            }\n        }\n        (Product(a), Product(b)) => a.iter().zip(b.iter()).all(|(a, b)| overlap(a, b)),\n        (Product(a), b) => a.iter().all(|a| overlap(a, b)),\n        (x, y) => x == y,\n    }\n}\n\n#[derive(Clone, Debug, PartialEq, PartialOrd)]\npub struct Matrix<'pat> {\n    pub expr_ty: Type,\n    len: usize,\n    matrix: Vec<Vec<&'pat Pattern>>,\n}\n\nimpl<'pat> Matrix<'pat> {\n    /// Create a new [`Matrix`] for a given type\n    pub fn new(expr_ty: Type) -> Matrix<'pat> {\n        let len = match &expr_ty {\n            Type::Product(p) => p.len(),\n            _ => 1,\n        };\n\n        Matrix {\n            expr_ty,\n            len,\n            matrix: Vec::new(),\n        }\n    }\n\n    /// Is the pattern [`Matrix`] exhaustive for this type?\n    ///\n    /// For a boolean type, True, False, or a wildcard/variable match are\n    /// required For a product type (tuple), the algorithm is slightly more\n    /// complicated: We generate a tuple of length N (equal to the length of\n    /// the case expressions' tuple) filled with Wildcard patterns, and see\n    /// if addition of tuple is a useful pattern. If the pattern is not\n    /// useful (i.e. it totally `overlap's` with an existing row), then the\n    /// matrix is exhaustive\n    ///\n    /// For a sum type, a dummy constructor of pattern `Const_i _` is generated\n    /// for all `i` of the possible constructors of the type. If none of the\n    /// dummy constructors are useful, then the current patterns are exhaustive\n    pub fn exhaustive(&self) -> bool {\n        match &self.expr_ty {\n            Type::Variant(v) => v.iter().all(|variant| {\n                // For all constructors in the sum type, generate a constructor\n                // pattern that will match all possible inhabitants of that\n                // constructor\n                let con = Pattern::Constructor(variant.label.clone(), Box::new(Pattern::Any));\n                let temp = [&con];\n                let mut ret = false;\n                for row in &self.matrix {\n                    if row.iter().zip(&temp).all(|(a, b)| overlap(a, b)) {\n                        ret = true;\n                        break;\n                    }\n                }\n                ret\n            }),\n            Type::Product(_) | Type::Nat => {\n                // Generate a tuple of wildcard patterns. If the pattern is\n                // useful, then we do not have an exhaustive matrix\n                let filler = (0..self.len).map(|_| Pattern::Any).collect::<Vec<_>>();\n                for row in &self.matrix {\n                    if row.iter().zip(filler.iter()).all(|(a, b)| overlap(a, b)) {\n                        return true;\n                    }\n                }\n                false\n            }\n            Type::Bool => {\n                // Boolean type is one of the simplest cases: we only need\n                // to match `true` and `false`, or one of those + a wildcard,\n                // or just a wildcard\n                let tru = Pattern::Literal(Literal::Bool(true));\n                let fal = Pattern::Literal(Literal::Bool(false));\n                !(self.can_add_row(vec![&tru]) && self.can_add_row(vec![&fal]))\n            }\n            Type::Unit => {\n                // Unit is a degenerate case\n                let unit = Pattern::Literal(Literal::Unit);\n                !self.can_add_row(vec![&unit])\n            }\n            _ => false,\n        }\n    }\n\n    /// Return true if a new pattern row is reachable\n    fn can_add_row(&self, new_row: Vec<&'pat Pattern>) -> bool {\n        assert_eq!(self.len, new_row.len());\n        for row in &self.matrix {\n            if row.iter().zip(new_row.iter()).all(|(a, b)| overlap(a, b)) {\n                return false;\n            }\n        }\n        true\n    }\n\n    fn try_add_row(&mut self, new_row: Vec<&'pat Pattern>) -> bool {\n        assert_eq!(self.len, new_row.len());\n        for row in &self.matrix {\n            if row.iter().zip(new_row.iter()).all(|(a, b)| overlap(a, b)) {\n                return false;\n            }\n        }\n        self.matrix.push(new_row);\n        true\n    }\n\n    /// Attempt to add a new [`Pattern`] to the [`Matrix`]\n    ///\n    /// Returns true on success, and false if the new pattern is\n    /// unreachable\n    pub fn add_pattern(&mut self, pat: &'pat Pattern) -> bool {\n        match pat {\n            Pattern::Any | Pattern::Variable(_) => {\n                let filler = (0..self.len).map(|_| &Pattern::Any).collect::<Vec<_>>();\n                self.try_add_row(filler)\n            }\n            Pattern::Product(tuple) => self.try_add_row(tuple.iter().collect()),\n            Pattern::Literal(lit) => {\n                if self.len == 1 {\n                    self.try_add_row(vec![pat])\n                } else {\n                    false\n                }\n            }\n            Pattern::Constructor(label, inner) => self.try_add_row(vec![pat]),\n        }\n    }\n}\n\nimpl Context {\n    /// Type check a case expression, returning the Type of the arms, assuming\n    /// that the case expression is exhaustive and well-typed\n    ///\n    /// This is one of the more complicated functions in the typechecker.\n    /// 1) We first have to check that each arm in the case expression has\n    /// a pattern that is proper for type of the case expression - we shouldn't\n    /// have case arms with patterns that can be never be matched!\n    ///\n    /// 2) We then need to bind any variables referenced in the pattern into\n    /// the typing context - `Cons (x, xs)` needs to bind both x and xs, as does\n    /// just `Cons x`.\n    ///\n    /// 3) After variable binding, we need to typecheck the actual case arm's\n    /// term, and store the result so that we can compare it to the types of\n    /// the other arms in the case expression\n    ///\n    /// 4) If the arm is properly typed, then we need to add it to a matrix so\n    /// that we can determine if the pattern is reachable, and if the case arms\n    /// are exhaustive - one, and only one, pattern should be matchable\n    ///\n    /// 5) Finally, assuming all of the previous checks have passed, we return\n    /// the shared type of all of the case arms - the term associated with each\n    /// arm should have one type, and that type should be the same for all of\n    /// the arms.\n    pub(crate) fn type_check_case(&mut self, expr: &Term, arms: &[Arm]) -> Result<Type, Diagnostic> {\n        let ty = self.type_check(expr)?;\n        let mut matrix = patterns::Matrix::new(ty);\n\n        let mut set = HashSet::new();\n        for arm in arms {\n            if self.pattern_type_eq(&arm.pat, &matrix.expr_ty) {\n                let height = self.stack.len();\n\n                let binds = PatTyStack::collect(&matrix.expr_ty, &arm.pat);\n                for b in binds.into_iter().rev() {\n                    self.push(b.clone());\n                }\n\n                let arm_ty = self.type_check(&arm.term)?;\n\n                while self.stack.len() > height {\n                    self.pop();\n                }\n\n                set.insert(arm_ty);\n                if !matrix.add_pattern(&arm.pat) {\n                    return Err(Diagnostic::error(arm.span, \"unreachable pattern!\"));\n                }\n            } else {\n                return Err(\n                    Diagnostic::error(expr.span, format!(\"case binding has a type {:?}\", &matrix.expr_ty)).message(\n                        arm.span,\n                        format!(\"but this pattern cannot bind a value of type {:?}\", &matrix.expr_ty),\n                    ),\n                );\n            }\n        }\n\n        if set.len() != 1 {\n            return Err(Diagnostic::error(expr.span, format!(\"incompatible arms! {:?}\", set)));\n        }\n\n        if matrix.exhaustive() {\n            match set.into_iter().next() {\n                Some(s) => Ok(s),\n                None => Err(Diagnostic::error(\n                    expr.span,\n                    \"probably unreachable - expected variant type!\",\n                )),\n            }\n        } else {\n            Err(Diagnostic::error(expr.span, \"patterns are not exhaustive!\"))\n        }\n    }\n\n    /// Helper function for pattern to type equivalence\n    ///\n    /// A `_` wildcard pattern is obviously valid for every type, as is a\n    /// variable binding:\n    ///     case Some(10) of\n    ///         | None => None\n    ///         | x => x -- x will always match to Some(10) here\n    ///\n    /// A literal pattern should only be equal to the equivalent type, etc\n    ///\n    /// This function is primarily used as a first pass to ensure that a pattern\n    /// is valid for a given case expression\n    pub(crate) fn pattern_type_eq(&self, pat: &Pattern, ty: &Type) -> bool {\n        match pat {\n            Pattern::Any => true,\n            Pattern::Variable(_) => true,\n            Pattern::Literal(lit) => match (lit, ty) {\n                (Literal::Bool(_), Type::Bool) => true,\n                (Literal::Nat(_), Type::Nat) => true,\n                (Literal::Unit, Type::Unit) => true,\n                _ => false,\n            },\n            Pattern::Product(patterns) => match ty {\n                Type::Product(types) => {\n                    patterns.len() == types.len()\n                        && patterns\n                            .iter()\n                            .zip(types.iter())\n                            .all(|(pt, tt)| self.pattern_type_eq(pt, tt))\n                }\n                _ => false,\n            },\n            Pattern::Constructor(label, inner) => match ty {\n                Type::Variant(v) => {\n                    for discriminant in v {\n                        if label == &discriminant.label && self.pattern_type_eq(&inner, &discriminant.ty) {\n                            return true;\n                        }\n                    }\n                    false\n                }\n                _ => false,\n            },\n        }\n    }\n}\n\n#[cfg(test)]\nmod test {\n    use super::*;\n    use Pattern::*;\n\n    #[test]\n    fn product() {\n        let ty = Type::Product(vec![Type::Bool, Type::Bool, Type::Nat]);\n        let pat = prod!(boolean!(true), boolean!(true), num!(10));\n        let ctx = Context::default();\n        assert!(ctx.pattern_type_eq(&pat, &ty));\n    }\n\n    #[test]\n    #[should_panic]\n    fn product_mistyped() {\n        let ty = Type::Product(vec![Type::Bool, Type::Bool, Type::Bool]);\n        let pat = prod!(boolean!(true), boolean!(true), num!(10));\n        let ctx = Context::default();\n        assert!(ctx.pattern_type_eq(&pat, &ty));\n    }\n\n    #[test]\n    fn constructor() {\n        let ty = Type::Variant(vec![\n            Variant {\n                label: \"A\".into(),\n                ty: Type::Unit,\n            },\n            Variant {\n                label: \"B\".into(),\n                ty: Type::Nat,\n            },\n        ]);\n\n        let pat1 = con!(\"A\", Pattern::Any);\n        let pat2 = con!(\"A\", boolean!(true));\n        let pat3 = con!(\"B\", num!(1));\n\n        let ctx = Context::default();\n        assert!(ctx.pattern_type_eq(&pat1, &ty));\n        assert!(!ctx.pattern_type_eq(&pat2, &ty));\n        assert!(ctx.pattern_type_eq(&pat3, &ty));\n    }\n\n    #[test]\n    fn constructor_product() {\n        let ty = Type::Variant(vec![\n            Variant {\n                label: \"A\".into(),\n                ty: Type::Unit,\n            },\n            Variant {\n                label: \"B\".into(),\n                ty: Type::Product(vec![Type::Nat, Type::Nat]),\n            },\n        ]);\n\n        let pat1 = con!(\"A\", Any);\n        let pat2 = con!(\"B\", Any);\n        let pat3 = con!(\"B\", prod!(Any, Variable(\"x\".into())));\n        let pat4 = con!(\"B\", prod!(num!(1), Variable(\"x\".into())));\n        let pat5 = con!(\"A\", num!(1));\n\n        let ctx = Context::default();\n        assert!(ctx.pattern_type_eq(&pat1, &ty));\n        assert!(ctx.pattern_type_eq(&pat2, &ty));\n        assert!(ctx.pattern_type_eq(&pat3, &ty));\n        assert!(ctx.pattern_type_eq(&pat4, &ty));\n        assert!(!ctx.pattern_type_eq(&pat5, &ty));\n    }\n\n    #[test]\n    fn matrix_tuple() {\n        let pats = vec![\n            prod!(num!(0), num!(1)),\n            prod!(num!(1), num!(1)),\n            prod!(Any, num!(2)),\n            prod!(num!(2), Any),\n            prod!(num!(1), num!(4)),\n            prod!(Any, Variable(String::default())),\n        ];\n        let ty = Type::Product(vec![Type::Nat, Type::Nat]);\n        let mut matrix = Matrix::new(ty);\n        for pat in &pats {\n            assert!(matrix.add_pattern(pat));\n        }\n        assert!(!matrix.add_pattern(&Any));\n        assert!(matrix.exhaustive());\n    }\n\n    #[test]\n    fn matrix_constructor() {\n        let ty = Type::Variant(vec![\n            variant!(\"A\", Type::Nat),\n            variant!(\"B\", Type::Nat),\n            variant!(\"C\", Type::Product(vec![Type::Nat, Type::Nat])),\n        ]);\n\n        let pats = vec![\n            con!(\"A\", num!(20)),\n            con!(\"A\", Any),\n            con!(\"B\", Any),\n            con!(\"C\", prod!(num!(1), num!(1))),\n            con!(\"C\", prod!(Any, num!(1))),\n            con!(\"C\", prod!(num!(1), Any)),\n        ];\n\n        let ctx = Context::default();\n        assert!(pats.iter().all(|p| ctx.pattern_type_eq(p, &ty)));\n        let mut matrix = Matrix::new(ty);\n\n        for p in &pats {\n            assert!(matrix.add_pattern(p));\n        }\n        let last = con!(\"C\", Any);\n\n        assert!(!matrix.exhaustive());\n        assert!(matrix.add_pattern(&last));\n        assert!(matrix.exhaustive());\n    }\n\n    #[test]\n    fn matrix_bool() {\n        let pats = vec![boolean!(true), boolean!(false)];\n\n        let ty = Type::Bool;\n        let ctx = Context::default();\n        assert!(pats.iter().all(|p| ctx.pattern_type_eq(p, &ty)));\n\n        let mut matrix = Matrix::new(ty);\n        for p in &pats {\n            assert!(matrix.add_pattern(p));\n        }\n        assert!(!matrix.add_pattern(&pats[1]));\n        assert!(matrix.exhaustive());\n    }\n}\n"
  },
  {
    "path": "06_system_f/src/types/visit.rs",
    "content": "use super::Type;\nuse crate::visit::MutTypeVisitor;\nuse std::convert::TryFrom;\n\npub struct Shift {\n    pub cutoff: usize,\n    pub shift: isize,\n}\n\nimpl Shift {\n    pub const fn new(shift: isize) -> Shift {\n        Shift { cutoff: 0, shift }\n    }\n}\n\nimpl MutTypeVisitor for Shift {\n    fn visit_var(&mut self, var: &mut usize) {\n        if *var >= self.cutoff {\n            *var = usize::try_from(*var as isize + self.shift).expect(\"Variable has been shifted below 0! Fatal bug\");\n        }\n    }\n\n    fn visit_universal(&mut self, inner: &mut Type) {\n        self.cutoff += 1;\n        self.visit(inner);\n        self.cutoff -= 1;\n    }\n\n    fn visit_existential(&mut self, inner: &mut Type) {\n        self.cutoff += 1;\n        self.visit(inner);\n        self.cutoff -= 1;\n    }\n\n    fn visit_rec(&mut self, ty: &mut Type) {\n        self.cutoff += 1;\n        self.visit(ty);\n        self.cutoff -= 1;\n    }\n}\n\npub struct Subst {\n    pub cutoff: usize,\n    pub ty: Type,\n}\n\nimpl Subst {\n    pub fn new(ty: Type) -> Subst {\n        Subst { cutoff: 0, ty }\n    }\n}\n\nimpl MutTypeVisitor for Subst {\n    fn visit_universal(&mut self, inner: &mut Type) {\n        self.cutoff += 1;\n        self.visit(inner);\n        self.cutoff -= 1;\n    }\n\n    fn visit_existential(&mut self, inner: &mut Type) {\n        self.cutoff += 1;\n        self.visit(inner);\n        self.cutoff -= 1;\n    }\n\n    fn visit_rec(&mut self, ty: &mut Type) {\n        self.cutoff += 1;\n        self.visit(ty);\n        self.cutoff -= 1;\n    }\n\n    fn visit(&mut self, ty: &mut Type) {\n        match ty {\n            Type::Unit | Type::Bool | Type::Nat => {}\n            Type::Var(v) if *v >= self.cutoff => {\n                Shift::new(self.cutoff as isize).visit(&mut self.ty);\n                *ty = self.ty.clone();\n            }\n            Type::Var(v) => self.visit_var(v),\n            Type::Variant(v) => self.visit_variant(v),\n            Type::Product(v) => self.visit_product(v),\n            Type::Alias(v) => self.visit_alias(v),\n            Type::Arrow(ty1, ty2) => self.visit_arrow(ty1, ty2),\n            Type::Universal(ty) => self.visit_universal(ty),\n            Type::Existential(ty) => self.visit_existential(ty),\n            Type::Rec(ty) => self.visit_rec(ty),\n        }\n    }\n}\n"
  },
  {
    "path": "06_system_f/src/visit.rs",
    "content": "//! Visitor traits for [`Pattern`], [`Term`], and [`Type`] objects\nuse crate::patterns::Pattern;\nuse crate::terms::{Arm, Kind, Literal, Primitive, Term};\nuse crate::types::{Type, Variant};\nuse util::span::Span;\n\npub trait MutTypeVisitor: Sized {\n    fn visit_var(&mut self, var: &mut usize) {}\n    fn visit_alias(&mut self, alias: &mut String) {}\n\n    fn visit_arrow(&mut self, ty1: &mut Type, ty2: &mut Type) {\n        self.visit(ty1);\n        self.visit(ty2);\n    }\n\n    fn visit_universal(&mut self, inner: &mut Type) {\n        self.visit(inner);\n    }\n\n    fn visit_existential(&mut self, inner: &mut Type) {\n        self.visit(inner);\n    }\n\n    fn visit_variant(&mut self, variant: &mut Vec<Variant>) {\n        for v in variant {\n            self.visit(&mut v.ty);\n        }\n    }\n\n    fn visit_product(&mut self, product: &mut Vec<Type>) {\n        for v in product {\n            self.visit(v);\n        }\n    }\n\n    fn visit_rec(&mut self, ty: &mut Type) {\n        self.visit(ty);\n    }\n\n    fn visit(&mut self, ty: &mut Type) {\n        match ty {\n            Type::Unit | Type::Bool | Type::Nat => {}\n            Type::Var(v) => self.visit_var(v),\n            Type::Variant(v) => self.visit_variant(v),\n            Type::Product(v) => self.visit_product(v),\n            Type::Alias(s) => self.visit_alias(s),\n            Type::Arrow(ty1, ty2) => self.visit_arrow(ty1, ty2),\n            Type::Universal(ty) => self.visit_universal(ty),\n            Type::Existential(ty) => self.visit_existential(ty),\n            Type::Rec(ty) => self.visit_rec(ty),\n        }\n    }\n}\n\npub trait MutTermVisitor: Sized {\n    fn visit_lit(&mut self, sp: &mut Span, lit: &mut Literal) {}\n    fn visit_var(&mut self, sp: &mut Span, var: &mut usize) {}\n\n    fn visit_abs(&mut self, sp: &mut Span, ty: &mut Type, term: &mut Term) {\n        self.visit(term);\n    }\n\n    fn visit_app(&mut self, sp: &mut Span, t1: &mut Term, t2: &mut Term) {\n        self.visit(t1);\n        self.visit(t2);\n    }\n\n    fn visit_let(&mut self, sp: &mut Span, pat: &mut Pattern, t1: &mut Term, t2: &mut Term) {\n        self.visit(t1);\n        self.visit(t2);\n    }\n\n    fn visit_tyabs(&mut self, sp: &mut Span, term: &mut Term) {\n        self.visit(term);\n    }\n\n    fn visit_tyapp(&mut self, sp: &mut Span, term: &mut Term, ty: &mut Type) {\n        self.visit(term);\n    }\n\n    fn visit_primitive(&mut self, sp: &mut Span, prim: &mut Primitive) {}\n    fn visit_injection(&mut self, sp: &mut Span, label: &mut String, term: &mut Term, ty: &mut Type) {\n        self.visit(term);\n    }\n\n    fn visit_case(&mut self, sp: &mut Span, term: &mut Term, arms: &mut Vec<Arm>) {\n        self.visit(term);\n        for arm in arms {\n            self.visit(&mut arm.term);\n        }\n    }\n\n    fn visit_product(&mut self, sp: &mut Span, product: &mut Vec<Term>) {\n        for t in product {\n            self.visit(t);\n        }\n    }\n\n    fn visit_projection(&mut self, sp: &mut Span, term: &mut Term, index: &mut usize) {\n        self.visit(term);\n    }\n\n    fn visit_fold(&mut self, sp: &mut Span, ty: &mut Type, term: &mut Term) {\n        self.visit(term);\n    }\n    fn visit_unfold(&mut self, sp: &mut Span, ty: &mut Type, term: &mut Term) {\n        self.visit(term);\n    }\n\n    fn visit_pack(&mut self, sp: &mut Span, witness: &mut Type, evidence: &mut Term, signature: &mut Type) {\n        self.visit(evidence);\n    }\n\n    fn visit_unpack(&mut self, sp: &mut Span, package: &mut Term, term: &mut Term) {\n        self.visit(package);\n        self.visit(term);\n    }\n\n    fn visit(&mut self, term: &mut Term) {\n        self.walk(term);\n    }\n\n    fn walk(&mut self, term: &mut Term) {\n        let sp = &mut term.span;\n        match &mut term.kind {\n            Kind::Lit(l) => self.visit_lit(sp, l),\n            Kind::Var(v) => self.visit_var(sp, v),\n            Kind::Abs(ty, term) => self.visit_abs(sp, ty, term),\n            Kind::App(t1, t2) => self.visit_app(sp, t1, t2),\n            // Do we need a separate branch?\n            Kind::Fix(term) => self.visit(term),\n            Kind::Primitive(p) => self.visit_primitive(sp, p),\n            Kind::Injection(label, tm, ty) => self.visit_injection(sp, label, tm, ty),\n            Kind::Projection(term, idx) => self.visit_projection(sp, term, idx),\n            Kind::Product(terms) => self.visit_product(sp, terms),\n            Kind::Case(term, arms) => self.visit_case(sp, term, arms),\n            Kind::Let(pat, t1, t2) => self.visit_let(sp, pat, t1, t2),\n            Kind::TyAbs(term) => self.visit_tyabs(sp, term),\n            Kind::TyApp(term, ty) => self.visit_tyapp(sp, term, ty),\n            Kind::Fold(ty, term) => self.visit_fold(sp, ty, term),\n            Kind::Unfold(ty, term) => self.visit_unfold(sp, ty, term),\n            Kind::Pack(wit, term, sig) => self.visit_pack(sp, wit, term, sig),\n            Kind::Unpack(package, term) => self.visit_unpack(sp, package, term),\n        }\n    }\n}\n\npub trait PatternVisitor: Sized {\n    fn visit_literal(&mut self, lit: &Literal) {}\n    fn visit_variable(&mut self, var: &String) {}\n    fn visit_product(&mut self, pats: &Vec<Pattern>) {\n        for p in pats {\n            self.visit_pattern(p);\n        }\n    }\n\n    fn visit_constructor(&mut self, label: &String, pat: &Pattern) {\n        self.visit_pattern(pat);\n    }\n\n    fn visit_pattern(&mut self, pattern: &Pattern) {\n        match pattern {\n            Pattern::Any => {}\n            Pattern::Constructor(label, pat) => self.visit_constructor(label, pat),\n            Pattern::Product(pat) => self.visit_product(pat),\n            Pattern::Literal(lit) => self.visit_literal(lit),\n            Pattern::Variable(var) => self.visit_variable(var),\n        }\n    }\n}\n"
  },
  {
    "path": "06_system_f/test.sf",
    "content": "let func = \\X (\\c: {None | Some X}. \\x: X->(X, X). \n\tcase c of \n\t\t| None => None of {None | Some (X, X)}\n\t\t| Some val => Some (val, val) of {None | Some (X, X)} )\nin func [Nat] (Some 10 of {None|Some Nat}) (\\x: Nat. (x, x))\n;\n\nlet poly = \\X \\x: X. x in \n\tlet x = poly [Nat] 0 in \n\tlet y = poly [Bool] false in \n\tlet z = poly [(Nat, Bool)] in \n\tz (x, y)\n;\n\nlet poly = \\X \\Y (\\func: X->Y. \\val: X. func val) in poly [Nat][Bool]\n;\n\n\ncase Some (5, 2) of {None | Some (Nat, Nat)} of \n | None => (0, 0)\n | Some (1, _) => (1, 1)\n | Some(x, y) => (y, x)\n;\n\ncase (1, (2, 3)) of \n\t| (x, (y, z)) => ((z, y), x)\n;\nlet x = \n\t\\z: (Nat, Nat)->Nat. \n\t\t\\y: (Nat, Nat).\n\t\t\tcase y of\n\t\t\t\t| (0, x) => x,\n\t\t\t\t| x => z (pred y.0, succ (succ x.1))\n\tin (fix x) (10, 0)\n\n;\n\nlet cdr = \\list: NatList. \n\tcase unfold NatList list of \n\t\t| Nil => Nil of NatList\n\t\t| Cons (x, xs) => xs\nin cdr Cons (10, Cons (20, Nil of NatList) of NatList) of NatList\n;\n\ncase unfold NatList Cons (10, Cons (20, Nil of NatList) of NatList) of NatList of \n\t| Nil => Nil of NatList \n\t| Cons (10, xs) => Cons (11, xs) of NatList\n\t| Cons (x, xs) => xs\n\n;\n\nlet nil = Nil of NatList in \nlet cons = (\\val: Nat. \\list: NatList. Cons (val, list) of NatList) in\ncase unfold NatList (cons 1 nil) of \n\t| Nil => nil\n\t| Cons (x, y) => y\n\n;\n\nlet x = 10 in let (y, _) = (x, 1) in y;\n\nlet (x, y) = (0, 10) in let z = x in z ;\n\n(\\x: Nat. \\Y \\y: Nat->Y. y x) 10 [Nat] succ\n\n;\n\nlet x = \\struct: (Nat, Nat, Nat). \n\tlet (_, q, _) = struct in q \n\tin x (10, 12, 13)\n\nlet x = \\A \\B \\C \\tuple: (A, B, (C, C)).\n\tlet (_, mid, (n, s)) = tuple in \n\t(n, mid, s, mid) in\n\tx [Nat] [Bool] [Nat] (10, true, (1, 11))\n\n;\n\nlet package = (pack Nat, ((\\x: Nat. succ (succ x)), 0) as exists X. (X->Nat, X)) in\n\tunpack package as T, mod in mod.0 ((\\x: T. x) mod.1)\n;;\n\nlet package = (pack Bool, ((\\x: Bool. case x of | true => 10 | false => 0), true) as exists REPR. (REPR->Nat, REPR)) in\nlet x = (\\x: exists T. (T->Nat, T). unpack x as T, mod in succ (mod.0 mod.1)) in\n\tx package \n;\n\n"
  },
  {
    "path": "07_system_fw/Cargo.toml",
    "content": "[package]\nname = \"system_fw\"\nversion = \"0.1.0\"\nauthors = [\"Michael Lazear <lazear@scripps.edu>\"]\nedition = \"2018\"\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nutil = { path = \"../util\" }"
  },
  {
    "path": "07_system_fw/README.md",
    "content": "# System Fω\n\nThis is an implementation (mostly of just the type system) of the higher-order polymorphic lambda calculus with explicit typing. This allows us to express functions with impredicative arguments, and we can emulate Haskell style typeclasses using functors over existential types (akin to 1ML) - something not expressible in Standard ML. \n\n\n#### References\nI've included some selected references on implementing System Fw, particularly with respect to the addition of recursive types (System F omega-mu):\n\n-  Mendler, N.P.: Recursive types and type constraints in second-order lambda calculus. In: Proceedings of the Second Annual IEEE Symposium on Logic in Computer\nScience, Ithaca, N.Y., IEEE Computer Society Press (1987) 30–36\n\n   - One of the classic, highly reference papers\n\n\n- Andreas Abel, Ralph Matthes, Tarmo Uustalu, \"Iteration and coiteration schemes for higher-order and nested datatypes\", Theoretical Computer Science, Volume 333, Issues 1–2, 2005, Pages 3-66,\n\n   - Interesting implementations, a paper that allowed me to better understand \"Mendler iterations\"\n\n- Andreas Abel, Ralph Matthes, \"Fixed Points of Type Constructors and Primitive Recursion\", International Workshop on Computer Science Logic (2004)\n\n- Ahn, Ki Yung, \"The Nax Language: Unifying Functional Programming and Logical Reasoning in a Language based on Mendler-style\nRecursion Schemes and Term-indexed Types\" (2014). Dissertations and Theses. Paper 2088.\n\n   - This reference is quite useful as it restates much of the literature in easily understandable terms\n\n- Yufei Cai, Paolo G. Giarrusso, and Klaus Ostermann. 2016. System f-omega with equirecursive types for datatype-generic programming. SIGPLAN Not. 51, 1 (January 2016), 30-43. DOI: https://doi.org/10.1145/2914770.2837660\n\n   - Interesting, but I found it to be of not too much practical use\n\n- A Polymorphic Lambda-Calculus with Sized Higher-Order Types, Andreas Abel, PhD thesis\n\n   -  Page 76 seems to give some good hints on how to type Fold/Unfold operators (but for equirecursive, isorecursive on pp 85). It also seems that the kinding rules/type-equivalence can treat a type constructor abstraction (* => *) and a recursive type of kind (* => *) as the same. Iso-coinductive construtors are also discussed, pp 157.\n"
  },
  {
    "path": "07_system_fw/src/diagnostics.rs",
    "content": "use std::fmt;\nuse util::span::Span;\n\n#[derive(Debug, Clone, PartialEq)]\npub enum Level {\n    Warn,\n    Error,\n}\n\n#[derive(Debug, Clone, PartialEq)]\npub struct Annotation {\n    pub span: Span,\n    pub info: String,\n}\n\n#[derive(Clone, PartialEq)]\npub struct Diagnostic {\n    pub level: Level,\n    pub primary: Annotation,\n    pub info: Vec<String>,\n    pub other: Vec<Annotation>,\n}\n\nimpl Annotation {\n    pub fn new<S: Into<String>>(span: Span, message: S) -> Annotation {\n        Annotation {\n            span,\n            info: message.into(),\n        }\n    }\n}\n\nimpl Diagnostic {\n    pub fn error<S: Into<String>>(span: Span, message: S) -> Diagnostic {\n        Diagnostic {\n            level: Level::Error,\n            primary: Annotation::new(span, message),\n            other: Vec::new(),\n            info: Vec::new(),\n        }\n    }\n\n    pub fn warn<S: Into<String>>(span: Span, message: S) -> Diagnostic {\n        Diagnostic {\n            level: Level::Warn,\n            primary: Annotation::new(span, message),\n            other: Vec::new(),\n            info: Vec::new(),\n        }\n    }\n\n    pub fn message<S: Into<String>>(mut self, span: Span, message: S) -> Diagnostic {\n        self.other.push(Annotation::new(span, message));\n        self\n    }\n\n    pub fn info<S: Into<String>>(mut self, info: S) -> Diagnostic {\n        self.info.push(info.into());\n        self\n    }\n\n    pub fn lines(&self) -> std::ops::Range<u32> {\n        let mut range = std::ops::Range {\n            start: self.primary.span.start.line,\n            end: self.primary.span.end.line + 1,\n        };\n\n        for addl in &self.other {\n            if addl.span.start.line < range.start {\n                range.start = addl.span.start.line;\n            }\n            if addl.span.end.line + 1 > range.end {\n                range.end = addl.span.end.line + 1;\n            }\n        }\n        range\n    }\n}\n\nimpl fmt::Debug for Diagnostic {\n    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n        write!(\n            f,\n            \"\\n{:?}: {} starting at line {}, col {}\\n{}\",\n            self.level,\n            self.primary.info,\n            self.primary.span.start.line,\n            self.primary.span.start.col,\n            self.other.iter().map(|a| a.info.clone()).collect::<Vec<_>>().join(\"\\n\")\n        )\n    }\n}\n"
  },
  {
    "path": "07_system_fw/src/elaborate.rs",
    "content": "use super::ast::*;\nuse super::hir::{self, Constructor, DeBruijn, HirId};\nuse super::stack::Stack;\nuse super::syntax::visit::*;\nuse std::collections::{HashMap, HashSet};\nuse std::iter::IntoIterator;\n\n/// Validate that a [`Program`] is closed, e.g. it has no free\n/// term or type variables. We traverse the program in execution order,\n/// adding bindings for top-level declarations, and also keeping track of\n/// bindings that occur in local scopes for de Bruijn index tracking\n#[derive(Default)]\npub struct ElaborationContext<'s> {\n    tyvars: Stack<&'s str>,\n    tmvars: Stack<&'s str>,\n\n    namespaces: Vec<Namespace>,\n    current: usize,\n    constructors: HashMap<HirId, Constructor>,\n    elaborated: HashMap<HirId, hir::Decl>,\n    next_hir_id: HirId,\n}\n\npub struct Elaborated {\n    pub constructors: HashMap<HirId, Constructor>,\n    pub elaborated: HashMap<HirId, hir::Decl>,\n    pub decls: Vec<HirId>,\n}\n\n#[derive(Default)]\npub struct Namespace {\n    id: usize,\n    parent: Option<usize>,\n    values: HashMap<String, HirId>,\n    types: HashMap<String, HirId>,\n}\n\n#[derive(Clone, Debug, PartialEq)]\n\npub enum ElabError {\n    UndefinedType(String, util::span::Span),\n    UndefinedValue(String, util::span::Span),\n    UndefinedConstr(String, util::span::Span),\n    InvalidBinding(String, util::span::Span),\n}\n\n/// Housekeeping, namespace methods\nimpl<'s> ElaborationContext<'s> {\n    pub fn new() -> Self {\n        let mut ec = Self::default();\n        let global_ns = Namespace::default();\n        ec.namespaces.push(global_ns);\n        ec\n    }\n\n    pub fn elaborate(program: &'s Program) -> Result<Elaborated, ElabError> {\n        let mut ec = Self::new();\n        let decls = ec.elab_program(program)?;\n        Ok(Elaborated {\n            constructors: ec.constructors,\n            elaborated: ec.elaborated,\n            decls,\n        })\n    }\n\n    /// Keep track of the type variable stack, while executing the combinator\n    /// function `f` on `self`. Any stack growth is popped off after `f`\n    /// returns.\n    fn with_tyvars<T, F: Fn(&mut ElaborationContext<'s>) -> T>(&mut self, f: F) -> T {\n        let n = self.tyvars.len();\n        let r = f(self);\n        let to_pop = self.tyvars.len() - n;\n        self.tyvars.popn(to_pop);\n        r\n    }\n\n    /// Keep track of the term variable stack, while executing the combinator\n    /// function `f` on `self`. Any stack growth is popped off after `f`\n    /// returns.\n    fn with_tmvars<T, F: Fn(&mut ElaborationContext<'s>) -> T>(&mut self, f: F) -> T {\n        let n = self.tmvars.len();\n        let r = f(self);\n        let to_pop = self.tmvars.len() - n;\n        self.tmvars.popn(to_pop);\n        r\n    }\n\n    fn elab_kind(&self, k: &Kind) -> hir::Kind {\n        match k {\n            Kind::Star => hir::Kind::Star,\n            Kind::Arrow(k1, k2) => hir::Kind::Arrow(Box::new(self.elab_kind(k1)), Box::new(self.elab_kind(k2))),\n        }\n    }\n\n    fn allocate_hir_id(&mut self) -> HirId {\n        let id = self.next_hir_id;\n        self.next_hir_id = HirId(self.next_hir_id.0 + 1);\n        id\n    }\n\n    fn define_value(&mut self, name: String, expr: hir::Expr) -> HirId {\n        let id = self.allocate_hir_id();\n        self.elaborated.insert(id, hir::Decl::Value(expr));\n        self.namespaces[self.current].values.insert(name, id);\n        id\n    }\n\n    fn define_type(&mut self, name: String, ty: hir::Type) -> HirId {\n        let id = self.allocate_hir_id();\n        self.elaborated.insert(id, hir::Decl::Type(ty));\n        self.namespaces[self.current].types.insert(name, id);\n        id\n    }\n\n    pub fn dump(&self) {\n        for n in &self.namespaces {\n            println!(\"Current value bindings:\");\n            for (name, key) in &n.values {\n                println!(\"\\t[{:?}] {}: {:?}\", key, name, self.elaborated.get(key).unwrap());\n            }\n            println!(\"Current type bindings:\");\n            for (name, key) in &n.types {\n                println!(\"\\t[{:?}] {}: {:?}\", key, name, self.elaborated.get(key).unwrap());\n            }\n        }\n\n        println!(\"Current constr bindings:\");\n        for (name, key) in &self.constructors {\n            println!(\"{:?}\", key,);\n        }\n    }\n\n    /// Starting from the current [`Namespace`], search for a bound name.\n    /// If it's not found, then recursively search parent namespaces\n    fn lexical_value(&self, s: &str) -> Option<HirId> {\n        let mut ptr = &self.namespaces[self.current];\n        loop {\n            match ptr.values.get(s) {\n                Some(idx) => return Some(*idx),\n                None => ptr = &self.namespaces[ptr.parent?],\n            }\n        }\n    }\n\n    /// Search for a variable bound in a temporary lexical scope (i.e. a function)\n    fn debruijn_value(&self, s: &str) -> Option<hir::Expr> {\n        self.tmvars\n            .lookup(&s)\n            .map(|idx| hir::Expr::LocalVar(DeBruijn { idx, name: s.into() }))\n    }\n\n    /// Search for a value binding, starting with any temporary lambda captures,\n    /// and then working upwards through top level definitions\n    fn lookup_value(&self, s: &str) -> Option<hir::Expr> {\n        if let Some(db) = self.debruijn_value(s) {\n            return Some(db);\n        }\n        self.lexical_value(s).map(hir::Expr::ProgramVar)\n    }\n\n    fn lexical_type(&self, s: &str) -> Option<HirId> {\n        let mut ptr = &self.namespaces[self.current];\n        loop {\n            match ptr.types.get(s) {\n                Some(idx) => return Some(*idx),\n                None => ptr = &self.namespaces[ptr.parent?],\n            }\n        }\n    }\n\n    fn debruijn_type(&self, s: &str) -> Option<hir::Type> {\n        self.tyvars\n            .lookup(&s)\n            .map(|idx| hir::Type::Var(DeBruijn { idx, name: s.into() }))\n    }\n\n    fn enter_namespace(&mut self) -> usize {\n        let id = self.namespaces.len();\n        self.namespaces.push(Namespace {\n            id,\n            parent: Some(self.current),\n            types: HashMap::new(),\n            values: HashMap::new(),\n        });\n        self.current = id;\n        id\n    }\n\n    fn leave_namespace(&mut self) {\n        match self.namespaces[self.current].parent {\n            Some(id) => self.current = id,\n            None => panic!(\"trying to leave global namespace!\"),\n        }\n    }\n\n    /// Perform all bindings within `f` in a fresh [`Namespace`],\n    /// and then return to the current one\n    fn with_new_namespace<T, F: Fn(&mut ElaborationContext<'s>) -> T>(&mut self, f: F) -> T {\n        self.enter_namespace();\n        let t = f(self);\n        self.leave_namespace();\n        t\n    }\n}\n\n/// Type elaboration\nimpl<'s> ElaborationContext<'s> {\n    fn elab_ty_row(&mut self, row: &'s Row) -> Result<hir::Row, ElabError> {\n        Ok(hir::Row {\n            label: row.label.clone(),\n            ty: self.elab_type(&row.ty)?,\n        })\n    }\n\n    fn elab_ty_inner(&mut self, tv: &'s str, ty: &'s Type) -> Result<hir::Type, ElabError> {\n        self.with_tyvars(|f| {\n            f.tyvars.push(tv);\n            f.elab_type(ty)\n        })\n    }\n\n    fn elab_type(&mut self, ty: &'s Type) -> Result<hir::Type, ElabError> {\n        use TypeKind::*;\n        match &ty.kind {\n            Int => Ok(hir::Type::Int),\n            Bool => Ok(hir::Type::Bool),\n            Unit => Ok(hir::Type::Unit),\n            Infer => Ok(hir::Type::Infer),\n            Defined(s) => self\n                .lexical_type(s)\n                .map(hir::Type::Defined)\n                .ok_or_else(|| ElabError::UndefinedType(s.into(), ty.span)),\n            Variable(s) => self\n                .debruijn_type(s)\n                .ok_or_else(|| ElabError::UndefinedType(s.into(), ty.span)),\n            Function(ty1, ty2) => Ok(hir::Type::Arrow(\n                Box::new(self.elab_type(ty1)?),\n                Box::new(self.elab_type(ty2)?),\n            )),\n\n            // Sum types can only be constructed through a DeclKind::Datatype\n            // so it's okay to be unreachable!() here, as it would be a fatal\n            // bug if we reached this path somehow.\n            Sum(_) => unreachable!(),\n            Product(tys) => Ok(hir::Type::Product(\n                tys.iter().map(|t| self.elab_type(t)).collect::<Result<_, _>>()?,\n            )),\n            Record(rows) => Ok(hir::Type::Record(\n                rows.iter().map(|t| self.elab_ty_row(t)).collect::<Result<_, _>>()?,\n            )),\n            Existential(s, k, ty) => Ok(hir::Type::Existential(\n                Box::new(self.elab_kind(k)),\n                Box::new(self.elab_ty_inner(s, ty)?),\n            )),\n            Universal(s, k, ty) => Ok(hir::Type::Universal(\n                Box::new(self.elab_kind(k)),\n                Box::new(self.elab_ty_inner(s, ty)?),\n            )),\n            Abstraction(s, k, ty) => Ok(hir::Type::Abstraction(\n                Box::new(self.elab_kind(k)),\n                Box::new(self.elab_ty_inner(s, ty)?),\n            )),\n            Application(ty1, ty2) => Ok(hir::Type::Application(\n                Box::new(self.elab_type(ty1)?),\n                Box::new(self.elab_type(ty2)?),\n            )),\n            Recursive(ty) => self.elab_type(ty).map(|ty| hir::Type::Recursive(Box::new(ty))),\n        }\n    }\n}\n\n/// Expr elaboration\nimpl<'s> ElaborationContext<'s> {\n    fn elab_let(&mut self, decls: &'s [Decl], expr: &'s Expr) -> Result<hir::Expr, ElabError> {\n        self.with_new_namespace(|f| {\n            for d in decls {\n                f.elab_decl(d)?;\n            }\n            f.elab_expr(expr)\n        })\n    }\n\n    fn elab_arm(&mut self, arm: &'s Arm) -> Result<hir::Arm, ElabError> {\n        Ok(hir::Arm {\n            pat: self.elab_pattern(&arm.pat, true)?,\n            expr: self.elab_expr(&arm.expr)?,\n        })\n    }\n\n    fn elab_case(&mut self, expr: &'s Expr, arms: &'s [Arm]) -> Result<hir::Expr, ElabError> {\n        let ex = self.elab_expr(expr)?;\n        let arms = arms.iter().map(|a| self.elab_arm(a)).collect::<Result<_, _>>()?;\n        Ok(hir::Expr::Case(Box::new(ex), arms))\n    }\n\n    fn elab_field(&mut self, field: &'s Field) -> Result<hir::Field, ElabError> {\n        Ok(hir::Field {\n            label: field.label.clone(),\n            expr: self.elab_expr(&field.expr)?,\n        })\n    }\n\n    /// We desugar to a case expression\n    /// fn (Some x) => x + 1\n    /// fn $x : Infer option => case $x of (Some x) => x + 1\n    fn elab_abs(&mut self, pat: &'s Pattern, body: &'s Expr) -> Result<hir::Expr, ElabError> {\n        // Wow we have a lot of bindings\n        self.with_tmvars(|f| {\n            let pat = f.elab_pattern(pat, true)?;\n            let expr = f.elab_expr(body)?;\n            let ty = f.naive_type_infer(&pat)?;\n            let arm = hir::Arm { pat, expr };\n            let dummy = hir::Expr::LocalVar(DeBruijn {\n                name: \"$anon\".into(),\n                idx: 0,\n            });\n            let case = hir::Expr::Case(Box::new(dummy), vec![arm]);\n            Ok(hir::Expr::Abs(Box::new(ty), Box::new(case)))\n        })\n    }\n\n    fn elab_expr(&mut self, expr: &'s Expr) -> Result<hir::Expr, ElabError> {\n        use ExprKind::*;\n        match &expr.kind {\n            Unit => Ok(hir::Expr::Unit),\n            Int(i) => Ok(hir::Expr::Int(*i)),\n            Var(s) => self\n                .lookup_value(s)\n                .ok_or_else(|| ElabError::UndefinedValue(s.into(), expr.span)),\n            Constr(s) => self\n                .lexical_value(s)\n                .map(|id| self.constructors.get(&id))\n                .flatten()\n                .map(|c| hir::Expr::Constr(c.type_id, c.tag))\n                .ok_or_else(|| ElabError::UndefinedConstr(s.into(), expr.span)),\n            If(e1, e2, e3) => Ok(hir::Expr::If(\n                Box::new(self.elab_expr(e1)?),\n                Box::new(self.elab_expr(e2)?),\n                Box::new(self.elab_expr(e3)?),\n            )),\n            Abs(pat, expr) => self.elab_abs(pat, expr),\n            App(e1, e2) => Ok(hir::Expr::App(\n                Box::new(self.elab_expr(e1)?),\n                Box::new(self.elab_expr(e2)?),\n            )),\n            TyAbs(s, k, e) => self.with_tyvars(|f| {\n                f.tyvars.push(s);\n                let e = f.elab_expr(e)?;\n                Ok(hir::Expr::TyAbs(Box::new(f.elab_kind(k)), Box::new(e)))\n            }),\n            TyApp(e, t) => Ok(hir::Expr::TyApp(\n                Box::new(self.elab_expr(e)?),\n                Box::new(self.elab_type(t)?),\n            )),\n            Record(fields) => fields\n                .iter()\n                .map(|e| self.elab_field(e))\n                .collect::<Result<_, _>>()\n                .map(hir::Expr::Record),\n            Tuple(exprs) => exprs\n                .iter()\n                .map(|e| self.elab_expr(e))\n                .collect::<Result<_, _>>()\n                .map(hir::Expr::Tuple),\n            Projection(e1, e2) => match &e2.kind {\n                ExprKind::Var(label) => Ok(hir::Expr::RecordProj(Box::new(self.elab_expr(e1)?), label.clone())),\n                ExprKind::Int(idx) => Ok(hir::Expr::TupleProj(Box::new(self.elab_expr(e1)?), *idx)),\n                _ => Err(ElabError::InvalidBinding(\n                    format!(\"attempt to project using {:?}\", e2),\n                    expr.span,\n                )),\n            },\n            Case(e, arms) => self.elab_case(e, arms),\n            Let(decls, e) => self.elab_let(decls, e),\n        }\n    }\n}\n\n/// Pattern elaboration\nimpl<'s> ElaborationContext<'s> {\n    fn naive_type_infer(&self, pat: &hir::Pattern) -> Result<hir::Type, ElabError> {\n        use hir::Pattern::*;\n        match pat {\n            Any => Ok(hir::Type::Infer),\n            Unit => Ok(hir::Type::Unit),\n            Literal(_) => Ok(hir::Type::Int),\n            Ascribe(_, ty) => Ok(*ty.clone()),\n            Constructor(id) => {\n                let con = self.constructors.get(&id).expect(\"internal error\");\n                let cty = hir::Type::Defined(con.type_id);\n                if con.type_arity != 0 {\n                    Ok(hir::Type::Application(Box::new(cty), Box::new(hir::Type::Infer)))\n                } else {\n                    Ok(cty)\n                }\n            }\n            Product(pats) => pats\n                .into_iter()\n                .map(|p| self.naive_type_infer(p))\n                .collect::<Result<_, _>>()\n                .map(hir::Type::Product),\n\n            // Maybe we should go back to sub pats...\n            Record(s) => Ok(hir::Type::Record(\n                s.into_iter()\n                    .map(|s| hir::Row {\n                        label: s.clone(),\n                        ty: hir::Type::Infer,\n                    })\n                    .collect(),\n            )),\n            Application(id, arg) => {\n                let con = self.constructors.get(&id).expect(\"internal error\");\n                let cty = hir::Type::Defined(con.type_id);\n                // Ok(cty)\n                self.naive_type_infer(arg)\n                    .map(|ty| hir::Type::Application(Box::new(cty), Box::new(ty)))\n            }\n            Variable(_) => Ok(hir::Type::Infer),\n        }\n    }\n    fn elab_pattern(&mut self, pat: &'s Pattern, bind: bool) -> Result<hir::Pattern, ElabError> {\n        match &pat.kind {\n            PatKind::Any => Ok(hir::Pattern::Any),\n            PatKind::Unit => Ok(hir::Pattern::Unit),\n            PatKind::Literal(i) => Ok(hir::Pattern::Literal(*i)),\n            PatKind::Variable(s) => {\n                if bind {\n                    self.tmvars.push(s);\n                }\n                Ok(hir::Pattern::Variable(s.clone()))\n            }\n            PatKind::Product(sub) => sub\n                .iter()\n                .map(|p| self.elab_pattern(p, bind))\n                .collect::<Result<_, _>>()\n                .map(hir::Pattern::Product),\n            PatKind::Record(sub) => Ok(hir::Pattern::Record(sub.clone())),\n            PatKind::Ascribe(pat, ty) => Ok(hir::Pattern::Ascribe(\n                Box::new(self.elab_pattern(pat, bind)?),\n                Box::new(self.elab_type(ty)?),\n            )),\n            PatKind::Constructor(s) => self\n                .lexical_value(s)\n                .ok_or_else(|| ElabError::UndefinedConstr(s.clone(), pat.span))\n                .map(hir::Pattern::Constructor),\n            PatKind::Application(con, arg) => {\n                let econ = self.elab_pattern(con, bind)?;\n                let earg = self.elab_pattern(arg, bind)?;\n                let id = match econ {\n                    hir::Pattern::Constructor(id) => {\n                        let con_info = self.constructors.get(&id).unwrap();\n                        if !con_info.arity {\n                            let name = match &con.as_ref().kind {\n                                PatKind::Constructor(s) => s.clone(),\n                                _ => panic!(\"interal error!\"),\n                            };\n                            return Err(ElabError::InvalidBinding(\n                                format!(\"constructor {} doesn't accept arguments!\", name),\n                                pat.span,\n                            ));\n                        }\n                        id\n                    }\n                    _ => {\n                        return Err(ElabError::InvalidBinding(\n                            format!(\"cannot apply {:?} to non-constructor {:?}\", arg, con),\n                            pat.span,\n                        ))\n                    }\n                };\n                Ok(hir::Pattern::Application(id, Box::new(earg)))\n            }\n        }\n    }\n}\n\n/// Decl elaboration\nimpl<'s> ElaborationContext<'s> {\n    fn elab_decl_type(&mut self, tyvars: &'s [Type], name: &'s str, ty: &'s Type) -> Result<HirId, ElabError> {\n        let ty = self.elab_type(ty)?;\n        let ty = tyvars.iter().fold(ty, |ty, var| {\n            hir::Type::Abstraction(Box::new(hir::Kind::Star), Box::new(ty))\n        });\n        Ok(self.define_type(name.into(), ty))\n    }\n\n    fn elab_constructor(\n        &mut self,\n        name: &'s str,\n        tag: usize,\n        tyvar_arity: usize,\n        type_signature: Option<&hir::Type>,\n        type_id: HirId,\n    ) -> HirId {\n        let expr = match type_signature {\n            Some(ty) => hir::Expr::Abs(\n                Box::new(ty.clone()),\n                Box::new(hir::Expr::App(\n                    Box::new(hir::Expr::Constr(type_id, tag)),\n                    Box::new(hir::Expr::LocalVar(DeBruijn {\n                        name: String::from(\"x\"),\n                        idx: 0,\n                    })),\n                )),\n            ),\n            None => hir::Expr::Constr(type_id, tag),\n        };\n\n        let expr = (0..tyvar_arity).fold(expr, |e, _| hir::Expr::TyAbs(Box::new(hir::Kind::Star), Box::new(e)));\n\n        let arity = type_signature.is_some();\n\n        let con_id = self.define_value(name.into(), expr);\n        self.constructors.insert(\n            con_id,\n            Constructor {\n                type_id,\n                con_id,\n                tag,\n                arity,\n                type_arity: tyvar_arity as u8,\n            },\n        );\n        con_id\n    }\n\n    fn elab_decl_datatype(&mut self, tyvars: &'s [Type], name: &'s str, ty: &'s Type) -> Result<HirId, ElabError> {\n        // Quickly collection all names that this type points to\n        let mut coll = TyNameCollector::default();\n        coll.visit_ty(&ty);\n        let is_recur = coll.definitions.contains(name);\n\n        // Insert first, so we can be recursive if we need to\n        let id = self.allocate_hir_id();\n        self.namespaces[self.current].types.insert(name.into(), id);\n\n        // We just do all of this inside of the closure, rather than delegrating\n        // to visit_sum, because we need access to both `tyvars` for generating\n        // value-bindings for the constructors\n        let ty = self.with_tyvars(|f| {\n            f.tyvars.extend(tyvars.iter().map(|t| t.kind.as_tyvar()));\n\n            let mut elab = Vec::new();\n            for (idx, v) in ty.kind.variants().iter().enumerate() {\n                let ty = v.ty.as_ref().map(|ty| f.elab_type(ty)).transpose()?;\n\n                // Generate a function or constant value for the constructor\n                f.elab_constructor(&v.label, idx, tyvars.len(), ty.as_ref(), id);\n                elab.push(hir::Variant {\n                    label: v.label.clone(),\n                    ty,\n                });\n            }\n            Ok(hir::Type::Sum(elab))\n        })?;\n\n        // We have the raw sum type, so now wrap it in type abstractions\n        let ty = tyvars.iter().fold(ty, |ty, var| {\n            hir::Type::Abstraction(Box::new(hir::Kind::Star), Box::new(ty))\n        });\n        let ty = if is_recur {\n            hir::Type::Recursive(Box::new(ty))\n        } else {\n            ty\n        };\n\n        self.elaborated.insert(id, hir::Decl::Type(ty));\n        Ok(id)\n    }\n\n    /// Caller is responsible for checking tmvar and tyvar stack growth\n    /// Note: this function directly adds bindings to the global definition states\n    fn deconstruct_pat_binding(\n        &mut self,\n        pat: hir::Pattern,\n        expr: hir::Expr,\n        span: util::span::Span,\n    ) -> Result<HirId, ElabError> {\n        use hir::Pattern::*;\n        match pat {\n            Any | Unit => Ok(self.define_value(String::default(), expr)),\n            Variable(s) => Ok(self.define_value(s, expr)),\n            Product(sub) => {\n                // No need for extra redirection\n                let id = match expr {\n                    hir::Expr::ProgramVar(id) => id,\n                    _ => self.define_value(String::default(), expr),\n                };\n\n                let base = Box::new(hir::Expr::ProgramVar(id));\n                for (idx, pat) in sub.into_iter().enumerate() {\n                    self.deconstruct_pat_binding(pat, hir::Expr::TupleProj(base.clone(), idx), span)?;\n                }\n                Ok(id)\n            }\n            Record(sub) => {\n                let id = match expr {\n                    hir::Expr::ProgramVar(id) => id,\n                    _ => self.define_value(String::default(), expr),\n                };\n                let base = Box::new(hir::Expr::ProgramVar(id));\n\n                for (idx, pat) in sub.into_iter().enumerate() {\n                    self.define_value(pat, hir::Expr::TupleProj(base.clone(), idx));\n                }\n                Ok(id)\n            }\n            Ascribe(pat, _) => self.deconstruct_pat_binding(*pat, expr, span),\n            Constructor(_) => Err(ElabError::InvalidBinding(\n                format!(\"cannot bind constructor to a value!\"),\n                span,\n            )),\n            Application(con, arg) => {\n                //      con  arg     expr\n                // val Some (x, y) = Some (10, 9)\n                // val Some (x, y) = funct 10\n                //     $anon = func 10\n                //      case $anon of\n\n                let con_info = self.constructors.get(&con).unwrap();\n                let e = hir::Expr::App(\n                    Box::new(hir::Expr::Deconstr(con_info.type_id, con_info.tag)),\n                    Box::new(expr),\n                );\n\n                let id = self.with_new_namespace(|f| f.define_value(\"$anon_bind_decon\".into(), e.clone()));\n                let e = hir::Expr::ProgramVar(id);\n                self.deconstruct_pat_binding(*arg, e, span)\n            }\n            Literal(_) => Err(ElabError::InvalidBinding(\n                format!(\"cannot bind a literal pattern to a value!\"),\n                span,\n            )),\n        }\n    }\n\n    fn elab_decl_value(&mut self, tyvars: &'s [Type], pat: &'s Pattern, expr: &'s Expr) -> Result<HirId, ElabError> {\n        self.with_tyvars(|f| {\n            f.tyvars.extend(tyvars.iter().map(|t| t.kind.as_tyvar()));\n            f.with_tmvars(|f| {\n                let sp = pat.span;\n                let pat = f.elab_pattern(pat, false)?;\n                let ex = f.elab_expr(expr)?;\n                f.deconstruct_pat_binding(pat, ex, sp)\n            })\n        })\n    }\n\n    fn build_pat_matrix(&mut self, arms: &'s [FnArm]) -> Result<PatternMatrix, ElabError> {\n        let rows = arms.len();\n        let mut pats: Vec<Vec<hir::Pattern>> = Vec::with_capacity(rows);\n        let mut exprs = Vec::with_capacity(rows);\n\n        let mut cols = 0;\n        for arm in arms {\n            cols = cols.max(arm.pats.len());\n            pats.push(\n                arm.pats\n                    .iter()\n                    .map(|p| self.elab_pattern(p, true))\n                    .collect::<Result<_, _>>()?,\n            );\n            dbg!(&self.tmvars);\n            exprs.push(self.elab_expr(&arm.expr)?);\n        }\n\n        for r in pats.iter_mut() {\n            if r.len() < cols {\n                r.extend(std::iter::repeat(hir::Pattern::Any).take(cols - r.len()));\n            }\n        }\n\n        Ok(PatternMatrix {\n            pats,\n            exprs,\n            rows,\n            cols,\n        })\n    }\n\n    fn infer_type_matrix(&self, mat: &PatternMatrix) -> Result<Vec<HashSet<hir::Type>>, ElabError> {\n        let mut cols: Vec<HashSet<hir::Type>> = (0..mat.cols).map(|_| HashSet::default()).collect();\n\n        for i in 0..mat.cols {\n            for j in 0..mat.rows {\n                let ty = self.naive_type_infer(&mat.pats[j][i])?;\n                cols[i].insert(ty);\n            }\n        }\n\n        Ok(cols)\n    }\n\n    fn try_unify_type_matrix(mat: Vec<HashSet<hir::Type>>) -> Vec<hir::Type> {\n        fn unify(a: hir::Type, b: hir::Type) -> hir::Type {\n            use hir::Type::*;\n            if a == b {\n                return a;\n            }\n            match (a, b) {\n                (Infer, x) => x,\n                (x, Infer) => x,\n                (Application(r1, r2), Application(r3, r4)) if r1 == r3 => Application(r1, Box::new(unify(*r2, *r4))),\n                (Product(xs), Product(ys)) if xs.len() == ys.len() => {\n                    Product(xs.into_iter().zip(ys.into_iter()).map(|(x, y)| unify(x, y)).collect())\n                }\n                _ => hir::Type::Unclear,\n            }\n        }\n\n        mat.into_iter()\n            .map(|col| col.into_iter().fold(hir::Type::Infer, |ty, x| unify(ty, x)))\n            .collect()\n    }\n\n    fn elab_decl_fun(&mut self, tyvars: &'s [Type], name: &'s str, arms: &'s [FnArm]) -> Result<HirId, ElabError> {\n        self.with_tyvars(|f| {\n            f.tyvars.extend(tyvars.iter().map(|t| t.kind.as_tyvar()));\n            f.with_tmvars(|f| {\n                f.tmvars.push(name);\n\n                let matrix = f.build_pat_matrix(arms)?;\n                let tys = f.infer_type_matrix(&matrix)?;\n                let tys = Self::try_unify_type_matrix(tys);\n\n                let arms = matrix.collapse();\n                let expr = hir::Expr::Tuple(\n                    (0..tys.len())\n                        .rev()\n                        .map(|idx| {\n                            hir::Expr::LocalVar(DeBruijn {\n                                name: String::new(),\n                                idx,\n                            })\n                        })\n                        .collect(),\n                );\n\n                let case = hir::Expr::Case(Box::new(expr), arms);\n\n                let fun = tys\n                    .into_iter()\n                    .rev()\n                    .fold(case, |acc, ty| hir::Expr::Abs(Box::new(ty), Box::new(acc)));\n                // let fun = hir::Expr::Abs(\n                //     Box::new(hir::Type::Arrow(\n                //         Box::new(hir::Type::Infer),\n                //         Box::new(hir::Type::Infer),\n                //     )),\n                //     Box::new(fun),\n                // );\n                // let fun = hir::Expr::Fix(Box::new(fun));\n\n                Ok(f.define_value(name.into(), fun))\n            })\n        })\n    }\n\n    fn elab_decl_expr(&mut self, expr: &'s Expr) -> Result<HirId, ElabError> {\n        let e = self.elab_expr(expr)?;\n        Ok(self.define_value(String::default(), e))\n    }\n\n    fn elab_decl_and(&mut self, a: &'s Decl, b: &'s Decl) -> Result<HirId, ElabError> {\n        let mut names = DeclNames::default();\n        names.visit_decl(a);\n        names.visit_decl(b);\n\n        for name in names.values {\n            // Insert first, so we can be recursive if we need to\n            let id = self.allocate_hir_id();\n            self.namespaces[self.current].values.insert(name.into(), id);\n        }\n\n        unimplemented!()\n    }\n\n    fn elab_decl(&mut self, decl: &'s Decl) -> Result<HirId, ElabError> {\n        match &decl.kind {\n            DeclKind::Datatype(tyvars, name, ty) => self.elab_decl_datatype(tyvars, name, ty),\n            DeclKind::Type(tyvars, name, ty) => self.elab_decl_type(tyvars, name, ty),\n            DeclKind::Value(tyvars, pat, expr) => self.elab_decl_value(tyvars, pat, expr),\n            DeclKind::And(d1, d2) => unimplemented!(),\n            DeclKind::Function(tyvars, name, arms) => self.elab_decl_fun(tyvars, name, arms),\n            DeclKind::Expr(e) => self.elab_decl_expr(e),\n        }\n    }\n\n    pub fn elab_program(&mut self, prog: &'s Program) -> Result<Vec<HirId>, ElabError> {\n        let mut v = Vec::with_capacity(prog.decls.len());\n        for d in &prog.decls {\n            v.push(self.elab_decl(d)?);\n            self.dump();\n        }\n        Ok(v)\n    }\n}\n\n#[derive(Debug, Clone)]\npub struct PatternMatrix {\n    pats: Vec<Vec<hir::Pattern>>,\n    exprs: Vec<hir::Expr>,\n    rows: usize,\n    cols: usize,\n}\n\nimpl PatternMatrix {\n    fn collapse(self) -> Vec<hir::Arm> {\n        let mut arms = Vec::new();\n        for (pat, expr) in self.pats.into_iter().zip(self.exprs.into_iter()) {\n            arms.push(hir::Arm {\n                pat: hir::Pattern::Product(pat),\n                expr,\n            });\n        }\n        arms\n    }\n}\n\n/// Helper struct for walking top-level declarations and extracting\n/// bound type and value names. This does no validation or checking\n#[derive(Default)]\nstruct DeclNames<'s> {\n    values: Vec<&'s str>,\n    types: Vec<&'s str>,\n}\n\nimpl<'s> DeclNames<'s> {\n    fn visit_pat(&mut self, pat: &'s Pattern) {\n        match &pat.kind {\n            PatKind::Variable(s) => self.values.push(&s),\n            PatKind::Product(sub) => {\n                for p in sub {\n                    self.visit_pat(p);\n                }\n            }\n            PatKind::Record(sub) => {\n                for p in sub {\n                    self.values.push(p);\n                }\n            }\n            PatKind::Ascribe(pat, ty) => self.visit_pat(&pat),\n            PatKind::Application(con, arg) => self.visit_pat(&arg),\n            _ => {}\n        }\n    }\n\n    fn visit_decl(&mut self, d: &'s Decl) {\n        match &d.kind {\n            DeclKind::Datatype(_, name, ty) => self.types.push(&name),\n            DeclKind::Type(_, name, ty) => self.types.push(&name),\n            DeclKind::Value(_, pat, expr) => self.visit_pat(pat),\n            DeclKind::And(d1, d2) => {\n                self.visit_decl(d1);\n                self.visit_decl(d2);\n            }\n            DeclKind::Function(_, name, arms) => self.values.push(&name),\n            _ => {}\n        }\n    }\n}\n\n/// Collect type variables and references to defined names\n#[derive(Default, Debug, Clone)]\npub struct TyNameCollector<'s> {\n    pub tyvars: HashSet<&'s str>,\n    pub definitions: HashSet<&'s str>,\n}\n\nimpl<'s> TypeVisitor<'s> for TyNameCollector<'s> {\n    fn visit_variable(&mut self, s: &'s str) {\n        self.tyvars.insert(s);\n    }\n\n    fn visit_defined(&mut self, s: &'s str) {\n        self.definitions.insert(s);\n    }\n}\n"
  },
  {
    "path": "07_system_fw/src/functor.rs",
    "content": "use super::*;\n\npub fn parameterized_set() -> Type {\n    tyop!(kind!(*), exist!(kind!(* => *), op_app!(Type::Var(0), Type::Var(1))))\n}\n\nfn list_type() -> Type {\n    let inner = tyop!(\n        kind!(* => *),\n        tyop!(\n            kind!(*),\n            sum!(\n                (\"Nil\", Type::Unit),\n                (\n                    \"Cons\",\n                    record!((\"head\", Type::Var(0)), (\"tail\", op_app!(Type::Var(1), Type::Var(0))))\n                )\n            )\n        )\n    );\n    Type::Recursive(Box::new(inner))\n}\n\npub fn parameterized_set_term() -> Term {\n    let body = Term::new(\n        terms::Kind::Fold(\n            Box::new(op_app!(list_type(), Type::Var(0))),\n            Box::new(Term::new(\n                terms::Kind::Injection(\n                    \"Nil\".into(),\n                    Box::new(unit!()),\n                    // Manually perform an unfold on list_type()\n                    // - In the System F language, we had an\n                    // InjRewriter macro that takes care of this,\n                    // and we could probably tack it directly\n                    // into the type-checker since we can do simplification\n                    // now\n                    Box::new(op_app!(unfold(list_type()), Type::Var(0))),\n                ),\n                Span::default(),\n            )),\n        ),\n        Span::default(),\n    );\n\n    // \\X :: * => pack type 'a list = Nil | Cons 'a * 'a list with Nil as /\\T::*\n    // {*X::*=>*, X T}\n    tyabs!(\n        kind!(*),\n        pack!(list_type(), body, op_app!(parameterized_set(), Type::Var(0)))\n    )\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn parameterized_functor() {\n        let mut ctx = typecheck::Context::default();\n        let func = tyapp!(functor::parameterized_set_term(), Type::Nat);\n        let func_actual_ty = ctx.typecheck(&func).unwrap();\n        let func_described_ty = op_app!(functor::parameterized_set(), Type::Nat);\n        assert_eq!(ctx.equiv(&func_actual_ty, &func_described_ty), Ok(true));\n    }\n}\n"
  },
  {
    "path": "07_system_fw/src/hir/bidir.rs",
    "content": "use super::*;\nuse crate::elaborate::Elaborated;\nuse std::collections::HashMap;\n\nuse super::Type::*;\n\n#[derive(Debug)]\npub struct Context<'hir> {\n    hir_map: &'hir HashMap<HirId, Decl>,\n    defs: HashMap<HirId, Type>,\n    ctx: Vec<Element>,\n    gen: usize,\n}\n\n/// An element in the typing context\n#[derive(Clone, Debug, PartialEq)]\npub enum Element {\n    /// Universal type variable\n    Var,\n    /// Term variable typing x : A. We differ from the paper in that we use\n    /// de Bruijn indices for variables, so we don't need to mark which var\n    /// this annotation belongs to - it always belongs to the innermost binding (idx 0)\n    /// and we will find this by traversing the stack\n    Ann(Type),\n    /// Unsolved existential type variable\n    Exist(usize),\n    /// Existential type variable that has been solved\n    /// to some monotype\n    Solved(usize, Type),\n    /// I am actually unsure if we really need a marker, due to how we structure\n    /// scoping, see `with_scope` method.\n    Marker(usize),\n}\n\npub enum Error {\n    UnboundVariable,\n}\n\nimpl<'hir> Context<'hir> {\n    /// Find the term annotation corresponding to de Bruijn index `idx`.\n    /// We traverse the stack in a reversed order, counting each annotation\n    /// we come across\n    fn find_annotation(&self, idx: usize) -> Option<&Type> {\n        let mut ix = 0;\n        for elem in self.ctx.iter().rev() {\n            match &elem {\n                Element::Ann(ty) => {\n                    if ix == idx {\n                        return Some(&ty);\n                    }\n                    ix += 1\n                }\n                _ => {}\n            }\n        }\n\n        None\n    }\n\n    pub fn infer(&mut self, e: &'hir Expr) -> Result<Type, Error> {\n        use Expr::*;\n        match e {\n            Unit => Ok(Type::Unit),\n            Int(usize) => Ok(Type::Int),\n            LocalVar(db) => self.find_annotation(db.idx).cloned().ok_or(Error::UnboundVariable),\n            ProgramVar(id) => unimplemented!(),\n\n            // Datatype constructor, pointing to type def and tag of the constr\n            Constr(id, tag) => unimplemented!(),\n            Deconstr(id, tag) => unimplemented!(),\n            If(e1, e2, e3) => unimplemented!(),\n\n            Abs(ty, ex) => {\n                dbg!(ty);\n                unimplemented!()\n            }\n            App(e1, e2) => unimplemented!(),\n            TyAbs(k, ex) => unimplemented!(),\n            TyApp(ex, ty) => unimplemented!(),\n            Record(fields) => fields\n                .iter()\n                .map(|f| {\n                    Ok(Row {\n                        label: f.label.clone(),\n                        ty: self.infer(&f.expr)?,\n                    })\n                })\n                .collect::<Result<Vec<_>, _>>()\n                .map(Type::Record),\n            Tuple(exprs) => exprs\n                .iter()\n                .map(|e| self.infer(e))\n                .collect::<Result<Vec<_>, _>>()\n                .map(Type::Product),\n            RecordProj(ex, idx) => unimplemented!(),\n            TupleProj(ex, idx) => unimplemented!(),\n            Case(ex, arms) => unimplemented!(),\n            Let(decls, ex) => unimplemented!(),\n            Fix(ex) => unimplemented!(),\n        }\n    }\n}\n\npub fn test(prog: Elaborated) {\n    let mut ctx = Context {\n        hir_map: &prog.elaborated,\n        defs: HashMap::new(),\n        ctx: Vec::new(),\n        gen: 0,\n    };\n\n    for id in prog.decls {\n        match prog.elaborated.get(&id) {\n            Some(Decl::Value(e)) => {\n                ctx.infer(e);\n            }\n            _ => {}\n        }\n\n        dbg!(&ctx);\n    }\n}\n"
  },
  {
    "path": "07_system_fw/src/hir/mod.rs",
    "content": "pub mod bidir;\n\nuse std::fmt;\n\n#[derive(Clone, Debug, PartialEq, PartialOrd, Eq, Hash)]\npub struct DeBruijn {\n    pub idx: usize,\n    pub name: String,\n}\n\n#[derive(Copy, Clone, Debug, Default, PartialEq, PartialOrd, Eq, Hash)]\npub struct HirId(pub(crate) u32);\n\n/// Arm of a case expression\n#[derive(Clone, Debug, PartialEq, PartialOrd)]\npub struct Arm {\n    pub pat: Pattern,\n    pub expr: Expr,\n}\n\n#[derive(Clone, Debug, PartialEq, PartialOrd)]\npub struct Field {\n    pub label: String,\n    pub expr: Expr,\n}\n\npub struct Program {\n    pub decls: Vec<Decl>,\n}\n\n// A lot of desugaring goes on here\n#[derive(Clone, Debug, PartialEq, PartialOrd)]\npub enum Decl {\n    Type(Type),\n    Value(Expr),\n}\n\n#[derive(Clone, Debug, PartialEq, PartialOrd)]\npub struct Constructor {\n    // Points to the constructor function in defined_values\n    pub con_id: HirId,\n    // Points to a Type::Sum in the defined_types map\n    pub type_id: HirId,\n    // Index of this constructor into the sum variants\n    pub tag: usize,\n    // Whether this constr takes an argument or not\n    pub arity: bool,\n    pub type_arity: u8,\n}\n\n/// Patterns for case and let expressions\n#[derive(Clone, Debug, PartialEq, PartialOrd)]\npub enum Pattern {\n    /// Wildcard pattern, this always matches\n    Any,\n    Unit,\n    Ascribe(Box<Pattern>, Box<Type>),\n    /// Constant pattern\n    Literal(usize),\n    /// Datatype constructor, HirId points to the constructor value binding\n    Constructor(HirId),\n    /// Variable binding\n    Variable(String),\n    /// Tuple of pattern bindings (_, x)\n    Product(Vec<Pattern>),\n    /// Record pattern { label1, label2 }\n    Record(Vec<String>),\n    /// Algebraic datatype constructor, along with binding pattern\n    Application(HirId, Box<Pattern>),\n}\n\n#[derive(Clone, Debug, PartialEq, PartialOrd)]\npub enum Expr {\n    Unit,\n    Int(usize),\n    LocalVar(DeBruijn),\n    ProgramVar(HirId),\n\n    // Datatype constructor, pointing to type def and tag of the constr\n    Constr(HirId, usize),\n    Deconstr(HirId, usize),\n    If(Box<Expr>, Box<Expr>, Box<Expr>),\n\n    // Desugar into explicit type bindings\n    Abs(Box<Type>, Box<Expr>),\n    App(Box<Expr>, Box<Expr>),\n\n    TyAbs(Box<Kind>, Box<Expr>),\n    TyApp(Box<Expr>, Box<Type>),\n    Record(Vec<Field>),\n    Tuple(Vec<Expr>),\n\n    RecordProj(Box<Expr>, String),\n    TupleProj(Box<Expr>, usize),\n    Case(Box<Expr>, Vec<Arm>),\n    Let(Vec<Decl>, Box<Expr>),\n    Fix(Box<Expr>),\n}\n\n#[derive(Clone, Debug, PartialEq, PartialOrd, Eq, Hash)]\npub enum Kind {\n    Star,\n    Arrow(Box<Kind>, Box<Kind>),\n}\n\n#[derive(Clone, PartialEq, PartialOrd, Eq, Hash)]\npub enum Type {\n    Int,\n    Bool,\n    Unit,\n    Infer,\n    Error,\n    Unclear,\n    /// Defined name\n    Defined(HirId),\n    /// Type variable 'a\n    Var(DeBruijn),\n    /// Type of functions from terms to terms\n    Arrow(Box<Type>, Box<Type>),\n    /// Sum type; None | Some of 'a\n    Sum(Vec<Variant>),\n    /// Tuple type (ty * ty * ... tyN), invariant that N >= 1\n    Product(Vec<Type>),\n    /// Record type { [label: ty],+ }, invariant that N >=1\n    Record(Vec<Row>),\n    /// Existential type: exists (a :: K) of ty\n    Existential(Box<Kind>, Box<Type>),\n    /// Universal type: forall (a :: K) of ty\n    Universal(Box<Kind>, Box<Type>),\n    /// Type level function abstraction\n    Abstraction(Box<Kind>, Box<Type>),\n    /// Type level function application\n    Application(Box<Type>, Box<Type>),\n    /// Recursive type\n    Recursive(Box<Type>),\n}\n\n#[derive(Clone, PartialEq, PartialOrd, Eq, Hash)]\npub struct Variant {\n    pub label: String,\n    pub ty: Option<Type>,\n}\n\n#[derive(Clone, PartialEq, PartialOrd, Eq, Hash)]\npub struct Row {\n    pub label: String,\n    pub ty: Type,\n}\n\nimpl fmt::Debug for Type {\n    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n        match self {\n            Type::Unit => write!(f, \"unit\"),\n            Type::Int => write!(f, \"int\"),\n            Type::Bool => write!(f, \"bool\"),\n            Type::Infer => write!(f, \"_\"),\n            Type::Error => write!(f, \"!\"),\n            Type::Unclear => write!(f, \"?\"),\n            Type::Var(v) => write!(f, \"{}\", &v.idx),\n            Type::Sum(v) => write!(\n                f,\n                \"{}\",\n                v.iter()\n                    .map(|x| format!(\n                        \"{}{}\",\n                        x.label,\n                        x.ty.as_ref().map(|i| format!(\" of {:?}\", i)).unwrap_or(String::new())\n                    ))\n                    .collect::<Vec<String>>()\n                    .join(\" | \")\n            ),\n            Type::Product(v) => write!(\n                f,\n                \"({})\",\n                v.iter().map(|x| format!(\"{:?}\", x)).collect::<Vec<String>>().join(\",\")\n            ),\n            Type::Record(v) => write!(\n                f,\n                \"{{{}}}\",\n                v.iter()\n                    .map(|x| format!(\"{}: {:?}\", x.label, x.ty))\n                    .collect::<Vec<String>>()\n                    .join(\", \")\n            ),\n            Type::Defined(s) => write!(f, \"tctx#{:?}\", s),\n            Type::Arrow(t1, t2) => write!(f, \"({:?}->{:?})\", t1, t2),\n            Type::Universal(k, ty) => write!(f, \"forall X :: {:?}.{:?}\", k, ty),\n            Type::Existential(k, ty) => write!(f, \"exists X. :: {:?}. {:?}\", k, ty),\n            Type::Abstraction(k, ty) => write!(f, \"fn (X. :: {:?}) => {:?}\", k, ty),\n            Type::Application(a, b) => write!(f, \"{:?} {:?}\", b, a),\n            Type::Recursive(ty) => write!(f, \"rec {:?}\", ty),\n        }\n    }\n}\n"
  },
  {
    "path": "07_system_fw/src/macros.rs",
    "content": "#![allow(unused_macros)]\n/// Boolean term\nmacro_rules! bool {\n    ($x:expr) => {\n        crate::terms::Term::new(\n            crate::terms::Kind::Const(crate::terms::Constant::Bool($x)),\n            util::span::Span::dummy(),\n        )\n    };\n}\n\n/// Integer term\nmacro_rules! nat {\n    ($x:expr) => {\n        crate::terms::Term::new(\n            crate::terms::Kind::Const(crate::terms::Constant::Nat($x)),\n            util::span::Span::dummy(),\n        )\n    };\n}\n\nmacro_rules! unit {\n    () => {\n        crate::terms::Term::new(\n            crate::terms::Kind::Const(crate::terms::Constant::Unit),\n            util::span::Span::dummy(),\n        )\n    };\n}\n\n/// TmVar term\nmacro_rules! var {\n    ($x:expr) => {\n        crate::terms::Term::new(crate::terms::Kind::Var($x), util::span::Span::dummy())\n    };\n}\n\n/// Application term\nmacro_rules! app {\n    ($t1:expr, $t2:expr) => {\n        crate::terms::Term::new(\n            crate::terms::Kind::App(Box::new($t1), Box::new($t2)),\n            util::span::Span::dummy(),\n        )\n    };\n}\n\n/// Lambda abstraction term\nmacro_rules! abs {\n    ($ty:expr, $t:expr) => {\n        crate::terms::Term::new(\n            crate::terms::Kind::Abs(Box::new($ty), Box::new($t)),\n            util::span::Span::dummy(),\n        )\n    };\n}\n\n/// Type application term\nmacro_rules! tyapp {\n    ($t1:expr, $t2:expr) => {\n        crate::terms::Term::new(\n            crate::terms::Kind::TyApp(Box::new($t1), Box::new($t2)),\n            util::span::Span::dummy(),\n        )\n    };\n}\n\n/// Type abstraction term\nmacro_rules! tyabs {\n    ($k:expr, $t:expr) => {\n        crate::terms::Term::new(\n            crate::terms::Kind::TyAbs(Box::new($k), Box::new($t)),\n            util::span::Span::dummy(),\n        )\n    };\n}\n\nmacro_rules! pack {\n    ($ty1:expr, $t:expr, $ty2:expr) => {\n        crate::terms::Term::new(\n            crate::terms::Kind::Pack(Box::new($ty1), Box::new($t), Box::new($ty2)),\n            util::span::Span::dummy(),\n        )\n    };\n}\n\nmacro_rules! unpack {\n    ($t1:expr, $t2:expr) => {\n        crate::terms::Term::new(\n            crate::terms::Kind::Unpack(Box::new($t1), Box::new($t2)),\n            util::span::Span::dummy(),\n        )\n    };\n}\n\nmacro_rules! access {\n    ($t1:expr, $t2:expr) => {\n        crate::terms::Term::new(\n            crate::terms::Kind::Index(Box::new($t1), $t2.into()),\n            util::span::Span::dummy(),\n        )\n    };\n}\n\nmacro_rules! exist {\n    ($k:expr, $ty:expr) => {\n        crate::types::Type::Existential(Box::new($k), Box::new($ty))\n    };\n}\n\nmacro_rules! univ {\n    ($ty:expr) => {\n        crate::types::Type::Universal(Box::new(kind!(*)), Box::new($ty))\n    };\n    ($k:expr, $ty:expr) => {\n        crate::types::Type::Universal(Box::new($k), Box::new($ty))\n    };\n}\n\nmacro_rules! arrow {\n    ($ty1:expr, $ty2:expr) => {\n        crate::types::Type::Arrow(Box::new($ty1), Box::new($ty2))\n    };\n}\n\nmacro_rules! field {\n    ($name:expr, $ty:expr) => {\n        crate::types::TyField {\n            label: $name.to_string(),\n            ty: Box::new($ty),\n        }\n    };\n}\n\nmacro_rules! record {\n    ($($name:expr),+) => {\n        crate::types::Type::Record(vec![$(field!($name.0, $name.1)),+])\n    }\n}\n\nmacro_rules! sum {\n    ($($name:expr),+) => {\n        crate::types::Type::Sum(vec![$(field!($name.0, $name.1)),+])\n    }\n}\n\nmacro_rules! product {\n    ($($name:expr),+) => {\n        crate::types::Type::Product(vec![$($name),+])\n    }\n}\n\nmacro_rules! tyop {\n    ($k:expr, $ty:expr) => {\n        crate::types::Type::Abs(Box::new($k), Box::new($ty))\n    };\n}\n\nmacro_rules! op_app {\n    ($ty1:expr, $ty2:expr) => {\n        crate::types::Type::App(Box::new($ty1), Box::new($ty2))\n    };\n}\n\nmacro_rules! kind {\n    (*) => { crate::types::TyKind::Star };\n    (* => *) => { crate::types::TyKind::Arrow(Box::new(kind!(*)), Box::new(kind!(*))) };\n    ($ex:expr => $ex2:expr) => { crate::types::TyKind::Arrow(Box::new($ex), Box::new($ex2)) };\n}\n\nmacro_rules! diag {\n    ($sp:expr, $str:expr) => { Err(crate::diagnostics::Diagnostic::error($sp, $str)) };\n    ($sp:expr, $fmt:expr, $($args:expr),+) => { Err(crate::diagnostics::Diagnostic::error($sp, format!($fmt, $($args),+))) };\n}\n"
  },
  {
    "path": "07_system_fw/src/main.rs",
    "content": "#![allow(dead_code)]\n#[macro_use]\npub mod macros;\npub mod diagnostics;\npub mod elaborate;\npub mod functor;\npub mod hir;\npub mod stack;\npub mod syntax;\npub mod terms;\npub mod typecheck;\npub mod types;\n\nuse std::io::prelude::*;\nuse syntax::ast;\nuse syntax::parser::{Error, ErrorKind, Parser};\nuse terms::Term;\nuse types::Type;\nuse util::span::Span;\n\nfn main() {\n    loop {\n        let mut buffer = String::new();\n        print!(\"repl: \");\n        std::io::stdout().flush().unwrap();\n        std::io::stdin().read_to_string(&mut buffer).unwrap();\n        let mut p = Parser::new(&buffer);\n        // let mut ctx = elaborate::ElaborationContext::new();\n        // loop {\n        match p.parse_program() {\n            Ok(d) => {\n                println!(\"====> {:?}\", &d.decls);\n                // println!(\"Validate: {:?}\", validate::ProgramValidation::validate(&d));\n                let elab = elaborate::ElaborationContext::elaborate(&d).unwrap();\n                println!(\"-----\");\n                hir::bidir::test(elab);\n            }\n            Err(Error {\n                kind: ErrorKind::EOF, ..\n            }) => {}\n            Err(e) => {\n                println!(\"[err] {:?}\", e);\n            }\n        }\n    }\n}\n\nfn unfold(ty: Type) -> Type {\n    match &ty {\n        Type::Recursive(inner) => op_app!(*inner.clone(), ty),\n        Type::App(a, b) => match a.as_ref() {\n            Type::Recursive(_) => op_app!(unfold(*a.clone()), *b.clone()),\n            _ => ty,\n        },\n        _ => ty,\n    }\n}\n"
  },
  {
    "path": "07_system_fw/src/stack.rs",
    "content": "//! Wrapper around a Vec for use as a de Bruijn indexed stack, e.g. index 0\n//! returns the last item pushed onto the stack\nuse std::fmt;\n\npub struct Stack<T> {\n    inner: Vec<T>,\n}\n\nimpl<T> Stack<T> {\n    #[inline]\n    pub fn push(&mut self, val: T) {\n        self.inner.push(val);\n    }\n\n    #[inline]\n    pub fn pop(&mut self) -> Option<T> {\n        self.inner.pop()\n    }\n\n    #[inline]\n    pub fn popn(&mut self, n: usize) {\n        for _ in 0..n {\n            let _ = self.pop();\n        }\n    }\n\n    #[inline]\n    pub fn get(&self, index: usize) -> Option<&T> {\n        self.inner.get(self.inner.len().checked_sub(1 + index)?)\n    }\n\n    #[inline]\n    pub fn with_capacity(size: usize) -> Self {\n        Stack {\n            inner: Vec::with_capacity(size),\n        }\n    }\n\n    #[inline]\n    pub fn new() -> Self {\n        Stack { inner: Vec::new() }\n    }\n\n    #[inline]\n    pub fn len(&self) -> usize {\n        self.inner.len()\n    }\n\n    pub fn iter(&self) -> std::slice::Iter<T> {\n        self.inner.iter()\n    }\n\n    pub fn iter_mut(&mut self) -> std::slice::IterMut<T> {\n        self.inner.iter_mut()\n    }\n}\n\nimpl<T: PartialEq> Stack<T> {\n    pub fn lookup(&self, key: &T) -> Option<usize> {\n        for (idx, s) in self.inner.iter().rev().enumerate() {\n            if key == s {\n                return Some(idx);\n            }\n        }\n        None\n    }\n}\n\nimpl<T> Extend<T> for Stack<T> {\n    fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {\n        for elem in iter {\n            self.push(elem);\n        }\n    }\n}\n\nimpl<T: Clone> Clone for Stack<T> {\n    fn clone(&self) -> Self {\n        Stack {\n            inner: self.inner.clone(),\n        }\n    }\n}\n\nimpl<T: Default> Default for Stack<T> {\n    fn default() -> Self {\n        Stack { inner: Vec::default() }\n    }\n}\n\nimpl<T: fmt::Debug> fmt::Debug for Stack<T> {\n    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n        write!(f, \"{:?}\", self.inner)\n    }\n}\n\n#[cfg(test)]\nmod test {\n    use super::*;\n    #[test]\n    fn order() {\n        let mut stack = Stack::default();\n        for i in 0..16 {\n            stack.push(i);\n        }\n\n        assert_eq!(stack.get(0), Some(&15));\n        assert_eq!(stack.get(1), Some(&14));\n        assert_eq!(stack.get(2), Some(&13));\n\n        stack.pop();\n        assert_eq!(stack.get(0), Some(&14));\n    }\n}\n"
  },
  {
    "path": "07_system_fw/src/syntax/ast.rs",
    "content": "use util::span::Span;\n\n#[derive(Copy, Clone, Debug, Default, PartialEq, PartialOrd, Eq, Hash)]\npub struct AstId(pub(crate) u32);\npub const AST_DUMMY: AstId = AstId(std::u32::MAX);\n\nmacro_rules! container {\n    ($id:ident, $id2:ident) => {\n        #[derive(Clone, PartialEq, PartialOrd)]\n        pub struct $id {\n            pub kind: $id2,\n            pub span: Span,\n            pub id: AstId,\n        }\n\n        impl $id {\n            pub fn new(kind: $id2, span: Span) -> $id {\n                $id {\n                    kind,\n                    span,\n                    id: AST_DUMMY,\n                }\n            }\n\n            pub fn with_id(kind: $id2, span: Span, id: AstId) -> $id {\n                $id { kind, span, id }\n            }\n        }\n\n        impl std::fmt::Debug for $id {\n            fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {\n                write!(f, \"{:?}\", self.kind)\n            }\n        }\n    };\n}\n\ncontainer!(Expr, ExprKind);\ncontainer!(Type, TypeKind);\ncontainer!(Decl, DeclKind);\ncontainer!(Pattern, PatKind);\n\npub struct Program {\n    pub decls: Vec<Decl>,\n}\n\n/// Arm of a case expression\n#[derive(Clone, Debug, PartialEq, PartialOrd)]\npub struct Arm {\n    pub pat: Pattern,\n    pub expr: Expr,\n    pub span: Span,\n}\n\n#[derive(Clone, Debug, PartialEq, PartialOrd)]\npub struct Field {\n    pub label: String,\n    pub expr: Expr,\n    pub span: Span,\n}\n\n/// Patterns for case and let expressions\n#[derive(Clone, Debug, PartialEq, PartialOrd)]\npub enum PatKind {\n    /// Wildcard pattern, this always matches\n    Any,\n    Unit,\n    Ascribe(Box<Pattern>, Box<Type>),\n    /// Constant pattern\n    Literal(usize),\n    /// Datatype constructor\n    Constructor(String),\n    /// Variable binding\n    Variable(String),\n    /// Tuple of pattern bindings (_, x)\n    Product(Vec<Pattern>),\n    /// Record pattern { label1, label2 }\n    Record(Vec<String>),\n    /// Algebraic datatype constructor, along with binding pattern\n    Application(Box<Pattern>, Box<Pattern>),\n}\n\n#[derive(Clone, Debug, PartialEq, PartialOrd)]\npub enum ExprKind {\n    Unit,\n    Int(usize),\n    Var(String),\n    Constr(String),\n    If(Box<Expr>, Box<Expr>, Box<Expr>),\n    Abs(Box<Pattern>, Box<Expr>),\n    App(Box<Expr>, Box<Expr>),\n\n    /// Explicit type abstraction `fn 'x value (arg: 'x) = arg`\n    TyAbs(String, Box<Kind>, Box<Expr>),\n\n    /// Explicit type application `e @ty`\n    TyApp(Box<Expr>, Box<Type>),\n    Record(Vec<Field>),\n    Tuple(Vec<Expr>),\n    Projection(Box<Expr>, Box<Expr>),\n    Case(Box<Expr>, Vec<Arm>),\n    Let(Vec<Decl>, Box<Expr>),\n}\n\n#[derive(Clone, Debug, PartialEq, PartialOrd)]\npub struct FnArm {\n    pub span: Span,\n    pub pats: Vec<Pattern>,\n    pub expr: Expr,\n}\n\n#[derive(Clone, Debug, PartialEq, PartialOrd)]\npub enum DeclKind {\n    Type(Vec<Type>, String, Type),\n    Datatype(Vec<Type>, String, Type),\n    Value(Vec<Type>, Pattern, Expr),\n    Function(Vec<Type>, String, Vec<FnArm>),\n    And(Box<Decl>, Box<Decl>),\n    Expr(Expr),\n}\n\n#[derive(Clone, Debug, PartialEq, PartialOrd)]\npub enum Kind {\n    Star,\n    Arrow(Box<Kind>, Box<Kind>),\n}\n\n#[derive(Clone, Debug, PartialEq, PartialOrd)]\npub enum TypeKind {\n    Int,\n    Bool,\n    Unit,\n    Infer,\n    /// Defined name\n    Defined(String),\n    /// Type variable 'a\n    Variable(String),\n    /// Type of functions from terms to terms\n    Function(Box<Type>, Box<Type>),\n    /// Sum type; None | Some of 'a\n    Sum(Vec<Variant>),\n    /// Tuple type (ty * ty * ... tyN), invariant that N >= 1\n    Product(Vec<Type>),\n    /// Record type { [label: ty],+ }, invariant that N >=1\n    Record(Vec<Row>),\n    /// Existential type: exists (a :: K) of ty\n    Existential(String, Box<Kind>, Box<Type>),\n    /// Universal type: forall (a :: K) of ty\n    Universal(String, Box<Kind>, Box<Type>),\n    /// Type level function abstraction\n    Abstraction(String, Box<Kind>, Box<Type>),\n    /// Type level function application\n    Application(Box<Type>, Box<Type>),\n    /// Recursive type\n    Recursive(Box<Type>),\n}\n\n#[derive(Clone, PartialEq, PartialOrd)]\npub struct Variant {\n    pub label: String,\n    pub ty: Option<Type>,\n    pub span: Span,\n}\n\n#[derive(Clone, PartialEq, PartialOrd)]\npub struct Row {\n    pub label: String,\n    pub ty: Type,\n    pub span: Span,\n}\n\nimpl TypeKind {\n    pub fn variants(&self) -> &[Variant] {\n        match self {\n            TypeKind::Sum(v) => &v,\n            _ => panic!(\"Not a sum type!\"),\n        }\n    }\n\n    pub fn as_tyvar(&self) -> &str {\n        match self {\n            TypeKind::Variable(s) => s,\n            _ => panic!(\"Not a type var!\"),\n        }\n    }\n\n    pub fn as_tyvar_d(self) -> String {\n        match self {\n            TypeKind::Variable(s) => s,\n            _ => panic!(\"Not a type var!\"),\n        }\n    }\n}\n\nimpl std::fmt::Debug for Variant {\n    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {\n        write!(f, \"{} of {:?}\", self.label, self.ty)\n    }\n}\n\nimpl std::fmt::Debug for Row {\n    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {\n        write!(f, \"{}: {:?}\", self.label, self.ty)\n    }\n}\n"
  },
  {
    "path": "07_system_fw/src/syntax/lexer.rs",
    "content": "use super::tokens::*;\nuse std::char;\nuse std::iter::Peekable;\nuse std::str::Chars;\nuse util::span::{Location, Span, Spanned};\n\n#[derive(Clone, Debug)]\npub struct Lexer<'s> {\n    input: Peekable<Chars<'s>>,\n    current: Location,\n}\n\nimpl<'s> Lexer<'s> {\n    pub fn new(input: Chars<'s>) -> Lexer<'s> {\n        Lexer {\n            input: input.peekable(),\n            current: Location {\n                line: 0,\n                col: 0,\n                abs: 0,\n            },\n        }\n    }\n\n    /// Peek at the next [`char`] in the input stream\n    fn peek(&mut self) -> Option<char> {\n        self.input.peek().copied()\n    }\n\n    /// Consume the next [`char`] and advance internal source position\n    fn consume(&mut self) -> Option<char> {\n        match self.input.next() {\n            Some('\\n') => {\n                self.current.line += 1;\n                self.current.col = 0;\n                self.current.abs += 1;\n                Some('\\n')\n            }\n            Some(ch) => {\n                self.current.col += 1;\n                self.current.abs += 1;\n                Some(ch)\n            }\n            None => None,\n        }\n    }\n\n    /// Consume characters from the input stream while pred(peek()) is true,\n    /// collecting the characters into a string.\n    fn consume_while<F: Fn(char) -> bool>(&mut self, pred: F) -> (String, Span) {\n        let mut s = String::new();\n        let start = self.current;\n        while let Some(n) = self.peek() {\n            if pred(n) {\n                match self.consume() {\n                    Some(ch) => s.push(ch),\n                    None => break,\n                }\n            } else {\n                break;\n            }\n        }\n        (s, Span::new(start, self.current))\n    }\n\n    /// Eat whitespace\n    fn consume_delimiter(&mut self) {\n        let _ = self.consume_while(char::is_whitespace);\n    }\n\n    fn id(&mut self) -> (String, Span) {\n        let (mut s, mut span) = self.consume_while(|ch| ch.is_ascii_alphanumeric());\n        while let Some(ch) = self.peek() {\n            if ch != '.' {\n                break;\n            }\n            self.consume();\n            s.push('.');\n            let (s2, sp2) = self.consume_while(|ch| ch.is_ascii_alphanumeric());\n            s += &s2;\n            span += sp2;\n        }\n        (s, span)\n    }\n\n    fn valid_id_char(c: char) -> bool {\n        match c {\n            '.' => false,\n            x if x.is_alphanumeric() => true,\n            '`' | '~' | '!' | '$' | '%' | '^' | '&' | '-' | '_' | '+' | '?' | '<' | '>' => true,\n            _ => false,\n        }\n    }\n\n    /// Lex a reserved keyword or identifier\n    fn keyword(&mut self) -> Spanned<Token> {\n        let (word, sp) = self.consume_while(Self::valid_id_char);\n        let kind = match word.as_ref() {\n            \"fun\" => Token::Function,\n            \"fn\" => Token::Lambda,\n            \"val\" => Token::Val,\n            \"let\" => Token::Let,\n            \"in\" => Token::In,\n            \"case\" => Token::Case,\n            \"of\" => Token::Of,\n            \"end\" => Token::End,\n            \"as\" => Token::As,\n            \"if\" => Token::If,\n            \"then\" => Token::Then,\n            \"else\" => Token::Else,\n            \"fix\" => Token::Fix,\n            \"rec\" => Token::Rec,\n            \"exists\" => Token::Exists,\n            \"forall\" => Token::Forall,\n            \"type\" => Token::Type,\n            \"datatype\" => Token::Datatype,\n            \"and\" => Token::And,\n            \"int\" => Token::TyInt,\n            \"unit\" => Token::TyUnit,\n            \"bool\" => Token::TyBool,\n            s if s.starts_with(char::is_uppercase) => Token::UpperId(word),\n            _ => Token::LowerId(word),\n        };\n        Spanned::new(sp, kind)\n    }\n\n    /// Consume the next input character, expecting to match `ch`.\n    /// Return a [`TokenKind::Invalid`] if the next character does not match,\n    /// or the argument `kind` if it does\n    fn eat(&mut self, ch: char, kind: Token) -> Spanned<Token> {\n        let loc = self.current;\n        // Lexer::eat() should only be called internally after calling peek()\n        // so we know that it's safe to unwrap the result of Lexer::consume()\n        let n = self.consume().unwrap();\n        let kind = if n == ch { kind } else { Token::Invalid(n) };\n        Spanned::new(Span::new(loc, self.current), kind)\n    }\n\n    /// Lex a natural number\n    fn number(&mut self) -> Spanned<Token> {\n        // Since we peeked at least one numeric char, we should always\n        // have a string containing at least 1 single digit, as such\n        // it is safe to call unwrap() on str::parse<u32>\n        let (data, span) = self.consume_while(char::is_numeric);\n        let n = data.parse::<usize>().unwrap();\n        Spanned::new(span, Token::Int(n))\n    }\n\n    pub fn lex(&mut self) -> Spanned<Token> {\n        self.consume_delimiter();\n        let next = match self.peek() {\n            Some(ch) => ch,\n            None => return Spanned::new(Span::new(self.current, self.current), Token::EOF),\n        };\n\n        macro_rules! disamb {\n            ($ch:expr, $($ch2:expr, $p:expr),+) => {{\n                self.consume();\n                match self.peek() {\n                    Some(ch) => match ch {\n                        $($ch2 => self.eat($ch2, $p)),+,\n                        _ => Spanned::new(Span::new(self.current, self.current), Token::Invalid($ch))\n                    },\n                    None => Spanned::new(Span::new(self.current, self.current), Token::Invalid($ch)),\n                }\n            }};\n            ($ch:expr, $p1:expr, $($ch2:expr, $p:expr),+) => {{\n                let fail = self.eat($ch, $p1);\n                match self.peek() {\n                    Some(ch) => match ch {\n                        $($ch2 => self.eat($ch2, $p)),+,\n                        _ => fail,\n                    },\n                    None => fail,\n                }\n            }};\n        }\n\n        match next {\n            '.' => self.eat('.', Token::Dot),\n            ':' => disamb!(':', Token::Colon, '>', Token::Opaque),\n            ';' => self.eat(';', Token::Semicolon),\n            ',' => self.eat(',', Token::Comma),\n            '\\'' => self.eat('\\'', Token::Apostrophe),\n            '|' => self.eat('|', Token::Bar),\n            '-' => disamb!('-', '>', Token::SingleArrow),\n            '=' => disamb!('=', Token::Equals, '>', Token::DoubleArrow),\n            '_' => self.eat('_', Token::Wildcard),\n            '*' => self.eat('*', Token::Asterisk),\n            '(' => disamb!('(', Token::LParen, ')', Token::Unit),\n            ')' => self.eat(')', Token::RParen),\n            '{' => self.eat('{', Token::LBrace),\n            '}' => self.eat('}', Token::RBrace),\n            '@' => self.eat('@', Token::TypeAppSigil),\n            '\\\\' => self.eat('\\\\', Token::Lambda),\n            'λ' => self.eat('λ', Token::Lambda),\n            '∀' => self.eat('∀', Token::Forall),\n            '∃' => self.eat('∃', Token::Exists),\n            x if x.is_ascii_alphabetic() => self.keyword(),\n            x if x.is_numeric() => self.number(),\n            _ => self.eat(' ', Token::EOF),\n            // _ => Spanned::new(Token::Invalid(next), Span::new(self.current, self.current)),\n        }\n    }\n}\n\nimpl<'s> Iterator for Lexer<'s> {\n    type Item = Spanned<Token>;\n    fn next(&mut self) -> Option<Self::Item> {\n        match self.lex() {\n            Spanned { data: Token::EOF, .. } => None,\n            tok => Some(tok),\n        }\n    }\n}\n"
  },
  {
    "path": "07_system_fw/src/syntax/mod.rs",
    "content": "pub mod ast;\npub mod lexer;\npub mod parser;\npub mod tokens;\npub mod visit;\n"
  },
  {
    "path": "07_system_fw/src/syntax/parser/README.md",
    "content": "# Parser\n\nWe use a handwritten recursive descent parser. In general, there is a top-level entry function for parsing of `types`, `expressions`, `declarations`, and `patterns`. Each of these functions attempts to match against the current token, without popping it. If a suitable match is found, then we dispatch to a function specifically for parsing that token, which may then pop off the current token. Once the current token has been popped, we actually begin to return real errors. Errors that occur before the current token has been popped may be generally ignored.\n"
  },
  {
    "path": "07_system_fw/src/syntax/parser/decls.rs",
    "content": "use super::*;\n\nimpl<'s> Parser<'s> {\n    fn decl_datatype(&mut self) -> Result<Decl, Error> {\n        let mut span = self.current.span;\n        self.expect(Token::Datatype)?;\n        let tyvars = self.parse_tyvar_sequence()?;\n        let tyname = self.expect_lower_id()?;\n        self.expect(Token::Equals)?;\n        self.bump_if(&Token::Bar);\n        let ty = self.type_sum()?;\n        span += self.prev;\n        Ok(Decl::with_id(\n            DeclKind::Datatype(tyvars, tyname, ty),\n            span,\n            self.allocate_ast_id(),\n        ))\n    }\n\n    fn decl_type(&mut self) -> Result<Decl, Error> {\n        let mut span = self.current.span;\n        self.expect(Token::Type)?;\n        let tyvars = self.parse_tyvar_sequence()?;\n        let tyname = self.expect_lower_id()?;\n        self.expect(Token::Equals)?;\n        let ty = self.parse_type()?;\n\n        span += self.prev;\n        Ok(Decl::with_id(\n            DeclKind::Type(tyvars, tyname, ty),\n            span,\n            self.allocate_ast_id(),\n        ))\n    }\n\n    fn decl_value(&mut self) -> Result<Decl, Error> {\n        let mut span = self.current.span;\n        self.expect(Token::Val)?;\n        let tyvars = self.parse_tyvar_sequence()?;\n        let pat = self.parse_pattern()?;\n        self.expect(Token::Equals)?;\n        let expr = self.parse_expr()?;\n        span += self.prev;\n        Ok(Decl::with_id(\n            DeclKind::Value(tyvars, pat, expr),\n            span,\n            self.allocate_ast_id(),\n        ))\n    }\n\n    fn decl_fun_arm(&mut self, ident: &str) -> Result<FnArm, Error> {\n        let mut span = self.current.span;\n        let id = self.expect_lower_id()?;\n        if id != ident {\n            return self.error(ErrorKind::FunctionIdMismatch);\n        }\n        let pats = self.plus(|p| p.atomic_pattern(), None)?;\n        self.expect(Token::Equals)?;\n        let expr = self.parse_expr()?;\n        span += self.prev;\n        Ok(FnArm { pats, expr, span })\n    }\n\n    fn decl_fun(&mut self) -> Result<Decl, Error> {\n        let mut span = self.current.span;\n        self.expect(Token::Function)?;\n        let tyvars = self.parse_tyvar_sequence()?;\n\n        // Peek the id and clone it, since decl_fun_arm will expect it to be there\n        let ident = match self.current() {\n            Token::LowerId(id) => id.clone(),\n            _ => return self.error(ErrorKind::ExpectedIdentifier),\n        };\n\n        let arms = self.delimited(|p| p.decl_fun_arm(&ident), Token::Bar)?;\n        span += self.prev;\n        Ok(Decl::with_id(\n            DeclKind::Function(tyvars, ident, arms),\n            span,\n            self.allocate_ast_id(),\n        ))\n    }\n\n    fn decl_expr(&mut self) -> Result<Decl, Error> {\n        let expr = self.parse_expr()?;\n        let sp = expr.span;\n        Ok(Decl::with_id(DeclKind::Expr(expr), sp, self.allocate_ast_id()))\n    }\n\n    /// Parse a simple declaration\n    /// decl ::=    type\n    ///             datatype\n    ///             val\n    ///             fun\n    ///             exp\n    pub fn parse_decl_atom(&mut self) -> Result<Decl, Error> {\n        match self.current() {\n            Token::Type => self.decl_type(),\n            Token::Datatype => self.decl_datatype(),\n            Token::Val => self.decl_value(),\n            Token::Function => self.decl_fun(),\n            _ => self.decl_expr(),\n        }\n    }\n\n    pub(crate) fn parse_decl(&mut self) -> Result<Decl, Error> {\n        let mut span = self.current.span;\n        let mut d = self.parse_decl_atom()?;\n        while let Token::And = self.current.data {\n            self.bump();\n            let d2 = self.once(|p| p.parse_decl_atom(), \"expected declaration after `and`\")?;\n            span += self.prev;\n            d = Decl::with_id(DeclKind::And(Box::new(d), Box::new(d2)), span, self.allocate_ast_id());\n        }\n        span += self.prev;\n        Ok(d)\n    }\n\n    pub fn parse_program(&mut self) -> Result<Program, Error> {\n        let mut decls = vec![self.parse_decl()?];\n        self.bump_if(&Token::Semicolon);\n        while let Ok(d) = self.parse_decl() {\n            decls.push(d);\n            self.bump_if(&Token::Semicolon);\n        }\n        Ok(Program { decls })\n    }\n}\n"
  },
  {
    "path": "07_system_fw/src/syntax/parser/exprs.rs",
    "content": "use super::*;\n\nimpl<'s> Parser<'s> {\n    fn record_row(&mut self) -> Result<Field, Error> {\n        let mut span = self.current.span;\n        let label = self.expect_lower_id()?;\n        self.expect(Token::Equals)?;\n        let expr = self.once(|p| p.parse_expr(), \"missing expr in record row\")?;\n        span += self.prev;\n        Ok(Field { label, expr, span })\n    }\n\n    fn record_expr(&mut self) -> Result<Expr, Error> {\n        let mut span = self.current.span;\n        self.expect(Token::LBrace)?;\n        let fields = self.delimited(|p| p.record_row(), Token::Comma)?;\n        self.expect(Token::RBrace)?;\n        span += self.prev;\n        Ok(Expr::new(ExprKind::Record(fields), span))\n    }\n\n    fn let_binding(&mut self) -> Result<Expr, Error> {\n        let mut span = self.current.span;\n        self.expect(Token::Let)?;\n        // let pat = self.once(|p| p.parse_pattern(), \"missing pattern in let\n        // binding\")?; self.expect(Token::Equals)?;\n        // let t1 = self.once(|p| p.parse_expr(), \"let binder required\")?;\n        let decls = self.parse_program()?.decls;\n        self.expect(Token::In)?;\n        let t2 = self.once(|p| p.parse_expr(), \"let body required\")?;\n        self.expect(Token::End)?;\n        span += self.prev;\n        Ok(Expr::new(ExprKind::Let(decls, Box::new(t2)), span))\n    }\n\n    fn case_arm(&mut self) -> Result<Arm, Error> {\n        let mut span = self.current.span;\n        let pat = self.once(|p| p.parse_pattern(), \"missing pattern in case arm\")?;\n        self.expect(Token::DoubleArrow)?;\n        let expr = self.once(|p| p.parse_expr(), \"missing expression in case arm\")?;\n        self.bump_if(&Token::Comma);\n        span += self.prev;\n        Ok(Arm { pat, expr, span })\n    }\n\n    fn case_expr(&mut self) -> Result<Expr, Error> {\n        let mut span = self.current.span;\n        self.expect(Token::Case)?;\n        let expr = self.once(|p| p.parse_expr(), \"missing case expression\")?;\n        self.expect(Token::Of)?;\n        self.bump_if(&Token::Bar);\n        let arms = self.delimited(|p| p.case_arm(), Token::Bar)?;\n        self.expect(Token::End)?;\n        span += self.prev;\n        Ok(Expr::new(ExprKind::Case(Box::new(expr), arms), span))\n    }\n\n    fn lambda_expr(&mut self) -> Result<Expr, Error> {\n        let mut span = self.current.span;\n        self.expect(Token::Lambda)?;\n        let arg = self.once(|p| p.parse_pattern(), \"expected pattern binding in lambda expression!\")?;\n        self.expect(Token::DoubleArrow)?;\n        let body = self.parse_expr()?;\n        span += self.prev;\n        Ok(Expr::new(ExprKind::Abs(Box::new(arg), Box::new(body)), span))\n    }\n\n    fn if_expr(&mut self) -> Result<Expr, Error> {\n        let mut span = self.current.span;\n        self.expect(Token::If)?;\n        let guard = self.parse_expr()?;\n        self.expect(Token::Then)?;\n        let cond = self.parse_expr()?;\n        self.expect(Token::Else)?;\n        let alt = self.parse_expr()?;\n        span += self.prev;\n        Ok(Expr::new(\n            ExprKind::If(Box::new(guard), Box::new(cond), Box::new(alt)),\n            span,\n        ))\n    }\n\n    /// atexp ::=   constant\n    ///             id\n    ///             { [label = exp] }\n    ///             ()\n    ///             ( exp, ... expN )\n    ///             ( exp )\n    ///             let decl in exp, ... expN end\n    fn atomic_expr(&mut self) -> Result<Expr, Error> {\n        let mut span = self.current.span;\n        match self.current.data {\n            Token::LowerId(_) => self.expect_lower_id().map(|e| Expr::new(ExprKind::Var(e), span)),\n            Token::UpperId(_) => self.expect_upper_id().map(|e| Expr::new(ExprKind::Constr(e), span)),\n            Token::LBrace => self.record_expr(),\n            Token::Let => self.let_binding(),\n            Token::Int(n) => {\n                self.bump();\n                Ok(Expr::new(ExprKind::Int(n), span))\n            }\n            Token::Unit => {\n                self.bump();\n                Ok(Expr::new(ExprKind::Unit, span))\n            }\n            Token::LParen => {\n                self.expect(Token::LParen)?;\n                let mut exprs = self.delimited(|p| p.parse_expr(), Token::Comma)?;\n                let e = match exprs.len() {\n                    1 => exprs.pop().unwrap(),\n                    _ => Expr::new(ExprKind::Tuple(exprs), span),\n                };\n                self.expect(Token::RParen)?;\n                span += self.prev;\n                Ok(e)\n            }\n            _ => self.error(ErrorKind::ExpectedExpr),\n        }\n    }\n\n    fn projection_expr(&mut self) -> Result<Expr, Error> {\n        let mut span = self.current.span;\n        let mut expr = self.atomic_expr()?;\n        while self.bump_if(&Token::Dot) {\n            span += self.prev;\n            let p = self.once(|p| p.atomic_expr(), \"expected expr after Dot\")?;\n            expr = Expr::new(ExprKind::Projection(Box::new(expr), Box::new(p)), span);\n        }\n        Ok(expr)\n    }\n\n    /// appexp ::=      atexp\n    ///                 appexp atexp\n    fn application_expr(&mut self) -> Result<Expr, Error> {\n        let mut span = self.current.span;\n        let mut expr = self.projection_expr()?;\n        loop {\n            if let Token::LowerId(s) = &self.current() {\n                if self.infix.get(&s).is_some() {\n                    break;\n                }\n            }\n\n            if let Ok(e) = self.projection_expr() {\n                span += self.prev;\n                expr = Expr::new(ExprKind::App(Box::new(expr), Box::new(e)), span);\n            } else if let Token::TypeAppSigil = self.current() {\n                self.bump();\n                let ty = self.type_atom()?;\n                span += self.prev;\n                expr = Expr::new(ExprKind::TyApp(Box::new(expr), Box::new(ty)), span);\n            } else {\n                break;\n            }\n        }\n        Ok(expr)\n    }\n\n    /// exp ::=     appexp\n    ///             exp path exp\n    // fn infix_expr(&mut self) -> Result<Expr, Error> {\n    //     let mut span = self.current.span;\n    //     let mut expr = self.application_expr()?;\n    //     while let Token::LowerId(s) = &self.current() {\n    //         if self.infix.get(s).is_some() {\n    //             let p = self.expect_lower_id()?;\n    //             let e = self.application_expr()?;\n    //             span += self.prev;\n    //             expr = Expr::new(ExprKind::Infix(p, Box::new(expr), Box::new(e)), span)\n    //         } else {\n    //             break;\n    //         }\n    //     }\n    //     Ok(expr)\n    // }\n\n    /// exp ::=     if exp then exp2 else exp3\n    ///             case exp of casearm end\n    ///             fn x\n    ///             infix\n    pub fn parse_expr(&mut self) -> Result<Expr, Error> {\n        match self.current() {\n            Token::Case => self.case_expr(),\n            Token::If => self.if_expr(),\n            Token::Lambda => self.lambda_expr(),\n            _ => self.application_expr(),\n        }\n    }\n}\n"
  },
  {
    "path": "07_system_fw/src/syntax/parser/infix.rs",
    "content": "use std::collections::HashMap;\n\n#[derive(Clone, Default, Debug)]\npub struct Infix {\n    precedence: HashMap<String, usize>,\n}\n\nimpl Infix {\n    pub fn insert(&mut self, s: String, prec: usize) {\n        self.precedence.insert(s, prec);\n    }\n\n    pub fn get(&self, s: &str) -> Option<usize> {\n        self.precedence.get(s).copied()\n    }\n}\n"
  },
  {
    "path": "07_system_fw/src/syntax/parser/mod.rs",
    "content": "pub mod decls;\npub mod exprs;\npub mod infix;\npub mod patterns;\npub mod types;\n\nuse super::ast::*;\nuse super::lexer::Lexer;\nuse super::tokens::*;\nuse infix::Infix;\nuse util::span::{Span, Spanned};\n\npub struct Parser<'s> {\n    tokens: Lexer<'s>,\n    current: Spanned<Token>,\n    prev: Span,\n    infix: Infix,\n    next_ast_id: AstId,\n}\n\n#[derive(Clone, Debug, PartialEq, PartialOrd)]\npub enum ErrorKind {\n    ExpectedToken(Token),\n    ExpectedIdentifier,\n    ExpectedType,\n    ExpectedExpr,\n    ExpectedPattern,\n    ExpectedDeclaration,\n    ExpectedSpecification,\n    ExpectedSignature,\n    ExpectedStructure,\n    UnboundTypeVar,\n    UnboundExprVar,\n    FunctionIdMismatch,\n    EOF,\n}\n\n#[derive(Default)]\npub struct InfixState(Infix);\n\n#[derive(Clone, Debug, PartialEq, PartialOrd)]\npub struct Error {\n    pub span: Span,\n    pub token: Token,\n    pub kind: ErrorKind,\n}\n\nimpl<'s> Parser<'s> {\n    pub fn new(input: &'s str) -> Parser<'s> {\n        Parser::with_infix_state(input, InfixState::default())\n    }\n\n    pub fn with_infix_state(input: &'s str, state: InfixState) -> Parser<'s> {\n        let mut p = Parser {\n            tokens: Lexer::new(input.chars()),\n            current: Spanned::new(Span::zero(), Token::Placeholder),\n            infix: state.0,\n            prev: Span::zero(),\n            next_ast_id: AstId(0),\n        };\n        p.bump();\n        p\n    }\n\n    pub fn top_level(&mut self) -> Result<Vec<Decl>, Error> {\n        let mut v = Vec::new();\n        while self.current() != &Token::EOF {\n            v.push(self.parse_decl()?);\n            self.bump_if(&Token::Semicolon);\n        }\n        Ok(v)\n    }\n\n    pub fn state(&self) -> InfixState {\n        InfixState(self.infix.clone())\n    }\n\n    fn allocate_ast_id(&mut self) -> AstId {\n        let id = self.next_ast_id;\n        self.next_ast_id = AstId(self.next_ast_id.0 + 1);\n        id\n    }\n\n    /// Generate a parsing error. These are not necessarily fatal\n    fn error<T>(&self, k: ErrorKind) -> Result<T, Error> {\n        Err(Error {\n            span: self.current.span,\n            token: self.current().clone(),\n            kind: k,\n        })\n    }\n\n    fn current(&self) -> &Token {\n        &self.current.data\n    }\n\n    /// Bump the current token, returning it, and pull a new token\n    /// from the lexer\n    fn bump(&mut self) -> Token {\n        match self.tokens.next() {\n            Some(t) => {\n                #[cfg(test)]\n                {\n                    let t = std::mem::replace(&mut self.current, t).data();\n                    self.current.span = Span::default();\n                    self.prev = Span::default();\n\n                    t\n                }\n                #[cfg(not(test))]\n                {\n                    self.prev = self.current.span;\n                    std::mem::replace(&mut self.current, t).data()\n                }\n            }\n            None => std::mem::replace(&mut self.current.data, Token::EOF),\n        }\n    }\n\n    /// Ignore a token matching `kind`\n    fn bump_if(&mut self, kind: &Token) -> bool {\n        if &self.current.data == kind {\n            self.bump();\n            true\n        } else {\n            false\n        }\n    }\n\n    fn expect(&mut self, kind: Token) -> Result<(), Error> {\n        if self.current() == &kind {\n            self.bump();\n            Ok(())\n        } else {\n            self.error(ErrorKind::ExpectedToken(kind))\n        }\n    }\n\n    fn expect_lower_id(&mut self) -> Result<String, Error> {\n        match self.current() {\n            Token::LowerId(_) => Ok(self.bump().extract_string()),\n            _ => self.error(ErrorKind::ExpectedIdentifier),\n        }\n    }\n\n    fn expect_upper_id(&mut self) -> Result<String, Error> {\n        match self.current() {\n            Token::UpperId(_) => Ok(self.bump().extract_string()),\n            _ => self.error(ErrorKind::ExpectedIdentifier),\n        }\n    }\n\n    /// Call `func` once, returning the `Result<T,E>` of the function.\n    /// A failure of `func` may have side effects, including emitting\n    /// diagnostics containing `message`\n    ///\n    /// Generally, this is just used to give better error messages\n    fn once<T, E, F>(&mut self, func: F, message: &str) -> Result<T, E>\n    where\n        F: Fn(&mut Parser) -> Result<T, E>,\n    {\n        match func(self) {\n            Ok(t) => Ok(t),\n            Err(e) => {\n                eprintln!(\"[Parser] {}\", message);\n                Err(e)\n            }\n        }\n    }\n\n    /// Collect the result of `func` into a `Vec<T>` as long as `func` returns\n    /// an `Ok(T)`. A call to `func` must succeed on the first try, or an error\n    /// is immediately returned. Subsequent calls to `func` may fail, in which\n    /// case the error is discarded, and the results are returned. If `delimit`\n    /// is supplied, the parser will discard matching tokens between each call\n    /// to `func`\n    fn plus<T, E, F>(&mut self, func: F, delimit: Option<&Token>) -> Result<Vec<T>, E>\n    where\n        F: Fn(&mut Parser) -> Result<T, E>,\n    {\n        let mut v = vec![func(self)?];\n        if let Some(t) = delimit {\n            if !self.bump_if(t) {\n                return Ok(v);\n            }\n        }\n        while let Ok(x) = func(self) {\n            v.push(x);\n            if let Some(t) = delimit {\n                if !self.bump_if(t) {\n                    break;\n                }\n            }\n        }\n        Ok(v)\n    }\n\n    /// Collect the result of `func` into a `Vec<T>` as long as `func` returns\n    /// an `Ok(T)`. If an error is encountered, it is discarded and the results\n    /// are immediately returned. If `delimit` is supplied, the parser will\n    /// discard matching tokens between each call to `func`\n    fn star<T, E, F>(&mut self, func: F, delimit: Option<&Token>) -> Vec<T>\n    where\n        F: Fn(&mut Parser) -> Result<T, E>,\n    {\n        let mut v = Vec::new();\n        while let Ok(x) = func(self) {\n            v.push(x);\n            if let Some(t) = delimit {\n                if !self.bump_if(t) {\n                    break;\n                }\n            }\n        }\n        v\n    }\n\n    /// Identical semantics to `Parser::plus`, except `delimit` must be supplied\n    fn delimited<T, E, F>(&mut self, func: F, delimit: Token) -> Result<Vec<T>, E>\n    where\n        F: Fn(&mut Parser) -> Result<T, E>,\n    {\n        let mut v = vec![func(self)?];\n        while self.bump_if(&delimit) {\n            v.push(func(self)?);\n        }\n        Ok(v)\n    }\n}\n"
  },
  {
    "path": "07_system_fw/src/syntax/parser/patterns.rs",
    "content": "use super::*;\n\nuse PatKind::*;\n\nimpl<'s> Parser<'s> {\n    fn tuple_pattern(&mut self) -> Result<Pattern, Error> {\n        let mut span = self.current.span;\n        self.expect(Token::LParen)?;\n        let mut v = self.star(|p| p.parse_pattern(), Some(&Token::Comma));\n        self.expect(Token::RParen)?;\n        span += self.prev;\n        match v.len() {\n            0 => Ok(Pattern::new(Unit, span)),\n            1 => Ok(v.pop().unwrap()),\n            _ => Ok(Pattern::new(Product(v), span)),\n        }\n    }\n\n    fn record_pattern(&mut self) -> Result<Pattern, Error> {\n        let mut span = self.current.span;\n        self.expect(Token::LBrace)?;\n        let v = self.delimited(|p| p.expect_lower_id(), Token::Comma)?;\n        self.expect(Token::RBrace)?;\n        span += self.prev;\n        Ok(Pattern::new(Record(v), span))\n    }\n\n    /// atpat ::=   constant\n    ///             id\n    ///             wildcard\n    ///             ( pat )\n    ///             ( pat, ... patN )\n    ///             { [patrow] }\n    pub(crate) fn atomic_pattern(&mut self) -> Result<Pattern, Error> {\n        let span = self.current.span;\n        match self.current.data {\n            Token::Wildcard => {\n                self.bump();\n                Ok(Pattern::new(Any, span))\n            }\n            Token::LowerId(_) => self.expect_lower_id().map(|s| Pattern::new(Variable(s), span)),\n            Token::UpperId(_) => self.expect_upper_id().map(|s| Pattern::new(Constructor(s), span)),\n            Token::Int(n) => {\n                self.bump();\n                Ok(Pattern::new(Literal(n), span))\n            }\n            Token::Unit => {\n                self.bump();\n                Ok(Pattern::new(PatKind::Unit, span))\n            }\n            Token::LParen => self.tuple_pattern(),\n            Token::LBrace => self.record_pattern(),\n            _ => self.error(ErrorKind::ExpectedPattern),\n        }\n    }\n\n    /// app_pat ::=     atpat\n    ///                 app_pat atpat\n    fn application_pattern(&mut self) -> Result<Pattern, Error> {\n        let mut span = self.current.span;\n        let pat = self.atomic_pattern()?;\n        if let PatKind::Constructor(_) = pat.kind {\n            match self.atomic_pattern() {\n                Ok(arg) => {\n                    span += self.prev;\n                    return Ok(Pattern::new(Application(Box::new(pat), Box::new(arg)), span));\n                }\n                _ => return Ok(pat),\n            }\n        }\n        // while let Ok(e) = self.atomic_pattern() {\n        //     span += self.prev;\n        //     pat = Pattern::new(Application(Box::new(pat), Box::new(e)), span);\n        // }\n\n        Ok(pat)\n    }\n\n    pub fn parse_pattern(&mut self) -> Result<Pattern, Error> {\n        let mut span = self.current.span;\n        let pat = self.application_pattern()?;\n        if self.bump_if(&Token::Colon) {\n            let ty = self.once(|p| p.parse_type(), \"expected type annotation after `pat :`\")?;\n            span += self.prev;\n            return Ok(Pattern::new(Ascribe(Box::new(pat), Box::new(ty)), span));\n        }\n        Ok(pat)\n    }\n}\n"
  },
  {
    "path": "07_system_fw/src/syntax/parser/types.rs",
    "content": "use super::*;\n\nuse TypeKind::*;\n\nimpl<'s> Parser<'s> {\n    /// Parse a datatype Constructor [A-Z]+\n    pub fn variant(&mut self) -> Result<Variant, Error> {\n        let mut span = self.current.span;\n        let label = self.expect_upper_id()?;\n        let ty = if self.bump_if(&Token::Of) {\n            Some(self.parse_type()?)\n        } else {\n            None\n        };\n        span += self.prev;\n        Ok(Variant { label, ty, span })\n    }\n\n    pub fn type_sum(&mut self) -> Result<Type, Error> {\n        let mut span = self.current.span;\n        let vars = self.delimited(|p| p.variant(), Token::Bar)?;\n        span += self.prev;\n        Ok(Type::new(Sum(vars), span))\n    }\n\n    /// Parse a single type variable '[a-z]+\n    fn parse_tyvar(&mut self) -> Result<Type, Error> {\n        let mut span = self.current.span;\n        self.expect(Token::Apostrophe)?;\n        let v = self.expect_lower_id().map(Variable);\n        span += self.prev;\n        v.map(|t| Type::new(t, span))\n    }\n\n    /// Parse a sequence of type variables ('a, 'b), which are N-arity arguments\n    /// to a type constructor.\n    /// This may return an empty Vec<>\n    pub(crate) fn parse_tyvar_sequence(&mut self) -> Result<Vec<Type>, Error> {\n        if self.bump_if(&Token::LParen) {\n            let ret = self.delimited(|p| p.parse_tyvar(), Token::Comma)?;\n            self.expect(Token::RParen)?;\n            return Ok(ret);\n        }\n        Ok(self.star(|p| p.parse_tyvar(), Some(&Token::Comma)))\n    }\n\n    /// Parse a type sequence (ty1, ty2) , which are N-arity arguments to a\n    /// type constructor.\n    /// If an `Ok(Vec)` is returned, then Vec<> will always have N>=1 items\n    fn parse_type_sequence(&mut self) -> Result<Vec<Type>, Error> {\n        self.expect(Token::LParen)?;\n        let ret = self.delimited(|p| p.parse_type(), Token::Comma)?;\n        self.expect(Token::RParen)?;\n        Ok(ret)\n    }\n\n    /// Parse a existential type of form `forall ('tv :: K) of ty`\n    fn existential(&mut self) -> Result<Type, Error> {\n        let mut span = self.current.span;\n        self.expect(Token::Exists)?;\n        let (name, kind) = self.once(\n            |p| p.abstraction_arg(),\n            \"existential type requires an arg of form ('t :: K)\",\n        )?;\n        self.expect(Token::Of)?;\n        let body = self.once(|p| p.parse_type(), \"existential type requires a body\")?;\n        span += self.prev;\n\n        // We should probably just parse tyvars as string directly...\n        Ok(Type::new(\n            Existential(name.kind.as_tyvar_d(), Box::new(kind), Box::new(body)),\n            span,\n        ))\n    }\n\n    /// Parse a universal type of form `forall ('tv :: K) of ty`\n    fn universal(&mut self) -> Result<Type, Error> {\n        let mut span = self.current.span;\n        self.expect(Token::Forall)?;\n        let (name, kind) = self.once(\n            |p| p.abstraction_arg(),\n            \"universal type requires an arg of form ('t :: K)\",\n        )?;\n        self.expect(Token::Of)?;\n        let body = self.once(|p| p.parse_type(), \"universal type requires a body\")?;\n        span += self.prev;\n        Ok(Type::new(\n            Universal(name.kind.as_tyvar_d(), Box::new(kind), Box::new(body)),\n            span,\n        ))\n    }\n\n    /// Parse a type row of form `label: ty`\n    fn row(&mut self) -> Result<Row, Error> {\n        let mut span = self.current.span;\n        let label = self.expect_lower_id()?;\n        self.expect(Token::Colon)?;\n        let ty = self.once(|p| p.parse_type(), \"record type row requires a type {label: ty, ...}\")?;\n        span += self.prev;\n\n        Ok(Row { label, ty, span })\n    }\n\n    /// Parse a type of form `{ label: ty, label2: ty2, ...}`\n    fn record(&mut self) -> Result<Type, Error> {\n        let mut span = self.current.span;\n        self.expect(Token::LBrace)?;\n        let rows = self.delimited(|p| p.row(), Token::Comma)?;\n        self.expect(Token::RBrace)?;\n        span += self.prev;\n        Ok(Type::new(Record(rows), span))\n    }\n\n    /// Parse a type of form:\n    /// ty ::=  'var\n    ///         id\n    ///         ( ty )\n    ///         ( ty1, ... tyN) ty\n    ///         fn (var :: kind) => ty\n    ///         exists (var :: kind) of ty\n    ///         forall (var :: kind) of ty\n    ///         rec ty\n    ///         { label: ty, ...}\n    pub(crate) fn type_atom(&mut self) -> Result<Type, Error> {\n        let mut span = self.current.span;\n        match self.current.data {\n            Token::TyInt => {\n                self.bump();\n                Ok(Type::new(Int, span))\n            }\n            Token::TyBool => {\n                self.bump();\n                Ok(Type::new(Bool, span))\n            }\n            Token::TyUnit => {\n                self.bump();\n                Ok(Type::new(Unit, span))\n            }\n            Token::Apostrophe => self.parse_tyvar(),\n            Token::LowerId(_) => self.expect_lower_id().map(|p| Type::new(Defined(p), span)),\n            Token::Lambda => self.abstraction(),\n            Token::Exists => self.existential(),\n            Token::Forall => self.universal(),\n            Token::Rec => {\n                self.expect(Token::Rec)?;\n                let ty = self.parse_type()?;\n                span += self.prev;\n                Ok(Type::new(Recursive(Box::new(ty)), span))\n            }\n            Token::LBrace => self.record(),\n            Token::LParen => {\n                // Handle a set of N-arity arguments to constructors\n                let mut v = self.parse_type_sequence()?;\n                if v.len() == 1 {\n                    Ok(v.pop().unwrap())\n                } else {\n                    let tycon = self.type_atom()?;\n                    Ok(v.into_iter().fold(tycon, |ty, v| {\n                        let sp = ty.span + v.span;\n                        Type::new(Application(Box::new(ty), Box::new(v)), sp)\n                    }))\n                }\n            }\n            Token::Wildcard => {\n                self.bump();\n                Ok(Type::new(Infer, span))\n            }\n            _ => self.error(ErrorKind::ExpectedType),\n        }\n    }\n\n    /// Parse an argument of form: `('t :: K)`\n    fn abstraction_arg(&mut self) -> Result<(Type, Kind), Error> {\n        self.expect(Token::LParen)?;\n        let tyvar = self.parse_tyvar()?;\n        self.expect(Token::Colon)?;\n        self.expect(Token::Colon)?;\n        let k = self.kind()?;\n        self.expect(Token::RParen)?;\n        Ok((tyvar, k))\n    }\n\n    /// Parse a type of form: `lambda ('t :: K) => ty`\n    fn abstraction(&mut self) -> Result<Type, Error> {\n        let mut span = self.current.span;\n        self.expect(Token::Lambda)?;\n\n        // let args = self.plus(|p| p.abstraction_arg())?;\n        let (name, kind) = self.once(\n            |p| p.abstraction_arg(),\n            \"type abstraction requires an arg of form ('t :: K)\",\n        )?;\n        self.expect(Token::DoubleArrow)?;\n        let body = self.parse_type()?;\n        span += self.prev;\n        Ok(Type::new(\n            Abstraction(name.kind.as_tyvar_d(), Box::new(kind), Box::new(body)),\n            span,\n        ))\n    }\n\n    /// Parse an application of form: `('a, 'b, ...) ty1 ty2 ty3`\n    fn application(&mut self) -> Result<Type, Error> {\n        // TODO: Confirm this is incorrect for all cases\n        let mut tys = self.plus(|p| p.type_atom(), None)?;\n        tys.reverse();\n        let ty = tys.pop().unwrap();\n        Ok(tys.into_iter().rev().fold(ty, |ty, v| {\n            let sp = ty.span + v.span;\n            Type::new(Application(Box::new(v), Box::new(ty)), sp)\n        }))\n    }\n\n    /// Parse a type of form: `ty` | `ty * ty2 * ...`\n    fn product(&mut self) -> Result<Type, Error> {\n        let mut span = self.current.span;\n        let mut v = self.delimited(|p| p.application(), Token::Asterisk)?;\n        span += self.prev;\n        match v.len() {\n            1 => Ok(v.pop().unwrap()),\n            _ => Ok(Type::new(Product(v), span)),\n        }\n    }\n\n    /// Parse a type of form: `ty * ty` | `ty -> ty`\n    pub fn parse_type(&mut self) -> Result<Type, Error> {\n        let mut span = self.current.span;\n        let ty = self.product()?;\n        if self.bump_if(&Token::SingleArrow) {\n            let ty2 = self.parse_type()?;\n            span += ty2.span;\n            return Ok(Type::new(Function(Box::new(ty), Box::new(ty2)), span));\n        }\n        Ok(ty)\n    }\n\n    /// Parse a kind of form: `* | ( K )`\n    fn kind_single(&mut self) -> Result<Kind, Error> {\n        if self.bump_if(&Token::LParen) {\n            let k = self.kind()?;\n            self.expect(Token::RParen)?;\n            return Ok(k);\n        }\n        self.expect(Token::Asterisk)?;\n        Ok(Kind::Star)\n    }\n\n    /// Parse a kind of form: `K | K -> K`\n    pub fn kind(&mut self) -> Result<Kind, Error> {\n        let k = self.kind_single()?;\n        if self.bump_if(&Token::SingleArrow) {\n            let k2 = self.kind()?;\n            return Ok(Kind::Arrow(Box::new(k), Box::new(k2)));\n        }\n        Ok(k)\n    }\n}\n"
  },
  {
    "path": "07_system_fw/src/syntax/tokens.rs",
    "content": "#[allow(dead_code)]\n#[derive(Clone, Debug, PartialEq, PartialOrd)]\npub enum Token {\n    Dot,\n    Colon,\n    Opaque,\n    Semicolon,\n    Comma,\n    Apostrophe,\n    Bar,\n    SingleArrow,\n    DoubleArrow,\n    Wildcard,\n    Asterisk,\n    Equals,\n\n    LParen,\n    RParen,\n    LBrace,\n    RBrace,\n\n    And,\n    Function,\n    Lambda,\n    Val,\n    Let,\n    In,\n    Case,\n    Of,\n    End,\n    As,\n    If,\n    Then,\n    Else,\n    Type,\n    Datatype,\n    Fix,\n    Rec,\n    Exists,\n    Forall,\n    TyInt,\n    TyBool,\n    TyUnit,\n\n    TypeAppSigil,\n\n    LowerId(String),\n    UpperId(String),\n\n    Comment(String),\n    Int(usize),\n    Unit,\n    Placeholder,\n    Invalid(char),\n    EOF,\n}\n\nimpl Token {\n    pub fn extract_string(self) -> String {\n        match self {\n            Token::LowerId(s) | Token::UpperId(s) | Token::Comment(s) => s,\n            _ => panic!(\"Invalid token {:?}\", self),\n        }\n    }\n}\n"
  },
  {
    "path": "07_system_fw/src/syntax/visit/mod.rs",
    "content": "use super::*;\nmod types;\n\npub use types::TypeVisitor;\n"
  },
  {
    "path": "07_system_fw/src/syntax/visit/types.rs",
    "content": "use super::*;\nuse ast::{Kind, Row, Type, TypeKind, Variant};\n\npub trait TypeVisitor<'t>: Sized {\n    fn visit_defined(&mut self, _: &'t str) {}\n\n    fn visit_variable(&mut self, _: &'t str) {}\n\n    fn visit_function(&mut self, ty1: &'t Type, ty2: &'t Type) {\n        self.visit_ty(ty1);\n        self.visit_ty(ty2);\n    }\n\n    fn visit_application(&mut self, ty1: &'t Type, ty2: &'t Type) {\n        self.visit_ty(ty1);\n        self.visit_ty(ty2);\n    }\n\n    fn visit_sum(&mut self, var: &'t [Variant]) {\n        for v in var {\n            if let Some(ty) = &v.ty {\n                self.visit_ty(ty);\n            }\n        }\n    }\n\n    fn visit_product(&mut self, var: &'t [Type]) {\n        for v in var {\n            self.visit_ty(v);\n        }\n    }\n\n    fn visit_record(&mut self, var: &'t [Row]) {\n        for v in var {\n            self.visit_ty(&v.ty);\n        }\n    }\n\n    fn visit_existential(&mut self, _: &'t str, _: &'t Kind, ty: &'t Type) {\n        self.visit_ty(ty);\n    }\n\n    fn visit_universal(&mut self, _: &'t str, _: &'t Kind, ty: &'t Type) {\n        self.visit_ty(ty);\n    }\n\n    fn visit_abstraction(&mut self, _: &'t str, _: &'t Kind, ty: &'t Type) {\n        self.visit_ty(ty);\n    }\n\n    fn visit_recursive(&mut self, ty: &'t Type) {\n        self.visit_ty(ty);\n    }\n\n    fn visit_ty(&mut self, ty: &'t Type) {\n        self.walk_ty(ty);\n    }\n\n    fn walk_ty(&mut self, ty: &'t Type) {\n        use TypeKind::*;\n        match &ty.kind {\n            Int => {}\n            Bool => {}\n            Unit => {}\n            Infer => {}\n            Defined(s) => self.visit_defined(s),\n            Variable(s) => self.visit_variable(s),\n            Function(ty1, ty2) => self.visit_function(ty1, ty2),\n            Sum(var) => self.visit_sum(var),\n            Product(tys) => self.visit_product(tys),\n            Record(rows) => self.visit_record(rows),\n            Existential(s, k, ty) => self.visit_existential(s, k, ty),\n            Universal(s, k, ty) => self.visit_universal(s, k, ty),\n            Abstraction(s, k, ty) => self.visit_abstraction(s, k, ty),\n            Application(ty1, ty2) => self.visit_application(ty1, ty2),\n            Recursive(ty) => self.visit_recursive(ty),\n        }\n    }\n}\n"
  },
  {
    "path": "07_system_fw/src/terms.rs",
    "content": "use crate::types::{TyKind, Type};\nuse util::span::Span;\n\n/// Constant expression or pattern\n#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Eq, Hash)]\npub enum Constant {\n    Unit,\n    Bool(bool),\n    Nat(u32),\n}\n\n#[derive(Clone, Debug, PartialEq, PartialOrd)]\npub enum Kind {\n    /// Constant\n    Const(Constant),\n    /// Variable\n    Var(usize),\n    /// Term abstraction\n    /// \\x: Ty. x\n    /// Introduce a lambda term\n    Abs(Box<Type>, Box<Term>),\n    /// Term application\n    /// m n\n    /// Eliminate a lambda term\n    App(Box<Term>, Box<Term>),\n    /// Type abstraction\n    /// \\X. \\x: X. x\n    /// Introduce a universally quantified type\n    TyAbs(Box<TyKind>, Box<Term>),\n    /// Type application\n    /// id [Nat] 1\n    /// Eliminate a universally quantified type\n    TyApp(Box<Term>, Box<Type>),\n    /// Record term\n    /// {label1 = Tm1, label2 = Tm2, etc}\n    /// Invariant that all fields have unique labels\n    Record(Record),\n\n    Index(Box<Term>, String),\n\n    /// Injection into a sum type\n    /// fields: type constructor tag, term, and sum type\n    Injection(String, Box<Term>, Box<Type>),\n\n    Fold(Box<Type>, Box<Term>),\n    Unfold(Box<Type>, Box<Term>),\n\n    /// Introduce an existential type\n    /// { *Ty1, Term } as {∃X.Ty}\n    /// essentially, concrete representation as interface\n    Pack(Box<Type>, Box<Term>, Box<Type>),\n    /// Unpack an existential type\n    /// open {∃X, bind} in body -- X is bound as a TyVar, and bind as Var(0)\n    /// Eliminate an existential type\n    Unpack(Box<Term>, Box<Term>),\n}\n\n#[derive(Clone, Debug, PartialEq, PartialOrd)]\npub struct Field {\n    pub span: Span,\n    pub label: String,\n    pub expr: Box<Term>,\n}\n\n#[derive(Clone, Debug, PartialEq, PartialOrd)]\npub struct Record {\n    pub fields: Vec<Field>,\n}\n\n#[derive(Clone, Debug, PartialEq, PartialOrd)]\npub struct Term {\n    pub span: Span,\n    pub kind: Kind,\n}\n\nimpl Term {\n    pub fn new(kind: Kind, span: Span) -> Term {\n        Term { kind, span }\n    }\n}\n\nimpl Record {\n    pub fn get(&self, label: &str) -> Option<&Field> {\n        for field in &self.fields {\n            if field.label == label {\n                return Some(field);\n            }\n        }\n        None\n    }\n}\n\nuse std::fmt;\n\nimpl fmt::Display for Term {\n    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n        match &self.kind {\n            Kind::Var(idx) => write!(f, \"#{}\", idx),\n            Kind::Const(Constant::Bool(b)) => write!(f, \"{}\", b),\n            Kind::Const(Constant::Nat(b)) => write!(f, \"{}\", b),\n            Kind::Const(Constant::Unit) => write!(f, \"()\"),\n            Kind::Abs(ty, body) => write!(f, \"(λx:{}. {})\", ty, body),\n            Kind::App(m, n) => write!(f, \"{} {}\", m, n),\n            Kind::TyAbs(kind, body) => write!(f, \"ΛX::{}. {}\", kind, body),\n            Kind::TyApp(body, ty) => write!(f, \"{} [{}]\", body, ty),\n            Kind::Pack(witness, body, sig) => write!(f, \"{{*{}, {}}} as {}\", witness, body, sig),\n            Kind::Unpack(m, n) => write!(f, \"unpack {} as {}\", m, n),\n            Kind::Record(rec) => write!(\n                f,\n                \"{{\\n{}\\n}}\",\n                rec.fields\n                    .iter()\n                    .map(|fi| format!(\"\\t{}: {}\", fi.label, fi.expr))\n                    .collect::<Vec<_>>()\n                    .join(\",\\n\")\n            ),\n            Kind::Index(t1, t2) => write!(f, \"{}.{}\", t1, t2),\n            Kind::Injection(label, tm, ty) => write!(f, \"{} of {} as {}\", label, tm, ty),\n            Kind::Fold(ty, term) => write!(f, \"fold [{}] {}\", ty, term),\n            Kind::Unfold(ty, term) => write!(f, \"unfold [{}] {}\", ty, term),\n        }\n    }\n}\n"
  },
  {
    "path": "07_system_fw/src/typecheck.rs",
    "content": "use crate::diagnostics::Diagnostic;\nuse crate::stack::Stack;\nuse crate::terms::{Constant, Field, Kind, Record, Term};\nuse crate::types::{MutTypeVisitor, TyField, TyKind, Type};\nuse util::span::Span;\n/// A typing context, Γ\n#[derive(Debug)]\npub struct Context {\n    stack: Stack<Type>,\n    kstack: Stack<TyKind>,\n}\n\nimpl Default for Context {\n    fn default() -> Context {\n        Context {\n            stack: Stack::with_capacity(16),\n            kstack: Stack::with_capacity(16),\n        }\n    }\n}\n\n#[derive(Debug, PartialEq)]\npub enum KindError {\n    Mismatch(TyKind, TyKind),\n    NotArrow(TyKind),\n    NotProduct,\n    Unbound(usize),\n}\n\nstruct TypeSimplifier<'a> {\n    ctx: &'a mut Context,\n    res: Result<bool, KindError>,\n}\n\nimpl<'a> TypeSimplifier<'a> {}\n\nimpl<'a> MutTypeVisitor for TypeSimplifier<'a> {\n    fn visit_universal(&mut self, kind: &mut TyKind, ty: &mut Type) {\n        self.ctx.kstack.push(kind.clone());\n        self.visit(ty);\n        self.ctx.kstack.pop();\n    }\n\n    fn visit_existential(&mut self, kind: &mut TyKind, ty: &mut Type) {\n        self.ctx.kstack.push(kind.clone());\n        self.visit(ty);\n        self.ctx.kstack.pop();\n    }\n\n    fn visit_abs(&mut self, kind: &mut TyKind, ty: &mut Type) {\n        self.ctx.kstack.push(kind.clone());\n        self.visit(ty);\n        self.ctx.kstack.pop();\n    }\n\n    fn visit(&mut self, ty: &mut Type) {\n        match ty {\n            Type::App(m, n) => {\n                self.visit(m);\n                self.visit(n);\n                if let Type::Abs(k, t) = m.as_mut() {\n                    match self.ctx.kinding(&n) {\n                        Ok(n_kind) => {\n                            if k.as_ref() == &n_kind {\n                                t.subst(*n.clone());\n                                *ty = *t.clone();\n                                self.res = Ok(true);\n                            } else {\n                                self.res = Err(KindError::Mismatch(*k.clone(), n_kind))\n                            }\n                        }\n                        Err(e) => self.res = Err(e),\n                    }\n                }\n            }\n            Type::Projection(inner, idx) => {\n                self.visit(inner);\n                match inner.as_ref() {\n                    Type::Product(v) => match v.get(*idx) {\n                        Some(t) => {\n                            *ty = t.clone();\n                            self.res = Ok(true);\n                        }\n                        None => {\n                            self.res = Err(KindError::Unbound(*idx));\n                        }\n                    },\n                    // Type::Var(_) => {}\n                    // _ => self.res = Err(KindError::NotProduct),\n                    _ => {}\n                }\n            }\n            _ => self.walk(ty),\n        }\n    }\n}\n\nimpl KindError {\n    fn to_diag(self, span: Span) -> Diagnostic {\n        match self {\n            KindError::Mismatch(k1, k2) => Diagnostic::error(\n                span,\n                format!(\n                    \"a type of kind {:?} is required, but a type of kind {:?} was supplied\",\n                    k1, k2\n                ),\n            ),\n            KindError::NotArrow(k) => Diagnostic::error(\n                span,\n                format!(\n                    \"a type of kind *->* was required, but a type of kind {:?} was supplied\",\n                    k\n                ),\n            ),\n            KindError::Unbound(idx) => {\n                Diagnostic::error(span, format!(\"unbound type variable with de Bruijn index {}\", idx))\n            }\n            KindError::NotProduct => Diagnostic::error(span, format!(\"a product kind is required\")),\n        }\n    }\n}\n\nimpl Context {\n    pub fn kinding(&mut self, ty: &Type) -> Result<TyKind, KindError> {\n        match ty {\n            Type::Var(idx) => self.kstack.get(*idx).cloned().ok_or(KindError::Unbound(*idx)),\n            Type::Abs(kind, t) => {\n                self.kstack.push(*kind.clone());\n                let k_ = self.kinding(&t)?;\n                self.kstack.pop();\n                Ok(TyKind::Arrow(kind.clone(), Box::new(k_)))\n            }\n            Type::App(s, t) => match self.kinding(&s)? {\n                TyKind::Arrow(a, b) => {\n                    let k = self.kinding(&t)?;\n                    if k == *a {\n                        Ok(*b)\n                    } else {\n                        Err(KindError::Mismatch(*a, k))\n                    }\n                }\n                k => Err(KindError::NotArrow(k)),\n            },\n            Type::Arrow(s, t) => match self.kinding(&s)? {\n                TyKind::Star => match self.kinding(&t)? {\n                    TyKind::Star => Ok(TyKind::Star),\n                    k => Err(KindError::Mismatch(TyKind::Star, k)),\n                },\n                k => Err(KindError::Mismatch(TyKind::Star, k)),\n            },\n            Type::Universal(kind, t) => {\n                self.kstack.push(*kind.clone());\n                let k_ = self.kinding(&t)?;\n                self.kstack.pop();\n                match k_ {\n                    TyKind::Star => Ok(TyKind::Star),\n                    k => Err(KindError::Mismatch(TyKind::Star, k)),\n                }\n            }\n            Type::Existential(kind, t) => {\n                self.kstack.push(*kind.clone());\n                let k_ = self.kinding(&t)?;\n                self.kstack.pop();\n                match k_ {\n                    TyKind::Star => Ok(TyKind::Star),\n                    k => Err(KindError::Mismatch(TyKind::Star, k)),\n                }\n            }\n            Type::Record(fields) | Type::Sum(fields) => {\n                for f in fields {\n                    let k = self.kinding(&f.ty)?;\n                    if k != TyKind::Star {\n                        return Err(KindError::Mismatch(TyKind::Star, k));\n                    }\n                }\n                Ok(TyKind::Star)\n            }\n            Type::Product(tys) => {\n                // for ty in tys {\n                //     let k = self.kinding(&ty)?;\n                //     if k != TyKind::Star {\n                //         return Err(KindError::Mismatch(TyKind::Star, k));\n                //     }\n                // }\n                // Ok(TyKind::Star)\n                tys.iter()\n                    .map(|t| self.kinding(t))\n                    .collect::<Result<Vec<TyKind>, _>>()\n                    .map(TyKind::Product)\n            }\n            Type::Projection(ty, idx) => {\n                match self.kinding(ty)? {\n                    TyKind::Product(v) => v.get(*idx).cloned().ok_or(KindError::Unbound(*idx)),\n                    k => Err(KindError::Mismatch(TyKind::Product(vec![]), k)),\n                }\n                // match ty.as_ref() {\n                //     Type::Product(v) =>\n                // v.get(idx).ok_or(KindError::Unbound(idx)),\n                //     _ => Err(KindError::Mismatch())\n                // }\n            }\n            Type::Recursive(inner) => {\n                let k = self.kinding(inner)?;\n                match k {\n                    TyKind::Arrow(k1, k2) => {\n                        if &k1 == &k2 {\n                            Ok(*k1)\n                        } else {\n                            Err(KindError::Mismatch(*k1, *k2))\n                        }\n                    }\n                    _ => Err(KindError::NotArrow(k)),\n                }\n            }\n            _ => Ok(TyKind::Star),\n        }\n    }\n\n    pub fn simplify_ty(&mut self, ty: &mut Type) -> Result<bool, KindError> {\n        let mut ts = TypeSimplifier {\n            ctx: self,\n            res: Ok(false),\n        };\n        let mut work = false;\n        loop {\n            ts.res = Ok(false);\n            ts.visit(ty);\n            match ts.res {\n                Ok(false) => return Ok(work),\n                Ok(true) => work = true,\n                Err(e) => return Err(e),\n            }\n        }\n    }\n\n    pub fn equiv(&mut self, lhs: &Type, rhs: &Type) -> Result<bool, KindError> {\n        if lhs == rhs {\n            Ok(true)\n        } else {\n            let mut lhs_ = lhs.clone();\n            let mut rhs_ = rhs.clone();\n            self.simplify_ty(&mut lhs_)?;\n            self.simplify_ty(&mut rhs_)?;\n            Ok(lhs_ == rhs_)\n        }\n    }\n\n    fn is_star_kind(&mut self, ty: &Type, err_span: Span) -> Result<(), Diagnostic> {\n        let kind = self.kinding(ty).map_err(|k| KindError::to_diag(k, err_span))?;\n        if kind == TyKind::Star {\n            Ok(())\n        } else {\n            return Err(Diagnostic::error(\n                err_span,\n                format!(\n                    \"type bound in type abstraction must have a kind *, {} has a kind of {}\",\n                    ty, kind\n                ),\n            ));\n        }\n    }\n\n    pub fn typecheck(&mut self, term: &Term) -> Result<Type, Diagnostic> {\n        match &term.kind {\n            Kind::Const(c) => match c {\n                Constant::Unit => Ok(Type::Unit),\n                Constant::Nat(_) => Ok(Type::Nat),\n                Constant::Bool(_) => Ok(Type::Bool),\n            },\n            Kind::Var(idx) => self\n                .stack\n                .get(*idx)\n                .cloned()\n                .ok_or(Diagnostic::error(term.span, \"unbound variable\")),\n            Kind::Abs(ty, tm) => {\n                self.is_star_kind(ty, term.span)?;\n                self.stack.push(*ty.clone());\n                let ty2 = self.typecheck(&tm)?;\n                self.stack.pop();\n                Ok(Type::Arrow(ty.clone(), Box::new(ty2)))\n            }\n            Kind::App(m, n) => {\n                let mut ty = self.typecheck(&m)?;\n                self.simplify_ty(&mut ty).map_err(|ke| ke.to_diag(term.span))?;\n                if let Type::Arrow(ty11, ty12) = ty {\n                    let ty2 = self.typecheck(&n)?;\n                    if self.equiv(&ty11, &ty2).map_err(|ke| ke.to_diag(term.span))? {\n                        Ok(*ty12)\n                    } else {\n                        dbg!(&self.stack);\n                        dbg!(&self.kstack);\n                        let d = Diagnostic::error(term.span, \"type mismatch in application\")\n                            .message(\n                                m.span,\n                                format!(\"abstraction {} requires type {} to return {}\", m, ty11, ty12),\n                            )\n                            .message(n.span, format!(\"term {} has a type of {}\", n, ty2));\n                        return Err(d);\n                    }\n                } else {\n                    // dbg!(&self.stack);\n                    dbg!(&m);\n                    dbg!(&ty);\n                    let d = Diagnostic::error(term.span, \"type mismatch in application\")\n                        .message(m.span, format!(\"this term {} has a type {}, not T->U\", m, ty));\n                    return Err(d);\n                }\n            }\n            Kind::TyAbs(tk, polymorphic) => {\n                // Reference commit log eda3417 for explanation of below code\n                // TODO: Do we need to the same thing for the kinding stack?\n\n                self.kstack.push(*tk.clone());\n                self.stack.iter_mut().for_each(|ty| match ty {\n                    Type::Var(v) => *v += 1,\n                    _ => {}\n                });\n                let ty = self.typecheck(&polymorphic)?;\n                self.stack.iter_mut().for_each(|ty| match ty {\n                    Type::Var(v) => *v -= 1,\n                    _ => {}\n                });\n                self.kstack.pop();\n                Ok(Type::Universal(tk.clone(), Box::new(ty)))\n            }\n            Kind::TyApp(tyabs, applied) => {\n                let mut ty = self.typecheck(&tyabs)?;\n                self.simplify_ty(&mut ty).map_err(|ke| ke.to_diag(term.span))?;\n                match ty {\n                    Type::Universal(k1, u) => {\n                        let k2 = self.kinding(&applied).map_err(|k| KindError::to_diag(k, term.span))?;\n                        if k2 == *k1 {\n                            // actually do subst\n                            let mut u = *u;\n                            u.subst(*applied.clone());\n                            Ok(u)\n                        } else {\n                            let d = Diagnostic::error(term.span, \"type kind mismatch in term-level type application\")\n                                .message(\n                                    tyabs.span,\n                                    format!(\n                                        \"universal type requires a type of kind {}, but a kind of {} is given\",\n                                        &k1, k2\n                                    ),\n                                );\n                            Err(d)\n                        }\n                    }\n                    ty => {\n                        let d = Diagnostic::error(term.span, \"type mismatch in term-level type application\")\n                            .message(tyabs.span, format!(\"this term has a type {}, not forall. X::K\", ty));\n                        Err(d)\n                    }\n                }\n            }\n\n            Kind::Record(rec) => {\n                let mut tys = Vec::with_capacity(rec.fields.len());\n                for f in &rec.fields {\n                    tys.push(TyField {\n                        label: f.label.clone(),\n                        ty: Box::new(self.typecheck(&f.expr)?),\n                    });\n                }\n                Ok(Type::Record(tys))\n            }\n\n            Kind::Index(tm, field) => {\n                let ty = self.typecheck(tm)?;\n                match ty {\n                    Type::Record(fields) => {\n                        for f in fields {\n                            if &f.label == field {\n                                return Ok(*f.ty);\n                            }\n                        }\n                        Err(Diagnostic::error(term.span, \"invalid field access\")\n                            .message(tm.span, format!(\"term does not have a label named {}\", field)))\n                    }\n                    _ => Err(Diagnostic::error(term.span, \"invalid field access\")\n                        .message(tm.span, format!(\"term has a type of {}, not Record\", ty))),\n                }\n            }\n            Kind::Injection(label, tm, ty) => {\n                let mut ty = ty.clone();\n                self.simplify_ty(&mut ty).map_err(|ke| ke.to_diag(term.span))?;\n                match ty.as_ref() {\n                    Type::Sum(fields) => {\n                        for f in fields {\n                            if label == &f.label {\n                                let mut ty_ = self.typecheck(tm)?;\n                                self.simplify_ty(&mut ty_).map_err(|ke| ke.to_diag(term.span))?;\n                                if &ty_ == f.ty.as_ref() {\n                                    return Ok(*ty.clone());\n                                } else {\n                                    let d = Diagnostic::error(term.span, \"Invalid associated type in variant\").message(\n                                        tm.span,\n                                        format!(\"variant {} requires type {}, but this is {}\", label, f.ty, ty_),\n                                    );\n                                    return Err(d);\n                                }\n                            }\n                        }\n                        Err(Diagnostic::error(\n                            term.span,\n                            format!(\n                                \"constructor {} does not belong to the variant {}\",\n                                label,\n                                fields\n                                    .iter()\n                                    .map(|f| f.label.clone())\n                                    .collect::<Vec<String>>()\n                                    .join(\" | \")\n                            ),\n                        ))\n                    }\n                    _ => Err(Diagnostic::error(\n                        term.span,\n                        format!(\"Cannot inject {} into non-variant type {}\", label, ty),\n                    )),\n                }\n            }\n            Kind::Unfold(rec, tm) => match rec.as_ref() {\n                Type::Recursive(inner) => {\n                    let ty_ = self.typecheck(&tm)?;\n                    if self.equiv(&ty_, &rec).map_err(|ke| ke.to_diag(term.span))? {\n                        let mut s = inner.clone();\n                        s.subst(*rec.clone());\n                        Ok(*s)\n                    } else {\n                        let d = Diagnostic::error(term.span, \"Type mismatch in unfold\")\n                            .message(term.span, format!(\"unfold requires type {}\", rec))\n                            .message(tm.span, format!(\"term has a type of {}\", ty_));\n                        Err(d)\n                    }\n                }\n                _ => Err(Diagnostic::error(\n                    term.span,\n                    format!(\"Expected a recursive type, not {}\", rec),\n                )),\n            },\n\n            Kind::Fold(rec, tm) => {\n                // Fold takes an argument of type μF, term where term types to F(μF)\n                // and wraps the type into μF\n                // Alternatively, Fold can also take an argument of type μF A,\n                // term where term types to F(μF) A\n                let rec = rec.clone();\n                // self.simplify_ty(&mut rec)\n                //     .map_err(|ke| ke.to_diag(term.span))?;\n                match rec.as_ref() {\n                    Type::Recursive(inner) => {\n                        let ty_ = self.typecheck(&tm)?;\n                        let mut s = Type::App(inner.clone(), rec.clone());\n                        self.simplify_ty(&mut s).map_err(|ke| ke.to_diag(term.span))?;\n                        if self.equiv(&ty_, &s).map_err(|ke| ke.to_diag(term.span))? {\n                            Ok(*rec)\n                        } else {\n                            let d = Diagnostic::error(term.span, \"Type mismatch in fold\")\n                                .message(term.span, format!(\"fold requires type {}\", s))\n                                .message(tm.span, format!(\"term has a type of {}\", ty_));\n                            Err(d)\n                        }\n                    }\n                    Type::App(ty1, ty2) => match ty1.as_ref() {\n                        Type::Recursive(rec_inner) => {\n                            let mut apped = Type::App(Box::new(Type::App(rec_inner.clone(), ty1.clone())), ty2.clone());\n                            self.simplify_ty(&mut apped).map_err(|ke| ke.to_diag(term.span))?;\n                            let ty_ = self.typecheck(&tm)?;\n                            if self.equiv(&ty_, &apped).map_err(|ke| ke.to_diag(term.span))? {\n                                Ok(*rec)\n                            } else {\n                                let d = Diagnostic::error(term.span, \"Type mismatch in fold\")\n                                    .message(term.span, format!(\"fold requires type {}\", apped))\n                                    .message(tm.span, format!(\"term has a type of {}\", ty_));\n                                Err(d)\n                            }\n                        }\n                        _ => {\n                            let d = Diagnostic::error(\n                                term.span,\n                                format!(\"Fold requires a recursive type in application of {} to {}\", ty1, ty2),\n                            );\n                            Err(d)\n                        }\n                    },\n                    _ => Err(Diagnostic::error(\n                        term.span,\n                        format!(\"Expected a recursive type, not {}\", rec),\n                    )),\n                }\n            }\n            Kind::Pack(witness, packed, sig) => {\n                // where sig =  {∃X, T2}\n                // Γ⊢ packed : [ X -> witness ] T2 and Γ⊢  {∃X, T2} :: *\n                // then {*witness, packed} as  {∃X, T2}\n\n                let k = self.kinding(sig).map_err(|k| KindError::to_diag(k, term.span))?;\n                if k != TyKind::Star {\n                    return diag!(term.span, \"existential type definition does not have a kind of *\");\n                }\n\n                let mut sig = sig.clone();\n                self.simplify_ty(&mut sig).map_err(|ke| ke.to_diag(term.span))?;\n\n                match sig.as_mut() {\n                    Type::Existential(kind, t2) => {\n                        let witness_kind = self.kinding(&witness).map_err(|k| KindError::to_diag(k, term.span))?;\n\n                        if &witness_kind != kind.as_ref() {\n                            return diag!(\n                                term.span,\n                                \"existential type requires a type of kind {}, but implementation type has a kind of {}\",\n                                kind,\n                                witness_kind\n                            );\n                        }\n\n                        let ty_packed = self.typecheck(packed)?;\n                        let mut ty_packed_prime = *t2.clone();\n                        ty_packed_prime.subst(*witness.clone());\n                        // Pierce's code has kind checking before type-substitution,\n                        // does this matter? He also directly kind-checks the\n                        // witness type against kind\n\n                        if self\n                            .equiv(&ty_packed, &ty_packed_prime)\n                            .map_err(|ke| ke.to_diag(term.span))?\n                        {\n                            Ok(*sig.clone())\n                        } else {\n                            Err(Diagnostic::error(term.span, \"type mismatch in existential package\")\n                                .message(packed.span, format!(\"term has a type of {}\", ty_packed))\n                                .message(\n                                    term.span,\n                                    format!(\"but the existential package type is defined as {}\", ty_packed_prime,),\n                                ))\n                        }\n                    }\n                    ty => diag!(term.span, \"cannot pack an existential type into {}\", ty),\n                }\n            }\n\n            Kind::Unpack(packed, body) => {\n                let ty = self.typecheck(packed)?;\n                match ty {\n                    Type::Existential(kind, sig) => {\n                        self.kstack.push(*kind);\n                        self.stack.push(*sig);\n                        let body_ty = self.typecheck(body)?;\n                        self.stack.pop();\n                        self.kstack.pop();\n                        Ok(body_ty)\n                    }\n                    _ => Err(Diagnostic::error(term.span, \"type mismatch during unpack\")\n                        .message(packed.span, format!(\"term has a type of {}, not {{∃X::K, T}}\", ty))),\n                }\n            }\n        }\n    }\n}\n\n#[cfg(test)]\nmod test {\n    use super::*;\n\n    #[test]\n    fn ty_app() {\n        // ΛX. λx: X. x  should typecheck to ∀X. X->X\n        let id = tyabs!(kind!(*), abs!(Type::Var(0), var!(0)));\n        // Instantiations of polymorphic identity function ∀X. X->X\n        let inst1 = tyapp!(id.clone(), Type::Nat);\n        let inst2 = tyapp!(id.clone(), arrow!(Type::Unit, Type::Nat));\n        let inst3 = tyapp!(id.clone(), univ!(kind!(*), arrow!(Type::Var(0), Type::Var(0))));\n\n        let mut ctx = Context::default();\n        // ΛX. λx: X. x  should typecheck to ∀X. X->X\n        assert_eq!(\n            ctx.typecheck(&id),\n            Ok(univ!(kind!(*), arrow!(Type::Var(0), Type::Var(0))))\n        );\n        assert_eq!(ctx.typecheck(&inst1), Ok(arrow!(Type::Nat, Type::Nat)));\n        assert_eq!(\n            ctx.typecheck(&inst2),\n            Ok(arrow!(arrow!(Type::Unit, Type::Nat), arrow!(Type::Unit, Type::Nat)))\n        );\n        assert_eq!(\n            ctx.typecheck(&inst3),\n            Ok(arrow!(\n                univ!(kind!(*), arrow!(Type::Var(0), Type::Var(0))),\n                univ!(kind!(*), arrow!(Type::Var(0), Type::Var(0)))\n            ))\n        );\n    }\n\n    #[test]\n    fn ty_exist() {\n        let interface_ty = exist!(\n            kind!(*),\n            record!((\"new\", Type::Var(0)), (\"get\", arrow!(Type::Var(0), Type::Nat)))\n        );\n        let adt = Term::new(\n            Kind::Record(Record {\n                fields: vec![\n                    Field {\n                        span: Span::zero(),\n                        label: \"new\".to_string(),\n                        expr: Box::new(nat!(0)),\n                    },\n                    Field {\n                        span: Span::zero(),\n                        label: \"get\".to_string(),\n                        expr: Box::new(abs!(Type::Nat, var!(0))),\n                    },\n                ],\n            }),\n            Span::zero(),\n        );\n        let counter = pack!(Type::Nat, adt, interface_ty.clone());\n        let mut ctx = Context::default();\n        assert_eq!(ctx.typecheck(&counter), Ok(interface_ty));\n\n        let unpacked = unpack!(counter, app!(access!(var!(0), \"get\"), access!(var!(0), \"new\")));\n        assert_eq!(ctx.typecheck(&unpacked), Ok(Type::Nat));\n    }\n\n    #[test]\n    fn ty_abs() {\n        let ty = tyop!(kind!(*), Type::Var(0));\n        let mut ctx = Context::default();\n        assert_eq!(ctx.kinding(&ty), Ok(kind!(* => *)));\n        assert_eq!(ctx.kinding(&Type::App(Box::new(ty), Box::new(Type::Nat))), Ok(kind!(*)));\n\n        let pair = tyop!(kind!(*), tyop!(kind!(*), univ!(kind!(*), Type::Var(0))));\n        assert_eq!(ctx.kinding(&pair), Ok(kind!(kind!(*) => kind!(* => *))));\n    }\n\n    #[test]\n    fn ty_equivalence() {\n        let ty1 = op_app!(tyop!(kind!(*), Type::Var(0)), Type::Nat);\n        let ty2 = Type::Nat;\n        let mut ctx = Context::default();\n        assert_eq!(ctx.equiv(&ty1, &ty2), Ok(true), \"{:?}\", ty1);\n    }\n\n    #[test]\n    fn ty_record() {\n        let adt = Term::new(\n            Kind::Record(Record {\n                fields: vec![\n                    Field {\n                        span: Span::zero(),\n                        label: \"new\".to_string(),\n                        expr: Box::new(nat!(0)),\n                    },\n                    Field {\n                        span: Span::zero(),\n                        label: \"get\".to_string(),\n                        expr: Box::new(abs!(Type::Nat, var!(0))),\n                    },\n                ],\n            }),\n            Span::zero(),\n        );\n\n        let mut ctx = Context::default();\n        let rty = record!((\"new\", Type::Nat), (\"get\", arrow!(Type::Nat, Type::Nat)));\n        assert_eq!(ctx.typecheck(&adt), Ok(rty));\n\n        let t1 = access!(adt.clone(), \"new\");\n        let t2 = access!(adt.clone(), \"get\");\n        assert_eq!(ctx.typecheck(&t1), Ok(Type::Nat));\n        assert_eq!(ctx.typecheck(&t2), Ok(arrow!(Type::Nat, Type::Nat)));\n    }\n}\n"
  },
  {
    "path": "07_system_fw/src/types.rs",
    "content": "use std::convert::TryFrom;\nuse std::fmt;\n\n#[derive(Clone, Debug, PartialEq, PartialOrd)]\npub enum Type {\n    Unit,\n    Nat,\n    Bool,\n    Var(usize),\n    Record(Vec<TyField>),\n    Product(Vec<Type>),\n    Projection(Box<Type>, usize),\n    Arrow(Box<Type>, Box<Type>),\n    Universal(Box<TyKind>, Box<Type>),\n    Existential(Box<TyKind>, Box<Type>),\n    Abs(Box<TyKind>, Box<Type>),\n    App(Box<Type>, Box<Type>),\n    Recursive(Box<Type>),\n    Sum(Vec<TyField>),\n}\n\n#[derive(Clone, Debug, PartialEq, PartialOrd)]\npub struct TyField {\n    pub label: String,\n    pub ty: Box<Type>,\n}\n\n#[derive(Clone, Debug, PartialEq, PartialOrd)]\npub enum TyKind {\n    Star,\n    Arrow(Box<TyKind>, Box<TyKind>),\n    Product(Vec<TyKind>),\n}\n\nimpl Type {\n    pub fn subst(&mut self, mut s: Type) {\n        Shift::new(1).visit(&mut s);\n        Subst::new(s).visit(self);\n        Shift::new(-1).visit(self);\n    }\n\n    /// Support function for quickly accessing labelled subtypes\n    pub fn label(&self, label: &str) -> Option<&Type> {\n        match self {\n            Type::Sum(fields) | Type::Record(fields) => {\n                for f in fields {\n                    if f.label == label {\n                        return Some(&f.ty);\n                    }\n                }\n                None\n            }\n            _ => None,\n        }\n    }\n}\n\nimpl fmt::Display for Type {\n    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n        match &self {\n            Type::Var(idx) => write!(f, \"TyVar({})\", idx),\n            Type::Unit => write!(f, \"Unit\"),\n            Type::Nat => write!(f, \"Nat\"),\n            Type::Bool => write!(f, \"Bool\"),\n            Type::Abs(kind, ty) => write!(f, \"(ΛX::{}. {})\", kind, ty),\n            Type::App(m, n) => write!(f, \"{} {}\", m, n),\n            Type::Arrow(m, n) => write!(f, \"{}->{}\", m, n),\n            Type::Universal(k, ty) => write!(f, \"∀X::{}. {}\", k, ty),\n            Type::Existential(k, ty) => write!(f, \"{{∃X::{}, {}}}\", k, ty),\n            Type::Record(fields) => write!(\n                f,\n                \"{{\\n{}\\n}}\",\n                fields\n                    .iter()\n                    .map(|fi| format!(\"\\t{}: {}\", fi.label, fi.ty))\n                    .collect::<Vec<_>>()\n                    .join(\",\\n\")\n            ),\n            Type::Product(tys) => write!(\n                f,\n                \"({})\",\n                tys.iter().map(|ty| ty.to_string()).collect::<Vec<_>>().join(\",\")\n            ),\n            Type::Projection(ty, idx) => write!(f, \"{}.{}\", ty, idx),\n            Type::Sum(fields) => write!(\n                f,\n                \"{}\",\n                fields\n                    .iter()\n                    .map(|fi| format!(\"{} {}\", fi.label, fi.ty))\n                    .collect::<Vec<_>>()\n                    .join(\"|\")\n            ),\n            Type::Recursive(inner) => write!(f, \"rec {}\", inner),\n        }\n    }\n}\n\nimpl fmt::Display for TyKind {\n    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n        match &self {\n            TyKind::Star => write!(f, \"*\"),\n            TyKind::Arrow(k1, k2) => match k2.as_ref() {\n                TyKind::Star => match k1.as_ref() {\n                    TyKind::Star => write!(f, \"{}->{}\", k1, k2),\n                    TyKind::Arrow(k11, k12) => write!(f, \"({}->{})->{}\", k11, k12, k2),\n                    _ => write!(f, \"{}->{}\", k1, k2),\n                },\n                TyKind::Arrow(_, _) => write!(f, \"{}->({})\", k1, k2),\n                k => write!(f, \"{}->{}\", k1, k),\n            },\n            TyKind::Product(v) => {\n                let s = v.iter().map(|k| format!(\"{}\", k)).collect::<Vec<String>>().join(\",\");\n                write!(f, \"({})\", s)\n            }\n        }\n    }\n}\n\npub trait MutTypeVisitor: Sized {\n    fn visit_var(&mut self, _: &mut usize) {}\n\n    fn visit_arrow(&mut self, ty1: &mut Type, ty2: &mut Type) {\n        self.visit(ty1);\n        self.visit(ty2);\n    }\n\n    fn visit_universal(&mut self, _: &mut TyKind, ty: &mut Type) {\n        self.visit(ty);\n    }\n\n    fn visit_existential(&mut self, _: &mut TyKind, ty: &mut Type) {\n        self.visit(ty);\n    }\n\n    fn visit_abs(&mut self, _: &mut TyKind, ty: &mut Type) {\n        self.visit(ty);\n    }\n\n    fn visit_app(&mut self, s: &mut Type, t: &mut Type) {\n        self.visit(s);\n        self.visit(t);\n    }\n\n    fn visit_record(&mut self, fields: &mut [TyField]) {\n        for f in fields {\n            self.visit(f.ty.as_mut());\n        }\n    }\n\n    fn visit_product(&mut self, tys: &mut [Type]) {\n        for ty in tys {\n            self.visit(ty);\n        }\n    }\n\n    fn visit_projection(&mut self, ty: &mut Type, _: usize) {\n        self.visit(ty);\n    }\n\n    fn visit_recursive(&mut self, ty: &mut Type) {\n        self.visit(ty);\n    }\n\n    fn visit(&mut self, ty: &mut Type) {\n        self.walk(ty);\n    }\n\n    fn walk(&mut self, ty: &mut Type) {\n        match ty {\n            Type::Unit | Type::Bool | Type::Nat => {}\n            Type::Var(v) => self.visit_var(v),\n            Type::Record(fields) => self.visit_record(fields),\n            Type::Product(tys) => self.visit_product(tys),\n            Type::Projection(ty, _) => self.visit(ty),\n            Type::Sum(variants) => self.visit_record(variants),\n            Type::Recursive(ty1) => self.visit_recursive(ty1),\n            Type::Arrow(ty1, ty2) => self.visit_arrow(ty1, ty2),\n            Type::Universal(k, ty) => self.visit_universal(k, ty),\n            Type::Existential(k, ty) => self.visit_existential(k, ty),\n            Type::Abs(s, t) => self.visit_abs(s, t),\n            Type::App(k, t) => self.visit_app(k, t),\n        }\n    }\n}\n\npub struct Shift {\n    pub cutoff: usize,\n    pub shift: isize,\n}\n\nimpl Shift {\n    pub const fn new(shift: isize) -> Shift {\n        Shift { cutoff: 0, shift }\n    }\n}\n\nimpl MutTypeVisitor for Shift {\n    fn visit_var(&mut self, var: &mut usize) {\n        if *var >= self.cutoff {\n            *var =\n                usize::try_from(*var as isize + self.shift).expect(\"Type variable has been shifted below 0! Fatal bug\");\n        }\n    }\n\n    fn visit_universal(&mut self, _: &mut TyKind, ty: &mut Type) {\n        self.cutoff += 1;\n        self.visit(ty);\n        self.cutoff -= 1;\n    }\n\n    fn visit_existential(&mut self, _: &mut TyKind, ty: &mut Type) {\n        self.cutoff += 1;\n        self.visit(ty);\n        self.cutoff -= 1;\n    }\n\n    fn visit_abs(&mut self, _: &mut TyKind, ty: &mut Type) {\n        self.cutoff += 1;\n        self.visit(ty);\n        self.cutoff -= 1;\n    }\n\n    // fn visit_recursive(&mut self, ty: &mut Type) {\n    //     self.cutoff += 1;\n    //     self.visit(ty);\n    //     self.cutoff -= 1;\n    // }\n}\n\npub struct Subst {\n    pub cutoff: usize,\n    pub ty: Type,\n}\n\nimpl Subst {\n    pub fn new(ty: Type) -> Subst {\n        Subst { cutoff: 0, ty }\n    }\n}\n\nimpl MutTypeVisitor for Subst {\n    fn visit_universal(&mut self, _: &mut TyKind, ty: &mut Type) {\n        self.cutoff += 1;\n        self.visit(ty);\n        self.cutoff -= 1;\n    }\n\n    fn visit_existential(&mut self, _: &mut TyKind, ty: &mut Type) {\n        self.cutoff += 1;\n        self.visit(ty);\n        self.cutoff -= 1;\n    }\n\n    fn visit_abs(&mut self, _: &mut TyKind, ty: &mut Type) {\n        self.cutoff += 1;\n        self.visit(ty);\n        self.cutoff -= 1;\n    }\n\n    // fn visit_recursive(&mut self, ty: &mut Type) {\n    //     self.cutoff += 1;\n    //     self.visit(ty);\n    //     self.cutoff -= 1;\n    // }\n\n    fn visit(&mut self, ty: &mut Type) {\n        match ty {\n            Type::Var(v) if *v == self.cutoff => {\n                Shift::new(self.cutoff as isize).visit(&mut self.ty);\n                *ty = self.ty.clone();\n            }\n            _ => self.walk(ty),\n        }\n    }\n}\n"
  },
  {
    "path": "07_system_fw/test.fw",
    "content": "datatype 'a list = Nil | Cons of 'a * 'a list \ndatatype 'a option = None | Some of 'a \ndatatype ('a, 'b) either = Left of 'a | Right of 'b \n\nfun t (Left 10) = 10\n  | t (Right _) = 9\n\nfun test (Some _) 9 = 9\n  | test (Some 8) 8 = 8\n  | test (None) 7 = 0\n\n\ndatatype expr = Var of int | Abs of expr | App of expr * expr;\n\ntype env = expr * list \n\ndatatype kont = Mt | Fn of expr * env * kont | Arg of expr * env * kont\n\nfun lookup env i = i\n\nfun extend env x = x\n\nfun step (c: expr) (e: env) (k: kont) : (expr, env, kont) =\n    case (c, e, k) of \n        | (Var i, e, k) => (lookup e i, e, k)\n        | (App (e1, e2), e, k) => (e1, e, Arg (e2, e, k))\n        | (Abs x, env, Arg (a, e, k)) => (a, e, Fn (x, env, k))\n        | (Abs x, env, Fn (a, e, k)) => (a, extend e x, k),\n        | (c, e, Mt) => (c, e, Mt)\n        | (_, _, _) => (Var 0, Nil, Mt)\n    end"
  },
  {
    "path": "Cargo.toml",
    "content": "[workspace]\nmembers = [\"01_arith\", \"02_lambda\",  \"03_typedarith\", \"04_stlc\", \"05_recon\",  \"06_system_f\", \"07_system_fw\", \"x1_bidir\", \"x2_dependent\", \"util\"]"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2019 Michael Lazear\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "# types-and-programming-languages\n\n![](https://github.com/lazear/types-and-programming-languages/workflows/Rust/badge.svg)\n\nSeveral Rust implementations of exercises from Benjamin Pierce's \"Types and Programming Languages\" are organized into different folders, as described below:\n\n- `arith` is an implementation of the untyped lambda calculus extended with simple numeric operations\n\n- `lambda` is an implementation of the untyped lambda calculus as presented in chapter 5, 6, and 7.\n\n- `typedarith` is the `arith` project extended with simple types: `Nat` and `Bool`\n\n- `stlc` is an implementation of the simply typed lambda calculus, as discussed in chapters 9 and 10 of TAPL. This simply typed calculus has the types, `Unit`, `Nat`, `Bool`, `T -> T` (arrow), and `Record` types.\n\n- `recon` contains several implementations of Hindley-Milner based type reconstruction from the untyped lambda calculus to System F, with let-polymorphism. Both Algorithm W (the more common) and Algorithm J (the more efficient) are presented. For Alg. W, both a naive equality constraint solver, and a faster union-find (with path compression) solver are provided. Algorithm J makes use shared mutable references to promote type sharing instead.\n\n- `system_f` contains a parser, typechecker, and evaluator for the simply typed lambda calculus with parametric polymorphism (System F). The implementation of System F is the most complete so far, and I've tried to write a parser, typechecker and diagnostic system that can given meaningful messages\n\n- `system_fw` contains a parser for a high-level, Standard ML like source language that is desugared into an HIR, and then System F-omega. This extends `system_f` with type operators and higher-kinded types. This is where most of the ongoing work is located, as I'd like to make this the basis of a toy (but powerful, and useable) programming language. Ideally we will have some form of bidirectional type inference. Work on this has accidentally turned into a full fledged [SML compiler](https://github.com/SomewhatML/sml-compiler), so it's likely that I will roll back the work on the system_fw project to just type checking\n\n- `bidir` is is an implementation of the bidirectional typechecker from 'Complete and Easy Bidirectional Typechecking', extended with booleans, product, and sum types. I make no claims on the correctness of the implementation for the extended features not present in the paper.\n\n- `dependent` is WIP, implementing a simple, dependently typed lambda calculus as discussed in ATAPL.\n\n"
  },
  {
    "path": "util/.gitignore",
    "content": "/target\n**/*.rs.bk\n.vscode/"
  },
  {
    "path": "util/Cargo.toml",
    "content": "[package]\nname = \"util\"\nversion = \"0.1.0\"\nauthors = [\"Michael Lazear <lazear@scripps.edu>\"]\nedition = \"2018\"\n\n[dependencies]"
  },
  {
    "path": "util/src/arena.rs",
    "content": "//! A safe, fast, and space-efficient typed Arena allocator\n//!\n//! # Examples:\n//!\n//! ```\n//! use util::arena::Arena;\n//!\n//! let mut arena: Arena<u32> = Arena::default();\n//! let index = arena.insert(10);\n//!\n//! // Get a reference to the item stored in the arena\n//! let r = arena.get(index);\n//! assert_eq!(r, Some(&10));\n//! let i = arena.remove(index);\n//!\n//! assert_eq!(i, Some(10));\n//!\n//! // Attempting to access the Arena at this index should return None\n//! // since the item was removed\n//! assert_eq!(arena.get(index), None);\n//! ```\n//!\n//! ## Invariants:\n//!\n//! - Arena must have a capacity >= `MIN_CAPACITY` (16). Calls to\n//! `Arena::with_capacity` that use a capacity less than this value will\n//! default to a capacity of `MIN_CAPACITY`\n//!\n//! - The first entry (index 0) in the Arena is used to store the head of the\n//! list of free/vacant entries in the Arena (free list). As such, all\n//! `Index`'s are wrappers around a `NonZeroU32`, since accessing the first\n//! entry in the Arena's internal data would likely cause data corruption\n\n#![forbid(unsafe_code)]\n#![allow(dead_code)]\n\nuse std::num::NonZeroU32;\n\n/// Minimum capacity for an `Arena`\npub const MIN_CAPACITY: u32 = 16;\n\n/// The `Arena`, an allocator\npub struct Arena<T> {\n    data: Vec<Entry<T>>,\n}\n\n/// An index into an `Arena`\n#[derive(PartialEq, PartialOrd, Debug, Copy, Clone)]\npub struct Index(NonZeroU32);\n\n/// Internal entry data structure\n#[derive(PartialEq, PartialOrd)]\nenum Entry<T> {\n    Vacant(Option<NonZeroU32>),\n    Occupied(T),\n}\n\nuse std::fmt;\nimpl<T: fmt::Debug> fmt::Debug for Entry<T> {\n    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n        match self {\n            Entry::Vacant(opt) => write!(f, \"Vacant({:?})\", opt),\n            Entry::Occupied(item) => write!(f, \"{:?}\", item),\n        }\n    }\n}\n\nimpl<T> std::default::Default for Arena<T> {\n    fn default() -> Arena<T> {\n        Arena::with_capacity(MIN_CAPACITY)\n    }\n}\n\nimpl<T> Arena<T> {\n    /// Allocate an `Arena` capable of storing `n` items before re-allocating\n    /// The mininimum capacity for an `Arena` is specified in `MIN_CAPACITY`,\n    /// which defaults to `16`\n    ///\n    /// # Examples\n    /// ```\n    /// use util::arena::Arena;\n    ///\n    /// let arena: Arena<u32> = Arena::with_capacity(256);\n    /// assert_eq!(arena.capacity(), 256);\n    ///\n    /// let arena2: Arena<i32> = Arena::with_capacity(8);\n    /// assert_eq!(arena2.capacity(), 16);\n    /// ```\n    pub fn with_capacity(n: u32) -> Arena<T> {\n        // Invariant that we have at least MIN_CAPACITY vacant entries when we\n        // initialize the Arena, so setting the first element to point to\n        // element 1 is safe.\n        let mut arena = Arena {\n            data: vec![Entry::Vacant(None)],\n        };\n        arena.reserve(n.max(MIN_CAPACITY));\n        arena\n    }\n\n    /// Returns the number of items the `Arena` can store without allocating\n    pub fn capacity(&self) -> u32 {\n        self.data.capacity() as u32 - 1\n    }\n\n    /// Return the index of the next free slot in the `Arena`, if one exists\n    /// or return None.\n    ///\n    /// The free-list head resides in index 0 of the `Arena`\n    #[inline]\n    fn get_free(&self) -> Option<NonZeroU32> {\n        match self.data.get(0) {\n            Some(Entry::Vacant(next)) => *next,\n            _ => None,\n        }\n    }\n\n    /// Convenience function to set the free-list pointer\n    #[inline]\n    fn set_free(&mut self, next: Option<NonZeroU32>) {\n        self.data[0] = Entry::Vacant(next);\n    }\n\n    /// Reserve capacity for `n` additional items in the `Arena`, updating\n    /// the free-list head as well to point to the beginning of the new items.\n    ///\n    /// This may cause the Arena to become somewhat segmented, so it may be\n    /// desirable to revisit this behavior\n    fn reserve(&mut self, n: u32) {\n        debug_assert!(n >= MIN_CAPACITY);\n\n        let start = self.data.len() as u32;\n        let end = start + n;\n        let head = self.get_free();\n\n        self.data.reserve(n as usize);\n\n        // Subtract one for the free-list pointer\n        for idx in start..end - 1 {\n            self.data.push(Entry::Vacant(Some(NonZeroU32::new(idx + 1).unwrap())));\n        }\n\n        *self.data.last_mut().unwrap() = Entry::Vacant(head);\n        self.set_free(Some(NonZeroU32::new(start).unwrap()));\n    }\n\n    /// Attempt to insert an item into the `Arena` without performing any\n    /// additional allocations.\n    ///\n    /// Will return an `Err` if the `Arena` has no remaining capacity\n    ///\n    /// # May panic (should never happen)\n    ///\n    /// In the event that the `Arena`'s free list is corrupted, this\n    /// function will panic\n    pub fn try_insert(&mut self, item: T) -> Result<Index, T> {\n        match self.get_free() {\n            None => Err(item),\n            Some(free) => {\n                let index = free.get() as usize;\n                let old = std::mem::replace(&mut self.data[index], Entry::Occupied(item));\n                match old {\n                    Entry::Occupied(_) => panic!(\"Corrupted arena!\"),\n                    Entry::Vacant(next) => {\n                        self.set_free(next);\n                        Ok(Index(free))\n                    }\n                }\n            }\n        }\n    }\n\n    /// Insert an `item` into the `Arena`. Insertion will only allocate\n    /// additional storage capacity in the event that there are no free\n    /// slots in the currently allocated space\n    #[inline]\n    pub fn insert(&mut self, item: T) -> Index {\n        match self.try_insert(item) {\n            Ok(idx) => idx,\n            Err(item) => self.reserve_insert(item),\n        }\n    }\n\n    /// Reserve additional capacity, and then insert an item\n    /// into the newly allocated space\n    fn reserve_insert(&mut self, item: T) -> Index {\n        self.reserve(self.capacity());\n        self.try_insert(item).map_err(|_| ()).expect(\"Out of memory\")\n    }\n\n    /// Remove an `item` from the `Arena` at the specified index,\n    /// returning `Some<T>` if the index was occupied, or `None` if\n    /// the index was vacant\n    pub fn remove(&mut self, index: Index) -> Option<T> {\n        let i = index.0.get() as usize;\n        let free = self.get_free();\n        let prev = std::mem::replace(&mut self.data[i], Entry::Vacant(free));\n\n        match prev {\n            Entry::Occupied(item) => {\n                self.set_free(Some(index.0));\n                Some(item)\n            }\n            Entry::Vacant(_) => {\n                std::mem::replace(&mut self.data[i], prev);\n                None\n            }\n        }\n    }\n\n    #[inline]\n    /// Get a reference to the item stored at `index`, if it exists\n    pub fn get(&self, index: Index) -> Option<&T> {\n        match self.data.get(index.0.get() as usize) {\n            Some(Entry::Occupied(ptr)) => Some(ptr),\n            _ => None,\n        }\n    }\n\n    #[inline]\n    /// Return a mutable reference to the data stored at `index`, if it exists\n    pub fn get_mut(&mut self, index: Index) -> Option<&mut T> {\n        match self.data.get_mut(index.0.get() as usize) {\n            Some(Entry::Occupied(ptr)) => Some(ptr),\n            _ => None,\n        }\n    }\n\n    /// Returns an iterator over the occupied data in the [`Arena`]\n    pub fn iter(&self) -> Iter<'_, T> {\n        Iter {\n            data: &self.data,\n            idx: 1,\n        }\n    }\n}\n\n/// Immutable iterator\n///\n/// This struct is created by the [`iter`] method on [`Arena`]\n///\n/// [`iter`]: Arena::iter()\npub struct Iter<'a, T> {\n    data: &'a [Entry<T>],\n    idx: usize,\n}\n\nimpl<'a, T> Iterator for Iter<'a, T> {\n    type Item = &'a T;\n    fn next(&mut self) -> Option<Self::Item> {\n        while self.idx < self.data.len() {\n            self.idx += 1;\n            if let Entry::Occupied(t) = &self.data[self.idx - 1] {\n                return Some(&t);\n            }\n        }\n        None\n    }\n}\n\n/// An owning iterator over the data in an [`Arena`]\npub struct IntoIter<T> {\n    data: Vec<Entry<T>>,\n    idx: usize,\n}\n\nimpl<T> Iterator for IntoIter<T> {\n    type Item = T;\n    fn next(&mut self) -> Option<Self::Item> {\n        while self.idx < self.data.len() {\n            self.idx += 1;\n            if let Entry::Occupied(t) = std::mem::replace(&mut self.data[self.idx - 1], Entry::Vacant(None)) {\n                return Some(t);\n            }\n        }\n        None\n    }\n}\n\nimpl<T> IntoIterator for Arena<T> {\n    type Item = T;\n    type IntoIter = IntoIter<T>;\n\n    /// Creates a consuming iterator\n    fn into_iter(self) -> Self::IntoIter {\n        IntoIter {\n            data: self.data,\n            idx: 1,\n        }\n    }\n}\n\nimpl<'a, T> IntoIterator for &'a Arena<T> {\n    type Item = &'a T;\n    type IntoIter = Iter<'a, T>;\n\n    fn into_iter(self) -> Self::IntoIter {\n        Iter {\n            data: &self.data,\n            idx: 1,\n        }\n    }\n}\n\nimpl<T> std::iter::FromIterator<T> for Arena<T> {\n    /// Collect elements from an [`Iterator`] into an [`Arena`]\n    ///\n    /// # Note\n    ///\n    /// You won't be able to receive an [`Index`] for each item\n    fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Arena<T> {\n        let mut arena = Arena::default();\n        for i in iter {\n            arena.insert(i);\n        }\n        arena\n    }\n}\n\n#[cfg(test)]\nmod test {\n    use super::*;\n\n    #[test]\n    fn index_size() {\n        assert_eq!(std::mem::size_of::<Index>(), 4);\n    }\n\n    #[test]\n    fn smoke_insert() {\n        let mut a = Arena::default();\n        assert_eq!(a.insert(255u8).0.get(), 1);\n    }\n\n    #[test]\n    fn smoke_remove() {\n        let mut a = Arena::default();\n        let idx = a.insert(255u8);\n        assert_eq!(a.remove(idx), Some(255u8));\n        assert_eq!(a.get(idx), None);\n    }\n\n    #[test]\n    fn smoke_iter() {\n        let mut a = Arena::with_capacity(32);\n        for i in 0..32 {\n            a.insert(i);\n        }\n        assert_eq!(a.iter().zip(0..32).fold(0, |acc, x| acc + (x.0 - x.1)), 0);\n    }\n\n    #[test]\n    fn fill() {\n        let mut arena = Arena::default();\n        assert_eq!(arena.capacity(), MIN_CAPACITY);\n        dbg!(&arena.data);\n        for i in 0..15 {\n            arena.insert(i);\n        }\n        dbg!(&arena.data);\n        assert_eq!(arena.data[0], Entry::Vacant(None));\n        assert_eq!(arena.capacity(), MIN_CAPACITY);\n    }\n}\n"
  },
  {
    "path": "util/src/diagnostic.rs",
    "content": "//! Diagnostic handling for errors detected in source code.\n//!\n//! Dropping a [`Diagnostic`] without calling `emit` will cause a [`panic`]!\nuse crate::span::*;\n\n/// Struct that handles collecting and reporting Parser errors and diagnostics\npub struct Diagnostic<'s> {\n    src: &'s str,\n    messages: Vec<Spanned<String>>,\n}\n\nimpl Diagnostic<'_> {\n    pub fn new(src: &str) -> Diagnostic<'_> {\n        Diagnostic {\n            src,\n            messages: Vec::new(),\n        }\n    }\n\n    pub fn push<S: Into<String>>(&mut self, msg: S, span: Span) {\n        self.messages.push(Spanned::new(span, msg.into()));\n    }\n\n    pub fn error_count(&self) -> usize {\n        self.messages.len()\n    }\n\n    /// Remove the last error message\n    pub fn pop(&mut self) -> Option<String> {\n        let msg = self.messages.pop()?;\n        let line = self.src.lines().nth(msg.span.start.line as usize)?;\n        Some(format!(\n            \"Error occuring at line {}, col: {}: {}\\n{}\\n{}^{}\\n\",\n            msg.span.start.line,\n            msg.span.start.col,\n            msg.data,\n            &line,\n            (0..msg.span.start.col).map(|_| ' ').collect::<String>(),\n            (0..msg.span.end.col - msg.span.start.col)\n                .map(|_| '~')\n                .collect::<String>(),\n        ))\n    }\n\n    #[must_use]\n    /// Emit all remaining error message, if there are any\n    pub fn emit(mut self) -> String {\n        let mut s = String::new();\n\n        let lines = self.src.lines().collect::<Vec<&str>>();\n        for i in 0..self.messages.len() {\n            let msg: &Spanned<String> = &self.messages[i];\n            let mut squiggly = (1..msg.span.end.col.saturating_sub(msg.span.start.col))\n                .map(|_| '~')\n                .collect::<String>();\n            squiggly.push('^');\n            s.push_str(&format!(\n                \"Error occuring at line {}, col: {}: {}\\n{}\\n{}^{}\\n\",\n                msg.span.start.line,\n                msg.span.start.col,\n                msg.data,\n                &lines[msg.span.start.line as usize],\n                (0..msg.span.start.col).map(|_| ' ').collect::<String>(),\n                squiggly\n            ));\n        }\n        self.messages.clear();\n        s\n    }\n}\n\nimpl Drop for Diagnostic<'_> {\n    fn drop(&mut self) {\n        if self.error_count() != 0 {\n            panic!(\"Diagnostic dropped without handling {} errors!\", self.error_count());\n        }\n    }\n}\n"
  },
  {
    "path": "util/src/lib.rs",
    "content": "//! Source code locations and diagnostic reporting that can be shared\n//! across different projects\npub mod arena;\npub mod diagnostic;\npub mod span;\npub mod unsafe_arena;\n"
  },
  {
    "path": "util/src/span.rs",
    "content": "//! Source code locations and spans\n\nuse std::fmt;\n\n#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Default)]\n/// Struct representing a location in a source string\npub struct Location {\n    pub line: u32,\n    pub col: u32,\n    pub abs: u32,\n}\n\nimpl Location {\n    pub fn new(line: u32, col: u32, abs: u32) -> Location {\n        Location { line, col, abs }\n    }\n}\n\nimpl fmt::Display for Location {\n    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n        write!(f, \"{}:{}\", self.line, self.col)\n    }\n}\n\n#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Default)]\n/// A span of code\npub struct Span {\n    pub start: Location,\n    pub end: Location,\n}\n\n/// Data with associated code span\npub struct Spanned<T> {\n    pub span: Span,\n    pub data: T,\n}\n\nimpl Span {\n    pub fn new(start: Location, end: Location) -> Span {\n        Span { start, end }\n    }\n\n    pub const fn dummy() -> Span {\n        let max = Location {\n            line: std::u32::MAX,\n            col: std::u32::MAX,\n            abs: std::u32::MAX,\n        };\n        Span { start: max, end: max }\n    }\n\n    pub const fn zero() -> Span {\n        let max = Location {\n            line: 0,\n            col: 0,\n            abs: 0,\n        };\n        Span { start: max, end: max }\n    }\n}\n\nimpl<T> Spanned<T> {\n    /// Create a new [`Spanned`], representing a [`Span`] and data pair\n    pub fn new(span: Span, data: T) -> Spanned<T> {\n        Spanned { span, data }\n    }\n\n    /// Map a [`Spanned`]'s wrapped data into a new [`Spanned`]\n    pub fn map<B, F: Fn(T) -> B>(self, f: F) -> Spanned<B> {\n        Spanned {\n            span: self.span,\n            data: f(self.data),\n        }\n    }\n\n    /// Replace the data in self with `src`, dropping the previous data\n    pub fn replace<V>(self, src: V) -> Spanned<V> {\n        Spanned {\n            span: self.span,\n            data: src,\n        }\n    }\n\n    /// Consume self, returning the wrapped `T`\n    pub fn into_inner(self) -> T {\n        self.data\n    }\n\n    #[inline]\n    pub fn span(&self) -> Span {\n        self.span\n    }\n\n    #[inline]\n    pub fn data(self) -> T {\n        self.data\n    }\n}\n\nimpl<T, E> Spanned<Result<T, E>> {\n    /// Transpose a [`Spanned<Result<T, E>>`] into a [`Result<Spanned<T>,\n    /// Spanned<E>>`]\n    pub fn map_result(self) -> Result<Spanned<T>, Spanned<E>> {\n        let Spanned { span, data } = self;\n        data.map(|t| Spanned::new(span, t)).map_err(|e| Spanned::new(span, e))\n    }\n}\n\nimpl<T> Spanned<Option<T>> {\n    pub fn map_option(self) -> Option<Spanned<T>> {\n        let Spanned { span, data } = self;\n        data.map(|t| Spanned::new(span, t))\n    }\n}\n\nimpl<T: fmt::Display> fmt::Display for Spanned<T> {\n    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n        write!(f, \"{}: {}\", self.span.start, self.data)\n    }\n}\n\nimpl<T: fmt::Debug> fmt::Debug for Spanned<T> {\n    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n        write!(f, \"{:?}: {:?}\", self.span, self.data)\n    }\n}\n\nimpl<T> std::ops::Deref for Spanned<T> {\n    type Target = T;\n    fn deref(&self) -> &Self::Target {\n        &self.data\n    }\n}\n\nimpl<T: Clone> Clone for Spanned<T> {\n    fn clone(&self) -> Self {\n        Spanned {\n            span: self.span,\n            data: self.data.clone(),\n        }\n    }\n}\n\nimpl<T: Copy> Copy for Spanned<T> {}\n\nimpl std::ops::Add<Span> for Span {\n    type Output = Self;\n    fn add(self, rhs: Self) -> Self::Output {\n        Span {\n            start: self.start,\n            end: rhs.end,\n        }\n    }\n}\n\nimpl std::ops::AddAssign<Span> for Span {\n    fn add_assign(&mut self, rhs: Self) {\n        self.end = rhs.end;\n    }\n}\n"
  },
  {
    "path": "util/src/unsafe_arena.rs",
    "content": "//! A fast and efficient typed arena\n//!\n//! Translated from rustc's TypedArena into stable rust\n//!\n//! https://doc.rust-lang.org/1.1.0/src/arena/lib.rs.html\nuse std::alloc::{alloc, dealloc, Layout};\nuse std::cell::Cell;\nuse std::cmp;\nuse std::marker;\nuse std::mem;\nuse std::ptr;\n\npub struct Arena<T> {\n    ptr: Cell<*mut T>,\n    end: Cell<*mut T>,\n    chunk: Cell<*mut Chunk<T>>,\n    marker: marker::PhantomData<T>,\n}\n\nstruct Chunk<T> {\n    capacity: usize,\n    entries: usize,\n    prev: *mut Chunk<T>,\n    marker: marker::PhantomData<T>,\n    // data stored here\n}\n\n#[derive(Debug, PartialEq, Copy, Clone)]\nstruct Info {\n    capacity: usize,\n    used: usize,\n}\n\nimpl<T> Default for Arena<T> {\n    fn default() -> Arena<T> {\n        Arena {\n            ptr: Cell::new(ptr::null_mut()),\n            end: Cell::new(ptr::null_mut()),\n            chunk: Cell::new(ptr::null_mut()),\n            marker: marker::PhantomData,\n        }\n    }\n}\n\nimpl<T> Arena<T> {\n    pub fn with_capacity(capacity: usize) -> Arena<T> {\n        unsafe {\n            let chunk: *mut Chunk<T> = Chunk::new(ptr::null_mut(), capacity);\n            Arena {\n                ptr: Cell::new((*chunk).start()),\n                end: Cell::new((*chunk).end()),\n                chunk: Cell::new(chunk),\n                marker: marker::PhantomData,\n            }\n        }\n    }\n\n    #[inline]\n    fn can_alloc(&self, n: usize) -> bool {\n        let remaining = self.end.get() as usize - self.ptr.get() as usize;\n        let required = mem::size_of::<T>().checked_mul(n).unwrap();\n        remaining >= required\n    }\n\n    #[inline]\n    fn ensure_capacity(&self, n: usize) {\n        if !self.can_alloc(n) {\n            self.grow(n)\n        }\n    }\n\n    #[inline]\n    fn entries(&self) -> usize {\n        unsafe {\n            let bytes = self.ptr.get() as usize - (*self.chunk.get()).start() as usize;\n            bytes / mem::size_of::<T>()\n        }\n    }\n\n    #[inline]\n    fn chunks(&self) -> Vec<Info> {\n        let mut count = Vec::new();\n        let mut ptr = self.chunk.get();\n\n        unsafe {\n            if !ptr.is_null() {\n                let cap = self.end.get() as usize - (*ptr).start() as usize;\n                count.push(Info {\n                    capacity: cap,\n                    used: self.entries(),\n                });\n                ptr = (*ptr).prev;\n            }\n            while !ptr.is_null() {\n                count.push(Info {\n                    capacity: (*ptr).capacity,\n                    used: (*ptr).entries,\n                });\n                ptr = (*ptr).prev;\n            }\n        }\n        count\n    }\n\n    #[inline]\n    fn grow(&self, n: usize) {\n        unsafe {\n            let mut chunk = self.chunk.get();\n            let mut new_cap;\n\n            if !chunk.is_null() {\n                (*chunk).entries = self.entries();\n\n                new_cap = (*chunk).capacity.checked_mul(2).unwrap();\n                while new_cap < (*chunk).capacity + n {\n                    new_cap = new_cap.checked_mul(2).unwrap();\n                }\n            } else {\n                new_cap = cmp::max(n, 0x1000 / mem::size_of::<T>());\n            }\n\n            // Allocate at least 1 page\n            new_cap = cmp::max(new_cap, 0x1000 / mem::size_of::<T>());\n\n            let chunk = Chunk::<T>::new(chunk, new_cap);\n            self.ptr.set((*chunk).start());\n            self.end.set((*chunk).end());\n            self.chunk.set(chunk);\n        }\n    }\n\n    #[inline]\n    pub fn alloc(&self, value: T) -> &mut T {\n        if self.ptr == self.end {\n            self.grow(1);\n        }\n\n        unsafe {\n            let ptr: &mut T = mem::transmute(self.ptr.get());\n            ptr::write(ptr, value);\n            self.ptr.set(self.ptr.get().offset(1 as isize));\n            ptr\n        }\n    }\n\n    #[inline]\n    unsafe fn alloc_raw_slice(&self, n: usize) -> *mut T {\n        assert!(n != 0);\n        self.ensure_capacity(n);\n\n        let ptr = self.ptr.get();\n        self.ptr.set(ptr.offset(n as isize));\n        ptr\n    }\n\n    #[inline]\n    pub fn alloc_slice(&self, slice: &[T]) -> &mut [T]\n    where\n        T: Copy,\n    {\n        unsafe {\n            let len = slice.len();\n            let ptr = self.alloc_raw_slice(len);\n            slice.as_ptr().copy_to_nonoverlapping(ptr, len);\n            std::slice::from_raw_parts_mut(ptr, len)\n        }\n    }\n}\n\nimpl<T> std::ops::Drop for Arena<T> {\n    fn drop(&mut self) {\n        unsafe {\n            (*self.chunk.get()).destroy(self.entries());\n        }\n    }\n}\n\n#[inline]\nfn padding_needed(l: &Layout, align: usize) -> usize {\n    let len = l.size();\n    let rounded = len.wrapping_add(align).wrapping_sub(1) & !align.wrapping_sub(1);\n    rounded.wrapping_sub(len)\n}\n\n#[inline]\nfn round(layout: &Layout, align: usize) -> usize {\n    let pad = padding_needed(layout, align);\n    let offset = layout.size().checked_add(pad).unwrap();\n    offset\n}\n\n#[inline]\nfn extend(a: Layout, b: Layout) -> Layout {\n    let new_align = std::cmp::max(a.align(), b.align());\n    let pad = padding_needed(&a, b.align());\n    let off = a.size().checked_add(pad).unwrap();\n    let sz = off.checked_add(b.size()).unwrap();\n\n    Layout::from_size_align(sz, new_align).unwrap()\n}\n\nimpl<T> Chunk<T> {\n    #[inline]\n    fn layout(capacity: usize) -> Layout {\n        let chunk_layout = Layout::from_size_align(mem::size_of::<Chunk<T>>(), mem::align_of::<Chunk<T>>()).unwrap();\n\n        let size = mem::size_of::<T>().checked_mul(capacity).unwrap();\n        let elem_layout = Layout::from_size_align(size, mem::align_of::<T>()).unwrap();\n\n        extend(chunk_layout, elem_layout)\n    }\n\n    unsafe fn new(prev: *mut Chunk<T>, capacity: usize) -> *mut Chunk<T> {\n        let layout = Self::layout(capacity);\n        let chunk = alloc(layout) as *mut Chunk<T>;\n\n        if chunk.is_null() {\n            panic!(\"out of memory!\");\n        }\n\n        (*chunk).prev = prev;\n        (*chunk).capacity = capacity;\n        chunk\n    }\n\n    #[inline]\n    unsafe fn destroy(&mut self, len: usize) {\n        for i in 0..len {\n            // copy to stack, destructor will run\n            ptr::read(self.start().offset(i as isize));\n        }\n\n        let prev = self.prev;\n        let layout = Self::layout(self.capacity);\n        let ptr: *mut Chunk<T> = self;\n        dealloc(ptr as *mut u8, layout);\n\n        if !prev.is_null() {\n            let entries = (*prev).entries;\n            (*prev).destroy(entries);\n        }\n    }\n\n    #[inline]\n    pub fn start(&self) -> *mut T {\n        let ptr: *const Chunk<T> = self;\n        let layout = Layout::from_size_align(mem::size_of::<Chunk<T>>(), mem::align_of::<Chunk<T>>()).unwrap();\n\n        let r = round(&layout, mem::align_of::<T>());\n\n        unsafe {\n            let mut p = ptr as usize;\n            p += r;\n            mem::transmute(p)\n        }\n    }\n\n    #[inline]\n    pub fn end(&self) -> *mut T {\n        unsafe { self.start().offset(self.capacity as isize) }\n    }\n}\n\n#[cfg(test)]\nmod test {\n    use super::*;\n\n    struct DropGuard {\n        ptr: *mut usize,\n    }\n\n    impl std::ops::Drop for DropGuard {\n        fn drop(&mut self) {\n            unsafe { *self.ptr += 1 }\n        }\n    }\n\n    #[allow(dead_code)]\n    struct Test {\n        data_a: usize,\n        data_b: usize,\n        data_c: [usize; 16],\n        data_d: Vec<usize>,\n        data_e: Box<Test>,\n    }\n\n    #[test]\n    fn new_chunk() {\n        unsafe {\n            let ptr: *mut Chunk<Test> = Chunk::new(ptr::null_mut(), 256);\n\n            let mut start = ptr as usize;\n            start += std::mem::size_of::<Chunk<Test>>();\n\n            assert_eq!(start, (*ptr).start() as usize);\n            assert_eq!((*ptr).start().offset(256 as isize), (*ptr).end());\n        }\n    }\n\n    #[test]\n    fn drop_test() {\n        let mut flag: usize = 0;\n        let arena: Arena<DropGuard> = Arena::default();\n\n        for _ in 0..32 {\n            arena.alloc(DropGuard {\n                ptr: &mut flag as *mut _,\n            });\n        }\n\n        assert_eq!(flag, 0);\n        drop(arena);\n        assert_eq!(flag, 32);\n    }\n\n    #[test]\n    fn references() {\n        #[derive(Debug, PartialEq)]\n        struct Val(usize);\n        struct Ref<'arena>(&'arena mut Val);\n\n        let arena = Arena::<Val>::with_capacity(32);\n\n        let r1: Ref = Ref(arena.alloc(Val(1)));\n        let _r2: Ref = Ref(arena.alloc(Val(2)));\n        let _r3: Ref = Ref(arena.alloc(Val(3)));\n        let _r4: Ref = Ref(arena.alloc(Val(4)));\n\n        (*r1.0) = Val(10);\n        assert_eq!(*r1.0, Val(10));\n    }\n\n    #[test]\n    fn slice() {\n        let c = 0x1000 / mem::size_of::<usize>();\n        let a = Arena::with_capacity(c);\n        assert!(a.can_alloc(c));\n\n        let v = (0..c - 1).map(|i| i as usize).collect::<Vec<usize>>();\n        // chunk 1 will have 2 elements only\n        a.alloc(1);\n        a.alloc(2);\n        assert!(a.can_alloc(c - 2));\n\n        // should be in chunk 2\n        a.alloc_slice(&v);\n        a.alloc(3);\n\n        let mut new_cap = c.checked_mul(2).unwrap();\n        while new_cap < c + v.len() {\n            new_cap = new_cap.checked_mul(2).unwrap();\n        }\n        new_cap = cmp::max(new_cap, 0x1000 / mem::size_of::<usize>());\n\n        // where is 0x2000 coming from??\n        assert_eq!(\n            a.chunks(),\n            vec![\n                Info {\n                    capacity: 0x2000,\n                    used: v.len() + 1\n                },\n                Info { capacity: c, used: 2 }\n            ]\n        );\n    }\n}\n"
  },
  {
    "path": "x1_bidir/Cargo.toml",
    "content": "[package]\nname = \"bidir\"\nversion = \"0.1.0\"\nauthors = [\"Michael Lazear <lazear@scripps.edu>\"]\nedition = \"2018\"\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\n"
  },
  {
    "path": "x1_bidir/src/helpers.rs",
    "content": "use super::*;\n\nmacro_rules! var {\n    ($x:expr) => {\n        Expr::Var($x)\n    };\n}\n\nmacro_rules! app {\n    ($x:expr, $y:expr) => {\n        Expr::App(Box::new($x), Box::new($y))\n    };\n}\n\nmacro_rules! abs {\n    ($x:expr) => {\n        Expr::Abs(Box::new($x))\n    };\n}\n\nmacro_rules! ann {\n    ($x:expr, $t:expr) => {\n        Expr::Ann(Box::new($x), Box::new($t))\n    };\n}\n\nmacro_rules! ife {\n    ($a:expr, $b:expr, $c:expr) => {\n        Expr::If(Box::new($a), Box::new($b), Box::new($c))\n    };\n}\n\nmacro_rules! arrow {\n    ($t1:expr, $t2:expr) => {\n        Type::Arrow(Box::new($t1), Box::new($t2))\n    };\n}\n\nmacro_rules! karrow {\n    ($t1:expr, $t2:expr) => {\n        Kind::Arrow(Box::new($t1), Box::new($t2))\n    };\n}\n\nmacro_rules! forall {\n    ($t1:expr) => {\n        Type::Univ(Box::new(Kind::Star), Box::new($t1))\n    };\n    ($k:expr, $t1:expr) => {\n        Type::Univ(Box::new($k), Box::new($t1))\n    };\n}\n\nmacro_rules! case {\n    ($ex:expr, $pat1:expr => $arm1:expr, $pat2:expr => $arm2:expr) => {\n        Expr::Case(\n            Box::new($ex),\n            Arm {\n                pat: Box::new($pat1),\n                expr: Box::new($arm1),\n            },\n            Arm {\n                pat: Box::new($pat2),\n                expr: Box::new($arm2),\n            },\n        )\n    };\n}\n\nmacro_rules! inj {\n    (l; $ex:expr, $ty:expr) => {\n        Expr::Inj(LR::Left, Box::new($ex), Box::new($ty))\n    };\n    (r; $ex:expr, $ty:expr) => {\n        Expr::Inj(LR::Right, Box::new($ex), Box::new($ty))\n    };\n}\n\nmacro_rules! proj {\n    (l; $ex:expr) => {\n        Expr::Proj(LR::Left, Box::new($ex))\n    };\n    (r; $ex:expr) => {\n        Expr::Proj(LR::Right, Box::new($ex))\n    };\n}\n\nmacro_rules! pair {\n    ($a:expr, $b:expr) => {\n        Expr::Pair(Box::new($a), Box::new($b))\n    };\n}\n\nmacro_rules! sum {\n    ($a:expr, $b:expr) => {\n        Type::Sum(Box::new($a), Box::new($b))\n    };\n}\n\nmacro_rules! product {\n    ($a:expr, $b:expr) => {\n        Type::Product(Box::new($a), Box::new($b))\n    };\n}\n\nfn ty_display(ty: &Type) -> String {\n    use std::collections::HashMap;\n    let mut map = HashMap::new();\n    fn walk(ty: &Type, map: &mut HashMap<usize, char>) -> String {\n        let nc = ('a' as u8 + map.len() as u8) as char;\n        let vc = ('A' as u8 + map.len() as u8) as char;\n        match ty {\n            Type::Unit => \"()\".into(),\n            Type::Bool => \"bool\".into(),\n            Type::Int => \"int\".into(),\n            Type::Arrow(a, b) => format!(\"({}->{})\", walk(a, map), walk(b, map)),\n            Type::Univ(k, ty) => format!(\"forall {}. {}\", vc, walk(ty, map)),\n            Type::Exist(idx) => format!(\"{}\", map.entry(*idx).or_insert(nc)),\n            Type::Var(idx) => format!(\"{}\", map.entry(0xdeadbeef + *idx).or_insert(vc)),\n            Type::Sum(a, b) => format!(\"{} + {}\", walk(a, map), walk(b, map)),\n            Type::Product(a, b) => format!(\"({} x {})\", walk(a, map), walk(b, map)),\n            _ => \"\".into(),\n        }\n    }\n    walk(ty, &mut map)\n}\n\nfn expr_display(ex: &Expr) -> String {\n    use std::collections::HashMap;\n    let mut map = HashMap::new();\n\n    fn walk(ex: &Expr, map: &mut HashMap<usize, char>) -> String {\n        match ex {\n            Expr::Unit => \"()\".into(),\n            Expr::True => \"true\".into(),\n            Expr::False => \"false\".into(),\n            Expr::Int(i) => format!(\"{}\", i),\n            Expr::If(e1, e2, e3) => format!(\"if {} then {} else {}\", walk(e1, map), walk(e2, map), walk(e3, map)),\n            Expr::App(a, b) => format!(\"({} {})\", walk(a, map), walk(b, map)),\n            Expr::Abs(body) => {\n                let vc = ('a' as u8 + map.len() as u8) as char;\n                let vc = *map.entry(map.len()).or_insert(vc);\n                format!(\"(\\\\{}. {})\", vc, walk(body, map))\n            }\n            Expr::Var(idx) => {\n                let i = map.len() - (*idx + 1);\n                let vc = ('a' as u8 + i as u8) as char;\n                format!(\"{}\", map.entry(i).or_insert(vc))\n            }\n            Expr::Ann(e, ty) => format!(\"<{} : {}>\", walk(e, map), ty_display(ty)),\n            Expr::Inj(LR::Left, e, ty) => format!(\"inl {}\", walk(e, map)),\n            Expr::Inj(LR::Right, e, ty) => format!(\"inr {}\", walk(e, map)),\n            Expr::Case(e, la, ra) => format!(\n                \"case {} of {} => {}, {} => {}\",\n                walk(e, map),\n                walk(&la.pat, map),\n                walk(&la.expr, map),\n                walk(&ra.pat, map),\n                walk(&ra.expr, map)\n            ),\n            Expr::Proj(LR::Left, e) => format!(\"{}.0\", walk(e, map)),\n            Expr::Proj(LR::Right, e) => format!(\"{}.1\", walk(e, map)),\n            Expr::Pair(a, b) => format!(\"({},{})\", walk(a, map), walk(b, map)),\n            _ => \"\".into(),\n        }\n    }\n    walk(ex, &mut map)\n}\n\nimpl std::fmt::Display for Type {\n    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {\n        write!(f, \"{}\", ty_display(self))\n    }\n}\nimpl std::fmt::Display for Expr {\n    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {\n        write!(f, \"{}\", expr_display(self))\n    }\n}\n"
  },
  {
    "path": "x1_bidir/src/main.rs",
    "content": "//! \"Complete and Easy Bidirectional Typechecking for Higher-Rank Polymorphism\"\n//! Paper by J. Dunfield and N. Krishnaswami\n//!\n//! Also see very useful Haskell implementation:\n//! https://github.com/lexi-lambda/higher-rank/\n\n#![allow(non_snake_case)]\n#[macro_use]\nmod helpers;\n\n#[derive(Clone, Debug, PartialEq)]\nenum Kind {\n    Star,\n    Arrow(Box<Kind>, Box<Kind>),\n}\n\n/// A source-level type\n#[derive(Clone, Debug, PartialEq)]\nenum Type {\n    Unit,\n    Int,\n    Bool,\n    /// A type variable\n    Var(usize),\n    /// The type of functions\n    Arrow(Box<Type>, Box<Type>),\n    /// Existential type variable that can be instantiated to a monotype\n    Exist(usize),\n    /// Universally quantified type, forall. A\n    Univ(Box<Kind>, Box<Type>),\n    /// Class left/right sum type\n    Sum(Box<Type>, Box<Type>),\n    /// Simple pair type\n    Product(Box<Type>, Box<Type>),\n\n    Abs(Box<Kind>, Box<Type>),\n    App(Box<Type>, Box<Type>),\n}\n\nimpl Type {\n    fn monotype(&self) -> bool {\n        match &self {\n            Type::Univ(_, _) => false,\n            Type::Arrow(t1, t2) => t1.monotype() && t2.monotype(),\n            _ => true,\n        }\n    }\n\n    /// Collect the free existential variables of the type\n    fn freevars(&self) -> Vec<usize> {\n        fn walk(ty: &Type, vec: &mut Vec<usize>) {\n            match ty {\n                Type::Unit | Type::Int | Type::Bool | Type::Var(_) => {}\n                Type::Exist(v) => vec.push(*v),\n                Type::Arrow(a, b) => {\n                    walk(a, vec);\n                    walk(b, vec);\n                }\n                Type::Sum(a, b) => {\n                    walk(a, vec);\n                    walk(b, vec);\n                }\n                Type::Product(a, b) => {\n                    walk(a, vec);\n                    walk(b, vec);\n                }\n                Type::Univ(k, a) => walk(a, vec),\n                Type::Abs(k, a) => walk(a, vec),\n                Type::App(a, b) => {\n                    walk(a, vec);\n                    walk(b, vec);\n                }\n            }\n        }\n        let mut v = Vec::new();\n        walk(self, &mut v);\n        v\n    }\n\n    /// Perform de Bruijn shifting, algorithm from TAPL\n    fn shift(&mut self, s: isize) {\n        fn walk(t: &mut Type, c: usize, s: isize) {\n            match t {\n                Type::Var(n) if *n >= c => *n = (*n as isize + s) as usize,\n                Type::Arrow(a, b) => {\n                    walk(a, c, s);\n                    walk(b, c, s);\n                }\n                Type::Sum(a, b) => {\n                    walk(a, c, s);\n                    walk(b, c, s);\n                }\n                Type::Product(a, b) => {\n                    walk(a, c, s);\n                    walk(b, c, s);\n                }\n                Type::Univ(k, a) => walk(a, c + 1, s),\n                Type::Abs(k, a) => walk(a, c + 1, s),\n                Type::App(a, b) => {\n                    walk(a, c, s);\n                    walk(b, c, s);\n                }\n                Type::Unit | Type::Int | Type::Bool | Type::Var(_) => {}\n                Type::Exist(_) => {}\n            }\n        }\n        walk(self, 0, s);\n    }\n\n    /// Perform subsitution of type `s` into self, algorithm from TAPL\n    fn subst(&mut self, s: &mut Type) {\n        fn walk<F: Fn(&mut Type, usize)>(t: &mut Type, c: usize, f: &F) {\n            match t {\n                Type::Var(n) if *n == c => f(t, c),\n                Type::Arrow(a, b) => {\n                    walk(a, c, f);\n                    walk(b, c, f);\n                }\n                Type::Sum(a, b) => {\n                    walk(a, c, f);\n                    walk(b, c, f);\n                }\n                Type::Product(a, b) => {\n                    walk(a, c, f);\n                    walk(b, c, f);\n                }\n                Type::Univ(k, a) => walk(a, c + 1, f),\n                Type::Abs(k, a) => walk(a, c + 1, f),\n                Type::App(a, b) => {\n                    walk(a, c, f);\n                    walk(b, c, f);\n                }\n                Type::Unit | Type::Int | Type::Bool | Type::Var(_) => {}\n                Type::Exist(_) => {}\n            }\n        }\n        s.shift(1);\n        walk(self, 0, &|f, c| {\n            let mut s = s.clone();\n            s.shift(c as isize);\n            *f = s\n        });\n        self.shift(-1);\n    }\n}\n\n#[derive(Copy, Clone, Debug, PartialEq)]\nenum LR {\n    Left,\n    Right,\n}\n\n/// An expression in our simply typed lambda calculus\n#[derive(Clone, Debug, PartialEq)]\nenum Expr {\n    /// The unit expression, ()\n    Unit,\n    True,\n    False,\n    If(Box<Expr>, Box<Expr>, Box<Expr>),\n    Int(usize),\n    /// A term variable, given in de Bruijn notation\n    Var(usize),\n    /// A lambda abstraction, with it's body. (\\x. body)\n    Abs(Box<Expr>),\n    /// Application (e1 e2)\n    App(Box<Expr>, Box<Expr>),\n    /// Explicit type annotation of a term, (x : A)\n    Ann(Box<Expr>, Box<Type>),\n    /// Injection left/right into a sum type x1\n    Inj(LR, Box<Expr>, Box<Type>),\n    /// Simplified case expr\n    Case(Box<Expr>, Arm, Arm),\n    /// Introduction of a pair\n    Pair(Box<Expr>, Box<Expr>),\n    /// Projection left/right from a pair\n    Proj(LR, Box<Expr>),\n}\n\n#[derive(Clone, Debug, PartialEq)]\nstruct Arm {\n    pat: Box<Expr>,\n    expr: Box<Expr>,\n}\n\n/// An element in the typing context\n#[derive(Clone, Debug, PartialEq)]\nenum Element {\n    /// Universal type variable\n    Var(Kind),\n    /// Term variable typing x : A. We differ from the paper in that we use\n    /// de Bruijn indices for variables, so we don't need to mark which var\n    /// this annotation belongs to - it always belongs to the innermost binding (idx 0)\n    /// and we will find this by traversing the stack\n    Ann(Type),\n    /// Unsolved existential type variable\n    Exist(usize),\n    /// Existential type variable that has been solved\n    /// to some monotype\n    Solved(usize, Type),\n    /// I am actually unsure if we really need a marker, due to how we structure\n    /// scoping, see `with_scope` method.\n    Marker(usize),\n}\n\n#[derive(Clone, Debug, Default, PartialEq)]\npub struct Context {\n    /// We model the algorithmic context as a simple stack of elements\n    ctx: Vec<Element>,\n    /// We assign fresh exist. variables a unique, strictly increasing number\n    ev: usize,\n}\n\nimpl Context {\n    /// Generate a fresh identifier\n    fn fresh_ev(&mut self) -> usize {\n        let e = self.ev;\n        self.ev += 1;\n        e\n    }\n\n    /// Requires a mutable reference to self because we need to push/pop onto the stack\n    /// in the case of universally quantified variables. However, this can be considered\n    /// mostly immutable, since self should be equal before and after the call\n    fn well_formed(&mut self, ty: &Type) -> bool {\n        match ty {\n            Type::Exist(alpha) => self.ctx.contains(&Element::Exist(*alpha)) || self.find_solved(*alpha).is_some(),\n            Type::Univ(k, alpha) => self.with_scope(Element::Var(*k.clone()), |f| f.well_formed(&alpha)),\n            Type::Var(idx) => self.find_type_var(*idx).is_some(),\n            Type::Arrow(a, b) => self.well_formed(&a) && self.well_formed(&b),\n            Type::Sum(a, b) => self.well_formed(&a) && self.well_formed(&b),\n            Type::Product(a, b) => self.well_formed(&a) && self.well_formed(&b),\n            Type::Abs(k, a) => self.with_scope(Element::Var(*k.clone()), |f| f.well_formed(&a)),\n            Type::App(a, b) => self.well_formed(&a) && self.well_formed(&b),\n            Type::Unit | Type::Int | Type::Bool => true,\n        }\n    }\n\n    fn check_wf(&mut self, ty: &Type) -> Result<bool, String> {\n        if self.well_formed(ty) {\n            Ok(true)\n        } else {\n            Err(format!(\"Type {:?} is not well formed!\", ty))\n        }\n    }\n\n    // Pop off any stack growth incurred from calling `f`\n    fn with_scope<T, F: FnMut(&mut Context) -> T>(&mut self, e: Element, mut f: F) -> T {\n        self.ctx.push(e.clone());\n        let t = f(self);\n\n        while let Some(elem) = self.ctx.pop() {\n            if elem == e {\n                break;\n            }\n        }\n        t\n    }\n\n    /// Apply the context to a type, replacing any solved existential variables\n    /// in the context onto the type, if it contains a matching existential\n    fn apply(&self, ty: Type) -> Type {\n        match ty {\n            Type::Unit | Type::Int | Type::Bool | Type::Var(_) => ty,\n            Type::Arrow(a, b) => Type::Arrow(Box::new(self.apply(*a)), Box::new(self.apply(*b))),\n            Type::Sum(a, b) => Type::Sum(Box::new(self.apply(*a)), Box::new(self.apply(*b))),\n            Type::Product(a, b) => Type::Product(Box::new(self.apply(*a)), Box::new(self.apply(*b))),\n            Type::Abs(k, a) => Type::Abs(k, Box::new(self.apply(*a))),\n            Type::App(a, b) => Type::App(Box::new(self.apply(*a)), Box::new(self.apply(*b))),\n            Type::Univ(k, ty) => Type::Univ(k, Box::new(self.apply(*ty))),\n            Type::Exist(n) => {\n                match self.find_solved(n) {\n                    // Apply to the solved variable also - this is important\n                    // since we can have solved references deeper in the stack\n                    Some(solved) => self.apply(solved.clone()),\n                    None => ty,\n                }\n            }\n        }\n    }\n\n    /// Find the term annotation corresponding to de Bruijn index `idx`.\n    /// We traverse the stack in a reversed order, counting each annotation\n    /// we come across\n    fn find_annotation(&self, idx: usize) -> Option<&Type> {\n        let mut ix = 0;\n        for elem in self.ctx.iter().rev() {\n            match &elem {\n                Element::Ann(ty) => {\n                    if ix == idx {\n                        return Some(&ty);\n                    }\n                    ix += 1\n                }\n                _ => {}\n            }\n        }\n\n        None\n    }\n\n    /// Find the term annotation corresponding to de Bruijn index `idx`.\n    /// We traverse the stack in a reversed order, counting each annotation\n    /// we come across\n    fn find_type_var(&self, idx: usize) -> Option<&Kind> {\n        let mut ix = 0;\n        for elem in self.ctx.iter().rev() {\n            match &elem {\n                Element::Var(k) => {\n                    if ix == idx {\n                        return Some(&k);\n                    }\n                    ix += 1\n                }\n                _ => {}\n            }\n        }\n        None\n    }\n\n    /// Find the monotype associated with a solved existential variable `alpha`\n    /// in the context, if it exists.\n    fn find_solved(&self, alpha: usize) -> Option<&Type> {\n        for elem in &self.ctx {\n            match &elem {\n                Element::Solved(n, ty) if *n == alpha => return Some(ty),\n                _ => {}\n            }\n        }\n        None\n    }\n\n    /// This is one of the more confusing parts of the paper, IMO. We have to open\n    /// a 'hole' in the context, where we can replace/insert some arbitrary amount\n    /// of bindings where an unsolved existential (or marker, in the paper) was\n    /// previously located\n    fn splice_hole<F: Fn(&mut Vec<Element>)>(&mut self, exist: usize, f: F) -> Result<(), String> {\n        let (l, r) = self.split_context(exist)?;\n        f(&mut l.ctx);\n        l.ctx.extend(r);\n        Ok(())\n    }\n\n    fn split_context(&mut self, exist: usize) -> Result<(&mut Self, Vec<Element>), String> {\n        let mut ret = None;\n        for (idx, el) in self.ctx.iter().enumerate() {\n            match el {\n                Element::Exist(n) if *n == exist => ret = Some(idx),\n                _ => {}\n            }\n        }\n        let idx = ret.ok_or_else(|| format!(\"{} not bound in ctx\", exist))?;\n        let rest = self.ctx.split_off(idx + 1);\n        self.ctx.pop();\n        Ok((self, rest))\n    }\n\n    fn kinding(&mut self, ty: &Type) -> Option<Kind> {\n        Some(Kind::Star)\n    }\n\n    fn beta_reduce(&mut self, ty: &mut Type) -> Result<(), String> {\n        match ty {\n            Type::Unit | Type::Int | Type::Bool | Type::Var(_) => Ok(()),\n            Type::Exist(v) => Ok(()),\n            Type::Arrow(a, b) => {\n                self.beta_reduce(a)?;\n                self.beta_reduce(b)\n            }\n            Type::Sum(a, b) => {\n                self.beta_reduce(a)?;\n                self.beta_reduce(b)\n            }\n            Type::Product(a, b) => {\n                self.beta_reduce(a)?;\n                self.beta_reduce(b)\n            }\n            Type::Univ(k, a) => self.with_scope(Element::Var(*k.clone()), |f| f.beta_reduce(a)),\n            Type::Abs(k, a) => self.with_scope(Element::Var(*k.clone()), |f| f.beta_reduce(a)),\n            Type::App(a, b) => {\n                self.beta_reduce(a)?;\n                self.beta_reduce(b)?;\n                if let Type::Abs(k, body) = a.as_mut() {\n                    match self.kinding(b) {\n                        Some(arg_kind) => {\n                            if &arg_kind == k.as_ref() {\n                                body.subst(b);\n                                *ty = *body.clone();\n                                self.beta_reduce(ty)\n                            } else {\n                                Err(format!(\"kind mismatch\"))\n                            }\n                        }\n                        None => Err(format!(\"No kind!?\")),\n                    }\n                } else {\n                    Ok(())\n                }\n            }\n        }\n    }\n\n    fn subtype(&mut self, mut a: Type, mut b: Type) -> Result<(), String> {\n        println!(\"{:?} <: {:?}\", a, b);\n        self.beta_reduce(&mut a)?;\n        self.beta_reduce(&mut b)?;\n        println!(\"{:?} <: {:?}\", a, b);\n        use Type::*;\n        match (a, b) {\n            (Bool, Bool) => Ok(()),\n            (Int, Int) => Ok(()),\n            // Rule <: Unit\n            (Unit, Unit) => Ok(()),\n            // Rule <: Var\n            (Var(a), Var(b)) if a == b => Ok(()),\n            // Rule <: Exvar\n            (Exist(a), Exist(b)) if a == b => Ok(()),\n            // Rule <: ->\n            (Arrow(a1, a2), Arrow(b1, b2)) => {\n                self.subtype(*b1, *a1)?;\n                self.subtype(self.apply(*a2), self.apply(*b2))\n            }\n            (Sum(l1, r1), Sum(l2, r2)) => {\n                self.subtype(*l1, *l2)?;\n                self.subtype(self.apply(*r1), self.apply(*r2))\n            }\n            (Product(l1, r1), Product(l2, r2)) => {\n                self.subtype(*l1, *l2)?;\n                self.subtype(self.apply(*r1), self.apply(*r2))\n            }\n            // Rule <: forall. L\n            (Univ(k, a), b) => {\n                let alpha = self.fresh_ev();\n                let mut a_ = *a;\n                a_.subst(&mut b.clone());\n                self.with_scope(Element::Marker(alpha), |f| {\n                    f.ctx.push(Element::Exist(alpha));\n                    f.subtype(a_.clone(), b.clone())\n                })\n            }\n            // Rule <: forall. R\n            (a, Univ(k, b)) => {\n                // let alpha = self.fresh_ev();\n                self.with_scope(Element::Var(*k.clone()), |f| f.subtype(a.clone(), *b.clone()))\n            }\n            // Rule <: InstantiateL\n            (Exist(alpha), a) if !a.freevars().contains(&alpha) => self.instantiateL(alpha, &a),\n            // Rule <: InstantiateR\n            (a, Exist(alpha)) if !a.freevars().contains(&alpha) => self.instantiateR(&a, alpha),\n            (a, b) => Err(format!(\"{:?} is not a subtype of {:?}\", a, b)),\n        }\n    }\n\n    fn instantiateL(&mut self, alpha: usize, a: &Type) -> Result<(), String> {\n        // We need to split our context into Γ1, alpha, Γ2 so that we\n        // can ensure that alpha is a well formed Existenial in Γ1, e.g.\n        // that alpha appears in Γ1. This ensures that alpha is declared\n        // \"to the left\" (outer scope) of the type `a`\n        let (l, r) = self.split_context(alpha)?;\n        if a.monotype() && l.well_formed(a) {\n            l.ctx.push(Element::Solved(alpha, a.clone()));\n            l.ctx.extend(r);\n            return Ok(());\n        }\n\n        // Okay, alpha is *not* well-formed, but that's okay. `split_context`\n        // removed alpha from the context, so we add it back and then reform\n        // Γ1, alpha, Γ2 into a full context again. When we add it back\n        // and reform the context depends on how we dispatch below\n        match a {\n            // InstLArr\n            Type::Arrow(A1, A2) => {\n                let a1 = l.fresh_ev();\n                let a2 = l.fresh_ev();\n\n                // Rather than reforming, then calling splice, we can just\n                // directly push to `l`, since it currently points at the\n                // hole corresponding to [^\u000b]\n                l.ctx.push(Element::Exist(a2));\n                l.ctx.push(Element::Exist(a1));\n                l.ctx.push(Element::Solved(\n                    alpha,\n                    Type::Arrow(Box::new(Type::Exist(a1)), Box::new(Type::Exist(a2))),\n                ));\n                l.ctx.extend(r);\n                self.instantiateR(A1, a1)?;\n                let A2_ = self.apply(*A2.clone());\n                self.instantiateL(a2, &A2_)\n            }\n            // InstLAllR\n            Type::Univ(k, beta) => {\n                l.ctx.push(Element::Exist(alpha));\n                l.ctx.extend(r);\n                self.with_scope(Element::Var(*k.clone()), |f| {\n                    f.instantiateL(alpha, &Type::Univ(k.clone(), beta.clone()))\n                })\n            }\n            // InstLReach\n            Type::Exist(beta) => {\n                // We need to ensure that beta only appears to the right of alpha,\n                // e.g. that beta is well-formed in Γ2, so we make a temporary\n                // context so that we can call the splice_hole method\n                let mut gamma = Context { ctx: r, ev: 0 };\n                gamma.splice_hole(*beta, |ctx| ctx.push(Element::Solved(*beta, Type::Exist(alpha))))?;\n                // As explained above, Exist(alpha) was popped off of `l` in the\n                // `split_context` method, so we need to add it back in. We\n                // now have some context such that Γ[alpha][beta=alpha]\n                l.ctx.push(Element::Exist(alpha));\n                l.ctx.extend(gamma.ctx);\n                Ok(())\n            }\n            _ => Err(format!(\"Could not instantiate Exist({}) to {:?}\", alpha, a)),\n        }\n    }\n\n    fn instantiateR(&mut self, a: &Type, alpha: usize) -> Result<(), String> {\n        let (l, r) = self.split_context(alpha)?;\n        if a.monotype() && l.well_formed(a) {\n            l.ctx.push(Element::Solved(alpha, a.clone()));\n            l.ctx.extend(r);\n            return Ok(());\n        }\n        match a {\n            // InstRArr\n            Type::Arrow(A1, A2) => {\n                let a1 = l.fresh_ev();\n                let a2 = l.fresh_ev();\n\n                l.ctx.push(Element::Exist(a2));\n                l.ctx.push(Element::Exist(a1));\n                l.ctx.push(Element::Solved(\n                    alpha,\n                    Type::Arrow(Box::new(Type::Exist(a1)), Box::new(Type::Exist(a2))),\n                ));\n                l.ctx.extend(r);\n\n                // Much the same as InstLArr, except the following lines are swapped\n                self.instantiateL(a1, &A1)?;\n                let A2_ = self.apply(*A2.clone());\n                self.instantiateR(&A2_, a2)\n            }\n            // InstRAllL\n            Type::Univ(k, beta) => {\n                l.ctx.push(Element::Exist(alpha));\n                l.ctx.extend(r);\n\n                let b = self.fresh_ev();\n\n                let mut beta_prime = *beta.clone();\n                beta_prime.subst(&mut Type::Exist(b));\n\n                self.with_scope(Element::Exist(b), |f| {\n                    f.instantiateR(&Type::Univ(k.clone(), Box::new(beta_prime.clone())), alpha)\n                })\n            }\n            // InstRReach\n            Type::Exist(beta) => {\n                let mut gamma = Context { ctx: r, ev: 0 };\n                gamma.splice_hole(*beta, |ctx| ctx.push(Element::Solved(*beta, Type::Exist(alpha))))?;\n                l.ctx.push(Element::Exist(alpha));\n                l.ctx.extend(gamma.ctx);\n                Ok(())\n            }\n            _ => Err(format!(\"Could not instantiate Exist({}) to {:?}\", alpha, a)),\n        }\n    }\n\n    fn infer(&mut self, e: &Expr) -> Result<Type, String> {\n        match e {\n            Expr::True | Expr::False => Ok(Type::Bool),\n            Expr::Int(_) => Ok(Type::Int),\n            // Rule 1l=>\n            Expr::Unit => Ok(Type::Unit),\n            // Rule Anno\n            Expr::Ann(x, ty) => {\n                self.check_wf(ty)?;\n                self.check(x, ty)?;\n                Ok(*ty.clone())\n            }\n            // Rule Var\n            Expr::Var(x) => self.find_annotation(*x).cloned().ok_or(format!(\"unbound db {:?}\", x)),\n            // Rule ->I =>\n            Expr::Abs(e) => {\n                let alpha = self.fresh_ev();\n                let beta = self.fresh_ev();\n                // Fresh existential var for function domain\n                self.ctx.push(Element::Exist(alpha));\n                // And for codomain\n                self.ctx.push(Element::Exist(beta));\n\n                // Check the function body against Beta\n                self.with_scope(Element::Ann(Type::Exist(alpha)), |f| f.check(e, &Type::Exist(beta)))?;\n\n                // alpha and beta stay on the stack, since they appear in the output type\n                Ok(Type::Arrow(Box::new(Type::Exist(alpha)), Box::new(Type::Exist(beta))))\n            }\n            // Rule ->E\n            Expr::App(e1, e2) => {\n                let a = self.infer(&e1)?;\n                let a = self.apply(a);\n                println!(\"{:?} {:?} {:?} {:?}\", a, &e1, &e2, &self.ctx);\n                self.infer_app(&a, e2)\n            }\n            Expr::If(e1, e2, e3) => {\n                self.check(e1, &Type::Bool)?;\n                let alpha = self.fresh_ev();\n                self.ctx.push(Element::Exist(alpha));\n\n                let exist = Type::Exist(alpha);\n                self.check(&e2, &exist)?;\n                self.check(&e3, &exist)?;\n                Ok(exist)\n            }\n            Expr::Inj(lr, e, ty) => {\n                self.check_wf(ty)?;\n                let mut ty = self.apply(*ty.clone());\n                self.beta_reduce(&mut ty)?;\n\n                match &ty {\n                    Type::Sum(l, r) => {\n                        match lr {\n                            LR::Left => self.check(e, l)?,\n                            LR::Right => self.check(e, r)?,\n                        }\n                        Ok(ty.clone())\n                    }\n                    Type::Abs(_, _) => {\n                        let arg_ty = self.infer(e)?;\n                        self.infer(&Expr::Inj(\n                            *lr,\n                            e.clone(),\n                            Box::new(Type::App(Box::new(ty.clone()), Box::new(arg_ty))),\n                        ))\n                    }\n                    _ => Err(format!(\"#Expr::Inj {:?} is not a sum type!\", ty)),\n                }\n            }\n            Expr::Case(scrutinee, la, ra) => {\n                let ty = self.infer(scrutinee)?;\n                let ty = self.apply(ty);\n                if let Type::Sum(left, right) = &ty {\n                    self.check(&la.pat, &ty)?;\n                    self.check(&ra.pat, &ty)?;\n\n                    fn bind_infer(ctx: &mut Context, arm: &Arm, left: &Type, right: &Type) -> Result<Type, String> {\n                        match arm.pat.as_ref() {\n                            Expr::Inj(lr, ex, _) => match (ex.as_ref(), lr) {\n                                (Expr::Var(_), LR::Left) => {\n                                    ctx.with_scope(Element::Ann(left.clone()), |f| f.infer(&arm.expr))\n                                }\n                                (Expr::Var(_), LR::Right) => {\n                                    ctx.with_scope(Element::Ann(right.clone()), |f| f.infer(&arm.expr))\n                                }\n                                _ => ctx.infer(&arm.expr),\n                            },\n                            _ => Err(format!(\"Not injection expressions!\")),\n                        }\n                    }\n\n                    let l = bind_infer(self, la, &left, &right)?;\n                    let r = bind_infer(self, ra, &left, &right)?;\n                    if l == r {\n                        Ok(l)\n                    } else {\n                        Err(format!(\"Case arms have different return types!\"))\n                    }\n                } else {\n                    Err(format!(\"{:?} is not a sum type!\", ty))\n                }\n            }\n            Expr::Pair(a, b) => {\n                let ta = self.infer(a)?;\n                let ta = self.apply(ta);\n                let tb = self.infer(b)?;\n                let tb = self.apply(tb);\n                Ok(Type::Product(Box::new(ta), Box::new(tb)))\n            }\n            Expr::Proj(lr, ex) => {\n                let ty = self.infer(ex)?;\n                let ty = self.apply(ty);\n                match ty {\n                    Type::Product(left, right) => match lr {\n                        LR::Left => Ok(*left),\n                        LR::Right => Ok(*right),\n                    },\n                    _ => Err(format!(\"{:?} is not a pair!\", ex)),\n                }\n            } // _ => panic!(\"cant infer {:?}\", e)\n        }\n    }\n\n    fn infer_app(&mut self, ty: &Type, e2: &Expr) -> Result<Type, String> {\n        match ty {\n            // Rule alpha_hat App\n            Type::Exist(alpha) => {\n                let a1 = self.fresh_ev();\n                let a2 = self.fresh_ev();\n\n                self.splice_hole(*alpha, |ctx| {\n                    ctx.push(Element::Exist(a2));\n                    ctx.push(Element::Exist(a1));\n                    ctx.push(Element::Solved(\n                        *alpha,\n                        Type::Arrow(Box::new(Type::Exist(a1)), Box::new(Type::Exist(a2))),\n                    ));\n                })?;\n\n                self.check(e2, &Type::Exist(a1))?;\n                Ok(Type::Exist(a2))\n            }\n            // Rule ->App\n            Type::Arrow(a, b) => {\n                self.check(e2, a)?;\n                Ok(*b.clone())\n            }\n            // Rule forall. App\n            Type::Univ(k, a) => {\n                let alpha = self.fresh_ev();\n                let mut a_prime = a.clone();\n                a_prime.subst(&mut Type::Exist(alpha));\n                self.ctx.push(Element::Exist(alpha));\n                self.infer_app(&a_prime, e2)\n            }\n            _ => Err(format!(\"Cannot appl ty {:?} to expr {:?}\", e2, ty)),\n        }\n    }\n\n    fn check(&mut self, e: &Expr, a: &Type) -> Result<(), String> {\n        match (e, a) {\n            (Expr::Int(_), Type::Int) => Ok(()),\n            (Expr::False, Type::Bool) => Ok(()),\n            (Expr::True, Type::Bool) => Ok(()),\n            (Expr::If(e1, e2, e3), a) => {\n                self.check(&e1, &Type::Bool)?;\n                self.check(&e2, a)?;\n                self.check(&e3, a)\n            }\n            (Expr::Inj(lr, ex, tagged), Type::Sum(left, right)) => {\n                self.subtype(*tagged.clone(), a.clone())?;\n                match lr {\n                    LR::Left => self.check(ex, left),\n                    LR::Right => self.check(ex, right),\n                }\n            }\n            (Expr::Pair(a, b), Type::Product(t1, t2)) => {\n                self.check(a, t1)?;\n                self.check(b, t2)\n            }\n            // (Expr::Proj(lr, expr), t) => {\n            //     let ty = self.infer(expr)?;\n            //     let ty = self.apply(ty);\n            //     dbg!(&self.ctx);\n            //     match (ty, lr) {\n            //         (Type::Product(left, _), LR::Left) => self.subtype(&left, t),\n            //         (Type::Product(right, _), LR::Right) => self.subtype(&right, t),\n            //         _ => Err(format!(\"{:?} is not a product type\", t))\n            //     }\n            // }\n            // Rule 1l\n            (Expr::Unit, Type::Unit) => Ok(()),\n            // Rule ->I\n            (Expr::Abs(body), Type::Arrow(a1, a2)) => self.with_scope(Element::Ann(*a1.clone()), |f| f.check(body, a2)),\n            // Rule forall. I\n            (e, Type::Univ(k, ty)) => self.with_scope(Element::Var(*k.clone()), |f| f.check(e, &ty)),\n            // Rule Sub\n            (e, b) => {\n                // let mut a = a.clone();\n                // let mut b = b.clone();\n\n                // self.beta_reduce(&mut a)?;\n                // self.beta_reduce(&mut b)?;\n\n                let a = self.infer(e)?;\n                let a = self.apply(a);\n                let b = self.apply(b.clone());\n                dbg!(&e, &self.ctx);\n                self.subtype(a, b)?;\n                Ok(())\n            }\n        }\n    }\n}\n\nfn infer(ex: &Expr) -> Result<Type, String> {\n    let mut ctx = Context::default();\n    let inf = ctx.infer(ex)?;\n    let mut ty = ctx.apply(inf);\n    ctx.beta_reduce(&mut ty)?;\n    Ok(ty)\n}\n\nfn main() {\n    // \\x. (x 1, x True) : forall A. (A -> A) -> (Int, Bool)\n    let h = abs!(pair!(app!(var!(0), Expr::Int(1)), app!(var!(0), Expr::True)));\n    let h = ann!(\n        h,\n        arrow!(\n            forall!(arrow!(Type::Var(0), Type::Var(0))),\n            product!(Type::Int, Type::Bool)\n        )\n    );\n    let g = app!(h, abs!(var!(0)));\n\n    let ty = Type::Abs(Box::new(Kind::Star), Box::new(Type::Var(0)));\n    let ty = Type::App(Box::new(ty), Box::new(Type::Int));\n    let f = ann!(Expr::Int(99), ty);\n\n    let ty_opt = Type::Abs(Box::new(Kind::Star), Box::new(sum!(Type::Var(0), Type::Unit)));\n    // \\x. inl x of [\\X::* => X + ()] @ 'A\n    let some = abs!(inj!(l; var!(0), ty_opt.clone()));\n    let some = ann!(\n        some,\n        forall!(arrow!(\n            Type::Var(0),\n            Type::App(Box::new(ty_opt.clone()), Box::new(Type::Var(0)))\n        ))\n    );\n\n    // let some = app!(some, Expr::Int(10));\n\n    println!(\"{} : {:?}\", some, infer(&some));\n}\n\n#[cfg(test)]\nmod test {\n    use super::*;\n    use helpers::*;\n\n    #[test]\n    fn identity() {\n        let id = abs!(var!(0));\n        let id_ann = ann!(id.clone(), forall!(arrow!(Type::Var(0), Type::Var(0))));\n\n        let id_ex = arrow!(Type::Exist(0), Type::Exist(0));\n        let id_ann_ex = forall!(arrow!(Type::Var(0), Type::Var(0)));\n        assert_eq!(infer(&id), Ok(id_ex));\n        assert_eq!(infer(&id_ann), Ok(id_ann_ex));\n    }\n\n    #[test]\n    fn application() {\n        // \\f. \\g. \\x. f (g x)\n        // x: C\n        // g: C -> A\n        // f: A -> B\n        // (A -> B) -> (C -> A) -> C -> B\n        let t = abs!(abs!(abs!(app!(var!(2), app!(var!(1), var!(0))))));\n        let ty = infer(&t).unwrap();\n        assert_eq!(ty.to_string(), \"((a->b)->((c->a)->(c->b)))\");\n    }\n\n    #[test]\n    fn application2() {\n        // \\x. if x then 1 else 0 : Bool -> Int\n        let f = abs!(ife!(var!(0), Expr::Int(1), Expr::Int(0)));\n\n        // \\f. \\g. \\x. f (g x)\n        // : (e6 -> e7) -> ((e14 -> e6) -> (e14 -> e7))\n        // : (a -> b) -> ((c -> a) -> (c -> b))\n        let t1 = abs!(abs!(abs!(app!(var!(2), app!(var!(1), var!(0))))));\n\n        // : ((c -> bool) -> (c -> int))\n        let f2 = app!(t1.clone(), f);\n        // : (c -> int)\n        let f3 = app!(f2, abs!(Expr::True));\n        let f4 = app!(f3, Expr::Unit);\n\n        assert_eq!(infer(&f4), Ok(Type::Int))\n    }\n\n    #[test]\n    fn sum_type() {\n        let ty = sum!(Type::Unit, Type::Bool);\n        let f_ty = arrow!(ty.clone(), Type::Int);\n\n        // \\x. case x of inl () => 0 | inr True => 1\n        let f = abs!(\n            case!(var!(0), inj!(l; Expr::Unit, ty.clone()) => Expr::Int(0), inj!(r; Expr::True, ty.clone()) => Expr::Int(1))\n        );\n        let f = ann!(f, f_ty);\n\n        infer(&f).unwrap();\n\n        let a = arrow!(forall!(arrow!(Type::Var(0), Type::Var(0))), ty.clone());\n        // \\x. if True then inl (x ()) else inr (x False) : (forall A. (A -> A)) -> (() + Bool)\n        let f = abs!(ife!(\n            Expr::True,\n            inj!(l; app!(var!(0), Expr::Unit), ty.clone()),\n            inj!(r; app!(var!(0), Expr::False), ty.clone())\n        ));\n        let f = ann!(f, a);\n\n        infer(&f).unwrap();\n    }\n\n    #[test]\n    fn product_type() {\n        // \\x. r.0 : forall A. (A, A) -> A\n        let f = ann!(\n            abs!(proj!(r; var!(0))),\n            forall!(arrow!(product!(Type::Var(0), Type::Var(0)), Type::Var(0)))\n        );\n        // (\\x. fst 0) (1, 1)\n        let f = app!(f, pair!(Expr::Int(1), Expr::Int(1)));\n\n        assert_eq!(infer(&f), Ok(Type::Int));\n\n        // \\x. (x 1, x True) : (forall A. (A -> A)) -> (Int, Bool)\n        let h = abs!(pair!(app!(var!(0), Expr::Int(1)), app!(var!(0), Expr::True)));\n        let h = ann!(\n            h,\n            arrow!(\n                forall!(arrow!(Type::Var(0), Type::Var(0))),\n                product!(Type::Int, Type::Bool)\n            )\n        );\n        let g = app!(h, abs!(var!(0)));\n        assert_eq!(infer(&g), Ok(product!(Type::Int, Type::Bool)))\n    }\n}\n"
  },
  {
    "path": "x2_dependent/Cargo.toml",
    "content": "[package]\nname = \"dependent\"\nversion = \"0.1.0\"\nauthors = [\"Michael Lazear <lazear@scripps.edu>\"]\nedition = \"2018\"\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\n"
  },
  {
    "path": "x2_dependent/src/main.rs",
    "content": "#[derive(Debug, Clone, PartialEq)]\nenum Term {\n    Universe(usize),\n    Nat,\n    Var(usize),\n    Int(usize),\n    App(Box<Term>, Box<Term>),\n    Abs(Box<Term>, Box<Term>),\n    Pi(Box<Term>, Box<Term>),\n}\n\nimpl Term {\n    fn normal(&self) -> bool {\n        match self {\n            Term::App(_, _) => false,\n            Term::Pi(a, b) | Term::Abs(a, b) => a.normal() && b.normal(),\n            _ => true,\n        }\n    }\n\n    fn whnf(&self) -> bool {\n        match self {\n            Term::App(_, _) => false,\n            Term::Pi(a, _) | Term::Abs(a, _) => a.normal(),\n            _ => true,\n        }\n    }\n\n    fn subst(&mut self, mut t2: Term) {\n        println!(\"subst {:?} {:?}\", self, t2);\n        let mut v = Visitor::new();\n\n        fn shift(v: &mut Visitor, t: &mut Term, s: isize) {\n            v.visit(t, &|f, c| {\n                if let Term::Var(n) = f {\n                    if *n >= c {\n                        *n = (*n as isize + s) as usize;\n                    }\n                }\n            });\n        }\n\n        shift(&mut v, &mut t2, 1);\n        v.visit(self, &|f, i| {\n            let mut t = t2.clone();\n            let mut v = Visitor::new();\n            v.visit(&mut t, &|f, _| {\n                if let Term::Var(n) = f {\n                    *n += i;\n                }\n            });\n            if let Term::Var(n) = f {\n                if *n == i {\n                    *f = t;\n                }\n            }\n        });\n        shift(&mut v, self, -1);\n    }\n}\n\n#[derive(Default, Debug, Clone)]\nstruct Context {\n    binding: Vec<Term>,\n}\n\n#[derive(Debug, Clone)]\nenum Error {\n    Unbound,\n    NotPi(Term),\n    Mismatch(Term, Term),\n}\n\nstruct Visitor {\n    cutoff: usize,\n}\n\nimpl Visitor {\n    fn new() -> Visitor {\n        Visitor { cutoff: 0 }\n    }\n\n    fn visit<F: Fn(&mut Term, usize)>(&mut self, term: &mut Term, f: &F) {\n        match term {\n            Term::Universe(_) => {}\n            Term::Nat | Term::Int(_) => {}\n            Term::Var(_) => {\n                f(term, self.cutoff);\n            }\n            Term::Pi(t1, t2) | Term::Abs(t1, t2) => {\n                self.visit(t1, f);\n                self.cutoff += 1;\n                self.visit(t2, f);\n                self.cutoff -= 1;\n            }\n            Term::App(t1, t2) => {\n                self.visit(t1, f);\n                self.visit(t2, f);\n            }\n        }\n    }\n}\n\nimpl Context {\n    fn get(&self, idx: usize) -> Option<&Term> {\n        self.binding.get(self.binding.len().checked_sub(idx + 1)?)\n    }\n\n    fn with_bind<T, F: Fn(&mut Context) -> T>(&mut self, bind: Term, f: F) -> T {\n        self.binding.push(bind);\n        let r = f(self);\n        self.binding.pop();\n        r\n    }\n\n    fn equiv(&mut self, t1: &Term, t2: &Term) -> bool {\n        let mut t1p = t1.clone();\n        let mut t2p = t2.clone();\n\n        while !t1p.normal() {\n            t1p = beta_reduce(t1p);\n        }\n\n        while !t2p.normal() {\n            t2p = beta_reduce(t2p);\n        }\n\n        t1p == t2p\n    }\n\n    fn type_of(&mut self, term: &Term) -> Result<Term, Error> {\n        println!(\"type of {:?}\", term);\n        match &term {\n            Term::Universe(n) => Ok(Term::Universe(*n + 1)),\n            Term::Var(i) => self.get(*i).cloned().ok_or(Error::Unbound),\n            Term::Abs(S, t) => {\n                let k = self.type_of(&S)?;\n                let T = self.with_bind(k.clone(), |f| f.type_of(&t))?;\n                Ok(Term::Pi(Box::new(k), Box::new(T)))\n            }\n            Term::App(t1, t2) => {\n                let ty1 = self.type_of(&t1)?;\n                let ty2 = self.type_of(&t2)?;\n                match ty1 {\n                    Term::Pi(S, mut T) => {\n                        if self.equiv(&S, &ty2) {\n                            T.subst(*t2.clone());\n                            Ok(*T)\n                        } else {\n                            Err(Error::Mismatch(*S, ty2))\n                        }\n                    }\n                    _ => Err(Error::NotPi(ty1)),\n                }\n            }\n            Term::Pi(t1, t2) => {\n                let ty1 = self.type_of(&t1)?;\n                let ty2 = self.with_bind(ty1.clone(), |f| f.type_of(t2))?;\n                Ok(ty2)\n            }\n            Term::Nat => Ok(Term::Universe(0)),\n            Term::Int(_) => Ok(Term::Nat),\n        }\n    }\n}\n\n/// Small step beta reduction\nfn beta_reduce(mut term: Term) -> Term {\n    match term {\n        Term::App(mut abs, arg) => match (abs.normal(), arg.normal()) {\n            (false, _) => Term::App(Box::new(beta_reduce(*abs)), arg),\n            (_, false) => Term::App(abs, Box::new(beta_reduce(*arg))),\n            _ => match *abs {\n                Term::Abs(_, mut body) => {\n                    body.subst(*arg.clone());\n                    *body\n                }\n                x => Term::App(Box::new(x), arg),\n            },\n        },\n        Term::Abs(ty, body) => {\n            if body.normal() {\n                Term::Abs(ty, body)\n            } else {\n                Term::Abs(ty, Box::new(beta_reduce(*body)))\n            }\n        }\n        _ => term,\n    }\n}\n\nfn main() {\n    macro_rules! term {\n        (Abs; $ex1:expr, $ex2:expr) => {\n            Term::Abs(Box::new($ex1), Box::new($ex2))\n        };\n        (App; $ex1:expr, $ex2:expr) => {\n            Term::App(Box::new($ex1), Box::new($ex2))\n        };\n        (Pi; $ex1:expr, $ex2:expr) => {\n            Term::Pi(Box::new($ex1), Box::new($ex2))\n        };\n        (Var; $ex1:expr) => {\n            Term::Var($ex1)\n        };\n        (Star) => {\n            Term::Universe(0)\n        };\n        (Universe; $ex:expr) => {\n            Term::Universe($ex)\n        };\n        (Int; $ex1:expr) => {\n            Term::Int($ex1)\n        };\n    };\n\n    println!(\"Hello, world!\");\n    let mut ctx = Context::default();\n    // let tm = term!(Abs; term!(Star), term!(App; Term::Nat, term!(Var; 0)));\n    // let tm = term!(App; tm, term!(Int; 10));\n\n    // Πx: Nat -> x\n    let mut tm = term!(Abs; Term::Nat, Term::Var(0));\n    tm = term!(App; tm, Term::Int(10));\n    // tm.subst(Term::Int(10));\n\n    dbg!(ctx.type_of(&tm));\n    // dbg!(&tm);\n    tm = beta_reduce(tm);\n    dbg!(&tm);\n}\n"
  }
]