From 67d94f681fe17b18bb9ba1a3cec0a15a48bc3251 Mon Sep 17 00:00:00 2001 From: Som Snytt Date: Sat, 27 Jul 2013 14:49:57 -0700 Subject: SI-7715 String inpatternation s"$_" for s"${_}" In a pattern, ``` scala> implicit class RX(val sc: StringContext) { | def rx = sc.parts.mkString("(.+)").r } defined class RX scala> "2 by 4" match { case rx"$a by $_" => a } res0: String = 2 scala> val rx"$_ by $b" = "2 by 4" b: String = 4 ``` --- .../scala/tools/nsc/ast/parser/Parsers.scala | 105 ++++++++++++--------- 1 file changed, 63 insertions(+), 42 deletions(-) (limited to 'src/compiler/scala/tools/nsc/ast/parser/Parsers.scala') diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala index eb924a811b..b8dc5b92e6 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala @@ -1137,32 +1137,70 @@ self => }) } - private def interpolatedString(inPattern: Boolean): Tree = atPos(in.offset) { - val start = in.offset - val interpolator = in.name + /** Handle placeholder syntax. + * If evaluating the tree produces placeholders, then make it a function. + */ + private def withPlaceholders(tree: =>Tree, isAny: Boolean): Tree = { + val savedPlaceholderParams = placeholderParams + placeholderParams = List() + var res = tree + if (placeholderParams.nonEmpty && !isWildcard(res)) { + res = atPos(res.pos)(Function(placeholderParams.reverse, res)) + if (isAny) placeholderParams foreach (_.tpt match { + case tpt @ TypeTree() => tpt setType definitions.AnyTpe + case _ => // some ascription + }) + placeholderParams = List() + } + placeholderParams = placeholderParams ::: savedPlaceholderParams + res + } - val partsBuf = new ListBuffer[Tree] - val exprBuf = new ListBuffer[Tree] + /** Consume a USCORE and create a fresh synthetic placeholder param. */ + private def freshPlaceholder(): Tree = { + val start = in.offset + val pname = freshName("x$") in.nextToken() - while (in.token == STRINGPART) { - partsBuf += literal() - exprBuf += ( - if (inPattern) dropAnyBraces(pattern()) - else in.token match { - case IDENTIFIER => atPos(in.offset)(Ident(ident())) - case LBRACE => expr() - case THIS => in.nextToken(); atPos(in.offset)(This(tpnme.EMPTY)) - case _ => syntaxErrorOrIncompleteAnd("error in interpolated string: identifier or block expected", skipIt = true)(EmptyTree) - } - ) - } - if (in.token == STRINGLIT) partsBuf += literal() + val id = atPos(start)(Ident(pname)) + val param = atPos(id.pos.focus)(gen.mkSyntheticParam(pname.toTermName)) + placeholderParams = param :: placeholderParams + id + } + + private def interpolatedString(inPattern: Boolean): Tree = { + def errpolation() = syntaxErrorOrIncompleteAnd("error in interpolated string: identifier or block expected", + skipIt = true)(EmptyTree) + // Like Swiss cheese, with holes + def stringCheese: Tree = atPos(in.offset) { + val start = in.offset + val interpolator = in.name + + val partsBuf = new ListBuffer[Tree] + val exprBuf = new ListBuffer[Tree] + in.nextToken() + while (in.token == STRINGPART) { + partsBuf += literal() + exprBuf += ( + if (inPattern) dropAnyBraces(pattern()) + else in.token match { + case IDENTIFIER => atPos(in.offset)(Ident(ident())) + //case USCORE => freshPlaceholder() // ifonly etapolation + case LBRACE => expr() // dropAnyBraces(expr0(Local)) + case THIS => in.nextToken(); atPos(in.offset)(This(tpnme.EMPTY)) + case _ => errpolation() + } + ) + } + if (in.token == STRINGLIT) partsBuf += literal() - val t1 = atPos(o2p(start)) { Ident(nme.StringContext) } - val t2 = atPos(start) { Apply(t1, partsBuf.toList) } - t2 setPos t2.pos.makeTransparent - val t3 = Select(t2, interpolator) setPos t2.pos - atPos(start) { Apply(t3, exprBuf.toList) } + val t1 = atPos(o2p(start)) { Ident(nme.StringContext) } + val t2 = atPos(start) { Apply(t1, partsBuf.toList) } + t2 setPos t2.pos.makeTransparent + val t3 = Select(t2, interpolator) setPos t2.pos + atPos(start) { Apply(t3, exprBuf.toList) } + } + if (inPattern) stringCheese + else withPlaceholders(stringCheese, isAny = true) // strinterpolator params are Any* by definition } /* ------------- NEW LINES ------------------------------------------------- */ @@ -1260,18 +1298,7 @@ self => */ def expr(): Tree = expr(Local) - def expr(location: Int): Tree = { - val savedPlaceholderParams = placeholderParams - placeholderParams = List() - var res = expr0(location) - if (!placeholderParams.isEmpty && !isWildcard(res)) { - res = atPos(res.pos){ Function(placeholderParams.reverse, res) } - placeholderParams = List() - } - placeholderParams = placeholderParams ::: savedPlaceholderParams - res - } - + def expr(location: Int): Tree = withPlaceholders(expr0(location), isAny = false) def expr0(location: Int): Tree = (in.token: @scala.annotation.switch) match { case IF => @@ -1520,13 +1547,7 @@ self => case IDENTIFIER | BACKQUOTED_IDENT | THIS | SUPER => path(thisOK = true, typeOK = false) case USCORE => - val start = in.offset - val pname = freshName("x$") - in.nextToken() - val id = atPos(start) (Ident(pname)) - val param = atPos(id.pos.focus){ gen.mkSyntheticParam(pname.toTermName) } - placeholderParams = param :: placeholderParams - id + freshPlaceholder() case LPAREN => atPos(in.offset)(makeParens(commaSeparated(expr()))) case LBRACE => -- cgit v1.2.3