summaryrefslogtreecommitdiff
path: root/examples/scala-js/ir/src/main/scala/scala/scalajs/ir/Serializers.scala
diff options
context:
space:
mode:
Diffstat (limited to 'examples/scala-js/ir/src/main/scala/scala/scalajs/ir/Serializers.scala')
-rw-r--r--examples/scala-js/ir/src/main/scala/scala/scalajs/ir/Serializers.scala790
1 files changed, 790 insertions, 0 deletions
diff --git a/examples/scala-js/ir/src/main/scala/scala/scalajs/ir/Serializers.scala b/examples/scala-js/ir/src/main/scala/scala/scalajs/ir/Serializers.scala
new file mode 100644
index 0000000..04ec5c2
--- /dev/null
+++ b/examples/scala-js/ir/src/main/scala/scala/scalajs/ir/Serializers.scala
@@ -0,0 +1,790 @@
+/* __ *\
+** ________ ___ / / ___ __ ____ Scala.js IR **
+** / __/ __// _ | / / / _ | __ / // __/ (c) 2014, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ |/_// /_\ \ http://scala-js.org/ **
+** /____/\___/_/ |_/____/_/ | |__/ /____/ **
+** |/____/ **
+\* */
+
+
+package scala.scalajs.ir
+
+import scala.annotation.switch
+
+import java.io._
+import java.net.URI
+
+import scala.collection.mutable
+
+import Position._
+import Trees._
+import Types._
+import Tags._
+
+import Utils.JumpBackByteArrayOutputStream
+
+object Serializers {
+ def serialize(stream: OutputStream, tree: Tree): Unit = {
+ new Serializer().serialize(stream, tree)
+ }
+
+ def deserialize(stream: InputStream, version: String): Tree = {
+ new Deserializer(stream, version).deserialize()
+ }
+
+ // true for easier debugging (not for "production", it adds 8 bytes per node)
+ private final val UseDebugMagic = false
+ private final val DebugMagic = 0x3fa8ef84
+ private final val PosDebugMagic = 0x65f0ec32
+
+ private object PositionFormat {
+ /* Positions are serialized incrementally as diffs wrt the last position.
+ *
+ * Formats are (the first byte is decomposed in bits):
+ *
+ * 1st byte | next bytes | description
+ * -----------------------------------------
+ * ccccccc0 | | Column diff (7-bit signed)
+ * llllll01 | CC | Line diff (6-bit signed), column (8-bit unsigned)
+ * ____0011 | LL LL CC | Line diff (16-bit signed), column (8-bit unsigned)
+ * ____0111 | 12 bytes | File index, line, column (all 32-bit signed)
+ * 11111111 | | NoPosition (is not compared/stored in last position)
+ *
+ * Underscores are irrelevant and must be set to 0.
+ */
+
+ final val Format1Mask = 0x01
+ final val Format1MaskValue = 0x00
+ final val Format1Shift = 1
+
+ final val Format2Mask = 0x03
+ final val Format2MaskValue = 0x01
+ final val Format2Shift = 2
+
+ final val Format3Mask = 0x0f
+ final val Format3MaskValue = 0x03
+
+ final val FormatFullMask = 0x0f
+ final val FormatFullMaskValue = 0x7
+
+ final val FormatNoPositionValue = -1
+ }
+
+ private final class Serializer {
+ private[this] val bufferUnderlying = new JumpBackByteArrayOutputStream
+ private[this] val buffer = new DataOutputStream(bufferUnderlying)
+
+ private[this] val files = mutable.ListBuffer.empty[URI]
+ private[this] val fileIndexMap = mutable.Map.empty[URI, Int]
+ private def fileToIndex(file: URI): Int =
+ fileIndexMap.getOrElseUpdate(file, (files += file).size - 1)
+
+ private[this] val strings = mutable.ListBuffer.empty[String]
+ private[this] val stringIndexMap = mutable.Map.empty[String, Int]
+ private def stringToIndex(str: String): Int =
+ stringIndexMap.getOrElseUpdate(str, (strings += str).size - 1)
+
+ private[this] var lastPosition: Position = Position.NoPosition
+
+ def serialize(stream: OutputStream, tree: Tree): Unit = {
+ // Write tree to buffer and record files and strings
+ writeTree(tree)
+
+ val s = new DataOutputStream(stream)
+
+ // Emit the files
+ s.writeInt(files.size)
+ files.foreach(f => s.writeUTF(f.toString))
+
+ // Emit the strings
+ s.writeInt(strings.size)
+ strings.foreach(s.writeUTF)
+
+ // Paste the buffer
+ bufferUnderlying.writeTo(s)
+
+ s.flush()
+ }
+
+ def writeTree(tree: Tree): Unit = {
+ import buffer._
+ writePosition(tree.pos)
+ tree match {
+ case EmptyTree =>
+ writeByte(TagEmptyTree)
+
+ case VarDef(ident, vtpe, mutable, rhs) =>
+ writeByte(TagVarDef)
+ writeIdent(ident); writeType(vtpe); writeBoolean(mutable); writeTree(rhs)
+
+ case ParamDef(ident, ptpe, mutable) =>
+ writeByte(TagParamDef)
+ writeIdent(ident); writeType(ptpe); writeBoolean(mutable)
+
+ case Skip() =>
+ writeByte(TagSkip)
+
+ case Block(stats) =>
+ writeByte(TagBlock)
+ writeTrees(stats)
+
+ case Labeled(label, tpe, body) =>
+ writeByte(TagLabeled)
+ writeIdent(label); writeType(tpe); writeTree(body)
+
+ case Assign(lhs, rhs) =>
+ writeByte(TagAssign)
+ writeTree(lhs); writeTree(rhs)
+
+ case Return(expr, label) =>
+ writeByte(TagReturn)
+ writeTree(expr); writeOptIdent(label)
+
+ case If(cond, thenp, elsep) =>
+ writeByte(TagIf)
+ writeTree(cond); writeTree(thenp); writeTree(elsep)
+ writeType(tree.tpe)
+
+ case While(cond, body, label) =>
+ writeByte(TagWhile)
+ writeTree(cond); writeTree(body); writeOptIdent(label)
+
+ case DoWhile(body, cond, label) =>
+ writeByte(TagDoWhile)
+ writeTree(body); writeTree(cond); writeOptIdent(label)
+
+ case Try(block, errVar, handler, finalizer) =>
+ writeByte(TagTry)
+ writeTree(block); writeIdent(errVar); writeTree(handler); writeTree(finalizer)
+ writeType(tree.tpe)
+
+ case Throw(expr) =>
+ writeByte(TagThrow)
+ writeTree(expr)
+
+ case Continue(label) =>
+ writeByte(TagContinue)
+ writeOptIdent(label)
+
+ case Match(selector, cases, default) =>
+ writeByte(TagMatch)
+ writeTree(selector)
+ writeInt(cases.size)
+ cases foreach { caze =>
+ writeTrees(caze._1); writeTree(caze._2)
+ }
+ writeTree(default)
+ writeType(tree.tpe)
+
+ case Debugger() =>
+ writeByte(TagDebugger)
+
+ case New(cls, ctor, args) =>
+ writeByte(TagNew)
+ writeClassType(cls); writeIdent(ctor); writeTrees(args)
+
+ case LoadModule(cls) =>
+ writeByte(TagLoadModule)
+ writeClassType(cls)
+
+ case StoreModule(cls, value) =>
+ writeByte(TagStoreModule)
+ writeClassType(cls); writeTree(value)
+
+ case Select(qualifier, item, mutable) =>
+ writeByte(TagSelect)
+ writeTree(qualifier); writeIdent(item); writeBoolean(mutable)
+ writeType(tree.tpe)
+
+ case Apply(receiver, method, args) =>
+ writeByte(TagApply)
+ writeTree(receiver); writeIdent(method); writeTrees(args)
+ writeType(tree.tpe)
+
+ case StaticApply(receiver, cls, method, args) =>
+ writeByte(TagStaticApply)
+ writeTree(receiver); writeClassType(cls); writeIdent(method); writeTrees(args)
+ writeType(tree.tpe)
+
+ case TraitImplApply(impl, method, args) =>
+ writeByte(TagTraitImplApply)
+ writeClassType(impl); writeIdent(method); writeTrees(args)
+ writeType(tree.tpe)
+
+ case UnaryOp(op, lhs) =>
+ writeByte(TagUnaryOp)
+ writeByte(op); writeTree(lhs)
+
+ case BinaryOp(op, lhs, rhs) =>
+ writeByte(TagBinaryOp)
+ writeByte(op); writeTree(lhs); writeTree(rhs)
+
+ case NewArray(tpe, lengths) =>
+ writeByte(TagNewArray)
+ writeArrayType(tpe); writeTrees(lengths)
+
+ case ArrayValue(tpe, elems) =>
+ writeByte(TagArrayValue)
+ writeArrayType(tpe); writeTrees(elems)
+
+ case ArrayLength(array) =>
+ writeByte(TagArrayLength)
+ writeTree(array)
+
+ case ArraySelect(array, index) =>
+ writeByte(TagArraySelect)
+ writeTree(array); writeTree(index)
+ writeType(tree.tpe)
+
+ case RecordValue(tpe, elems) =>
+ writeByte(TagRecordValue)
+ writeType(tpe); writeTrees(elems)
+
+ case IsInstanceOf(expr, cls) =>
+ writeByte(TagIsInstanceOf)
+ writeTree(expr); writeReferenceType(cls)
+
+ case AsInstanceOf(expr, cls) =>
+ writeByte(TagAsInstanceOf)
+ writeTree(expr); writeReferenceType(cls)
+
+ case Unbox(expr, charCode) =>
+ writeByte(TagUnbox)
+ writeTree(expr); writeByte(charCode.toByte)
+
+ case GetClass(expr) =>
+ writeByte(TagGetClass)
+ writeTree(expr)
+
+ case CallHelper(helper, args) =>
+ writeByte(TagCallHelper)
+ writeString(helper); writeTrees(args)
+ writeType(tree.tpe)
+
+ case JSNew(ctor, args) =>
+ writeByte(TagJSNew)
+ writeTree(ctor); writeTrees(args)
+
+ case JSDotSelect(qualifier, item) =>
+ writeByte(TagJSDotSelect)
+ writeTree(qualifier); writeIdent(item)
+
+ case JSBracketSelect(qualifier, item) =>
+ writeByte(TagJSBracketSelect)
+ writeTree(qualifier); writeTree(item)
+
+ case JSFunctionApply(fun, args) =>
+ writeByte(TagJSFunctionApply)
+ writeTree(fun); writeTrees(args)
+
+ case JSDotMethodApply(receiver, method, args) =>
+ writeByte(TagJSDotMethodApply)
+ writeTree(receiver); writeIdent(method); writeTrees(args)
+
+ case JSBracketMethodApply(receiver, method, args) =>
+ writeByte(TagJSBracketMethodApply)
+ writeTree(receiver); writeTree(method); writeTrees(args)
+
+ case JSDelete(prop) =>
+ writeByte(TagJSDelete)
+ writeTree(prop)
+
+ case JSUnaryOp(op, lhs) =>
+ writeByte(TagJSUnaryOp)
+ writeString(op); writeTree(lhs)
+
+ case JSBinaryOp(op, lhs, rhs) =>
+ writeByte(TagJSBinaryOp)
+ writeString(op); writeTree(lhs); writeTree(rhs)
+
+ case JSArrayConstr(items) =>
+ writeByte(TagJSArrayConstr)
+ writeTrees(items)
+
+ case JSObjectConstr(fields) =>
+ writeByte(TagJSObjectConstr)
+ writeInt(fields.size)
+ fields foreach { field =>
+ writePropertyName(field._1); writeTree(field._2)
+ }
+
+ case JSEnvInfo() =>
+ writeByte(TagJSEnvInfo)
+
+ // Literals
+
+ case Undefined() =>
+ writeByte(TagUndefined)
+
+ case UndefinedParam() =>
+ writeByte(TagUndefinedParam)
+ writeType(tree.tpe)
+
+ case Null() =>
+ writeByte(TagNull)
+
+ case BooleanLiteral(value) =>
+ writeByte(TagBooleanLiteral)
+ writeBoolean(value)
+
+ case IntLiteral(value) =>
+ writeByte(TagIntLiteral)
+ writeInt(value)
+
+ case LongLiteral(value) =>
+ writeByte(TagLongLiteral)
+ writeLong(value)
+
+ case FloatLiteral(value) =>
+ writeByte(TagFloatLiteral)
+ writeFloat(value)
+
+ case DoubleLiteral(value) =>
+ writeByte(TagDoubleLiteral)
+ writeDouble(value)
+
+ case StringLiteral(value) =>
+ writeByte(TagStringLiteral)
+ writeString(value)
+
+ case ClassOf(cls) =>
+ writeByte(TagClassOf)
+ writeReferenceType(cls)
+
+ case VarRef(ident, mutable) =>
+ writeByte(TagVarRef)
+ writeIdent(ident); writeBoolean(mutable)
+ writeType(tree.tpe)
+
+ case This() =>
+ writeByte(TagThis)
+ writeType(tree.tpe)
+
+ case Closure(captureParams, params, body, captureValues) =>
+ writeByte(TagClosure)
+ writeTrees(captureParams)
+ writeTrees(params)
+ writeTree(body)
+ writeTrees(captureValues)
+
+ case ClassDef(name, kind, parent, ancestors, defs) =>
+ writeByte(TagClassDef)
+ writeIdent(name)
+ writeByte(ClassKind.toByte(kind))
+ writeOptIdent(parent)
+ writeIdents(ancestors)
+ writeTrees(defs)
+
+ case methodDef: MethodDef =>
+ val MethodDef(name, args, resultType, body) = methodDef
+
+ writeByte(TagMethodDef)
+ writeOptHash(methodDef.hash)
+
+ // Prepare for back-jump and write dummy length
+ bufferUnderlying.markJump()
+ writeInt(-1)
+
+ // Write out method def
+ writePropertyName(name); writeTrees(args); writeType(resultType); writeTree(body)
+
+ // Jump back and write true length
+ val length = bufferUnderlying.jumpBack()
+ writeInt(length)
+ bufferUnderlying.continue()
+
+ case PropertyDef(name, getter, arg, setter) =>
+ writeByte(TagPropertyDef)
+ writePropertyName(name); writeTree(getter); writeTree(arg); writeTree(setter)
+
+ case ConstructorExportDef(fullName, args, body) =>
+ writeByte(TagConstructorExportDef)
+ writeString(fullName); writeTrees(args); writeTree(body)
+
+ case ModuleExportDef(fullName) =>
+ writeByte(TagModuleExportDef)
+ writeString(fullName)
+ }
+ if (UseDebugMagic)
+ writeInt(DebugMagic)
+ }
+
+ def writeTrees(trees: List[Tree]): Unit = {
+ buffer.writeInt(trees.size)
+ trees.foreach(writeTree)
+ }
+
+ def writeIdent(ident: Ident): Unit = {
+ writePosition(ident.pos)
+ writeString(ident.name); writeString(ident.originalName.getOrElse(""))
+ }
+
+ def writeIdents(idents: List[Ident]): Unit = {
+ buffer.writeInt(idents.size)
+ idents.foreach(writeIdent)
+ }
+
+ def writeOptIdent(optIdent: Option[Ident]): Unit = {
+ buffer.writeBoolean(optIdent.isDefined)
+ optIdent.foreach(writeIdent)
+ }
+
+ def writeType(tpe: Type): Unit = {
+ tpe match {
+ case AnyType => buffer.write(TagAnyType)
+ case NothingType => buffer.write(TagNothingType)
+ case UndefType => buffer.write(TagUndefType)
+ case BooleanType => buffer.write(TagBooleanType)
+ case IntType => buffer.write(TagIntType)
+ case LongType => buffer.write(TagLongType)
+ case FloatType => buffer.write(TagFloatType)
+ case DoubleType => buffer.write(TagDoubleType)
+ case StringType => buffer.write(TagStringType)
+ case NullType => buffer.write(TagNullType)
+ case NoType => buffer.write(TagNoType)
+
+ case tpe: ClassType =>
+ buffer.write(TagClassType)
+ writeClassType(tpe)
+
+ case tpe: ArrayType =>
+ buffer.write(TagArrayType)
+ writeArrayType(tpe)
+
+ case RecordType(fields) =>
+ buffer.write(TagRecordType)
+ buffer.writeInt(fields.size)
+ for (RecordType.Field(name, originalName, tpe, mutable) <- fields) {
+ writeString(name)
+ writeString(originalName.getOrElse(""))
+ writeType(tpe)
+ buffer.writeBoolean(mutable)
+ }
+ }
+ }
+
+ def writeClassType(tpe: ClassType): Unit =
+ writeString(tpe.className)
+
+ def writeArrayType(tpe: ArrayType): Unit = {
+ writeString(tpe.baseClassName)
+ buffer.writeInt(tpe.dimensions)
+ }
+
+ def writeReferenceType(tpe: ReferenceType): Unit =
+ writeType(tpe)
+
+ def writePropertyName(name: PropertyName): Unit = {
+ name match {
+ case name: Ident => buffer.writeBoolean(true); writeIdent(name)
+ case name: StringLiteral => buffer.writeBoolean(false); writeTree(name)
+ }
+ }
+
+ def writePosition(pos: Position): Unit = {
+ import buffer._
+ import PositionFormat._
+
+ def writeFull(): Unit = {
+ writeByte(FormatFullMaskValue)
+ writeInt(fileToIndex(pos.source))
+ writeInt(pos.line)
+ writeInt(pos.column)
+ }
+
+ if (pos == Position.NoPosition) {
+ writeByte(FormatNoPositionValue)
+ } else if (lastPosition == Position.NoPosition ||
+ pos.source != lastPosition.source) {
+ writeFull()
+ lastPosition = pos
+ } else {
+ val line = pos.line
+ val column = pos.column
+ val lineDiff = line - lastPosition.line
+ val columnDiff = column - lastPosition.column
+ val columnIsByte = column >= 0 && column < 256
+
+ if (lineDiff == 0 && columnDiff >= -64 && columnDiff < 64) {
+ writeByte((columnDiff << Format1Shift) | Format1MaskValue)
+ } else if (lineDiff >= -32 && lineDiff < 32 && columnIsByte) {
+ writeByte((lineDiff << Format2Shift) | Format2MaskValue)
+ writeByte(column)
+ } else if (lineDiff >= Short.MinValue && lineDiff <= Short.MaxValue && columnIsByte) {
+ writeByte(Format3MaskValue)
+ writeShort(lineDiff)
+ writeByte(column)
+ } else {
+ writeFull()
+ }
+
+ lastPosition = pos
+ }
+
+ if (UseDebugMagic)
+ writeInt(PosDebugMagic)
+ }
+
+ def writeOptHash(optHash: Option[TreeHash]): Unit = {
+ buffer.writeBoolean(optHash.isDefined)
+ for (hash <- optHash) {
+ buffer.write(hash.treeHash)
+ buffer.write(hash.posHash)
+ }
+ }
+
+ def writeString(s: String): Unit =
+ buffer.writeInt(stringToIndex(s))
+ }
+
+ private final class Deserializer(stream: InputStream, sourceVersion: String) {
+ private[this] val input = new DataInputStream(stream)
+
+ private[this] val files =
+ Array.fill(input.readInt())(new URI(input.readUTF()))
+
+ private[this] val strings =
+ Array.fill(input.readInt())(input.readUTF())
+
+ private[this] var lastPosition: Position = Position.NoPosition
+
+ def deserialize(): Tree = {
+ readTree()
+ }
+
+ def readTree(): Tree = {
+ import input._
+ implicit val pos = readPosition()
+ val tag = readByte()
+ val result = (tag: @switch) match {
+ case TagEmptyTree => EmptyTree
+
+ case TagVarDef => VarDef(readIdent(), readType(), readBoolean(), readTree())
+ case TagParamDef => ParamDef(readIdent(), readType(), readBoolean())
+
+ case TagSkip => Skip()
+ case TagBlock => Block(readTrees())
+ case TagLabeled => Labeled(readIdent(), readType(), readTree())
+ case TagAssign => Assign(readTree(), readTree())
+ case TagReturn => Return(readTree(), readOptIdent())
+ case TagIf => If(readTree(), readTree(), readTree())(readType())
+ case TagWhile => While(readTree(), readTree(), readOptIdent())
+ case TagDoWhile => DoWhile(readTree(), readTree(), readOptIdent())
+ case TagTry => Try(readTree(), readIdent(), readTree(), readTree())(readType())
+ case TagThrow => Throw(readTree())
+ case TagContinue => Continue(readOptIdent())
+ case TagMatch =>
+ Match(readTree(), List.fill(readInt()) {
+ (readTrees().map(_.asInstanceOf[Literal]), readTree())
+ }, readTree())(readType())
+ case TagDebugger => Debugger()
+
+ case TagNew => New(readClassType(), readIdent(), readTrees())
+ case TagLoadModule => LoadModule(readClassType())
+ case TagStoreModule => StoreModule(readClassType(), readTree())
+ case TagSelect => Select(readTree(), readIdent(), readBoolean())(readType())
+ case TagApply => Apply(readTree(), readIdent(), readTrees())(readType())
+ case TagStaticApply => StaticApply(readTree(), readClassType(), readIdent(), readTrees())(readType())
+ case TagTraitImplApply => TraitImplApply(readClassType(), readIdent(), readTrees())(readType())
+ case TagUnaryOp => UnaryOp(readByte(), readTree())
+ case TagBinaryOp => BinaryOp(readByte(), readTree(), readTree())
+ case TagNewArray => NewArray(readArrayType(), readTrees())
+ case TagArrayValue => ArrayValue(readArrayType(), readTrees())
+ case TagArrayLength => ArrayLength(readTree())
+ case TagArraySelect => ArraySelect(readTree(), readTree())(readType())
+ case TagRecordValue => RecordValue(readType().asInstanceOf[RecordType], readTrees())
+ case TagIsInstanceOf => IsInstanceOf(readTree(), readReferenceType())
+ case TagAsInstanceOf => AsInstanceOf(readTree(), readReferenceType())
+ case TagUnbox => Unbox(readTree(), readByte().toChar)
+ case TagGetClass => GetClass(readTree())
+ case TagCallHelper => CallHelper(readString(), readTrees())(readType())
+
+ case TagJSNew => JSNew(readTree(), readTrees())
+ case TagJSDotSelect => JSDotSelect(readTree(), readIdent())
+ case TagJSBracketSelect => JSBracketSelect(readTree(), readTree())
+ case TagJSFunctionApply => JSFunctionApply(readTree(), readTrees())
+ case TagJSDotMethodApply => JSDotMethodApply(readTree(), readIdent(), readTrees())
+ case TagJSBracketMethodApply => JSBracketMethodApply(readTree(), readTree(), readTrees())
+ case TagJSDelete => JSDelete(readTree())
+ case TagJSUnaryOp => JSUnaryOp(readString(), readTree())
+ case TagJSBinaryOp => JSBinaryOp(readString(), readTree(), readTree())
+ case TagJSArrayConstr => JSArrayConstr(readTrees())
+ case TagJSObjectConstr =>
+ JSObjectConstr(List.fill(readInt())((readPropertyName(), readTree())))
+ case TagJSEnvInfo => JSEnvInfo()
+
+ case TagUndefined => Undefined()
+ case TagUndefinedParam => UndefinedParam()(readType())
+ case TagNull => Null()
+ case TagBooleanLiteral => BooleanLiteral(readBoolean())
+ case TagIntLiteral => IntLiteral(readInt())
+ case TagLongLiteral => LongLiteral(readLong())
+ case TagFloatLiteral => FloatLiteral(readFloat())
+ case TagDoubleLiteral => DoubleLiteral(readDouble())
+ case TagStringLiteral => StringLiteral(readString())
+ case TagClassOf => ClassOf(readReferenceType())
+
+ case TagVarRef => VarRef(readIdent(), readBoolean())(readType())
+ case TagThis => This()(readType())
+ case TagClosure =>
+ Closure(readParamDefs(), readParamDefs(), readTree(), readTrees())
+
+ case TagClassDef =>
+ val name = readIdent()
+ val kind = ClassKind.fromByte(readByte())
+ val parent = readOptIdent()
+ val ancestors = readIdents()
+ val defs = readTrees()
+ ClassDef(name, kind, parent, ancestors, defs)
+
+ case TagMethodDef =>
+ val optHash = readOptHash()
+ // read and discard the length
+ val len = readInt()
+ assert(len >= 0)
+ MethodDef(readPropertyName(), readParamDefs(), readType(), readTree())(optHash)
+ case TagPropertyDef =>
+ PropertyDef(readPropertyName(), readTree(),
+ readTree().asInstanceOf[ParamDef], readTree())
+ case TagConstructorExportDef =>
+ ConstructorExportDef(readString(), readParamDefs(), readTree())
+ case TagModuleExportDef =>
+ ModuleExportDef(readString())
+ }
+ if (UseDebugMagic) {
+ val magic = readInt()
+ assert(magic == DebugMagic,
+ s"Bad magic after reading a ${result.getClass}!")
+ }
+ result
+ }
+
+ def readTrees(): List[Tree] =
+ List.fill(input.readInt())(readTree())
+
+ def readParamDefs(): List[ParamDef] =
+ readTrees().map(_.asInstanceOf[ParamDef])
+
+ def readIdent(): Ident = {
+ implicit val pos = readPosition()
+ val name = readString()
+ val originalName = readString()
+ Ident(name, if (originalName.isEmpty) None else Some(originalName))
+ }
+
+ def readIdents(): List[Ident] =
+ List.fill(input.readInt())(readIdent())
+
+ def readOptIdent(): Option[Ident] = {
+ if (input.readBoolean()) Some(readIdent())
+ else None
+ }
+
+ def readType(): Type = {
+ val tag = input.readByte()
+ (tag: @switch) match {
+ case TagAnyType => AnyType
+ case TagNothingType => NothingType
+ case TagUndefType => UndefType
+ case TagBooleanType => BooleanType
+ case TagIntType => IntType
+ case TagLongType => LongType
+ case TagFloatType => FloatType
+ case TagDoubleType => DoubleType
+ case TagStringType => StringType
+ case TagNullType => NullType
+ case TagNoType => NoType
+
+ case TagClassType => readClassType()
+ case TagArrayType => readArrayType()
+
+ case TagRecordType =>
+ RecordType(List.fill(input.readInt()) {
+ val name = readString()
+ val originalName = readString()
+ val tpe = readType()
+ val mutable = input.readBoolean()
+ RecordType.Field(name,
+ if (originalName.isEmpty) None else Some(originalName),
+ tpe, mutable)
+ })
+ }
+ }
+
+ def readClassType(): ClassType =
+ ClassType(readString())
+
+ def readArrayType(): ArrayType =
+ ArrayType(readString(), input.readInt())
+
+ def readReferenceType(): ReferenceType =
+ readType().asInstanceOf[ReferenceType]
+
+ def readPropertyName(): PropertyName = {
+ if (input.readBoolean()) readIdent()
+ else readTree().asInstanceOf[StringLiteral]
+ }
+
+ def readPosition(): Position = {
+ import input._
+ import PositionFormat._
+
+ val first = readByte()
+
+ val result = if (first == FormatNoPositionValue) {
+ Position.NoPosition
+ } else {
+ val result = if ((first & FormatFullMask) == FormatFullMaskValue) {
+ val file = files(readInt())
+ val line = readInt()
+ val column = readInt()
+ Position(file, line, column)
+ } else {
+ assert(lastPosition != NoPosition,
+ "Position format error: first position must be full")
+ if ((first & Format1Mask) == Format1MaskValue) {
+ val columnDiff = first >> Format1Shift
+ Position(lastPosition.source, lastPosition.line,
+ lastPosition.column + columnDiff)
+ } else if ((first & Format2Mask) == Format2MaskValue) {
+ val lineDiff = first >> Format2Shift
+ val column = readByte() & 0xff // unsigned
+ Position(lastPosition.source,
+ lastPosition.line + lineDiff, column)
+ } else {
+ assert((first & Format3Mask) == Format3MaskValue,
+ s"Position format error: first byte $first does not match any format")
+ val lineDiff = readShort()
+ val column = readByte() & 0xff // unsigned
+ Position(lastPosition.source,
+ lastPosition.line + lineDiff, column)
+ }
+ }
+ lastPosition = result
+ result
+ }
+
+ if (UseDebugMagic) {
+ val magic = readInt()
+ assert(magic == PosDebugMagic,
+ s"Bad magic after reading position with first byte $first")
+ }
+
+ result
+ }
+
+ def readOptHash(): Option[TreeHash] = {
+ if (input.readBoolean()) {
+ val treeHash = new Array[Byte](20)
+ val posHash = new Array[Byte](20)
+ input.readFully(treeHash)
+ input.readFully(posHash)
+ Some(new TreeHash(treeHash, posHash))
+ } else None
+ }
+
+ def readString(): String = {
+ strings(input.readInt())
+ }
+ }
+}