Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Staging 1.3 #8

Merged
merged 6 commits into from
Jan 9, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 16 additions & 14 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,19 @@ import org.scalajs.linker.interface.ESVersion
import com.typesafe.tools.mima.core._

val projectName = "parsley-cats"
val Scala213 = "2.13.10"
val Scala212 = "2.12.17"
val Scala3 = "3.2.1"
val Scala213 = "2.13.12"
val Scala212 = "2.12.18"
val Scala3 = "3.3.1"

Global / onChangedBuildSource := ReloadOnSourceChanges

inThisBuild(List(
tlBaseVersion := "1.2",
tlBaseVersion := "1.3",
organization := "com.github.j-mie6",
organizationName := "Parsley-Cats Contributors <https://github.com/j-mie6/parsley-cats/graphs/contributors>",
startYear := Some(2022),
homepage := Some(url("https://github.com/j-mie6/parsley-cats")),
licenses := List("BSD-3-Clause" -> url("https://opensource.org/licenses/BSD-3-Clause")),
developers := List(
tlGitHubDev("j-mie6", "Jamie Willis")
),
versionScheme := Some("early-semver"),
crossScalaVersions := Seq(Scala213, Scala212, Scala3),
scalaVersion := Scala213,
Expand All @@ -30,8 +28,9 @@ inThisBuild(List(
ProblemFilters.exclude[MissingClassProblem]("parsley.MonoidKForParsley"),
),
// CI Configuration
tlCiReleaseBranches := Seq("master"),
tlSonatypeUseLegacyHost := false,
tlCiReleaseBranches := Seq("staging/1.3"),
tlCiScalafmtCheck := false,
tlCiHeaderCheck := true,
githubWorkflowJavaVersions := Seq(JavaSpec.temurin("8"), JavaSpec.temurin("11"), JavaSpec.temurin("17")),
))

Expand All @@ -43,13 +42,16 @@ lazy val `parsley-cats` = crossProject(JVMPlatform, JSPlatform, NativePlatform)
.in(file("parsley-cats"))
.settings(
name := projectName,
headerLicenseStyle := HeaderLicenseStyle.SpdxSyntax,
headerEmptyLine := false,

resolvers ++= Opts.resolver.sonatypeOssReleases, // Will speed up MiMA during fast back-to-back releases
libraryDependencies ++= Seq(
"org.typelevel" %%% "cats-core" % "2.8.0",
"com.github.j-mie6" %%% "parsley" % "4.0.0",
"org.scalatest" %%% "scalatest" % "3.2.12" % Test,
"com.github.j-mie6" %%% "parsley" % "4.5.0",
"org.scalatest" %%% "scalatest" % "3.2.17" % Test,
"org.typelevel" %%% "cats-laws" % "2.8.0" % Test,
),
)
.jsSettings(
Test / scalaJSLinkerConfig := scalaJSLinkerConfig.value.withESFeatures(_.withESVersion(ESVersion.ES2018))

Test / testOptions += Tests.Argument(TestFrameworks.ScalaTest, "-oI"),
)
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ private [parsley] trait ApplicativeForParsley extends Applicative[Parsley] {
override def ap[A, B](mf: Parsley[A => B])(mx: Parsley[A]): Parsley[B] = mf <*> mx

override def replicateA[A](n: Int, mx: Parsley[A]): Parsley[List[A]] = parsley.combinator.exactly(n, mx)
override def replicateA_[A](n: Int, mx: Parsley[A]): Parsley[Unit] = parsley.combinator.skip(mx, (1 until n).map(_ => mx): _*)
override def replicateA_[A](n: Int, mx: Parsley[A]): Parsley[Unit] = replicateA(n, mx).void

// Maps and Tuples
override def map2[A, B, Z](mx: Parsley[A], my: Parsley[B])(f: (A, B) => Z): Parsley[Z] = lift2(f, mx, my)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
package parsley.cats

import parsley.Parsley
import parsley.registers.{RegisterMaker, RegisterMethods}
import parsley.state.{RefMaker, StateCombinators}

import cats.{Alternative, Monad}

Expand All @@ -17,17 +17,17 @@ private [parsley] trait MonadForParsley extends Monad[Parsley] {
}

// Monad Overrides
override def ifM[B](mx: Parsley[Boolean])(ifTrue: => Parsley[B], ifFalse: => Parsley[B]): Parsley[B] = parsley.combinator.ifP(mx, ifTrue, ifFalse)
override def ifM[B](mx: Parsley[Boolean])(ifTrue: => Parsley[B], ifFalse: => Parsley[B]): Parsley[B] = parsley.combinator.ifS(mx, ifTrue, ifFalse)
override def whileM_[A](p: Parsley[Boolean])(body: =>Parsley[A]): Parsley[Unit] = {
parsley.combinator.when(p, parsley.combinator.whileP(body ~> p))
parsley.combinator.whenS(p, parsley.combinator.whileS(body ~> p))
}
override def untilM_[A](body: Parsley[A])(p: => Parsley[Boolean]): Parsley[Unit] = parsley.combinator.whileP(body *> p.map(!_))
override def untilM_[A](body: Parsley[A])(p: => Parsley[Boolean]): Parsley[Unit] = parsley.combinator.whileS(body *> p.map(!_))

override def whileM[G[_]: Alternative, A](p: Parsley[Boolean])(body: => Parsley[A]): Parsley[G[A]] = {
val G = implicitly[Alternative[G]]
G.empty[A].makeReg { acc =>
G.empty[A].makeRef { acc =>
whileM_(p) {
acc.modify(body.map(x => (xs: G[A]) => G.appendK(xs, x)))
acc.update(body.map(x => (xs: G[A]) => G.appendK(xs, x)))
} *> acc.get
}
}
Expand All @@ -44,19 +44,19 @@ private [parsley] trait MonadForParsley extends Monad[Parsley] {

override def iterateUntil[A](mx: Parsley[A])(p: A => Boolean): Parsley[A] = {
lazy val loop: Parsley[A] = mx.persist { mx =>
parsley.combinator.ifP(mx.map(p), mx, loop)
parsley.combinator.ifS(mx.map(p), mx, loop)
}
loop
}
override def iterateWhile[A](mx: Parsley[A])(p: A => Boolean): Parsley[A] = {
lazy val loop: Parsley[A] = mx.persist { mx =>
parsley.combinator.ifP(mx.map(p), loop, mx)
parsley.combinator.ifS(mx.map(p), loop, mx)
}
loop
}
override def ifElseM[A](branches: (Parsley[Boolean], Parsley[A])*)(els: Parsley[A]): Parsley[A] = {
branches.foldRight(els) {
case ((cond, t), e) => parsley.combinator.ifP(cond, t, e)
case ((cond, t), e) => parsley.combinator.ifS(cond, t, e)
}
}
}
39 changes: 35 additions & 4 deletions parsley-cats/shared/src/main/scala/parsley/cats/combinator.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@ package parsley.cats

import cats.data.NonEmptyList

import parsley.Parsley, Parsley.notFollowedBy
import parsley.combinator.{many, manyUntil}
import parsley.Parsley, Parsley.{notFollowedBy, many}
import parsley.combinator.{manyTill}
import parsley.lift.lift2

import scala.annotation.nowarn
j-mie6 marked this conversation as resolved.
Show resolved Hide resolved

/** This module contains pre-made combinators that are very useful for a variety of purposes, specialised to `cats`.
*
* In particular, it contains functionality found normally in `parsley.combinator`, but returning the `cats` `NonEmptyList`
Expand Down Expand Up @@ -46,6 +48,34 @@ object combinator {
*/
def some[A](p: Parsley[A]): Parsley[NonEmptyList[A]] = nonEmptyList(p, many(p))

/** This combinator repeatedly parses a given parser '''one''' or more times, until the `end` parser succeeds, collecting the results into a list.
*
* First ensures that trying to parse `end` fails, then tries to parse `p`. If it succeed then it will repeatedly: try to parse `end`, if it fails
* '''without consuming input''', then parses `p`, which must succeed. When `end` does succeed, this combinator will return all of the results
* generated by `p`, `x,,1,,` through `x,,n,,` (with `n >= 1`), in a non-empty list: `NonEmptyList.of(x,,1,,, .., x,,n,,)`. The parser `p` must succeed
* at least once before `end` succeeds.
*
* @example This can be useful for scanning comments: {{{
* scala> import parsley.character.{string, item, endOfLine}
* scala> import parsley.cats.combinator.someTill
* scala> val comment = string("//") *> someTill(item, endOfLine)
* scala> p.parse("//hello world")
* val res0 = Failure(..)
* scala> p.parse("//hello world\n")
* val res1 = Success(NonEmptyList.of('h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd'))
* scala> p.parse("//\n")
* val res2 = Failure(..)
* scala> p.parse("//a\n")
* val res3 = Success(NonEmptyList.of('a'))
* }}}
*
* @param p the parser to execute multiple times.
* @param end the parser that stops the parsing of `p`.
* @return a parser that parses `p` until `end` succeeds, returning the non-empty list of all the successful results.
* @since 1.3.0
*/
def someTill[A](p: Parsley[A], end: Parsley[_]): Parsley[NonEmptyList[A]] = notFollowedBy(end) *> (nonEmptyList(p, manyTill(p, end)))

/** This combinator repeatedly parses a given parser '''one''' or more times, until the `end` parser succeeds, collecting the results into a list.
*
* First ensures that trying to parse `end` fails, then tries to parse `p`. If it succeed then it will repeatedly: try to parse `end`, if it fails
Expand All @@ -72,7 +102,8 @@ object combinator {
* @return a parser that parses `p` until `end` succeeds, returning the non-empty list of all the successful results.
* @since 1.2.0
*/
def someUntil[A](p: Parsley[A], end: Parsley[_]): Parsley[NonEmptyList[A]] = notFollowedBy(end) *> (nonEmptyList(p, manyUntil(p, end)))
@deprecated("This combinator will be removed in 2.0.0, use someTill instead", "1.3.0")
def someUntil[A](p: Parsley[A], end: Parsley[_]): Parsley[NonEmptyList[A]] = notFollowedBy(end) *> (nonEmptyList(p, manyTill(p, end)))

/** This combinator parses '''one''' or more occurrences of `p`, separated by `sep`.
*
Expand Down Expand Up @@ -127,7 +158,7 @@ object combinator {
* @since 1.2.0
*/
def sepEndBy1[A](p: Parsley[A], sep: =>Parsley[_]): Parsley[NonEmptyList[A]] = parsley.combinator.sepEndBy1(p, sep).map { xxs =>
val (x::xs) = xxs
val (x::xs) = xxs: @nowarn
NonEmptyList(x, xs)
}

Expand Down
3 changes: 1 addition & 2 deletions parsley-cats/shared/src/test/scala/parsley/ParsleyTest.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@ import org.scalatest.Assertions
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers

import parsley.combinator.eof
import parsley.Result
import parsley.Parsley.eof
import parsley.errors.{ErrorBuilder, tokenextractors}
import org.scalatest.Inside
import org.scalactic.source.Position
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ package parsley.cats
import Predef.{ArrowAssoc => _}

import parsley.{ParsleyTest, Success, Failure}
import parsley.implicits.character.{charLift, stringLift}
import parsley.syntax.character.{charLift, stringLift}
import parsley.cats.combinator._
import cats.data.NonEmptyList

Expand Down
2 changes: 1 addition & 1 deletion project/build.properties
Original file line number Diff line number Diff line change
@@ -1 +1 @@
sbt.version=1.8.2
sbt.version=1.9.8
19 changes: 6 additions & 13 deletions project/plugins.sbt
Original file line number Diff line number Diff line change
@@ -1,23 +1,16 @@
val sbtTypelevelVersion = "0.4.19"
val sbtTypelevelVersion = "0.6.5"

libraryDependencySchemes ++= Seq(
"org.scala-native" % "sbt-scala-native" % VersionScheme.Always,
"org.scala-lang.modules" %% "scala-xml" % VersionScheme.Always,
)

//addSbtPlugin("org.typelevel" % "sbt-typelevel" % sbtTypelevelVersion) // disabled because I don't want headers and formatting checks
addSbtPlugin("org.typelevel" % "sbt-typelevel-settings" % sbtTypelevelVersion)
addSbtPlugin("org.typelevel" % "sbt-typelevel-ci-release" % sbtTypelevelVersion)
addSbtPlugin("org.typelevel" % "sbt-typelevel" % sbtTypelevelVersion)

// Cross Project Setup
addSbtPlugin("org.portable-scala" % "sbt-scalajs-crossproject" % "1.2.0")
addSbtPlugin("org.portable-scala" % "sbt-scala-native-crossproject" % "1.2.0")
addSbtPlugin("org.scala-js" % "sbt-scalajs" % "1.11.0")
addSbtPlugin("org.scala-native" % "sbt-scala-native" % "0.4.8")
addSbtPlugin("org.scala-js" % "sbt-scalajs" % "1.13.2")
addSbtPlugin("org.scala-native" % "sbt-scala-native" % "0.4.15")

// Other
// This is here purely to enable the niceness settings
addSbtPlugin("ch.epfl.scala" % "sbt-bloop" % "1.4.8")
addSbtPlugin("com.beautiful-scala" % "sbt-scalastyle" % "1.5.1")
addSbtPlugin("org.scoverage" % "sbt-scoverage" % "2.0.5")
addSbtPlugin("org.jmotor.sbt" % "sbt-dependency-updates" % "1.2.7")
addSbtPlugin("org.scoverage" % "sbt-scoverage" % "2.0.9")
addSbtPlugin("com.timushev.sbt" % "sbt-rewarn" % "0.1.3")
Loading