Skip to content

Commit

Permalink
Merge pull request #2787 from tgodzik/fix-open
Browse files Browse the repository at this point in the history
bugfix: Manually skip newlines after soft keywords
  • Loading branch information
tgodzik committed Jul 20, 2022
2 parents a78362e + bf3f770 commit 54c5f61
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 34 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2695,8 +2695,8 @@ class ScalametaParser(input: Input)(implicit dialect: Dialect) { parser =>
}
}

private def modifier(isLocal: Boolean): Mod =
autoPos(token match {
private def modifier(isLocal: Boolean): Mod = {
val mod = autoPos(token match {
case t: Unquote => unquote[Mod](t)
case t: Ellipsis => ellipsis[Mod](t, 1)
case _: KwAbstract => next(); Mod.Abstract()
Expand All @@ -2719,41 +2719,49 @@ class ScalametaParser(input: Input)(implicit dialect: Dialect) { parser =>
syntaxError(s"${local}modifier expected but $n found", at = token)
}
})
newLinesOpt()
mod
}

def quasiquoteModifier(): Mod = entrypointModifier()

def entrypointModifier(): Mod = autoPos {
def annot() = annots(skipNewLines = false) match {
case annot :: Nil => annot
case _ :: other :: _ =>
syntaxError(s"end of file expected but ${token.name} found", at = other)
case Nil => unreachable
}
def fail() = syntaxError(s"modifier expected but ${parser.token.name} found", at = parser.token)
token match {
case t: Unquote => unquote[Mod](t)
case At() => annot()
case KwPrivate() => privateModifier()
case KwProtected() => protectedModifier()
case KwImplicit() => next(); Mod.Implicit()
case KwFinal() => next(); Mod.Final()
case KwSealed() => next(); Mod.Sealed()
case KwOverride() => next(); Mod.Override()
case KwCase() => next(); Mod.Case()
case KwAbstract() => next(); Mod.Abstract()
case Ident("+") => next(); Mod.Covariant()
case Ident("-") => next(); Mod.Contravariant()
case KwLazy() => next(); Mod.Lazy()
case KwVal() if !dialect.allowUnquotes => next(); Mod.ValParam()
case KwVar() if !dialect.allowUnquotes => next(); Mod.VarParam()
case soft.KwOpen() => next(); Mod.Open()
case soft.KwTransparent() => next(); Mod.Transparent()
case soft.KwInline() => next(); Mod.Inline()
case soft.KwInfix() => next(); Mod.Infix()
case Ident("valparam") if dialect.allowUnquotes => next(); Mod.ValParam()
case Ident("varparam") if dialect.allowUnquotes => next(); Mod.VarParam()
case _ => fail()
def entrypointModifier(): Mod = {
val mod = autoPos {
def annot() = annots(skipNewLines = false) match {
case annot :: Nil => annot
case _ :: other :: _ =>
syntaxError(s"end of file expected but ${token.name} found", at = other)
case Nil => unreachable
}
def fail() =
syntaxError(s"modifier expected but ${parser.token.name} found", at = parser.token)
token match {
case t: Unquote => unquote[Mod](t)
case At() => annot()
case KwPrivate() => privateModifier()
case KwProtected() => protectedModifier()
case KwImplicit() => next(); Mod.Implicit()
case KwFinal() => next(); Mod.Final()
case KwSealed() => next(); Mod.Sealed()
case KwOverride() => next(); Mod.Override()
case KwCase() => next(); Mod.Case()
case KwAbstract() => next(); Mod.Abstract()
case Ident("+") => next(); Mod.Covariant()
case Ident("-") => next(); Mod.Contravariant()
case KwLazy() => next(); Mod.Lazy()
case KwVal() if !dialect.allowUnquotes => next(); Mod.ValParam()
case KwVar() if !dialect.allowUnquotes => next(); Mod.VarParam()
case soft.KwOpen() => next(); Mod.Open();
case soft.KwTransparent() => next(); Mod.Transparent()
case soft.KwInline() => next(); Mod.Inline()
case soft.KwInfix() => next(); Mod.Infix()
case Ident("valparam") if dialect.allowUnquotes => next(); Mod.ValParam()
case Ident("varparam") if dialect.allowUnquotes => next(); Mod.VarParam()
case _ => fail()
}
}
newLinesOpt()
mod
}

def ctorModifiers(): Option[Mod] = token match {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -362,7 +362,6 @@ class ScannerTokens(tokens: Tokens, input: Input)(implicit dialect: Dialect) {
@classifier
trait CanEndStat {
def unapply(token: Token): Boolean = token match {
case SoftModifier() => false
case _: Ident | _: KwGiven | _: Literal | _: Interpolation.End | _: Xml.End | _: KwReturn |
_: KwThis | _: KwType | _: RightParen | _: RightBracket | _: RightBrace |
_: Underscore | _: Ellipsis | _: Unquote =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,66 @@ class MinorDottySuite extends BaseDottySuite {
stat("def open(open: open): open = ???").structure
}

test("open-soft-modifier-case") {
runTestAssert[Source](
"""|case class OHLCPrice(
| val open: Int
|) {
| val price = OHLCPrice(1)
| val price1 = price.open
| val price2 = 1
|}""".stripMargin,
assertLayout = Some(
"""|case class OHLCPrice(val open: Int) {
| val price = OHLCPrice(1)
| val price1 = price.open
| val price2 = 1
|}
|""".stripMargin
)
)(
Source(
List(
Defn.Class(
List(Mod.Case()),
Type.Name("OHLCPrice"),
Nil,
Ctor.Primary(
Nil,
Name(""),
List(
List(
Term.Param(List(Mod.ValParam()), Term.Name("open"), Some(Type.Name("Int")), None)
)
)
),
Template(
Nil,
Nil,
Self(Name(""), None),
List(
Defn.Val(
Nil,
List(Pat.Var(Term.Name("price"))),
None,
Term.Apply(Term.Name("OHLCPrice"), List(Lit.Int(1)))
),
Defn.Val(
Nil,
List(Pat.Var(Term.Name("price1"))),
None,
Term.Select(Term.Name("price"), Term.Name("open"))
),
Defn.Val(Nil, List(Pat.Var(Term.Name("price2"))), None, Lit.Int(1))
),
Nil
)
)
)
)
)
}

test("open-identifier") {
runTestAssert[Stat]("def run(): Unit = { start; open(p); end }", assertLayout = None)(
Defn.Def(
Expand Down

0 comments on commit 54c5f61

Please sign in to comment.