Main | About | Tags

Boxes

We are defining BFAE, arithmetic expressions with boxes that encloses a value.

BFAE adds box features to the language.

enum Expr: prevExpr {
    // includes all the former definition
    case Seqn(Expr, Expr)           //box
    case NewBox(Expr)
    case OpenBox(Expr)
    case SetBox(Expr, Expr)
}

We also need a new type of value BoxV for boxes.

enum Value: oldValue {
    case BoxV(Addr)                 //box
}

We are using Sto in order to manage the storage that the boxes use. Each box holds an address where the value is stored.

typealias Sto = [Addr : Value]
typealias Addr = Int

This is a simple, and very stupid version of memory allocation.

func malloc(_ sto: Sto) -> Addr {
    if let maxVal = sto.max(by: { a, b in a.key < b.key }) {
        return maxVal.key
    }
    return 0
}

Interpretation implementation.

func interp(_ e: Expr, _ env: Env, _ sto: Sto) -> (Value, Sto)
{
    switch e {
    case .Num(let n):
        return (.NumV(n), sto)
    case .Add(let l, let r):
        let (v1, s1) = interp(l, env, sto)
        let (v2, s2) = interp(r, env, s1)
        return (NumVOperation(ADD, v1, v2), s2)
    case .Sub(let l, let r):
        let (v1, s1) = interp(l, env, sto)
        let (v2, s2) = interp(r, env, s1)
        return (NumVOperation(SUB, v1, v2), s2)
    case .Val(let x, let i, let b):
        let (v, s) = interp(i, env, sto)
        return interp(b, env + [x : v], s)
    case .Id(let x):
        return (env[x]!, sto)
    case .Fun(let x, let b):
        return (.CloV(x, b, env), sto)
    case .App(let f, let a):
        let (v, s) = interp(f, env, sto)
        switch v {
        case .CloV(let x, let b, let fenv):
            let (va, sa) = interp(a, env, s)
            return interp(b, fenv + [x : va], sa)
        default:
            exit(1)
        }
    case .Seqn(let l, let r):
        let (_, s1) = interp(l, env, sto)
        return interp(r, env, s1)
        
    case .NewBox(let e):
        let (v, s) = interp(e, env, sto)
        let addr = malloc(sto)
        return (.BoxV(addr), s + [addr : v])
        
    case .OpenBox(let e):
        let (v, s) = interp(e, env, sto)
        switch v {
        case .BoxV(let addr):
            return (s[addr]!, s)
        default:
            exit(1)
        }
        
    case .SetBox(let b, let e):
        let (v, s) = interp(b, env, sto)
        switch v {
        case .BoxV(let addr):
            let (ve, se) = interp(e, env, s)
            return (ve, se + [addr : ve])
        default:
            exit(0)
        }
    }
}

func INTERP(_ e: Expr) -> Value {
    let (v, _) = interp(e, Env(), Sto())
    return v
}


print(INTERP(
        .Val("b", .NewBox(.Num(10)), .OpenBox(.Seqn(.SetBox(.Id("b"), .Num(3)), .Id("b"))))
)) //NumV(3)

All the materials are from CS320 class held on 2021 spring, KAIST.