うはwww Scala で Grass を実装してみたwwwwwwww

Scalaの勉強がてら ちょっと草植えときますね型言語 Grass を実装してみましたwwwwwww
今更感が今更だけど大自然の意志には逆らえないwwwwwww

    _, ._
  ( ・ω・) んも〜
  ○={=}〇,
   |:::::::::\, ', ´
、、、、し 、、、(((.@)wvwwWWwvwwWwwvwwwwWWWwwWw


事前目標

  • Scalaに慣れる。
  • javaのGrass実装を写経するのではなく(俺なりに)関数型言語っぽく書く。
  • Grassの仕様を理解する。

コード

class Grass {
  class CED(c :List[Insn], e :List[Value], d :List[CE]) {
    val code = c
    val env = e
    val dump = d
  }

  class CE(c :List[Insn], e :List[Value]) {
    val code = c
    val env = e
  }

  val ENV = List[Value](In, CharFn('w'), Succ, Out)
  val DUMP : List[CE] = List(new CE(Nil, Nil), new CE(List(App(1, 1)), Nil))
 
  def run(str : String) : Unit = evalGrass(new CED(parse(str), ENV, DUMP))

  def evalGrass(ced :CED) : Unit = {
    def loop(ced :CED) : CED = ced.code match {
      case head::tail => loop(eval(head, new CED(tail, ced.env, ced.dump)))
      case Nil => 
        if (!ced.dump.isEmpty) {
          loop(new CED(ced.dump.last.code, ced.dump.last.env:::List(ced.env.last), ced.dump.slice(0, ced.dump.length-1))) 
        } else {
          null
        }
    }
    loop(ced)
  }
  
  val PATTERN_ABS = "^(w+)(.*)".r
  val PATTERN_APP = "^(W+)(w+)(.*)".r

  def parse(src : String) : List[Insn] = {
    normalize(src).split("v").toList.flatMap(_ match {
      case PATTERN_ABS(x, y) => List(Abs(x.length, parseBody(y)))
      case PATTERN_APP(m, n, body) => App(m.length, n.length)::parseBody(body)
      case _ => throw new Exception("parse error")
    })
  }

  def normalize(s : String) = {
    "[^wWv]".r.replaceAllIn(
      "\\A[^w]*".r.replaceFirstIn(
        s.replaceAll("w", "w").
          replaceAll("W", "W").
          replaceAll("v", "v"),
        ""),
      "")
  }
  
  def parseBody(src : String) : List[Insn] = {
    def _parseBody(src : String, code : List[Insn]) : List[Insn] = src match {
      case PATTERN_APP(m, n, body) => _parseBody(body, code:::List(App(m.length, n.length)))
      case _ => code
    }
    _parseBody(src, Nil)
  }
  
  abstract class Insn
  case class App(m :Int, n :Int) extends Insn
  case class Abs(n :Int, code :List[Insn]) extends Insn

  def eval(insn :Insn, ced :CED) : CED = insn match {
    case App(m, n) => app(ced.env(ced.env.length - m), ced.env(ced.env.length - n), ced)
    case Abs(1, c) => new CED(ced.code, ced.env:::List(Fn(c, ced.env)), ced.dump)
    case Abs(n, c) => new CED(ced.code, ced.env:::List(Fn(List(Abs(n - 1, c)), ced.env)), ced.dump)
  }
  
  abstract class Value
  case class Fn(code : List[Insn], env : List[Value]) extends Value { override def toString() :String = "Fn" }
  case class CharFn(char : Char) extends Value
  case object Succ extends Value
  case object Out extends Value
  case object In extends Value

  val ChurchTrue = Fn(List(Abs(1, List(App(3, 2)))), List(Fn(Nil, Nil)))
  val ChurchFalse = Fn(List(Abs(1, Nil)), Nil)

  def app(v :Value, arg :Value, ced :CED) : CED = v match {
    case Fn(c, e) => new CED(c, e:::List(arg), ced.dump:::List(new CE(ced.code, ced.env)))
    case CharFn(char) => new CED(ced.code, ced.env:::List(if (char == getChar(arg)) ChurchTrue else ChurchFalse), ced.dump)
    case Succ => new CED(ced.code, ced.env:::List(CharFn(((getChar(arg) + 1) % 256).asInstanceOf[Char])), ced.dump)
    case Out => 
      System.out.print(getChar(arg))
      System.out.flush()
      new CED(ced.code, ced.env:::List(arg), ced.dump)
    case In => new CED(ced.code, ced.env:::List(CharFn(System.in.read().asInstanceOf[Char])), ced.dump)
  }
  
  def getChar(v :Value) : Char = v match {
    case CharFn(char) => char
    case _ => throw new Exception("eval error at getChar")
  }
}

100行ぐらいに収まりました。

実行例

object Main {
  def main(args : Array[String]) = {
    var grass = new Grass()
    // w
    grass.run("wWWwwww")
    println()
    // x
    grass.run("wWWWwwwwWWWw")
    println()
    // ww
     grass.run("wwWWwvwwwwWWWwwWwwWWWWWWwwwwWwwvwWWwwwWwwwwWwwwwwwWwwwwwwwww")
    println()
    // Hello, world!
    grass.run("wvwWwwwwWwwwwwwWWWWWwWWWWWwwwwvwwwwWWWwwWwwWWWWWWwwwwWwwvwWW" + 
              "wWwwvwwWWwvwWWWwwWWWWWwwwWwwWWWWWWwWWWWWWWwWWWWwWWWWWwWWWWWW" + 
              "wWWWWWWWWWWWWWWwwwwwwwwWwWwWWWwwWWWWwwwwwwwWWWWWwwwwwwwWWWWW" +
              "WwwwwwwwWWWWWWWWWWWWWWWWWWWWWwwwwwwwwwwwwwwwwwwwwwWwwwwwwwww" + 
              "wwwwwwwwwwwWwwwwwwwwwwwwwWwwwwwwWWwwwwwwWWWwwwwwwWWWWWWwwwww" + 
              "wwwwwwwwwwwwwwwWwwwwwwwwwwWWwwwwWWWwwwwWWWWwWWWWWwwwwwwwwwww" + 
              "wwwwwwwWWWWWWWWWWWwWwwwWWwWWWwWWWWwWWWWWWWWWWWWWWWWWwwwwwwww" + 
              "wwwwwwwwwWwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwWwwwwwwwwwww" + 
              "WWwwwwwwwwwwwWWWwwwwwwwWWWWwWWWWWwwwwwwwwWWWWWWwwwwwwwwwwwww" + 
              "wwwwwwwwWWWWWWWwwwwwwwwwwwwwwwwwwwwwwwwwwwwWWWWWWWWWwwwwwwww" + 
              "WwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwWWwwwwwwwwwwwwwWWWwwwwwwwww" + 
              "wwwwWWWWwwwwwwwwWWWWWwwwwwwwwwwwwwwwwwwwwwwwwwwWWWWWWwwwwwww" + 
              "wwwwwwwwwwwwwwwwww")
  }
}

芝が広がりんぐwwwwwww