diff --git a/parsley/shared/src/main/scala/parsley/token/descriptions/SpaceDesc.scala b/parsley/shared/src/main/scala/parsley/token/descriptions/SpaceDesc.scala index 27c3f47dd..20d9974c8 100644 --- a/parsley/shared/src/main/scala/parsley/token/descriptions/SpaceDesc.scala +++ b/parsley/shared/src/main/scala/parsley/token/descriptions/SpaceDesc.scala @@ -58,7 +58,7 @@ object SpaceDesc { lineCommentStart = "", lineCommentAllowsEOF = true, multiLineNestedComments = false, - space = Unicode(Character.isWhitespace), + space = Unicode(Character.isWhitespace(_)), whitespaceIsContextDependent = false ) } diff --git a/parsley/shared/src/main/scala/parsley/token/predicate/CharPredicate.scala b/parsley/shared/src/main/scala/parsley/token/predicate/CharPredicate.scala index 56f013692..65e213085 100644 --- a/parsley/shared/src/main/scala/parsley/token/predicate/CharPredicate.scala +++ b/parsley/shared/src/main/scala/parsley/token/predicate/CharPredicate.scala @@ -10,6 +10,8 @@ import parsley.character.satisfy import parsley.exceptions.ParsleyException import parsley.unicode.{satisfy => satisfyUtf16} +import scala.collection.immutable.NumericRange + /** Base class for character predicates. * @since 4.0.0 */ @@ -35,6 +37,9 @@ sealed abstract class CharPredicate { * @since 4.0.0 */ final case class Unicode(predicate: Int => Boolean) extends CharPredicate { + def this(c: Int) = this(_ == c) + def this(cs: NumericRange[Int]) = this(cs.contains) + def this(cs: Range) = this(cs.contains) private [token] override def toBmp = satisfy(c => predicate(c.toInt)) private [token] override def toUnicode = satisfyUtf16(predicate) private [token] override def toNative = toUnicode.void @@ -42,6 +47,33 @@ final case class Unicode(predicate: Int => Boolean) extends CharPredicate { private [token] def endsWith(s: String) = s.nonEmpty && predicate(s.codePointBefore(s.length)) private [parsley] def asInternalPredicate = new parsley.internal.machine.instructions.token.Unicode(predicate) } +object Unicode { + /** Lifts a regular full-width character predicate. + * @since 5.0.0 + */ + def apply(c: Int): Unicode = new Unicode(_ == c) + /** Constructs a predicate for anything in a range of specific unicode codepoints. + * @since 5.0.0 + */ + def apply(cs: NumericRange[Int]): Unicode = new Unicode(cs.contains) + /** Constructs a predicate for anything in a range of specific unicode codepoints. + * @since 5.0.0 + */ + def apply(cs: Range): Unicode = new Unicode(cs.contains) + + /** Lifts a regular character predicate. + * @since 5.0.0 + */ + def char(pred: Char => Boolean): Unicode = new Unicode(c => c.isValidChar && pred(c.toChar)) + /** Constructs a predicate for the specific given character. + * @since 5.0.0 + */ + def char(c: Char): Unicode = new Unicode(c.toInt) + /** Constructs a predicate for anything in a range of specific characters. + * @since 5.0.0 + */ + def char(cs: NumericRange[Char]): Unicode = char(cs.contains) +} /** Basic character predicate, which reads regular Scala 16-bit characters. * @@ -51,6 +83,8 @@ final case class Unicode(predicate: Int => Boolean) extends CharPredicate { * @since 4.0.0 */ final case class Basic(predicate: Char => Boolean) extends CharPredicate { + def this(c: Char) = this(_ == c) + def this(cs: NumericRange[Char]) = this(cs.contains) private [token] override def toBmp = satisfy(predicate) // $COVERAGE-OFF$ private [token] override def toUnicode = @@ -61,6 +95,16 @@ final case class Basic(predicate: Char => Boolean) extends CharPredicate { private [token] def endsWith(s: String) = s.lastOption.exists(predicate) private [parsley] def asInternalPredicate = new parsley.internal.machine.instructions.token.Basic(predicate) } +object Basic { + /** Constructs a predicate for the specific given character. + * @since 5.0.0 + */ + def apply(c: Char): Basic = new Basic(c) + /** Constructs a predicate for anything in a range of specific characters. + * @since 5.0.0 + */ + def apply(cs: NumericRange[Char]): Basic = new Basic(cs) +} /** Character predicate that never succeeds. * diff --git a/parsley/shared/src/main/scala/parsley/token/predicate/implicits.scala b/parsley/shared/src/main/scala/parsley/token/predicate/implicits.scala deleted file mode 100644 index a2dba9c4c..000000000 --- a/parsley/shared/src/main/scala/parsley/token/predicate/implicits.scala +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright 2020 Parsley Contributors - * - * SPDX-License-Identifier: BSD-3-Clause - */ -package parsley.token.predicate - -import scala.collection.immutable.NumericRange - -/** This object provides implicit functionality for constructing `CharPredicate` values. - * @since 4.1.0 - */ -object implicits { - /** Implicit conversions to make `Basic` values. - * @since 4.1.0 - */ - object Basic { - // $COVERAGE-OFF$ - /** Lifts a regular character predicate. - * @since 4.1.0 - */ - implicit def funToBasic(pred: Char => Boolean): CharPredicate = parsley.token.predicate.Basic(pred) - /** Constructs a predicate for the specific given character. - * @since 4.1.0 - */ - implicit def charToBasic(c: Char): CharPredicate = parsley.token.predicate.Basic(_ == c) - /** Constructs a predicate for anything in a range of specific characters. - * @since 4.1.0 - */ - implicit def rangeToBasic(cs: NumericRange[Char]): CharPredicate = parsley.token.predicate.Basic(cs.contains) - // $COVERAGE-ON$ - } - - /** Implicit conversions to make `Unicode` values. - * @since 4.1.0 - */ - object Unicode { - // $COVERAGE-OFF$ - /** Lifts a regular full-width character predicate. - * @since 4.1.0 - */ - implicit def funToUnicode(pred: Int => Boolean): CharPredicate = parsley.token.predicate.Unicode(pred) - /** Lifts a regular character predicate. - * @since 4.1.0 - */ - implicit def charFunToUnicode(pred: Char => Boolean): CharPredicate = parsley.token.predicate.Unicode(c => c.isValidChar && pred(c.toChar)) - /** Constructs a predicate for the specific given character. - * @since 4.1.0 - */ - implicit def charToUnicode(c: Char): CharPredicate = parsley.token.predicate.Unicode(_ == c.toInt) - /** Constructs a predicate for the specific given unicode codepoint. - * @since 4.1.0 - */ - implicit def intToUnicode(c: Int): CharPredicate = parsley.token.predicate.Unicode(_ == c) - /** Constructs a predicate for anything in a range of specific characters. - * @since 4.1.0 - */ - implicit def charRangeToUnicode(cs: NumericRange[Char]): CharPredicate = parsley.token.predicate.Unicode(cs.contains) - /** Constructs a predicate for anything in a range of specific unicode codepoints. - * @since 4.1.0 - */ - implicit def intRangeToUnicode(cs: NumericRange[Int]): CharPredicate = parsley.token.predicate.Unicode(cs.contains) - /** Constructs a predicate for anything in a range of specific unicode codepoints. - * @since 4.1.0 - */ - implicit def rangeToUnicode(cs: Range): CharPredicate = parsley.token.predicate.Unicode(cs.contains) - // $COVERAGE-ON$ - } -} diff --git a/parsley/shared/src/test/scala/parsley/token/SpaceTests.scala b/parsley/shared/src/test/scala/parsley/token/SpaceTests.scala index 7adf71a3c..41717c787 100644 --- a/parsley/shared/src/test/scala/parsley/token/SpaceTests.scala +++ b/parsley/shared/src/test/scala/parsley/token/SpaceTests.scala @@ -23,7 +23,7 @@ class SpaceTests extends ParsleyTest { private def makeSpace(space: SpaceDesc) = makeLexer(space).space val basicNoComments = SpaceDesc.plain.copy(space = predicate.Basic(Character.isWhitespace)) - val unicodeNoComments = basicNoComments.copy(space = predicate.Unicode(Character.isWhitespace)) + val unicodeNoComments = basicNoComments.copy(space = predicate.Unicode(Character.isWhitespace(_))) "whiteSpace" should "parse spaces when no comments are defined" in cases(makeSpace(basicNoComments).whiteSpace *> string("a")) ( "a" -> Some("a"), diff --git a/parsley/shared/src/test/scala/parsley/token/TokeniserTests.scala b/parsley/shared/src/test/scala/parsley/token/TokeniserTests.scala index 11ce2d841..14edd712b 100644 --- a/parsley/shared/src/test/scala/parsley/token/TokeniserTests.scala +++ b/parsley/shared/src/test/scala/parsley/token/TokeniserTests.scala @@ -12,15 +12,15 @@ import parsley.Parsley.eof import parsley.character.string import token.{descriptions => desc} -import token.predicate.implicits.Basic._ +import token.predicate.Basic class TokeniserTests extends ParsleyTest { val scala = desc.LexicalDesc( - desc.NameDesc(identifierStart = ('a' to 'z').toSet ++ ('A' to 'Z').toSet + '_', - identifierLetter = ('a' to 'z').toSet ++ ('A' to 'Z').toSet ++ ('0' to '9').toSet + '_', - operatorStart = Set('+', '-', ':', '/', '*', '='), - operatorLetter = Set('+', '-', '/', '*')), + desc.NameDesc(identifierStart = Basic(('a' to 'z').toSet ++ ('A' to 'Z').toSet + '_'), + identifierLetter = Basic(('a' to 'z').toSet ++ ('A' to 'Z').toSet ++ ('0' to '9').toSet + '_'), + operatorStart = Basic(Set('+', '-', ':', '/', '*', '=')), + operatorLetter = Basic(Set('+', '-', '/', '*'))), desc.SymbolDesc(hardKeywords = Set("if", "else", "for", "yield", "while", "def", "class", "trait", "abstract", "override", "val", "var", "lazy"), hardOperators = Set(":", "=", "::", ":="), diff --git a/parsley/shared/src/test/scala/parsley/token/descriptions/DescGen.scala b/parsley/shared/src/test/scala/parsley/token/descriptions/DescGen.scala index a71278195..bbadb8221 100644 --- a/parsley/shared/src/test/scala/parsley/token/descriptions/DescGen.scala +++ b/parsley/shared/src/test/scala/parsley/token/descriptions/DescGen.scala @@ -6,7 +6,6 @@ package parsley.token.descriptions import parsley.token.predicate._ -import parsley.token.predicate.implicits.Basic.charToBasic import org.scalacheck.Gen import org.scalacheck.Arbitrary @@ -19,7 +18,7 @@ object DescGen { NotRequired, Unicode(Character.isLetter(_)), Unicode(Character.isLetterOrDigit(_)), - '$' + Basic('$'), ) private val opCharGen = Gen.nonEmptyContainerOf[Set, Char](Gen.oneOf('+', '*', '/', 'a')) diff --git a/parsley/shared/src/test/scala/parsley/token/names/NamesTests.scala b/parsley/shared/src/test/scala/parsley/token/names/NamesTests.scala index ab8341081..7eee05d36 100644 --- a/parsley/shared/src/test/scala/parsley/token/names/NamesTests.scala +++ b/parsley/shared/src/test/scala/parsley/token/names/NamesTests.scala @@ -49,13 +49,13 @@ class NamesTests extends ParsleyTest { "hi" -> Some("hi"), "x7" -> Some("x7"), ) - identCases(Unicode(Character.isAlphabetic), Unicode(Character.isLetterOrDigit))( + identCases(Unicode(Character.isAlphabetic), Unicode(Character.isLetterOrDigit(_)))( "hello1" -> Some("hello1"), "7f" -> None, "hi" -> Some("hi"), "x7" -> Some("x7"), ) - identCases(Basic(_.isLetter), Unicode(Character.isDigit))( + identCases(Basic(_.isLetter), Unicode(Character.isDigit(_)))( "hello1" -> None, "7f" -> None, "7" -> None, diff --git a/parsley/shared/src/test/scala/parsley/token/symbol/SymbolTests.scala b/parsley/shared/src/test/scala/parsley/token/symbol/SymbolTests.scala index 4ddf7d5d0..338b61497 100644 --- a/parsley/shared/src/test/scala/parsley/token/symbol/SymbolTests.scala +++ b/parsley/shared/src/test/scala/parsley/token/symbol/SymbolTests.scala @@ -12,7 +12,7 @@ import parsley.token.LexemeImpl._ import parsley.token.descriptions._ import parsley.token.errors.ErrorConfig -import parsley.token.predicate._, implicits.Basic.charToBasic, implicits.Unicode.funToUnicode +import parsley.token.predicate._ import parsley.character.{spaces, string} import org.scalactic.source.Position @@ -24,13 +24,13 @@ class SymbolTests extends ParsleyTest { } def makeSymbol(nameDesc: NameDesc, symDesc: SymbolDesc): Symbol = new LexemeSymbol(new ConcreteSymbol(nameDesc, symDesc, errConfig), spaces) - val plainName = NameDesc.plain.copy(identifierLetter = Basic(_.isLetter), operatorLetter = ':') + val plainName = NameDesc.plain.copy(identifierLetter = Basic(_.isLetter), operatorLetter = Basic(':')) val plainSym = SymbolDesc.plain.copy(hardKeywords = Set("keyword", "hard"), hardOperators = Set("+", "<", "<=")) val plainSymbol = makeSymbol(plainName, plainSym) - val unicodeSymbol = makeSymbol(plainName.copy(identifierLetter = Character.isAlphabetic(_)), plainSym) + val unicodeSymbol = makeSymbol(plainName.copy(identifierLetter = Unicode(Character.isAlphabetic(_))), plainSym) val caseInsensitive = makeSymbol(plainName, plainSym.copy(caseSensitive = false)) - val caseInsensitiveUni = makeSymbol(plainName.copy(identifierLetter = Character.isAlphabetic(_)), plainSym.copy(caseSensitive = false)) + val caseInsensitiveUni = makeSymbol(plainName.copy(identifierLetter = Unicode(Character.isAlphabetic(_))), plainSym.copy(caseSensitive = false)) def boolCases(p: Parsley[Unit])(tests: (String, Boolean, Position)*): Unit = cases(p, noEof = true)(tests.map { case (i, r, pos) => (i, if (r) Some(()) else None, pos) }: _*) def namedCases(sym: String => Parsley[Unit])(ktests: (String, Seq[(String, Boolean, Position)])*): Unit = {