From 468904432df3a5afcd294ade0ac72a5ad9befc01 Mon Sep 17 00:00:00 2001 From: "P. Oscar Boykin" <johnynek@users.noreply.github.com> Date: Fri, 15 Mar 2024 17:50:34 -0700 Subject: [PATCH] Support comments in headers (#1168) * Support comments in headers * share more code --- .../scala/org/bykn/bosatsu/CommentStatement.scala | 4 ++-- core/src/main/scala/org/bykn/bosatsu/Package.scala | 14 ++++++++++---- core/src/main/scala/org/bykn/bosatsu/Padding.scala | 6 ++++-- core/src/main/scala/org/bykn/bosatsu/Parser.scala | 3 ++- .../test/scala/org/bykn/bosatsu/ParserTest.scala | 5 ++++- 5 files changed, 22 insertions(+), 10 deletions(-) diff --git a/core/src/main/scala/org/bykn/bosatsu/CommentStatement.scala b/core/src/main/scala/org/bykn/bosatsu/CommentStatement.scala index 042acdd98..d5adc46be 100644 --- a/core/src/main/scala/org/bykn/bosatsu/CommentStatement.scala +++ b/core/src/main/scala/org/bykn/bosatsu/CommentStatement.scala @@ -31,12 +31,12 @@ object CommentStatement { val commentBlock: P[NonEmptyList[String]] = // if the next line is part of the comment until we see the # or not (Parser.maybeSpace.with1.soft *> commentPart) - .repSep(sep = sep) <* Parser.newline.orElse(P.end) + .repSep(sep = sep) <* Parser.termination (commentBlock ~ onP(indent)) .map { case (m, on) => CommentStatement(m, on) } } val commentPart: P[String] = - P.char('#') *> P.until0(P.char('\n')) + P.char('#') *> P.until0(Parser.termination) } diff --git a/core/src/main/scala/org/bykn/bosatsu/Package.scala b/core/src/main/scala/org/bykn/bosatsu/Package.scala index 3d1285c36..5ed481ff1 100644 --- a/core/src/main/scala/org/bykn/bosatsu/Package.scala +++ b/core/src/main/scala/org/bykn/bosatsu/Package.scala @@ -190,12 +190,17 @@ object Package { Doc.intercalate(Doc.empty, p :: i :: e :: b) } + def headerParser(defaultPack: Option[PackageName]): P0[Header] = { - // TODO: support comments before the Statement + val spaceComment: P0[Unit] = + (Parser.spaces.? ~ CommentStatement.commentPart.?).void + + val eol = spaceComment <* Parser.termination val parsePack = Padding .parser( (P.string("package") - .soft ~ spaces) *> PackageName.parser <* Parser.toEOL + .soft ~ spaces) *> PackageName.parser <* eol, + spaceComment ) .map(_.padded) val pname: P0[PackageName] = @@ -204,12 +209,13 @@ object Package { case Some(p) => parsePack.?.map(_.getOrElse(p)) } - val im = Padding.parser(Import.parser <* Parser.toEOL).map(_.padded).rep0 + val im = Padding.parser(Import.parser <* eol, spaceComment).map(_.padded).rep0 val ex = Padding .parser( (P.string("export") .soft ~ spaces) *> ExportedName.parser.itemsMaybeParens - .map(_._2) <* Parser.toEOL + .map(_._2) <* eol, + spaceComment ) .map(_.padded) diff --git a/core/src/main/scala/org/bykn/bosatsu/Padding.scala b/core/src/main/scala/org/bykn/bosatsu/Padding.scala index f9286d121..231dbc061 100644 --- a/core/src/main/scala/org/bykn/bosatsu/Padding.scala +++ b/core/src/main/scala/org/bykn/bosatsu/Padding.scala @@ -22,13 +22,15 @@ object Padding { /** This allows an empty padding */ - def parser[T](p: P[T]): P[Padding[T]] = { - val spacing = (maybeSpace.with1.soft ~ Parser.newline).void.rep0 + def parser[T](p: P[T], space: P0[Unit]): P[Padding[T]] = { + val spacing = (space.with1.soft ~ Parser.newline).void.rep0 (spacing.with1.soft ~ p) .map { case (vec, t) => Padding(vec.size, t) } } + def parser[T](p: P[T]): P[Padding[T]] = parser(p, maybeSpace) + /** Parses a padding of length 1 or more, then p */ def parser1[T](p: P0[T]): P[Padding[T]] = diff --git a/core/src/main/scala/org/bykn/bosatsu/Parser.scala b/core/src/main/scala/org/bykn/bosatsu/Parser.scala index 89c9db043..3bb3e3a7e 100644 --- a/core/src/main/scala/org/bykn/bosatsu/Parser.scala +++ b/core/src/main/scala/org/bykn/bosatsu/Parser.scala @@ -448,7 +448,8 @@ object Parser { (P.char('(') ~ ws) *> pa <* (ws ~ P.char(')')) val newline: P[Unit] = P.char('\n') - val toEOL: P0[Unit] = maybeSpace *> newline.orElse(P.end) + val termination: P0[Unit] = newline.orElse(P.end) + val toEOL: P0[Unit] = maybeSpace *> termination val toEOL1: P[Unit] = maybeSpace.with1 *> newline def optionParse[A](pa: P0[A], str: String): Option[A] = diff --git a/core/src/test/scala/org/bykn/bosatsu/ParserTest.scala b/core/src/test/scala/org/bykn/bosatsu/ParserTest.scala index 4d1929f5d..4f0507613 100644 --- a/core/src/test/scala/org/bykn/bosatsu/ParserTest.scala +++ b/core/src/test/scala/org/bykn/bosatsu/ParserTest.scala @@ -1722,9 +1722,12 @@ external def foo2(i: Integer, b: a) -> String roundTrip( Package.parser(None), """ +# we can comment the package package Foo/Bar +# comments are allowed from Baz import Bippy -export foo +# even here +export foo # or here foo = 1 """