aboutsummaryrefslogtreecommitdiff
path: root/src/dotty/tools/dotc/core/pickling/TreePickler.scala
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2015-02-08 10:06:43 +0100
committerDmitry Petrashko <dmitry.petrashko@gmail.com>2015-03-18 11:09:43 +0100
commit340dc52a567de022c56acb1533c5772d21405f2a (patch)
treeae5dc41d2de3879d27abffc6413c18b25019e61b /src/dotty/tools/dotc/core/pickling/TreePickler.scala
parent61cb51acaedbe603add8c4af9e390a27f8b33f09 (diff)
downloaddotty-340dc52a567de022c56acb1533c5772d21405f2a.tar.gz
dotty-340dc52a567de022c56acb1533c5772d21405f2a.tar.bz2
dotty-340dc52a567de022c56acb1533c5772d21405f2a.zip
First prototype of pickler.
Diffstat (limited to 'src/dotty/tools/dotc/core/pickling/TreePickler.scala')
-rw-r--r--src/dotty/tools/dotc/core/pickling/TreePickler.scala371
1 files changed, 371 insertions, 0 deletions
diff --git a/src/dotty/tools/dotc/core/pickling/TreePickler.scala b/src/dotty/tools/dotc/core/pickling/TreePickler.scala
new file mode 100644
index 000000000..8c92e2ed8
--- /dev/null
+++ b/src/dotty/tools/dotc/core/pickling/TreePickler.scala
@@ -0,0 +1,371 @@
+package dotty.tools
+package dotc
+package core
+package pickling
+
+import util.Util.{bestFit, dble}
+import ast.Trees._
+import PickleFormat._
+import core._
+import Contexts._, Symbols._, Types._, Names._, Constants._, Decorators._
+import collection.mutable
+import TastyBuffer._
+
+class TreePickler(pickler: TastyPickler, picklePositions: Boolean) {
+ val buf = new TreeBuffer
+ pickler.newSection("ASTs", buf)
+ import buf._
+ import pickler.nameBuffer.nameIndex
+ import ast.tpd._
+
+ private val symRefs = new mutable.HashMap[Symbol, Addr]
+ private val forwardSymRefs = new mutable.HashMap[Symbol, List[Addr]]
+ private val pickledTypes = new java.util.IdentityHashMap[Type, Any] // Value type is really Addr, but that's not compatible with null
+
+ private def withLength(op: => Unit) = {
+ val lengthAddr = reserveRef(relative = true)
+ op
+ fillRef(lengthAddr, currentAddr, relative = true)
+ }
+
+ def registerDef(sym: Symbol) = {
+ symRefs(sym) = currentAddr
+ forwardSymRefs.get(sym) match {
+ case Some(refs) =>
+ refs.foreach(fillRef(_, currentAddr, relative = false))
+ forwardSymRefs -= sym
+ case None =>
+ }
+ }
+
+ private def pickleName(name: Name) = writeNat(nameIndex(name).index)
+ private def pickleName(name: TastyName) = writeNat(nameIndex(name).index)
+ private def pickleNameAndSig(name: Name, sig: Signature) = {
+ val Signature(params, result) = sig
+ pickleName(TastyName.Signed(nameIndex(name), params.map(nameIndex), nameIndex(result)))
+ }
+
+ private def pickleSym(sym: Symbol) = symRefs.get(sym) match {
+ case Some(label) =>
+ writeRef(label)
+ case None =>
+ val ref = reserveRef(relative = false)
+ forwardSymRefs(sym) = ref :: forwardSymRefs.getOrElse(sym, Nil)
+ }
+
+ def pickle(tree: Tree)(implicit ctx: Context) = {
+
+ def pickleConstant(c: Constant): Unit = {
+ def pickleNum(nonNegTag: Int, negTag: Int) = {
+ val x = c.longValue
+ if (x < 0) {
+ writeByte(negTag)
+ writeLongNat(-(x + 1))
+ }
+ else {
+ writeByte(nonNegTag)
+ writeLongNat(x)
+ }
+ }
+ c.tag match {
+ case UnitTag =>
+ writeByte(UNITconst)
+ case BooleanTag =>
+ writeByte(if (c.booleanValue) TRUEconst else FALSEconst)
+ case ByteTag =>
+ pickleNum(BYTEconst, BYTEneg)
+ case ShortTag =>
+ pickleNum(SHORTconst, SHORTneg)
+ case CharTag =>
+ writeByte(CHARconst)
+ writeNat(c.charValue)
+ case IntTag =>
+ pickleNum(INTconst, INTneg)
+ case LongTag =>
+ pickleNum(LONGconst, LONGneg)
+ case FloatTag =>
+ writeByte(FLOATconst)
+ writeRaw(java.lang.Float.floatToRawIntBits(c.floatValue), 4)
+ case DoubleTag =>
+ writeByte(DOUBLEconst)
+ writeRaw(java.lang.Double.doubleToRawLongBits(c.doubleValue), 8)
+ case StringTag =>
+ writeByte(STRINGconst)
+ writeNat(nameIndex(c.stringValue).index)
+ case NullTag =>
+ writeByte(NULLconst)
+ case ClazzTag =>
+ writeByte(CLASSconst)
+ withLength { pickleType(c.typeValue) }
+ case EnumTag =>
+ writeByte(ENUMconst)
+ withLength { pickleType(c.symbolValue.termRef) }
+ }
+ }
+
+ def pickleType(tpe: Type): Unit = {
+ val prev = pickledTypes.get(tpe)
+ if (prev == null) {
+ val addr = currentAddr
+ pickleNewType(tpe)
+ pickledTypes.put(tpe, addr)
+ }
+ else {
+ writeByte(SHARED)
+ writeRef(prev.asInstanceOf[Addr])
+ }
+ }
+
+ def pickleNewType(tpe: Type)= tpe match {
+ case ConstantType(value) => pickleConstant(value)
+ case tpe: WithFixedSym =>
+ if (tpe.prefix == NoPrefix) {
+ writeByte(if (tpe.isType) TYPEREFdirect else TERMREFdirect)
+ pickleSym(tpe.symbol)
+ }
+ else {
+ writeByte(if (tpe.isType) TYPEREFsymbol else TERMREFsymbol)
+ pickleType(tpe.prefix); pickleSym(tpe.symbol)
+ }
+ case tpe: TermRefWithSignature =>
+ writeByte(TERMREF)
+ pickleType(tpe.prefix); pickleNameAndSig(tpe.name, tpe.signature)
+ case tpe: NamedType =>
+ writeByte(if (tpe.isType) TYPEREF else TERMREF)
+ pickleType(tpe.prefix); pickleName(tpe.name)
+ case tpe: ThisType =>
+ writeByte(THIS)
+ pickleType(tpe.tref)
+ case tpe: SuperType =>
+ writeByte(SUPERtype)
+ withLength { pickleType(tpe.thistpe); pickleType(tpe.supertpe)}
+ case tpe: SkolemType =>
+ writeByte(SKOLEMtype)
+ withLength { pickleType(tpe.underlying) }
+ case tpe: RefinedType =>
+ val args = tpe.argInfos(interpolate = false)
+ if (args.isEmpty) {
+ writeByte(REFINEDtype)
+ withLength { pickleName(tpe.refinedName); pickleType(tpe.refinedInfo) }
+ }
+ else {
+ writeByte(APPLIEDtype)
+ withLength { pickleType(tpe.withoutArgs(args)); args.foreach(pickleType) }
+ }
+ case tpe: TypeAlias =>
+ writeByte(TYPEALIAS)
+ withLength { pickleType(tpe.alias) }
+ case tpe: TypeBounds =>
+ writeByte(TYPEBOUNDS)
+ withLength { pickleType(tpe.lo); pickleType(tpe.hi) }
+ case tpe: AnnotatedType =>
+ writeByte(ANNOTATED)
+ withLength { pickleTree(tpe.annot.tree); pickleType(tpe.tpe) }
+ case tpe: AndOrType =>
+ writeByte(if (tpe.isAnd) ANDtype else ORtype)
+ withLength { pickleType(tpe.tp1); pickleType(tpe.tp2) }
+ case tpe: ExprType =>
+ writeByte(BYNAMEtype)
+ withLength { pickleType(tpe.underlying) }
+ case NoType =>
+ writeByte(NOTYPE)
+// case NoPrefix => // not sure we need this!
+// writeByte(NOPREFIX)
+ }
+
+ def pickleTpt(tpt: Tree): Unit = pickleType(tpt.tpe) // TODO correlate with original when generating positions
+
+ def pickleTreeIfNonEmpty(tree: Tree): Unit =
+ if (!tree.isEmpty) pickleTree(tree)
+
+ def pickleTree(tree: Tree): Unit = tree match {
+ case Ident(_) | This(_) =>
+ pickleType(tree.tpe)
+ case Select(qual, name) =>
+ writeByte(SELECT)
+ val sig = tree.tpe.signature
+ if (sig == Signature.NotAMethod) pickleName(name)
+ else pickleNameAndSig(name, sig)
+ case Apply(fun, args) =>
+ writeByte(APPLY)
+ withLength {
+ pickleTree(fun)
+ args.foreach(pickleTree)
+ }
+ case TypeApply(fun, args) =>
+ writeByte(TYPEAPPLY)
+ withLength {
+ pickleTree(fun)
+ args.foreach(pickleTree)
+ }
+ case Literal(const) =>
+ pickleConstant(const)
+ case Super(qual, mix) =>
+ writeByte(SUPER)
+ withLength {
+ pickleTree(qual);
+ if (!mix.isEmpty) {
+ val SuperType(_, mixinType) = tree.tpe
+ pickleType(mixinType)
+ }
+ }
+ case New(tpt) =>
+ writeByte(NEW)
+ withLength { pickleTpt(tpt) }
+ case Pair(left, right) =>
+ writeByte(PAIR)
+ withLength { pickleTree(left); pickleTree(right) }
+ case Typed(expr, tpt) =>
+ writeByte(TYPED)
+ withLength { pickleTree(expr); pickleTpt(tpt) }
+ case NamedArg(name, arg) =>
+ writeByte(NAMEDARG)
+ withLength { pickleName(name); pickleTree(arg) }
+ case Assign(lhs, rhs) =>
+ writeByte(ASSIGN)
+ withLength { pickleTree(lhs); pickleTree(rhs) }
+ case Block(stats, expr) =>
+ writeByte(BLOCK)
+ withLength { pickleTree(expr); stats.foreach(pickleTree) }
+ case If(cond, thenp, elsep) =>
+ writeByte(IF)
+ withLength{ pickleTree(cond); pickleTree(thenp); pickleTree(elsep) }
+ case Closure(env, meth, tpt) =>
+ writeByte(CLOSURE)
+ withLength{ pickleTree(meth); pickleTpt(tpt); env.foreach(pickleTree) }
+ case Match(selector, cases) =>
+ writeByte(MATCH)
+ withLength { pickleTree(selector); cases.foreach(pickleTree) }
+ case CaseDef(pat, guard, rhs) =>
+ writeByte(CASEDEF)
+ withLength { pickleTree(pat); pickleTree(guard); pickleTree(rhs) }
+ case Return(expr, from) =>
+ writeByte(RETURN)
+ withLength { pickleSym(from.symbol); pickleTreeIfNonEmpty(expr) }
+ case Try(block, cases, finalizer) =>
+ writeByte(TRY)
+ withLength { pickleTree(block); cases.foreach(pickleTree); pickleTreeIfNonEmpty(finalizer) }
+ case Throw(expr) =>
+ writeByte(THROW)
+ withLength { pickleTree(expr) }
+ case SeqLiteral(elems) =>
+ writeByte(if (tree.isInstanceOf[JavaSeqLiteral]) JSEQLITERAL else SEQLITERAL)
+ withLength { elems.foreach(pickleTree) }
+ case TypeTree(original) =>
+ pickleTpt(tree)
+ case Bind(name, body) =>
+ registerDef(tree.symbol)
+ writeByte(BIND)
+ withLength { pickleName(name); pickleType(tree.symbol.info); pickleTree(body) }
+ case Alternative(alts) =>
+ writeByte(ALTERNATIVE)
+ withLength { alts.foreach(pickleTree) }
+ case UnApply(fun, implicits, patterns) =>
+ writeByte(UNAPPLY)
+ withLength {
+ pickleTree(fun)
+ for (implicitArg <- implicits) {
+ writeByte(IMPLICITARG)
+ withLength { pickleTree(implicitArg) }
+ }
+ patterns.foreach(pickleTree)
+ }
+ case tree: ValDef =>
+ pickleDef(VALDEF, tree.symbol, tree.rhs)
+ case tree: DefDef =>
+ def pickleParams = {
+ for (tparam <- tree.tparams) pickleDef(TYPEPARAM, tparam.symbol, EmptyTree)
+ for (vparams <- tree.vparamss) {
+ writeByte(PARAMS)
+ withLength {
+ for (vparam <- vparams) pickleDef(PARAM, vparam.symbol, EmptyTree)
+ }
+ }
+ }
+ pickleDef(DEFDEF, tree.symbol, tree.rhs, pickleParams)
+ case tree: TypeDef =>
+ pickleDef(TYPEDEF, tree.symbol, tree.rhs)
+ case tree: Template =>
+ writeByte(TEMPLATE)
+ withLength {
+ tree.parents.foreach(pickleTree)
+ if (!tree.self.isEmpty)
+ pickleDef(PARAM, tree.self.symbol, EmptyTree)
+ pickleTreeIfNonEmpty(tree.constr)
+ tree.body.foreach(pickleTree)
+ }
+ case Import(expr, selectors) =>
+ writeByte(IMPORT)
+ withLength {
+ pickleTree(expr)
+ selectors foreach {
+ case Pair(Ident(from), Ident(to)) =>
+ writeByte(RENAMED)
+ withLength { pickleName(from); pickleName(to) }
+ case Ident(name) =>
+ writeByte(IMPORTED)
+ withLength { pickleName(name) }
+ }
+ }
+ case PackageDef(pid, stats) =>
+ writeByte(PACKAGE)
+ withLength { pickleType(pid.tpe); stats.foreach(pickleTree) }
+ case Annotated(annot, arg) =>
+ writeByte(ANNOTATED)
+ withLength { pickleTree(annot); pickleTree(arg) }
+ }
+
+ def pickleDef(tag: Int, sym: Symbol, rhs: Tree, pickleParams: => Unit = ()) = {
+ registerDef(sym)
+ writeByte(tag)
+ withLength {
+ pickleName(sym.name)
+ pickleParams
+ if (tag != TYPEDEF) pickleType(sym.info.finalResultType)
+ if (tag != PARAM && tag != TYPEPARAM) pickleTree(rhs)
+ pickleModifiers(sym)
+ }
+ }
+
+ def pickleModifiers(sym: Symbol): Unit = {
+ import Flags._
+ val flags = sym.flags
+ val privateWithin = sym.privateWithin
+ if (privateWithin.exists) {
+ writeByte(if (flags is Protected) PROTECTEDqualified else PRIVATEqualified)
+ pickleSym(privateWithin)
+ }
+ if (flags is Private) writeByte(PRIVATE)
+ if (flags is Protected) if (!privateWithin.exists) writeByte(PROTECTED)
+ if (flags is Final) writeByte(FINAL)
+ if (flags is Case) writeByte(CASE)
+ if (flags is Override) writeByte(OVERRIDE)
+ if (flags is Inline) writeByte(INLINE)
+ if (flags is JavaStatic) writeByte(STATIC)
+ if (flags is Module) writeByte(MODULE)
+ if (flags is Local) writeByte(LOCAL)
+ if (flags is Synthetic) writeByte(SYNTHETIC)
+ if (flags is Artifact) writeByte(ARTIFACT)
+ if (flags is Scala2x) writeByte(SCALA2X)
+ if (sym.isTerm) {
+ if (flags is Implicit) writeByte(IMPLICIT)
+ if (flags is Lazy) writeByte(LAZY)
+ if (flags is AbsOverride) writeByte(ABSOVERRIDE)
+ if (flags is Mutable) writeByte(MUTABLE)
+ if (flags is Accessor) writeByte(FIELDaccessor)
+ if (flags is ParamAccessor) writeByte(PARAMaccessor)
+ if (flags is CaseAccessor) writeByte(CASEaccessor)
+ if (flags is DefaultParameterized) writeByte(DEFAULTparameterized)
+ if (flags is DefaultInit) writeByte(DEFAULTinit)
+ } else {
+ if (flags is Sealed) writeByte(SEALED)
+ if (flags is Abstract) writeByte(ABSTRACT)
+ if (flags is Covariant) writeByte(COVARIANT)
+ if (flags is Contravariant) writeByte(CONTRAVARIANT)
+ }
+ sym.annotations.foreach(ann => pickleTree(ann.tree))
+ }
+
+ pickleTree(tree)
+ }
+}