diff options
Diffstat (limited to 'src/compiler/scala/tools/reflect/quasiquotes/Parsers.scala')
-rw-r--r-- | src/compiler/scala/tools/reflect/quasiquotes/Parsers.scala | 94 |
1 files changed, 50 insertions, 44 deletions
diff --git a/src/compiler/scala/tools/reflect/quasiquotes/Parsers.scala b/src/compiler/scala/tools/reflect/quasiquotes/Parsers.scala index 9a6ba56c18..18a806e5ff 100644 --- a/src/compiler/scala/tools/reflect/quasiquotes/Parsers.scala +++ b/src/compiler/scala/tools/reflect/quasiquotes/Parsers.scala @@ -17,32 +17,38 @@ trait Parsers { self: Quasiquotes => abstract class Parser extends { val global: self.global.type = self.global } with ScalaParser { - /** Wraps given code to obtain a desired parser mode. - * This way we can just re-use standard parser entry point. - */ - def wrapCode(code: String): String = - s"object wrapper { self => $EOL $code $EOL }" - - def unwrapTree(wrappedTree: Tree): Tree = { - val PackageDef(_, List(ModuleDef(_, _, Template(_, _, _ :: parsed)))) = wrappedTree - parsed match { - case tree :: Nil => tree - case stats :+ tree => Block(stats, tree) - } - } - def parse(code: String): Tree = { try { - val wrapped = wrapCode(code) - debug(s"wrapped code\n=${wrapped}\n") - val file = new BatchSourceFile(nme.QUASIQUOTE_FILE, wrapped) - val tree = new QuasiquoteParser(file).parse() - unwrapTree(tree) + val file = new BatchSourceFile(nme.QUASIQUOTE_FILE, code) + new QuasiquoteParser(file).parseRule(entryPoint) } catch { - case mi: MalformedInput => c.abort(c.macroApplication.pos, s"syntax error: ${mi.msg}") + case mi: MalformedInput => c.abort(correspondingPosition(mi.offset), mi.msg) + } + } + + def correspondingPosition(offset: Int): Position = { + val posMapList = posMap.toList + def containsOffset(start: Int, end: Int) = start <= offset && offset <= end + def fallbackPosition = posMapList match { + case (pos1, (start1, end1)) :: _ if start1 > offset => pos1 + case _ :+ ((pos2, (start2, end2))) if offset > end2 => pos2.withPoint(pos2.point + (end2 - start2)) } + posMapList.sliding(2).collect { + case (pos1, (start1, end1)) :: _ if containsOffset(start1, end1) => (pos1, offset - start1) + case (pos1, (_, end1)) :: (_, (start2, _)) :: _ if containsOffset(end1, start2) => (pos1, end1) + case _ :: (pos2, (start2, end2)) :: _ if containsOffset(start2, end2) => (pos2, offset - start2) + }.map { case (pos, offset) => + pos.withPoint(pos.point + offset) + }.toList.headOption.getOrElse(fallbackPosition) } + override def token2string(token: Int): String = token match { + case EOF => "end of quote" + case _ => super.token2string(token) + } + + def entryPoint: QuasiquoteParser => Tree + class QuasiquoteParser(source0: SourceFile) extends SourceFileParser(source0) { override val treeBuilder = new ParserTreeBuilder { // q"(..$xs)" @@ -73,9 +79,11 @@ trait Parsers { self: Quasiquotes => } else super.caseClause() - def isHole = isIdent && holeMap.contains(in.name) + def isHole: Boolean = isIdent && holeMap.contains(in.name) - override def isAnnotation: Boolean = super.isAnnotation || (isHole && lookingAhead { isAnnotation }) + override def isAnnotation: Boolean = super.isAnnotation || (isHole && lookingAhead { isAnnotation }) + + override def isCaseDefStart: Boolean = super.isCaseDefStart || (in.token == EOF) override def isModifier: Boolean = super.isModifier || (isHole && lookingAhead { isModifier }) @@ -85,6 +93,12 @@ trait Parsers { self: Quasiquotes => override def isDclIntro: Boolean = super.isDclIntro || (isHole && lookingAhead { isDclIntro }) + override def isStatSep(token: Int) = token == EOF || super.isStatSep(token) + + override def expectedMsg(token: Int): String = + if (isHole) expectedMsgTemplate(token2string(token), "splicee") + else super.expectedMsg(token) + // $mods def foo // $mods T override def readAnnots(annot: => Tree): List[Tree] = in.token match { @@ -101,34 +115,26 @@ trait Parsers { self: Quasiquotes => } } - object TermParser extends Parser - - object CaseParser extends Parser { - override def wrapCode(code: String) = super.wrapCode("something match { case " + code + " }") - - override def unwrapTree(wrappedTree: Tree): Tree = { - val Match(_, head :: tail) = super.unwrapTree(wrappedTree) - if (tail.nonEmpty) - c.abort(c.macroApplication.pos, "Can't parse more than one casedef, consider generating a match tree instead") - head + object TermParser extends Parser { + def entryPoint = _.templateStats() match { + case Nil => EmptyTree + case tree :: Nil => tree + case stats :+ tree => Block(stats, tree) } } - object PatternParser extends Parser { - override def wrapCode(code: String) = super.wrapCode("something match { case " + code + " => }") - - override def unwrapTree(wrappedTree: Tree): Tree = { - val Match(_, List(CaseDef(pat, _, _))) = super.unwrapTree(wrappedTree) - pat - } + object TypeParser extends Parser { + def entryPoint = _.typ() } - object TypeParser extends Parser { - override def wrapCode(code: String) = super.wrapCode("type T = " + code) + object CaseParser extends Parser { + def entryPoint = _.caseClause() + } - override def unwrapTree(wrappedTree: Tree): Tree = { - val TypeDef(_, _, _, rhs) = super.unwrapTree(wrappedTree) - rhs + object PatternParser extends Parser { + def entryPoint = { parser => + val pat = parser.noSeq.pattern1() + parser.treeBuilder.patvarTransformer.transform(pat) } } }
\ No newline at end of file |