暗黙の型変換

暗黙の型変換を修正しました。
ネストした式にも対応しました。
関数呼び出しの型は、呼び出したリターン値の型にしました。
EIdにも型を持たせて、関数の型を入れるようにしました。

package t7;
object Main {

  trait TType
  case class TFloat() extends TType
  case class TInt() extends TType
  case class TNone() extends TType
  case class TStr() extends TType
  case class TFun(prms:List[TType],rc:TType) extends TType
  sealed abstract case class E(t:TType)
  case class EId(override val t:TType, s:String) extends E(t)
  case class ECast(override val t:TType, a:E) extends E(t)
  case class EInt(override val t:TType, a:scala.Int) extends E(t)
  case class EFloat(override val t:TType, a:Double) extends E(t)
  case class ECall(override val t:TType, f:E, a:List[E]) extends E(t)

  def main(argv:Array[String]) {
    println("*"+f(ECall(TNone(),EId(TNone(),"add"),List(EFloat(TFloat(),1),EInt(TInt(),2)))))
    println("*"+f(ECall(TNone(),EId(TNone(),"add"),List(EInt(TInt(),1),EInt(TInt(),2)))))
    println("*"+f(ECall(TNone(),EId(TNone(),"add"), List(ECall(TNone(),EId(TNone(),"add"),List(EFloat(TFloat(),
1),EInt(TInt(),1))),EInt(TInt(),2)))))
  }
  def f(e:E):E = e match {
    case ECast(t,a) => ECast(t, f(a))
    case EInt(t,i) => EInt(TInt(), i)
    case EFloat(t,i) => EFloat(TFloat(), i)
    case EId(t,a) => EId(t,a)
    case ECall(t,EId(tid,id),xs1) =>
      val xs = xs1.map(f)
     // 暗黙の型変換つき型チェック
      def typeCheck(ts:List[TType],es:List[E]):Option[List[E]] = {
       (ts,es) match {
          case (List(),List()) => Some(List())
          case (t::ts,e::es) =>
            typeCheck(ts,es) match {
              case None => None
              case Some(e2) =>
                val t2 = e match {
                  case ECall(TFun(_,r),_,_) => r
                  case e:E => e.t
                }
                if(t==t2) Some(e::e2)
                else if(implicitConversions.contains(t->t2)) Some(implicitConversions(t->t2)(e)::e2)
                else None
            }
          case _ => None
        }
      }
      // 関数を全て取り出す
      def fns(funs:List[TFun]):Option[E] = funs match {
        case List() => None
        case (i@TFun(l,r))::ls =>
          typeCheck(l, xs) match {
            case None => fns(ls)
            case Some(e) => Some(ECall(r, EId(i,id), e))
          }
      }
      fns(functions(id)) match {
        case None=> throw new Exception("not found method "+e)
        case Some(e) => e
      }
  }


  // 関数定義表

  var functions = Map[String,List[TFun]](
    "add"->List(
          TFun(List(TInt(),TInt()),TInt()),
      TFun(List(TStr(),TStr()),TStr()),
      TFun(List(TFloat(),TFloat()),TFloat())
          )
  )

  // 暗黙の型変換の表
  var implicitConversions = Map[(TType,TType),(E)=>E] (
    (TInt(),TStr()) -> ((a:E)=>ECast(TStr(),a)),
    (TFloat(),TStr()) -> ((a:E)=>ECast(TStr(),a)),
    (TFloat(),TInt()) -> ((a:E)=>ECast(TFloat(),a))
  )
}