Skip to content

Instantly share code, notes, and snippets.

@phenan
Created October 20, 2017 15:05
Show Gist options
  • Save phenan/02e3c4890ce89acb6c667630831f9e98 to your computer and use it in GitHub Desktop.
Save phenan/02e3c4890ce89acb6c667630831f9e98 to your computer and use it in GitHub Desktop.
バイナリ用パーザコンビネータ
import java.io._
import scalaz.std.list._
import scalaz.syntax.traverse._
// Tries.scala (https://gist.github.com/phenan/63833c2cc715c96c02a4c33e17d9e2ac)
import tries._
/**
* Created by phenan on 2017/10/18.
*/
object ParserExamples extends ByteParsers {
def u2_s4_data: ByteParser[(Int, Int)] = for {
a <- u2
b <- s4
} yield (a, b)
def length_bytes: ByteParser[Array[Byte]] = for {
n <- u2
bs <- bytes(n)
} yield bs
}
trait ByteParsers {
val u1 = ByteParser(_.u1)
val u2 = ByteParser(_.u2)
val s1 = ByteParser(_.s1)
val s2 = ByteParser(_.s2)
val s4 = ByteParser(_.s4)
val s8 = ByteParser(_.s8)
val f4 = ByteParser(_.f4)
val f8 = ByteParser(_.f8)
val utf = ByteParser(_.utf)
def ret [T] (v: => T): ByteParser[T] = ByteParser(_ => Tries(v))
def lift [T] (v: => Tries[T]): ByteParser[T] = ByteParser(_ => v)
def failure (e: => Exception): ByteParser[Nothing] = ByteParser(_ => Fails(e))
def bytes (n: Int) = ByteParser(_.bytes(n))
def list [T] (p: ByteParser[T]): ByteParser[List[T]] = u2 >>= p.rep
}
case class ByteParser[+T] private (val perform: ByteReader => Tries[T]) {
def parse (file: String): Tries[T] = ByteReader.read(file)(perform)
def parse (file: File): Tries[T] = ByteReader.read(file)(perform)
def parse (bytes: Array[Byte]): Tries[T] = ByteReader.read(bytes)(perform)
def parse (in: => InputStream): Tries[T] = ByteReader.read(in)(perform)
}
object ByteParser {
implicit class ByteParserUtils [T] (parser: => ByteParser[T]) {
def map [U] (f: T => U): ByteParser[U] = ByteParser { r => parser.perform(r).map(f) }
def flatMap [U] (f: T => ByteParser[U]): ByteParser[U] = ByteParser { r => parser.perform(r).flatMap(t => f(t).perform(r)) }
def filter (f: T => Boolean): ByteParser[T] = ByteParser { r => parser.perform(r).filters(f) }
def withFilter (f: T => Boolean): WithFilter[T] = new WithFilter(parser.perform, f)
def >>= [U] (f: T => ByteParser[U]): ByteParser[U] = flatMap(f)
def rep (n: Int): ByteParser[List[T]] = ByteParser { r =>
(0 until n).toList.traverse[Tries, T](_ => parser.perform(r))
}
}
class WithFilter[T] (run: ByteReader => Tries[T], filter: T => Boolean) {
final def map [U] (f: T => U): ByteParser[U] = ByteParser { r => run(r).filters(filter).map(f) }
final def flatMap [U] (f: T => ByteParser[U]): ByteParser[U] = ByteParser { r => run(r).filters(filter).flatMap(t => f(t).perform(r)) }
final def withFilter (f: T => Boolean): WithFilter[T] = new WithFilter(run, { t => filter(t) && f(t) })
}
}
class ByteReader private (in: DataInputStream) {
def u1: Tries[Int] = Tries { in.readUnsignedByte() }
def u2: Tries[Int] = Tries { in.readUnsignedShort() }
def s1: Tries[Byte] = Tries { in.readByte() }
def s2: Tries[Short] = Tries { in.readShort() }
def s4: Tries[Int] = Tries { in.readInt() }
def s8: Tries[Long] = Tries { in.readLong() }
def f4: Tries[Float] = Tries { in.readFloat() }
def f8: Tries[Double] = Tries { in.readDouble() }
def bytes(size: Int): Tries[Array[Byte]] = Tries {
val bs = new Array[Byte](size)
in.read(bs)
bs
}
def utf: Tries[String] = for {
size <- u2
bs <- bytes(size)
} yield new String(bs, "UTF-8")
private def close() = Tries { in.close() }
}
object ByteReader {
def read [T] (file: String)(f: ByteReader => Tries[T]): Tries[T] = read(new FileInputStream(file))(f)
def read [T] (file: File)(f: ByteReader => Tries[T]): Tries[T] = read(new FileInputStream(file))(f)
def read [T] (bytes: Array[Byte])(f: ByteReader => Tries[T]): Tries[T] = read(new ByteArrayInputStream(bytes))(f)
def read [T] (in: => InputStream)(f: ByteReader => Tries[T]): Tries[T] = for {
r <- Tries { new ByteReader(new DataInputStream(new BufferedInputStream(in))) }
v <- f(r)
_ <- r.close()
} yield v
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment