aboutsummaryrefslogtreecommitdiff
path: root/compiler/src/dotty/tools/dotc/parsing/Parsers.scala
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2016-11-17 18:29:09 +0100
committerMartin Odersky <odersky@gmail.com>2016-11-24 16:43:59 +0100
commit40c1913dd539beb4b6184b37d87e48d98803a465 (patch)
tree833a36016b51d3149525f1f6e7ea18a41d22b192 /compiler/src/dotty/tools/dotc/parsing/Parsers.scala
parent3588832eb3c45b151d78e66b5cde1f4e772d52a8 (diff)
downloaddotty-40c1913dd539beb4b6184b37d87e48d98803a465.tar.gz
dotty-40c1913dd539beb4b6184b37d87e48d98803a465.tar.bz2
dotty-40c1913dd539beb4b6184b37d87e48d98803a465.zip
More robust scheme for taking start/end of positions when parsing
Some trees, which do not consume input have unassigned positions (so that they can fit in whatever range they are integrated). It's therefore risky to take the start or end of a parsed tree's position. This commit guards against the case where the position of the tree does not exist.
Diffstat (limited to 'compiler/src/dotty/tools/dotc/parsing/Parsers.scala')
-rw-r--r--compiler/src/dotty/tools/dotc/parsing/Parsers.scala71
1 files changed, 40 insertions, 31 deletions
diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala
index fa0576c7a..838f7514c 100644
--- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala
+++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala
@@ -83,6 +83,14 @@ object Parsers {
def atPos[T <: Positioned](start: Offset)(t: T): T =
atPos(start, start)(t)
+ /** Defensive version of Position#start */
+ def startPos(t: Positioned): Int =
+ if (t.pos.exists) t.pos.start else in.offset
+
+ /** Defensive version of Position#end */
+ def endPos(t: Positioned): Int =
+ if (t.pos.exists) t.pos.end else in.lastOffset
+
def nameStart: Offset =
if (in.token == BACKQUOTED_IDENT) in.offset + 1 else in.offset
@@ -448,7 +456,7 @@ object Parsers {
val topInfo = opStack.head
opStack = opStack.tail
val od = reduceStack(base, topInfo.operand, 0, true)
- return atPos(od.pos.start, topInfo.offset) {
+ return atPos(startPos(od), topInfo.offset) {
PostfixOp(od, topInfo.operator)
}
}
@@ -492,7 +500,7 @@ object Parsers {
/** Accept identifier acting as a selector on given tree `t`. */
def selector(t: Tree): Tree =
- atPos(t.pos.start, in.offset) { Select(t, ident()) }
+ atPos(startPos(t), in.offset) { Select(t, ident()) }
/** Selectors ::= ident { `.' ident()
*
@@ -728,7 +736,7 @@ object Parsers {
def refinedTypeRest(t: Tree): Tree = {
newLineOptWhenFollowedBy(LBRACE)
- if (in.token == LBRACE) refinedTypeRest(atPos(t.pos.start) { RefinedTypeTree(t, refinement()) })
+ if (in.token == LBRACE) refinedTypeRest(atPos(startPos(t)) { RefinedTypeTree(t, refinement()) })
else t
}
@@ -749,7 +757,7 @@ object Parsers {
def annotType(): Tree = annotTypeRest(simpleType())
def annotTypeRest(t: Tree): Tree =
- if (in.token == AT) annotTypeRest(atPos(t.pos.start) { Annotated(t, annot()) })
+ if (in.token == AT) annotTypeRest(atPos(startPos(t)) { Annotated(t, annot()) })
else t
/** SimpleType ::= SimpleType TypeArgs
@@ -780,19 +788,19 @@ object Parsers {
val handleSingletonType: Tree => Tree = t =>
if (in.token == TYPE) {
in.nextToken()
- atPos(t.pos.start) { SingletonTypeTree(t) }
+ atPos(startPos(t)) { SingletonTypeTree(t) }
} else t
private def simpleTypeRest(t: Tree): Tree = in.token match {
case HASH => simpleTypeRest(typeProjection(t))
- case LBRACKET => simpleTypeRest(atPos(t.pos.start) { AppliedTypeTree(t, typeArgs(namedOK = true)) })
+ case LBRACKET => simpleTypeRest(atPos(startPos(t)) { AppliedTypeTree(t, typeArgs(namedOK = true)) })
case _ => t
}
private def typeProjection(t: Tree): Tree = {
accept(HASH)
val id = typeIdent()
- atPos(t.pos.start, id.pos.start) { Select(t, id.name) }
+ atPos(startPos(t), startPos(id)) { Select(t, id.name) }
}
/** NamedTypeArg ::= id `=' Type
@@ -846,7 +854,7 @@ object Parsers {
val t = toplevelTyp()
if (isIdent(nme.raw.STAR)) {
in.nextToken()
- atPos(t.pos.start) { PostfixOp(t, nme.raw.STAR) }
+ atPos(startPos(t)) { PostfixOp(t, nme.raw.STAR) }
} else t
}
@@ -971,7 +979,7 @@ object Parsers {
val t = expr1(location)
if (in.token == ARROW) {
placeholderParams = saved
- closureRest(t.pos.start, location, convertToParams(t))
+ closureRest(startPos(t), location, convertToParams(t))
}
else if (isWildcard(t)) {
placeholderParams = placeholderParams ::: saved
@@ -1025,7 +1033,7 @@ object Parsers {
assert(handlerStart != -1)
syntaxError(
new EmptyCatchBlock(body),
- Position(handlerStart, handler.pos.end)
+ Position(handlerStart, endPos(handler))
)
case _ =>
}
@@ -1035,7 +1043,7 @@ object Parsers {
else {
if (handler.isEmpty) warning(
EmptyCatchAndFinallyBlock(body),
- source atPos Position(tryOffset, body.pos.end)
+ source atPos Position(tryOffset, endPos(body))
)
EmptyTree
}
@@ -1057,21 +1065,21 @@ object Parsers {
case EQUALS =>
t match {
case Ident(_) | Select(_, _) | Apply(_, _) =>
- atPos(t.pos.start, in.skipToken()) { Assign(t, expr()) }
+ atPos(startPos(t), in.skipToken()) { Assign(t, expr()) }
case _ =>
t
}
case COLON =>
ascription(t, location)
case MATCH =>
- atPos(t.pos.start, in.skipToken()) {
+ atPos(startPos(t), in.skipToken()) {
inBraces(Match(t, caseClauses()))
}
case _ =>
t
}
- def ascription(t: Tree, location: Location.Value) = atPos(t.pos.start, in.skipToken()) {
+ def ascription(t: Tree, location: Location.Value) = atPos(startPos(t), in.skipToken()) {
in.token match {
case USCORE =>
val uscoreStart = in.skipToken()
@@ -1105,7 +1113,7 @@ object Parsers {
val id = termIdent()
val paramExpr =
if (location == Location.InBlock && in.token == COLON)
- atPos(id.pos.start, in.skipToken()) { Typed(id, infixType()) }
+ atPos(startPos(id), in.skipToken()) { Typed(id, infixType()) }
else
id
closureRest(start, location, convertToParam(paramExpr, mods) :: Nil)
@@ -1194,13 +1202,13 @@ object Parsers {
in.nextToken()
simpleExprRest(selector(t), canApply = true)
case LBRACKET =>
- val tapp = atPos(t.pos.start, in.offset) { TypeApply(t, typeArgs(namedOK = true)) }
+ val tapp = atPos(startPos(t), in.offset) { TypeApply(t, typeArgs(namedOK = true)) }
simpleExprRest(tapp, canApply = true)
case LPAREN | LBRACE if canApply =>
- val app = atPos(t.pos.start, in.offset) { Apply(t, argumentExprs()) }
+ val app = atPos(startPos(t), in.offset) { Apply(t, argumentExprs()) }
simpleExprRest(app, canApply = true)
case USCORE =>
- atPos(t.pos.start, in.skipToken()) { PostfixOp(t, nme.WILDCARD) }
+ atPos(startPos(t), in.skipToken()) { PostfixOp(t, nme.WILDCARD) }
case _ =>
t
}
@@ -1284,7 +1292,7 @@ object Parsers {
if (in.token == IF) guard()
else {
val pat = pattern1()
- if (in.token == EQUALS) atPos(pat.pos.start, in.skipToken()) { GenAlias(pat, expr()) }
+ if (in.token == EQUALS) atPos(startPos(pat), in.skipToken()) { GenAlias(pat, expr()) }
else generatorRest(pat)
}
@@ -1293,7 +1301,7 @@ object Parsers {
def generator(): Tree = generatorRest(pattern1())
def generatorRest(pat: Tree) =
- atPos(pat.pos.start, accept(LARROW)) { GenFrom(pat, expr()) }
+ atPos(startPos(pat), accept(LARROW)) { GenFrom(pat, expr()) }
/** ForExpr ::= `for' (`(' Enumerators `)' | `{' Enumerators `}')
* {nl} [`yield'] Expr
@@ -1357,7 +1365,7 @@ object Parsers {
val pattern = () => {
val pat = pattern1()
if (isIdent(nme.raw.BAR))
- atPos(pat.pos.start) { Alternative(pat :: patternAlts()) }
+ atPos(startPos(pat)) { Alternative(pat :: patternAlts()) }
else pat
}
@@ -1383,15 +1391,15 @@ object Parsers {
// compatibility for Scala2 `x @ _*` syntax
infixPattern() match {
case pt @ Ident(tpnme.WILDCARD_STAR) =>
- migrationWarningOrError("The syntax `x @ _*' is no longer supported; use `x : _*' instead", p.pos.start)
- atPos(p.pos.start, offset) { Typed(p, pt) }
+ migrationWarningOrError("The syntax `x @ _*' is no longer supported; use `x : _*' instead", startPos(p))
+ atPos(startPos(p), offset) { Typed(p, pt) }
case p =>
- atPos(p.pos.start, offset) { Bind(name, p) }
+ atPos(startPos(p), offset) { Bind(name, p) }
}
case p @ Ident(tpnme.WILDCARD_STAR) =>
// compatibility for Scala2 `_*` syntax
- migrationWarningOrError("The syntax `_*' is no longer supported; use `x : _*' instead", p.pos.start)
- atPos(p.pos.start) { Typed(Ident(nme.WILDCARD), p) }
+ migrationWarningOrError("The syntax `_*' is no longer supported; use `x : _*' instead", startPos(p))
+ atPos(startPos(p)) { Typed(Ident(nme.WILDCARD), p) }
case p =>
p
}
@@ -1415,7 +1423,7 @@ object Parsers {
val simplePattern = () => in.token match {
case IDENTIFIER | BACKQUOTED_IDENT | THIS =>
path(thisOK = true) match {
- case id @ Ident(nme.raw.MINUS) if isNumericLit => literal(id.pos.start)
+ case id @ Ident(nme.raw.MINUS) if isNumericLit => literal(startPos(id))
case t => simplePatternRest(t)
}
case USCORE =>
@@ -1445,9 +1453,9 @@ object Parsers {
def simplePatternRest(t: Tree): Tree = {
var p = t
if (in.token == LBRACKET)
- p = atPos(t.pos.start, in.offset) { TypeApply(p, typeArgs()) }
+ p = atPos(startPos(t), in.offset) { TypeApply(p, typeArgs()) }
if (in.token == LPAREN)
- p = atPos(t.pos.start, in.offset) { Apply(p, argumentPatterns()) }
+ p = atPos(startPos(t), in.offset) { Apply(p, argumentPatterns()) }
p
}
@@ -1573,7 +1581,8 @@ object Parsers {
case Select(qual, name) => cpy.Select(tree)(adjustStart(start)(qual), name)
case _ => tree
}
- if (start < tree1.pos.start) tree1.withPos(tree1.pos.withStart(start))
+ if (tree1.pos.exists && start < tree1.pos.start)
+ tree1.withPos(tree1.pos.withStart(start))
else tree1
}
@@ -1804,7 +1813,7 @@ object Parsers {
def importSelector(): Tree = {
val from = termIdentOrWildcard()
if (from.name != nme.WILDCARD && in.token == ARROW)
- atPos(from.pos.start, in.skipToken()) {
+ atPos(startPos(from), in.skipToken()) {
Thicket(from, termIdentOrWildcard())
}
else from