From fc8fc177d2dfd270e57996099deef2e4a3a975ed Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Tue, 23 Apr 2013 17:04:34 +0200 Subject: Modifications in prepation of parsing. --- src/dotty/tools/dotc/core/Contexts.scala | 1 + src/dotty/tools/dotc/core/Flags.scala | 4 + src/dotty/tools/dotc/core/StdNames.scala | 2 + src/dotty/tools/dotc/core/TreeInfo.scala | 10 +- src/dotty/tools/dotc/core/Trees.scala | 172 ++++++++++++++++----- src/dotty/tools/dotc/core/TypedTrees.scala | 11 +- src/dotty/tools/dotc/core/UntypedTrees.scala | 21 ++- src/dotty/tools/dotc/parsing/Scanners.scala | 46 +++--- .../tools/dotc/parsing/SymbolicXMLBuilder.scala | 2 +- src/dotty/tools/dotc/parsing/Tokens.scala | 9 +- src/dotty/tools/dotc/parsing/TreeBuilder.scala | 147 +++++++++--------- src/dotty/tools/dotc/util/Positions.scala | 14 +- 12 files changed, 285 insertions(+), 154 deletions(-) diff --git a/src/dotty/tools/dotc/core/Contexts.scala b/src/dotty/tools/dotc/core/Contexts.scala index 2838f1c7f..6e089dde6 100644 --- a/src/dotty/tools/dotc/core/Contexts.scala +++ b/src/dotty/tools/dotc/core/Contexts.scala @@ -294,6 +294,7 @@ object Contexts { def freshName(): String = freshNames.newName() def freshName(prefix: String): String = freshNames.newName(prefix) + def freshName(prefix: Name): String = freshName(prefix.toString) /** The loader that loads the members of _root_ */ def rootLoader(root: TermSymbol)(implicit ctx: Context): SymbolLoader = platform.rootLoader(root) diff --git a/src/dotty/tools/dotc/core/Flags.scala b/src/dotty/tools/dotc/core/Flags.scala index 4e88515e9..df4d873a5 100644 --- a/src/dotty/tools/dotc/core/Flags.scala +++ b/src/dotty/tools/dotc/core/Flags.scala @@ -84,6 +84,9 @@ object Flags { /** The number of non-kind flags in this set */ def numFlags: Int = java.lang.Long.bitCount(bits & ~KINDFLAGS) + /** The lowest non-kind bit set in this flagset */ + def firstBit: Int = java.lang.Long.numberOfTrailingZeros(bits & ~KINDFLAGS) + /** The list of non-empty names of flags with given index idx that are set in this FlagSet */ private def flagString(idx: Int): List[String] = if ((bits & (1L << idx)) == 0) Nil @@ -444,6 +447,7 @@ object Flags { final val SyntheticTermParam = allOf(Synthetic, TermParam) final val SyntheticTypeParam = allOf(Synthetic, TypeParam) final val SyntheticCase = allOf(Synthetic, Case) + final val AbstractAndOverride = allOf(Abstract, Override) implicit def conjToFlagSet(conj: FlagConjunction): FlagSet = FlagSet(conj.bits) diff --git a/src/dotty/tools/dotc/core/StdNames.scala b/src/dotty/tools/dotc/core/StdNames.scala index 4ef3456df..80d3ac6b6 100644 --- a/src/dotty/tools/dotc/core/StdNames.scala +++ b/src/dotty/tools/dotc/core/StdNames.scala @@ -290,6 +290,7 @@ object StdNames { val NoPrefix: N = "NoPrefix" val NoSymbol: N = "NoSymbol" val NoType: N = "NoType" + val Pair: N = "Pair" val Ref: N = "Ref" val RootPackage: N = "RootPackage" val RootClass: N = "RootClass" @@ -540,6 +541,7 @@ object StdNames { val ZOR = encode("||") // unary operators + val UNARY_PREFIX: N = "unary_" val UNARY_~ = encode("unary_~") val UNARY_+ = encode("unary_+") val UNARY_- = encode("unary_-") diff --git a/src/dotty/tools/dotc/core/TreeInfo.scala b/src/dotty/tools/dotc/core/TreeInfo.scala index cb621164c..c3d0d4ece 100644 --- a/src/dotty/tools/dotc/core/TreeInfo.scala +++ b/src/dotty/tools/dotc/core/TreeInfo.scala @@ -16,7 +16,7 @@ abstract class TreeInfo { def isDeclarationOrTypeDef(tree: Tree[_ >: Untyped]): Boolean = tree match { case DefDef(_, _, _, _, _, EmptyTree()) | ValDef(_, _, _, EmptyTree()) - | TypeDef(_, _, _) => true + | TypeDef(_, _, _, _) => true case _ => false } @@ -25,7 +25,7 @@ abstract class TreeInfo { def isInterfaceMember(tree: Tree[_ >: Untyped]): Boolean = tree match { case EmptyTree() => true case Import(_, _) => true - case TypeDef(_, _, _) => true + case TypeDef(_, _, _, _) => true case DefDef(mods, _, _, _, _, __) => mods.flags is Deferred case ValDef(mods, _, _, _) => mods is Deferred case _ => false @@ -37,7 +37,7 @@ abstract class TreeInfo { def isIdempotentDef(tree: Tree[Type])(implicit ctx: Context): Boolean = tree match { case EmptyTree() | ClassDef(_, _, _, _) - | TypeDef(_, _, _) + | TypeDef(_, _, _, _) | Import(_, _) | DefDef(_, _, _, _, _, _) => true @@ -231,7 +231,7 @@ abstract class TreeInfo { } def isEarlyTypeDef(tree: Tree[_ >: Untyped]) = tree match { - case TypeDef(mods, _, _) => mods is Scala2PreSuper + case TypeDef(mods, _, _, _) => mods is Scala2PreSuper case _ => false } @@ -476,4 +476,4 @@ abstract class TreeInfo { case _ => false })*/ } -object treeInfo extends TreeInfo \ No newline at end of file +object TreeInfo extends TreeInfo \ No newline at end of file diff --git a/src/dotty/tools/dotc/core/Trees.scala b/src/dotty/tools/dotc/core/Trees.scala index 7befc9956..07a6ada69 100644 --- a/src/dotty/tools/dotc/core/Trees.scala +++ b/src/dotty/tools/dotc/core/Trees.scala @@ -6,6 +6,7 @@ import Denotations._, StdNames._ import annotation.tailrec import language.higherKinds import collection.mutable +import collection.mutable.ArrayBuffer object Trees { @@ -19,22 +20,87 @@ object Trees { type TypedTree = Tree[Type] type UntypedTree = Tree[Untyped] + /** Modifiers and annotations for definitions + * @param flags The set flags + * @param privateWithin If a private or protected has is followed by a + * qualifier [q], the name q, "" as a typename otherwise. + * @param annotations The annotations preceding the modifers + * @param positions A flagPositions structure that records the positions + * of et flags. + * @param pos The position of the modifiers. This should start with + * the first modifier or annotation and have as point + * the start of the opening keyword(s) of the definition. + * It should have as end the end of the opening keywords(s). + */ case class Modifiers[T >: Untyped]( flags: FlagSet = EmptyFlags, privateWithin: TypeName = tpnme.EMPTY, - annotations: List[Tree[T]] = Nil) { + annotations: List[Tree[T]] = Nil, + positions: FlagPositions = NoFlagPositions)(implicit val cpos: Position = NoPosition) { + + def | (fs: FlagSet): Modifiers[T] = copy(flags = flags | fs)(cpos) + def & (fs: FlagSet): Modifiers[T] = copy(flags = flags & fs)(cpos) + def &~(fs: FlagSet): Modifiers[T] = copy(flags = flags &~ fs)(cpos) + + def is(fs: FlagSet): Boolean = flags is fs + def is(fc: FlagConjunction): Boolean = flags is fc + + def add(flag: FlagSet, start: Int) = + copy(flags = flags | flag, positions = positions.add(flag, start)) + + def withAnnotations(annots: List[Tree[T]]) = + if (annots.isEmpty) this + else copy(annotations = annotations ++ annots)(cpos) + + def withPrivateWithin(pw: TypeName) = + if (pw.isEmpty) this + else copy(privateWithin = pw)(cpos) + + def withPos(pos: Position) = copy()(pos) - def | (fs: FlagSet) = copy(flags = flags | fs) - def & (fs: FlagSet) = copy(flags = flags & fs) - def &~(fs: FlagSet) = copy(flags = flags &~ fs) - def is(fs: FlagSet) = flags is fs - def is(fc: FlagConjunction) = flags is fc + val pos: Position = unionPos(cpos, annotations) } - private val modCache = mutable.Map[FlagSet, Modifiers[Untyped]]() + private final val OffsetShift = 6 + private final val FlagMask = (1 << OffsetShift) - 1 - def apply[T >: Untyped](flags: FlagSet = EmptyFlags): Modifiers[T] = - modCache.getOrElseUpdate(flags, Modifiers(flags, tpnme.EMPTY, Nil)).asInstanceOf[Modifiers[T]] + class FlagPositions(val arr: Array[Int]) extends AnyVal { + def get(flag: FlagSet): Position = { + val str :: Nil = flag.flagStrings.toList + val code = flag.firstBit + var i = 0 + while (i < arr.length && ((arr(i) & FlagMask) != code)) i += 1 + if (i < arr.length) { + val start = arr(i) >>> OffsetShift + val end = start + str.length + Position(start, end) + } else + NoPosition + } + def add(flag: FlagSet, start: Int) = { + val newarr = new Array[Int](arr.length + 1) + arr.copyToArray(newarr) + setFlagPosition(newarr, arr.length, flag, start) + new FlagPositions(newarr) + } + } + + private def setFlagPosition(arr: Array[Int], idx: Int, flag: FlagSet, start: Int): Unit = { + val code = flag.firstBit + assert(code <= 64) + arr(idx) = code | (start << OffsetShift) + } + + def FlagPositions(assocs: ArrayBuffer[(FlagSet, Int)]): FlagPositions = { + val arr = Array[Int](assocs.size) + for (i <- 0 until assocs.size) { + val (flag, start) = assocs(i) + setFlagPosition(arr, i, flag, start) + } + FlagPositions(assocs) + } + + val NoFlagPositions = new FlagPositions(Array()) /** Trees take a parameter indicating what the type of their `tpe` field * is. Two choices: `Type` or `Untyped`. @@ -56,10 +122,14 @@ object Trees { /** The tree's position. Except * for SharedTree nodes, it is always ensured that a tree's position - * contains the positions of all its subtrees. + * contains the positions of all its immediate subtrees. However, it need not + * contain positions of other tree elements such as Modifiers. */ def pos: Position + /** The extended position. Unlike `pos`, this one contains positions of modifiers */ + def xpos: Position = pos + /** The type constructor at the root of the tree */ type ThisTree[T >: Untyped] <: Tree[T] @@ -129,6 +199,10 @@ object Trees { /** Is this tree either the empty tree or the empty ValDef? */ def isEmpty: Boolean = false + /** if this tree is the empty tree, the alternative, else this tree */ + def orElse(that: => Tree[T]): Tree[T] = + if (this eq theEmptyTree) that else this + override def toText(implicit ctx: Context) = ctx.toText(this) override def hashCode(): Int = System.identityHashCode(this) @@ -205,6 +279,19 @@ object Trees { override def isDef = true } + /** Tree defines a new symbol and carries modifiers. + * The position of a ModDefTree usually starts + * at the symbol that's being defined (known exception: + * A type definition starts at the +/- if there is one). + * The annotations, modifiers and keyword that come before + * are subsumed in the modifier position. + */ + trait ModDefTree[T >: Untyped] extends DefTree[T] { + type ThisTree[T >: Untyped] <: ModDefTree[T] + def mods: Modifiers[T] + override def xpos = mods.pos union pos + } + // ----------- Tree case classes ------------------------------------ /** name */ @@ -275,8 +362,16 @@ object Trees { val pos = cpos union tpt.pos } - def New[T >: Untyped](tpt: Tree[T], argss: List[List[Tree[T]]])(implicit cpos: Position): Tree[T] = - ((Select(New(tpt), nme.CONSTRUCTOR): Tree[T]) /: argss)(Apply(_, _)) + /** new tpt(args1)...(args_n) + * @param cpos A position spanning the new. + */ + def New[T >: Untyped](tpt: Tree[T], argss: List[List[Tree[T]]])(implicit cpos: Position): Tree[T] = { + val newPos = cpos.withEnd(tpt.pos.end min cpos.end) + locally { + implicit val cpos: Position = newPos + ((Select(New(tpt), nme.CONSTRUCTOR): Tree[T]) /: argss)(Apply(_, _)) + } + } /** (left, right) */ case class Pair[T >: Untyped](left: Tree[T], right: Tree[T])(implicit cpos: Position) @@ -343,7 +438,7 @@ object Trees { * After program transformations this is not necessarily the enclosing method, because * closures can intervene. */ - case class Return[T >: Untyped](expr: Tree[T], from: Ident[T])(implicit cpos: Position) + case class Return[T >: Untyped](expr: Tree[T], from: Tree[T] = EmptyTree[T]())(implicit cpos: Position) extends TermTree[T] { type ThisTree[T >: Untyped] = Return[T] val pos = cpos union expr.pos // from is synthetic, does not influence pos @@ -406,7 +501,7 @@ object Trees { } /** tpt { refinements } */ - case class RefineTypeTree[T >: Untyped](tpt: Tree[T], refinements: List[DefTree[T]])(implicit cpos: Position) + case class RefineTypeTree[T >: Untyped](tpt: Tree[T], refinements: List[Tree[T]])(implicit cpos: Position) extends ProxyTree[T] with TypTree[T] { type ThisTree[T >: Untyped] = RefineTypeTree[T] val pos = unionPos(cpos union tpt.pos, refinements) @@ -421,6 +516,9 @@ object Trees { def forwardTo = tpt } + def AppliedTypeTree[T >: Untyped](tpt: Tree[T], arg: Tree[T])(implicit cpos: Position): AppliedTypeTree[T] = + AppliedTypeTree(tpt, arg :: Nil) + /** >: lo <: hi */ case class TypeBoundsTree[T >: Untyped](lo: Tree[T], hi: Tree[T])(implicit cpos: Position) extends Tree[T] { @@ -451,14 +549,14 @@ object Trees { /** mods val name: tpt = rhs */ case class ValDef[T >: Untyped](mods: Modifiers[T], name: TermName, tpt: Tree[T], rhs: Tree[T])(implicit cpos: Position) - extends NameTree[T] with DefTree[T] { + extends NameTree[T] with ModDefTree[T] { type ThisTree[T >: Untyped] = ValDef[T] val pos = cpos union tpt.pos union rhs.pos } /** mods def name[tparams](vparams_1)...(vparams_n): tpt = rhs */ case class DefDef[T >: Untyped](mods: Modifiers[T], name: TermName, tparams: List[TypeDef[T]], vparamss: List[List[ValDef[T]]], tpt: Tree[T], rhs: Tree[T])(implicit cpos: Position) - extends NameTree[T] with DefTree[T] { + extends NameTree[T] with ModDefTree[T] { type ThisTree[T >: Untyped] = DefDef[T] val pos = (unionPos(cpos union tpt.pos union rhs.pos, tparams) /: vparamss)(unionPos) } @@ -471,22 +569,22 @@ object Trees { /** mods type name = rhs or * mods type name >: lo <: hi, if rhs = TypeBoundsTree(lo, hi) */ - case class TypeDef[T >: Untyped](mods: Modifiers[T], name: TypeName, rhs: Tree[T])(implicit cpos: Position) - extends NameTree[T] with DefTree[T] { + case class TypeDef[T >: Untyped](mods: Modifiers[T], name: TypeName, tparams: List[TypeDef[T]], rhs: Tree[T])(implicit cpos: Position) + extends NameTree[T] with ModDefTree[T] { type ThisTree[T >: Untyped] = TypeDef[T] - val pos = cpos union rhs.pos + val pos = unionPos(cpos union rhs.pos, tparams) } /** extends parents { self => body } */ case class Template[T >: Untyped](parents: List[Tree[T]], self: ValDef[T], body: List[Tree[T]])(implicit cpos: Position) extends DefTree[T] { type ThisTree[T >: Untyped] = Template[T] - val pos = unionPos(unionPos(cpos union self.pos, parents), body) + val pos = unionPos(unionPos(cpos union self.xpos, parents), body) } /** mods class name[tparams] impl */ case class ClassDef[T >: Untyped](mods: Modifiers[T], name: TypeName, tparams: List[TypeDef[T]], impl: Template[T])(implicit cpos: Position) - extends NameTree[T] with DefTree[T] { + extends NameTree[T] with ModDefTree[T] { type ThisTree[T >: Untyped] = ClassDef[T] val pos = unionPos(cpos union impl.pos, tparams) } @@ -537,7 +635,7 @@ object Trees { } class EmptyValDef[T >: Untyped] extends ValDef[T]( - Modifiers[T](Private), nme.WILDCARD, EmptyTree[T], EmptyTree[T])(NoPosition) with AlwaysEmpty[T] + Modifiers[T](Private)(NoPosition), nme.WILDCARD, EmptyTree[T], EmptyTree[T])(NoPosition) with AlwaysEmpty[T] private object theEmptyValDef extends EmptyValDef[Untyped] @@ -564,8 +662,8 @@ object Trees { /** mods object name impl */ case class ModuleDef(mods: Modifiers[Untyped], name: TermName, impl: Template[Untyped])(implicit cpos: Position) - extends NameTree[Untyped] with DefTree[Untyped] { - type ThisTree[T >: Untyped] <: NameTree[T] with DefTree[T] with ModuleDef + extends NameTree[Untyped] with ModDefTree[Untyped] { + type ThisTree[T >: Untyped] <: NameTree[T] with ModDefTree[T] with ModuleDef val pos = cpos union impl.pos def derivedModuleDef(mods: Modifiers[Untyped], name: TermName, impl: Template[Untyped]) = if (mods == this.mods && name == this.name && (impl eq this.impl)) this @@ -665,7 +763,7 @@ object Trees { // ----- Helper functions and classes --------------------------------------- @tailrec final def unionPos(base: Position, trees: List[Tree[_]]): Position = trees match { - case t :: ts => unionPos(base union t.pos, ts) + case t :: ts => unionPos(base union t.xpos, ts) case nil => base } @@ -738,7 +836,7 @@ object Trees { case tree: CaseDef[_] if (pat eq tree.pat) && (guard eq tree.guard) && (body eq tree.body) => tree case _ => CaseDef(pat, guard, body).copyAttr(tree) } - def derivedReturn(expr: Tree[T], from: Ident[T]): Return[T] = tree match { + def derivedReturn(expr: Tree[T], from: Tree[T]): Return[T] = tree match { case tree: Return[_] if (expr eq tree.expr) && (from eq tree.from) => tree case _ => Return(expr, from).copyAttr(tree) } @@ -774,7 +872,7 @@ object Trees { case tree: OrTypeTree[_] if (left eq tree.left) && (right eq tree.right) => tree case _ => OrTypeTree(left, right).copyAttr(tree) } - def derivedRefineTypeTree(tpt: Tree[T], refinements: List[DefTree[T]]): RefineTypeTree[T] = tree match { + def derivedRefineTypeTree(tpt: Tree[T], refinements: List[Tree[T]]): RefineTypeTree[T] = tree match { case tree: RefineTypeTree[_] if (tpt eq tree.tpt) && (refinements eq tree.refinements) => tree case _ => RefineTypeTree(tpt, refinements).copyAttr(tree) } @@ -806,9 +904,9 @@ object Trees { case tree: DefDef[_] if (mods == tree.mods) && (name == tree.name) && (tparams eq tree.tparams) && (vparamss eq tree.vparamss) && (tpt eq tree.tpt) && (rhs eq tree.rhs) => tree case _ => DefDef(mods, name, tparams, vparamss, tpt, rhs).copyAttr(tree) } - def derivedTypeDef(mods: Modifiers[T], name: TypeName, rhs: Tree[T]): TypeDef[T] = tree match { - case tree: TypeDef[_] if (mods == tree.mods) && (name == tree.name) && (rhs eq tree.rhs) => tree - case _ => TypeDef(mods, name, rhs).copyAttr(tree) + def derivedTypeDef(mods: Modifiers[T], name: TypeName, tparams: List[TypeDef[T]], rhs: Tree[T]): TypeDef[T] = tree match { + case tree: TypeDef[_] if (mods == tree.mods) && (name == tree.name) && (tparams eq tree.tparams) && (rhs eq tree.rhs) => tree + case _ => TypeDef(mods, name, tparams, rhs).copyAttr(tree) } def derivedTemplate(parents: List[Tree[T]], self: ValDef[T], body: List[Tree[T]]): Template[T] = tree match { case tree: Template[_] if (parents eq tree.parents) && (self eq tree.self) && (body eq tree.body) => tree @@ -873,7 +971,7 @@ object Trees { case CaseDef(pat, guard, body) => finishCaseDef(tree.derivedCaseDef(transform(pat, c), transform(guard, c), transform(body, c)), tree, c, plugins) case Return(expr, from) => - finishReturn(tree.derivedReturn(transform(expr, c), transformSub(from, c)), tree, c, plugins) + finishReturn(tree.derivedReturn(transform(expr, c), transform(from, c)), tree, c, plugins) case Try(block, catches, finalizer) => finishTry(tree.derivedTry(transform(block, c), transformSub(catches, c), transform(finalizer, c)), tree, c, plugins) case Throw(expr) => @@ -906,8 +1004,8 @@ object Trees { finishValDef(tree.derivedValDef(mods, name, transform(tpt, c), transform(rhs, c)), tree, c, plugins) case DefDef(mods, name, tparams, vparamss, tpt, rhs) => finishDefDef(tree.derivedDefDef(mods, name, transformSub(tparams, c), vparamss mapConserve (transformSub(_, c)), transform(tpt, c), transform(rhs, c)), tree, c, plugins) - case TypeDef(mods, name, rhs) => - finishTypeDef(tree.derivedTypeDef(mods, name, transform(rhs, c)), tree, c, plugins) + case TypeDef(mods, name, tparams, rhs) => + finishTypeDef(tree.derivedTypeDef(mods, name, transformSub(tparams, c), transform(rhs, c)), tree, c, plugins) case Template(parents, self, body) => finishTemplate(tree.derivedTemplate(transform(parents, c), transformSub(self, c), transform(body, c)), tree, c, plugins) case ClassDef(mods, name, tparams, impl) => @@ -1055,8 +1153,8 @@ object Trees { tree.derivedValDef(mods, name, transform(tpt), transform(rhs)) case DefDef(mods, name, tparams, vparamss, tpt, rhs) => tree.derivedDefDef(mods, name, transformSub(tparams), vparamss mapConserve (transformSub(_)), transform(tpt), transform(rhs)) - case TypeDef(mods, name, rhs) => - tree.derivedTypeDef(mods, name, transform(rhs)) + case TypeDef(mods, name, tparams, rhs) => + tree.derivedTypeDef(mods, name, transformSub(tparams), transform(rhs)) case Template(parents, self, body) => tree.derivedTemplate(transform(parents), transformSub(self), transform(body)) case ClassDef(mods, name, tparams, impl) => @@ -1157,8 +1255,8 @@ object Trees { this(this(x, tpt), rhs) case DefDef(mods, name, tparams, vparamss, tpt, rhs) => this(this((this(x, tparams) /: vparamss)(apply), tpt), rhs) - case TypeDef(mods, name, rhs) => - this(x, rhs) + case TypeDef(mods, name, tparams, rhs) => + this(this(x, tparams), rhs) case Template(parents, self, body) => this(this(this(x, parents), self), body) case ClassDef(mods, name, tparams, impl) => diff --git a/src/dotty/tools/dotc/core/TypedTrees.scala b/src/dotty/tools/dotc/core/TypedTrees.scala index bfe2c957d..348b2c37b 100644 --- a/src/dotty/tools/dotc/core/TypedTrees.scala +++ b/src/dotty/tools/dotc/core/TypedTrees.scala @@ -186,7 +186,7 @@ object TypedTrees { } def TypeDef(sym: TypeSymbol)(implicit ctx: Context): TypeDef = - Trees.TypeDef(Modifiers(sym), sym.name, TypeTree(sym.info))(defPos(sym)) + Trees.TypeDef(Modifiers(sym), sym.name, Nil, TypeTree(sym.info))(defPos(sym)) // !!! fill in typeParams .withType(refType(sym)).checked def ClassDef(cls: ClassSymbol, typeParams: List[TypeSymbol], body: List[Tree])(implicit ctx: Context): ClassDef = { @@ -227,7 +227,7 @@ object TypedTrees { def SharedTree(tree: Tree): SharedTree = Trees.SharedTree(tree).withType(tree.tpe) - def refType(sym: Symbol)(implicit ctx: Context) = NamedType.withSym(sym.owner.thisType, sym) + def refType(sym: Symbol)(implicit ctx: Context): NamedType = NamedType.withSym(sym.owner.thisType, sym) // ------ Creating typed equivalents of trees that exist only in untyped form ------- @@ -239,7 +239,8 @@ object TypedTrees { case pre => SelectFromTypeTree(TypeTree(pre), tp) } // no checks necessary - def ref(sym: TermSymbol)(implicit ctx: Context): tpd.NameTree = ref(sym.termRef) + def ref(sym: Symbol)(implicit ctx: Context): tpd.NameTree = + ref(NamedType(sym.owner.thisType, sym.name).withDenot(sym)) /** new C(args) */ def New(tp: Type, args: List[Tree])(implicit ctx: Context): Apply = @@ -479,7 +480,7 @@ object TypedTrees { check(left.isValueType); check(right.isValueType) case RefineTypeTree(tpt, refinements) => check(tpt.isValueType) - def checkRefinements(forbidden: Set[Symbol], rs: List[tpd.DefTree]): Unit = rs match { + def checkRefinements(forbidden: Set[Symbol], rs: List[tpd.Tree]): Unit = rs match { case r :: rs1 => val rsym = r.symbol check(rsym.isTerm || rsym.isAbstractOrAliasType) @@ -552,7 +553,7 @@ object TypedTrees { check(rhs.isValue) check(rhs.tpe <:< tpt.tpe) } - case TypeDef(mods, name, tpt) => + case TypeDef(mods, name, _, tpt) => check(tpt.tpe.isInstanceOf[TypeBounds]) case Template(parents, selfType, body) => case ClassDef(mods, name, tparams, impl) => diff --git a/src/dotty/tools/dotc/core/UntypedTrees.scala b/src/dotty/tools/dotc/core/UntypedTrees.scala index 2b1d6a0d6..509c0abfb 100644 --- a/src/dotty/tools/dotc/core/UntypedTrees.scala +++ b/src/dotty/tools/dotc/core/UntypedTrees.scala @@ -2,7 +2,7 @@ package dotty.tools.dotc package core import util.Positions._, Types._, Contexts._, Constants._, Names._, Flags._ -import SymDenotations._, Symbols._, StdNames._, Annotations._, Trees._ +import SymDenotations._, Symbols._, StdNames._, Annotations._, Trees._, TypedTrees._ object UntypedTrees { @@ -10,5 +10,24 @@ object UntypedTrees { } + import untpd._ + + class UGen(implicit ctx: Context) { + def constructor(mods: Modifiers, vparamAccessorss: List[List[Tree]], ofTrait: Boolean): DefDef = ??? + + def Template( + constrMods: Modifiers, + vparamAccessorss: List[List[Tree]], + parents: List[Tree], + self: ValDef, + stats: List[Tree], + ofTrait: Boolean): Template = { + val constr = constructor(constrMods, vparamAccessorss, ofTrait) + Trees.Template(parents, self, vparamAccessorss.flatten ++ (constr :: stats))(NoPosition) + } + } + + def ugen(implicit ctx: Context) = + new UGen } diff --git a/src/dotty/tools/dotc/parsing/Scanners.scala b/src/dotty/tools/dotc/parsing/Scanners.scala index 2b3ec9bc2..7260269f9 100644 --- a/src/dotty/tools/dotc/parsing/Scanners.scala +++ b/src/dotty/tools/dotc/parsing/Scanners.scala @@ -91,7 +91,7 @@ object Scanners { /** we need one token lookahead and one token history */ - private val next : TokenData = new TokenData0 + val next : TokenData = new TokenData0 private val prev : TokenData = new TokenData0 /** a stack of tokens which indicates whether line-ends can be statement separators @@ -193,32 +193,30 @@ object Scanners { def postProcessToken() = { // Join CASE + CLASS => CASECLASS, CASE + OBJECT => CASEOBJECT, SEMI + ELSE => ELSE - if (token == CASE) { + def lookahead() = { prev copyFrom this - val nextLastOffset = lastCharOffset fetchToken() - def resetOffset() { - offset = prev.offset - lastOffset = prev.lastOffset - } - if (token == CLASS) { - token = CASECLASS - resetOffset() - } else if (token == OBJECT) { - token = CASEOBJECT - resetOffset() - } else { - lastOffset = nextLastOffset - next copyFrom this - this copyFrom prev - } + } + def reset(nextLastOffset: Offset) = { + lastOffset = nextLastOffset + next copyFrom this + this copyFrom prev + } + def fuse(tok: Int) = { + token = tok + offset = prev.offset + lastOffset = prev.lastOffset + } + if (token == CASE) { + val nextLastOffset = lastCharOffset + lookahead() + if (token == CLASS) fuse(CASECLASS) + else if (token == OBJECT) fuse(CASEOBJECT) + else reset(nextLastOffset) } else if (token == SEMI) { - prev copyFrom this - fetchToken() - if (token != ELSE) { - next copyFrom this - this copyFrom prev - } + val nextLastOffset = lastCharOffset + lookahead() + if (token != ELSE) reset(nextLastOffset) } } diff --git a/src/dotty/tools/dotc/parsing/SymbolicXMLBuilder.scala b/src/dotty/tools/dotc/parsing/SymbolicXMLBuilder.scala index 3c7a1ec4f..77e336b34 100644 --- a/src/dotty/tools/dotc/parsing/SymbolicXMLBuilder.scala +++ b/src/dotty/tools/dotc/parsing/SymbolicXMLBuilder.scala @@ -24,7 +24,7 @@ import scala.language.implicitConversions * @author Burak Emir * @version 1.0 */ -abstract class SymbolicXMLBuilder(preserveWS: Boolean)(implicit ctx: Context) { +class SymbolicXMLBuilder(preserveWS: Boolean)(implicit ctx: Context) { import Constants.Constant import untpd._ diff --git a/src/dotty/tools/dotc/parsing/Tokens.scala b/src/dotty/tools/dotc/parsing/Tokens.scala index f573df49d..4483818c9 100644 --- a/src/dotty/tools/dotc/parsing/Tokens.scala +++ b/src/dotty/tools/dotc/parsing/Tokens.scala @@ -156,8 +156,11 @@ object Tokens { final val localModifierTokens = BitSet( ABSTRACT, FINAL, SEALED, IMPLICIT, LAZY) - final val modifierTokens = localModifierTokens | BitSet( - PRIVATE, PROTECTED, OVERRIDE) + final val accessModifierTokens = BitSet( + PRIVATE, PROTECTED) + + final val modifierTokens = localModifierTokens | accessModifierTokens | BitSet( + OVERRIDE) /** Is token only legal as start of statement (eof also included)? */ final val mustStartStatTokens = defIntroTokens | modifierTokens | BitSet( @@ -168,4 +171,6 @@ object Tokens { final val canEndStatTokens = atomicExprTokens | BitSet( TYPE, RPAREN, RBRACE, RBRACKET) + + final val numericLitTokens = BitSet(INTLIT, LONGLIT, FLOATLIT, DOUBLELIT) } diff --git a/src/dotty/tools/dotc/parsing/TreeBuilder.scala b/src/dotty/tools/dotc/parsing/TreeBuilder.scala index 2f415e6a5..772849e98 100644 --- a/src/dotty/tools/dotc/parsing/TreeBuilder.scala +++ b/src/dotty/tools/dotc/parsing/TreeBuilder.scala @@ -6,17 +6,15 @@ import core._ import Flags._, Trees._, TypedTrees._, UntypedTrees._, Names._, StdNames._, NameOps._, Contexts._ import scala.collection.mutable.ListBuffer import util.Positions._, Symbols._, Decorators._, Flags._, Constants._ +import TreeInfo._ /** Methods for building trees, used in the parser. All the trees * returned by this class must be untyped. */ -abstract class TreeBuilder(implicit ctx: Context) { +class TreeBuilder()(implicit ctx: Context) { import untpd._ - def o2p(offset: Int): Position - def r2p(start: Int, point: Int, end: Int): Position - def scalaDot(name: Name)(implicit cpos: Position): Select = Select(new TypedSplice(tpd.Ident(defn.ScalaPackageVal.termRef)), name) @@ -28,26 +26,28 @@ abstract class TreeBuilder(implicit ctx: Context) { def productConstrN(n: Int)(implicit cpos: Position) = scalaDot(("Product" + n).toTypeName) def serializableConstr(implicit cpos: Position) = scalaDot(tpnme.Serializable) - def convertToTypeName(t: Tree) = ??? + def convertToTypeName(t: Tree): Tree = ??? - implicit val cpos = NoPosition + private implicit val cpos = NoPosition /** Convert all occurrences of (lower-case) variables in a pattern as follows: * x becomes x @ _ * x: T becomes x @ (_: T) + * Also covert all toplevel lower-case type arguments as follows: + * t becomes t @ _ */ private object patvarTransformer extends TreeTransformer { override def transform(tree: Tree): Tree = tree match { - case Ident(name) if (treeInfo.isVarPattern(tree) && name != nme.WILDCARD) => + case Ident(name) if isVarPattern(tree) && name != nme.WILDCARD => Bind( name, Ident(nme.WILDCARD)(tree.pos.focus) )(tree.pos) - case Typed(id @ Ident(name), tpt) if (treeInfo.isVarPattern(id) && name != nme.WILDCARD) => + case Typed(id @ Ident(name), tpt) if isVarPattern(id) && name != nme.WILDCARD => Bind( name, Typed( Ident(nme.WILDCARD)(tree.pos.focus), - tpt + transform(tpt) )(tree.pos.withStart(tree.pos.point)) )(tree.pos.withPoint(id.pos.point)) case Apply(fn @ Apply(_, _), args) => @@ -55,17 +55,21 @@ abstract class TreeBuilder(implicit ctx: Context) { case Apply(fn, args) => tree.derivedApply(fn, transform(args)) case Typed(expr, tpt) => - tree.derivedTyped(transform(expr), tpt) + tree.derivedTyped(transform(expr), transform(tpt)) case Bind(name, body) => tree.derivedBind(name, transform(body)) - case Alternative(_) => + case AppliedTypeTree(tycon, args) => + tree.derivedAppliedTypeTree(tycon, args map transform) + case Alternative(_) | Typed(_, _) | AndTypeTree(_, _) | Annotated(_, _) => super.transform(tree) + case Parens(_) => + stripParens(tree) case _ => tree } } -case class VariableInfo(name: Name, tree: Tree, pos: Position) + case class VariableInfo(name: Name, tree: Tree, pos: Position) /** Traverse pattern and collect all variable names with their types in buffer * The variables keep their positions; whereas the pattern is converted to be @@ -89,7 +93,7 @@ case class VariableInfo(name: Name, tree: Tree, pos: Position) tree match { case Bind(nme.WILDCARD, _) => foldOver(buf, tree) - case Bind(name, Typed(tree1, tpt)) if !treeInfo.mayBeTypePat(tpt) => + case Bind(name, Typed(tree1, tpt)) if !mayBeTypePat(tpt) => apply(add(name, tpt), tree1) case Bind(name, tree1) => apply(add(name, TypeTree()), tree1) @@ -110,8 +114,13 @@ case class VariableInfo(name: Name, tree: Tree, pos: Position) def repeatedApplication(tpe: Tree)(implicit cpos: Position): Tree = AppliedTypeTree(scalaDot(tpnme.REPEATED_PARAM_CLASS), List(tpe)) - private def makeTuple(trees: List[Tree])(implicit cpos: Position): Tree = { - def mkPair(t1: Tree, t2: Tree) = Pair(t1, t2)(Position(t1.pos.start, cpos.end)) + def makeTuple(trees: List[Tree])(implicit cpos: Position): Tree = { + val endPos = cpos.endPos + def mkPair(t1: Tree, t2: Tree) = { + implicit val cpos = endPos + if (t1.isType) AppliedTypeTree(scalaDot(tpnme.Pair), List(t1, t2)) + else Pair(t1, t2) + } trees reduce mkPair } @@ -123,18 +132,19 @@ case class VariableInfo(name: Name, tree: Tree, pos: Position) def makeSelfDef(name: TermName, tpt: Tree)(implicit cpos: Position): ValDef = ValDef(Modifiers(Private), name, tpt, EmptyTree()) - /** If tree is a variable pattern, return Some("its name and type"). - * Otherwise return none */ - private def matchVarPattern(tree: Tree): Option[(Name, Tree)] = { + /** If tree is a variable pattern, return its variable info. + * Otherwise return none. + */ + private def matchVarPattern(tree: Tree): Option[VariableInfo] = { def wildType(t: Tree): Option[Tree] = t match { case Ident(x) if x.toTermName == nme.WILDCARD => Some(TypeTree()) case Typed(Ident(x), tpt) if x.toTermName == nme.WILDCARD => Some(tpt) case _ => None } tree match { - case Ident(name) => Some((name, TypeTree())) - case Bind(name, body) => wildType(body) map (x => (name, x)) - case Typed(Ident(name), tpt) => Some((name, tpt)) + case Ident(name) => Some(VariableInfo(name, TypeTree(), tree.pos)) + case Bind(name, body) => wildType(body) map (x => VariableInfo(name, x, tree.pos)) + case Typed(id @ Ident(name), tpt) => Some(VariableInfo(name, tpt, id.pos)) case _ => None } } @@ -151,7 +161,7 @@ case class VariableInfo(name: Name, tree: Tree, pos: Position) case _ => right :: Nil } if (isExpr) { - if (treeInfo.isLeftAssoc(op)) { + if (isLeftAssoc(op)) { Apply(Select(stripParens(left), op.encode)(opPos), arguments) } else { val x = ctx.freshName().toTermName @@ -164,20 +174,11 @@ case class VariableInfo(name: Name, tree: Tree, pos: Position) } } - /** Creates a tree representing new Object { stats }. - * To make sure an anonymous subclass of Object is created, - * if there are no stats, a () is added. - */ - def makeAnonymousNew(stats: List[Tree])(implicit cpos: Position): Tree = { - val stats1 = if (stats.isEmpty) Literal(Constant(())) :: Nil else stats - makeNew(Nil, EmptyValDef(), stats1) - } - /** tpt. */ def SelectConstructor(tpt: Tree)(implicit cpos: Position): Tree = Select(tpt, nme.CONSTRUCTOR) - def splitArgss(constr: Tree, outerArgss: List[List[Tree]]): (Tree, List[List[Tree]]) = constr match { + private def splitArgss(constr: Tree, outerArgss: List[List[Tree]]): (Tree, List[List[Tree]]) = constr match { case Apply(tree, args) => splitArgss(tree, args :: outerArgss) case _ => (constr, if (outerArgss.isEmpty) ListOfNil else outerArgss) } @@ -185,24 +186,36 @@ case class VariableInfo(name: Name, tree: Tree, pos: Position) /** new tpt(argss_1)...(argss_n) * @param npos the position spanning , without any arguments */ - def makeNew(parentConstr: Tree, npos: Position) = { - val (tpt, argss1) = splitArgss(parentConstr, Nil) - (SelectConstructor(tpt)(npos) /: argss1)(Apply(_, _)) + def makeNew(parentConstr: Tree)(implicit cpos: Position) = { + val (tpt, argss) = splitArgss(parentConstr, Nil) + New(tpt, argss) } /** Create positioned tree representing an object creation stats } - * @param pos the position of the new, focus should be the first parent's start. + */ + def makeNew(templ: Template)(implicit cpos: Position): Tree = { + val x = tpnme.ANON_CLASS + val nu = makeNew(Ident(x)) + val clsDef = { + implicit val cpos = NoPosition + ClassDef(Modifiers(Final), x, Nil, templ) + } + Block(clsDef, nu) + } + + /** Create positioned tree representing an object creation stats } + * @param cpos the position of the new, focus should be the first parent's start. */ def makeNew(parents: List[Tree], self: ValDef, stats: List[Tree])(implicit cpos: Position): Tree = { val newPos = Position(cpos.start, cpos.point) val clsPos = Position(cpos.point, cpos.end) if (parents.isEmpty) - makeNew(List(scalaAnyRefConstr(cpos.startPos)), self, stats) + makeNew(List(scalaAnyRefConstr(newPos.endPos)), self, stats) else if (parents.tail.isEmpty && stats.isEmpty) - makeNew(parents.head, newPos) + makeNew(parents.head) else { val x = tpnme.ANON_CLASS - val nu = makeNew(Ident(x)(newPos), newPos) + val nu = makeNew(Ident(x)(newPos))(newPos) val clsDef = { implicit val cpos = clsPos ClassDef(Modifiers(Final), x, Nil, Template(parents, self, stats)) @@ -212,7 +225,7 @@ case class VariableInfo(name: Name, tree: Tree, pos: Position) } /** Create a tree representing an assignment */ - def makeAssign(lhs: Tree, rhs: Tree): Tree = lhs match { + def makeAssign(lhs: Tree, rhs: Tree)(implicit cpos: Position): Tree = lhs match { case Apply(fn, args) => Apply(Select(fn, nme.update), args :+ rhs) case _ => @@ -225,7 +238,7 @@ case class VariableInfo(name: Name, tree: Tree, pos: Position) else CompoundTypeTree(Template(tps, emptyValDef, Nil))*/ private def labelDefAndCall(lname: TermName, rhs: Tree, call: Tree)(implicit cpos: Position) = { - val ldef = DefDef(Modifiers(Label), lname, Nil, ListOfNil, TypeTree(), rhs) + val ldef = DefDef(Modifiers(Label)(cpos.startPos), lname, Nil, ListOfNil, TypeTree(), rhs) Block(ldef, call) } @@ -256,7 +269,7 @@ case class VariableInfo(name: Name, tree: Tree, pos: Position) else if (stats.length == 1) stats.head else Block(stats.init, stats.last) - def makeFilter(tree: Tree, condition: Tree, canDrop: Boolean): Tree = { + def makePatFilter(tree: Tree, condition: Tree, canDrop: Boolean): Tree = { val cases = List( CaseDef(condition, EmptyTree(), Literal(Constant(true))), CaseDef(Ident(nme.WILDCARD), EmptyTree(), Literal(Constant(false))) @@ -272,14 +285,14 @@ case class VariableInfo(name: Name, tree: Tree, pos: Position) def makeGenerator(pat: Tree, valeq: Boolean, rhs: Tree)(implicit cpos: Position): Enumerator = { val pat1 = patvarTransformer.transform(pat) if (valeq) ValEq(pat1, rhs)(cpos) - else ValFrom(pat1, makeFilter(rhs, pat1, canDrop = true))(cpos) + else ValFrom(pat1, makePatFilter(rhs, pat1, canDrop = true))(cpos) } def makeParam(pname: TermName, tpe: Tree)(implicit cpos: Position) = - ValDef(Modifiers(Param), pname, tpe, EmptyTree()) + ValDef(Modifiers(Param)(cpos.startPos), pname, tpe, EmptyTree()) def makeSyntheticParam(pname: TermName)(implicit cpos: Position) = - ValDef(Modifiers(SyntheticTermParam), pname, TypeTree(), EmptyTree()) + ValDef(Modifiers(SyntheticTermParam)(cpos.startPos), pname, TypeTree(), EmptyTree()) /* def makeSyntheticTypeParam(pname: TypeName, bounds: Tree) = TypeDef(Modifiers(DEFERRED | SYNTHETIC), pname, Nil, bounds) @@ -351,8 +364,8 @@ case class VariableInfo(name: Name, tree: Tree, pos: Position) */ def makeClosure(pat: Tree, body: Tree)(implicit cpos: Position): Tree = matchVarPattern(pat) match { - case Some((name, tpt)) => - Function(ValDef(Modifiers(Param), name.toTermName, tpt, EmptyTree())(pat.pos), body) + case Some(VariableInfo(name, tpt, pos)) => + Function(ValDef(Modifiers(Param)(cpos.startPos), name.toTermName, tpt, EmptyTree())(pos), body) case None => makeVisitor(List(CaseDef(pat, EmptyTree(), body)), checkExhaustive = false) } @@ -399,7 +412,7 @@ case class VariableInfo(name: Name, tree: Tree, pos: Position) val rhss = valeqs map { case ValEq(_, rhs) => rhs } val defpat1 = makeBind(pat) val defpats = pats map makeBind - val pdefs = (defpats, rhss).zipped flatMap makePatDef + val pdefs = (defpats, rhss).zipped flatMap (makePatDef) val ids = (defpat1 :: defpats) map makeValue val rhs1 = makeForYield(ValFrom(defpat1, rhs) :: Nil, Block(pdefs, makeTuple(ids))) val allpats = pat :: pats @@ -419,12 +432,11 @@ case class VariableInfo(name: Name, tree: Tree, pos: Position) makeFor(nme.map, nme.flatMap, enums, body) /** Create tree for a pattern alternative */ - def makeAlternative(ts: List[Tree]): Tree = { - def alternatives(t: Tree): List[Tree] = t match { - case Alternative(ts) => ts - case _ => List(t) - } - Alternative(ts flatMap alternatives) + def makeAlternative(ts: List[Tree]): Tree = Alternative(ts flatMap alternatives) + + def alternatives(t: Tree): List[Tree] = t match { + case Alternative(ts) => ts + case _ => List(t) } def mkAnnotated(cls: Symbol, tree: Tree) = @@ -445,33 +457,14 @@ case class VariableInfo(name: Name, tree: Tree, pos: Position) def makeCaseDef(pat: Tree, guard: Tree, rhs: Tree): CaseDef = CaseDef(patvarTransformer.transform(pat), guard, rhs) - /** Creates tree representing: - * { case x: Throwable => - * val catchFn = catchExpr - * if (catchFn isDefinedAt x) catchFn(x) else throw x - * } - */ - def makeCatchFromExpr(catchExpr: Tree): CaseDef = { - implicit val cpos = catchExpr.pos.startPos - val binder = ctx.freshName("x").toTermName - val pat = Bind(binder, Typed(Ident(nme.WILDCARD), Ident(tpnme.Throwable))) - val catchDef = ValDef(Modifiers(), ctx.freshName("catchExpr").toTermName, TypeTree(), catchExpr) - val catchFn = Ident(catchDef.name) - val cond = Apply(Select(catchFn, nme.isDefinedAt), Ident(binder)) - val app = Apply(Select(catchFn, nme.apply), List(Ident(binder))) - val thro = Throw(Ident(binder)) - val body = Block(catchDef, If(cond, app, thro)) - makeCaseDef(pat, EmptyTree(), body) - } - /** Create tree for pattern definition */ def makePatDef(pat: Tree, rhs: Tree): List[Tree] = makePatDef(Modifiers(), pat, rhs) /** Create tree for pattern definition */ def makePatDef(mods: Modifiers, pat: Tree, rhs: Tree, varsArePatterns: Boolean = false): List[Tree] = matchVarPattern(pat) match { - case Some((name, tpt)) if varsArePatterns => - ValDef(mods, name.toTermName, tpt, rhs) :: Nil + case Some(VariableInfo(name, tpt, pos)) if varsArePatterns => + ValDef(mods, name.toTermName, tpt, rhs)(pos) :: Nil // point comes from pat.pos case _ => // in case there is exactly one variable x_1 in pattern @@ -525,7 +518,7 @@ case class VariableInfo(name: Name, tree: Tree, pos: Position) } /** Create a tree representing the function type (argtpes) => restpe */ - def makeFunctionTypeTree(argtpes: List[Tree], restpe: Tree): Tree = + def makeFunctionTypeTree(argtpes: List[Tree], restpe: Tree)(implicit cpos: Position): Tree = AppliedTypeTree(scalaDot(("Function" + argtpes.length).toTypeName), argtpes ::: List(restpe)) /** Append implicit parameter section if `contextBounds` nonempty */ @@ -534,7 +527,7 @@ case class VariableInfo(name: Name, tree: Tree, pos: Position) else { val mods = Modifiers(if (owner.isTypeName) PrivateLocal | ParamAccessor else Param) val evidenceParams = for (tpt <- contextBounds) yield { - val pname = ctx.freshName(nme.EVIDENCE_PARAM_PREFIX.toString).toTermName + val pname = ctx.freshName(nme.EVIDENCE_PARAM_PREFIX).toTermName ValDef(mods | Implicit | Synthetic, pname, tpt, EmptyTree()) } vparamss.reverse match { diff --git a/src/dotty/tools/dotc/util/Positions.scala b/src/dotty/tools/dotc/util/Positions.scala index 2ab6c1920..056af00d1 100644 --- a/src/dotty/tools/dotc/util/Positions.scala +++ b/src/dotty/tools/dotc/util/Positions.scala @@ -11,12 +11,12 @@ package util object Positions { private val StartEndBits = 26 - private val StartEndMask = (1 << StartEndBits) - 1 + private val StartEndMask: Long = (1L << StartEndBits) - 1 private val PointOffsetLimit = 1L << (64 - StartEndBits * 2) class Position(val coords: Long) extends AnyVal { - def point: Int = start + (coords >>> (StartEndBits * 2)).toInt def start: Int = (coords & StartEndMask).toInt + def point: Int = start + (coords >>> (StartEndBits * 2)).toInt def end: Int = ((coords >>> StartEndBits) & StartEndMask).toInt /** The union of two positions. Tries to keep the point offset of @@ -59,6 +59,16 @@ object Positions { val NoPosition = new Position(-1L) + case class PositionPrefix(val coords: Long) extends AnyVal { + def start: Int = (coords & StartEndMask).toInt + def point: Int = start + (coords >>> StartEndBits).toInt + def toPosition(end: Int) = Position(start, end, point - start max 0) + } + + def PositionPrefix(start: Int, pointOffset: Int = 0): PositionPrefix = + new PositionPrefix( + (start & StartEndMask).toLong | pointOffset.toLong << StartEndBits) + case class SourcePosition(source: SourceFile, pos: Position) { def point: Int = pos.point def start: Int = pos.start -- cgit v1.2.3