diff --git a/parsley/shared/src/main/scala/parsley/errors/patterns.scala b/parsley/shared/src/main/scala/parsley/errors/patterns.scala index 304744acb..90e0504a5 100644 --- a/parsley/shared/src/main/scala/parsley/errors/patterns.scala +++ b/parsley/shared/src/main/scala/parsley/errors/patterns.scala @@ -1,3 +1,6 @@ +/* SPDX-FileCopyrightText: © 2023 Parsley Contributors + * SPDX-License-Identifier: BSD-3-Clause + */ package parsley.errors import parsley.Parsley diff --git a/parsley/shared/src/main/scala/parsley/position.scala b/parsley/shared/src/main/scala/parsley/position.scala index 21f2232b4..75c0c768a 100644 --- a/parsley/shared/src/main/scala/parsley/position.scala +++ b/parsley/shared/src/main/scala/parsley/position.scala @@ -20,7 +20,7 @@ object position { * effect on the state of the parser. * * @example {{{ - * scala> import parsley.Parsley.line, parsley.character.char + * scala> import parsley.position.line, parsley.character.char * scala> line.parse("") * val res0 = Success(1) * scala> (char('a') *> line).parse("a") @@ -40,7 +40,7 @@ object position { * effect on the state of the parser. * * @example {{{ - * scala> import parsley.Parsley.col, parsley.character.char + * scala> import parsley.position.col, parsley.character.char * scala> col.parse("") * val res0 = Success(1) * scala> (char('a') *> col).parse("a") @@ -61,7 +61,7 @@ object position { * effect on the state of the parser. * * @example {{{ - * scala> import parsley.Parsley.pos, parsley.character.char + * scala> import parsley.position.pos, parsley.character.char * scala> pos.parse("") * val res0 = Success((1, 1)) * scala> (char('a') *> pos).parse("a") @@ -78,7 +78,26 @@ object position { // this is subject to change at the slightest notice, do NOT expose private [parsley] val internalOffset: Parsley[Int] = new Parsley(singletons.Offset) - /** TODO: Document */ + + /** This parser returns the current offset into the input (starting at 0) without having any other effect. + * + * When this combinator is ran, no input is required, nor consumed, and + * the current offset into the input will always be successfully returned. It has no other + * effect on the state of the parser. + * + * @example {{{ + * scala> import parsley.position.offset, parsley.character.char + * scala> offset.parse("") + * val res0 = Success(0) + * scala> (char('a') *> offset).parse("a") + * val res0 = Success(1) + * scala> (char('\n') *> offset).parse("\n") + * val res0 = Success(1) + * }}} + * + * @return a parser that returns the offset the parser is currently at. + * @note offset does not take wide unicode codepoints into account. + */ val offset: Parsley[Int] = internalOffset // These are useless at 5.0.0 I think diff --git a/parsley/shared/src/test/scala/parsley/PositionTests.scala b/parsley/shared/src/test/scala/parsley/PositionTests.scala new file mode 100644 index 000000000..322ddbc60 --- /dev/null +++ b/parsley/shared/src/test/scala/parsley/PositionTests.scala @@ -0,0 +1,44 @@ +/* SPDX-FileCopyrightText: © 2023 Parsley Contributors + * SPDX-License-Identifier: BSD-3-Clause + */ +package parsley + +import parsley.position._ +import parsley.character.char + +class PositionTests extends ParsleyTest { + "line" should "start at 1" in { + line.parse("") shouldBe Success(1) + } + it should "increment on newline" in { + (char('\n') ~> line).parse("\n") shouldBe Success(2) + } + it should "not increment on tabs or other chars" in { + (char('\t') ~> line).parse("\t") shouldBe Success(1) + (char('a') ~> line).parse("a") shouldBe Success(1) + } + + "col" should "start at 1" in { + col.parse("") shouldBe Success(1) + } + it should "reset on newline" in { + (char('a') ~> char('\n') ~> col).parse("a\n") shouldBe Success(1) + } + it should "go to tab boundaries" in { + (char('\t') ~> col).parse("\t") shouldBe Success(5) + (char('a') ~> char('\t') ~> col).parse("a\t") shouldBe Success(5) + (char('a') ~> char('a') ~> char('a') ~> char('a') ~> char('\t') ~> col).parse("aaaa\t") shouldBe Success(9) + } + it should "increment on other chars" in { + (char('a') ~> col).parse("a") shouldBe Success(2) + } + + "offset" should "start at 0" in { + offset.parse("") shouldBe Success(0) + } + it should "only increase by one regardless of character" in { + (char('\n') ~> offset).parse("\n") shouldBe Success(1) + (char('\t') ~> offset).parse("\t") shouldBe Success(1) + (char('a') ~> offset).parse("a") shouldBe Success(1) + } +}