progs/fun/simple-2steps.sc
author Christian Urban <christian.urban@kcl.ac.uk>
Fri, 17 Nov 2023 20:06:43 +0000
changeset 955 47acfd7f9096
parent 911 df8660143051
permissions -rw-r--r--
updated
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
911
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
     1
// Source language: arithmetic expressions with function calls 
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
     2
enum Expr {
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
     3
    case Num(n: Int)
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
     4
    case Aop(op: String, e1: Expr, e2: Expr)
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
     5
    case Call(fname: String, args: List[Expr])
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
     6
}
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
     7
import Expr._
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
     8
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
     9
// Target language 
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    10
// "trivial" KValues
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    11
enum KVal {
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    12
    case KVar(s: String)
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    13
    case KNum(n: Int)
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    14
    case KAop(op: String, v1: KVal, v2: KVal)
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    15
    case KCall(fname: String, args: List[KVal])
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    16
}
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    17
import KVal._
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    18
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    19
// KExpressions 
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    20
enum KExp {
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    21
    case KReturn(v: KVal)
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    22
    case KLet(x: String, v: KVal, e: KExp) 
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    23
}
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    24
import KExp._
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    25
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    26
// Intermediate KExpressions2 
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    27
enum KExp2 {
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    28
    case KPrim(v: KVal)
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    29
    case KLet2(x: String, e1: KExp2, e2: KExp2) 
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    30
}
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    31
import KExp2._
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    32
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    33
def pexp(e: KExp): String = e match {
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    34
    case KReturn(v) => s"KReturn($v)"
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    35
    case KLet(x,e1,e2) => s"KLet($x = ${e1} \n in ${pexp(e2)})"
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    36
}
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    37
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    38
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    39
var cnt = -1
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    40
def Fresh(s: String) = {
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    41
    cnt = cnt + 1
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    42
    s"${s}_${cnt}"
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    43
}
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    44
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    45
def KNorm(e: Expr): KExp2 = e match { 
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    46
    case Num(i) => KPrim(KNum(i))
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    47
    case Aop(op, l, r) => {
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    48
        val zl = Fresh("zl")
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    49
        val zr = Fresh("zr")
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    50
        KLet2(zl, KNorm(l), 
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    51
           KLet2(zr, KNorm(r), 
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    52
              KPrim(KAop(op, KVar(zl), KVar(zr)))))
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    53
    }
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    54
    case Call(fname, args) => {
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    55
        def aux(args: List[Expr], zs: List[KVal]) : KExp2 = args match {
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    56
            case Nil => KPrim(KCall(fname, zs))
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    57
            case a::as => {
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    58
                val z = Fresh("z")
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    59
                KLet2(z, KNorm(a), aux(as, zs ::: List(KVar(z))))
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    60
            }
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    61
        }
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    62
        aux(args, Nil)  
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    63
    }
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    64
}
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    65
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    66
def KNormi(e: Expr) = {
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    67
   val z = Fresh("z")
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    68
   KLet2(z, KNorm(e), KPrim(KVar(z)))
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    69
}
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    70
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    71
def Kdenest(ke: KExp2) : KExp = ke match {
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    72
    case KPrim(v) => KReturn(v)
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    73
    case KLet2(xt, e1, e2) => {
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    74
        def insert(ke: KExp) : KExp = ke match {
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    75
            case KLet(yt, e3, e4) => KLet(yt, e3, insert(e4))
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    76
            case KReturn(v) => KLet(xt, v, Kdenest(e2))
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    77
        }
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    78
        insert(Kdenest(e1))
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    79
    }
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    80
}
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    81
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    82
// Constant Folding
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    83
def opt(v: KVal, env: Map[String, Int]) : KVal = v match {
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    84
    case KVar(s) => if (env.isDefinedAt(s)) KNum(env(s)) else KVar(s)
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    85
    case KNum(n) => KNum(n)
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    86
    case KAop(op, v1, v2) => (op, opt(v1, env), opt(v2, env)) match {
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    87
        case ("+", KNum(n1), KNum(n2)) => KNum(n1 + n2)
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    88
        case ("*", KNum(n1), KNum(n2)) => KNum(n1 * n2)
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    89
        case (_, v1o, v2o) => KAop(op, v1o, v2o)
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    90
    }
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    91
    case KCall(fname, args) => KCall(fname, args.map(opt(_, env)))
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    92
}
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    93
    
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    94
def Koptimise(ke: KExp, env: Map[String, Int] = Map()) : KExp = ke match {
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    95
    case KReturn(v) => KReturn(opt(v, env)) 
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    96
    case KLet(x, v, e) => opt(v, env) match {
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    97
        case KNum(n) => Koptimise(e, env + (x -> n))
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    98
        case vo => KLet(x, vo, Koptimise(e, env))
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    99
    }
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
   100
}    
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
   101
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
   102
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
   103
//1 + foo(bar(4 * -7), 3, id(12))
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
   104
val etest = 
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
   105
    Aop("+", Num(1),
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
   106
             Call("foo", 
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
   107
                List(Call("bar", 
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
   108
                             List(Aop("*", Num(4), Num(-7)))), 
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
   109
                     Num(3), 
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
   110
                     Call("id", List(Num(12))))))
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
   111
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
   112
val ke = Koptimise(Kdenest(KNormi(etest)))
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
   113
df8660143051 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
   114
println(pexp(ke))