Skip to content

Commit

Permalink
Allowed for independent string start and ends, closing #155
Browse files Browse the repository at this point in the history
  • Loading branch information
j-mie6 committed Jan 11, 2024
1 parent 1f3452a commit 1fc03b3
Show file tree
Hide file tree
Showing 4 changed files with 20 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -219,11 +219,11 @@ object EscapeDesc {
*/
final case class TextDesc (escapeSequences: EscapeDesc,
characterLiteralEnd: Char,
stringEnds: Set[String],
multiStringEnds: Set[String],
stringEnds: Set[(String, String)],
multiStringEnds: Set[(String, String)],
graphicCharacter: CharPredicate) {
require(stringEnds.forall(_.nonEmpty), "string ends cannot be empty")
require(multiStringEnds.forall(_.nonEmpty), "multiline string ends cannot be empty")
require(stringEnds.forall { case (begin, end) => begin.nonEmpty && end.nonEmpty }, "string ends cannot be empty")
require(multiStringEnds.forall { case (begin, end) => begin.nonEmpty && end.nonEmpty }, "multiline string ends cannot be empty")
}

/** This object contains any preconfigured text definitions.
Expand All @@ -236,7 +236,7 @@ object TextDesc {
* {{{
* escapeSequences = EscapeDesc.plain
* characterLiteralEnd = '\''
* stringEnds = Set("\"")
* stringEnds = Set(("\"", "\""))
* multiStringEnds = Set.empty
* graphicCharacter = Unicode(_ >= ' '.toInt)
* }}}
Expand All @@ -245,7 +245,7 @@ object TextDesc {
*/
val plain = TextDesc(escapeSequences = EscapeDesc.plain,
characterLiteralEnd = '\'',
stringEnds = Set("\""),
stringEnds = Set(("\"", "\"")),
multiStringEnds = Set.empty,
graphicCharacter = Unicode(_ >= ' '.toInt))
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import parsley.syntax.zipped.Zipped2
import parsley.token.errors.{ErrorConfig, LabelConfig, LabelWithExplainConfig}
import parsley.token.predicate.CharPredicate

private [token] final class ConcreteString(ends: Set[String], stringChar: StringCharacter, isGraphic: CharPredicate,
private [token] final class ConcreteString(ends: Set[(String, String)], stringChar: StringCharacter, isGraphic: CharPredicate,
allowsAllSpace: Boolean, err: ErrorConfig) extends StringParsers {

private def stringLiteral(valid: Parsley[StringBuilder] => Parsley[StringBuilder],
Expand All @@ -28,8 +28,9 @@ private [token] final class ConcreteString(ends: Set[String], stringChar: String

private def makeStringParser(valid: Parsley[StringBuilder] => Parsley[StringBuilder],
openLabel: (Boolean, Boolean) => LabelWithExplainConfig, closeLabel: (Boolean, Boolean) => LabelConfig)
(terminalStr: String) = {
val terminalInit = terminalStr.charAt(0)
(terminalStr: (String, String)) = {
val (begin, end) = terminalStr
val terminalInit = end.charAt(0)
val strChar = stringChar(CharacterParsers.letter(terminalInit, allowsAllSpace, isGraphic))
val pf = (sb: StringBuilder, cpo: Option[Int]) => {
for (cp <- cpo) parsley.unicode.addCodepoint(sb, cp)
Expand All @@ -38,12 +39,11 @@ private [token] final class ConcreteString(ends: Set[String], stringChar: String
// `content` is in a dropped position, so needs the unsafe to avoid the mutation
// TODO: this could be fixed better with registers and skipMany?
val content = valid(parsley.expr.infix.secretLeft1((sbReg.get, strChar).zipped(pf), strChar, pure(pf)).impure)
val terminal = string(terminalStr)
// terminal should be first, to allow for a jump table on the main choice
openLabel(allowsAllSpace, stringChar.isRaw)(terminal) *>
// open should be first, to allow for a jump table on the main choice
openLabel(allowsAllSpace, stringChar.isRaw)(string(begin)) *>
// then only one string builder needs allocation
sbReg.set(fresh(new StringBuilder)) *>
skipManyUntil(sbReg.update(char(terminalInit).hide.as((sb: StringBuilder) => sb += terminalInit)) <|> content,
closeLabel(allowsAllSpace, stringChar.isRaw)(atomic(terminal))) //is the atomic needed here? not sure
closeLabel(allowsAllSpace, stringChar.isRaw)(atomic(string(end)))) //is the atomic needed here? not sure
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -113,10 +113,10 @@ class DescriptionRequireTests extends ParsleyTest {

"TextDesc" should "not allow for string literals without ends" in {
an [IllegalArgumentException] should be thrownBy TextDesc.plain.copy(
stringEnds = Set("", "'"),
stringEnds = Set(("", "'")),
)
an [IllegalArgumentException] should be thrownBy TextDesc.plain.copy(
multiStringEnds = Set("", "'"),
multiStringEnds = Set(("", "'")),
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ class StringTests extends ParsleyTest {
val plain = TextDesc.plain.copy(
graphicCharacter = Unicode(_ >= ' '),
escapeSequences = EscapeDesc.plain.copy(mapping = Map(("lf", '\n'), ("lam", 'λ'), ("pound", '£'), ("smile", 0x1F642 /*🙂*/))),
multiStringEnds = Set("\""),
multiStringEnds = Set(("\"", "\"")),
)
val plainStr = makeString(plain)
val plainMultiStr = makeMultiString(plain)
Expand Down Expand Up @@ -64,10 +64,10 @@ class StringTests extends ParsleyTest {
"\"abc\"" -> None,
)

they should "allow for change in literal end" in unicodeCases(makeString(plain.copy(stringEnds = Set("@@"))))(
"@@@@" -> Some(""),
"@@abc@@" -> Some("abc"),
"@@" -> None,
they should "allow for change in literal end" in unicodeCases(makeString(plain.copy(stringEnds = Set(("@-", "-@")))))(
"@--@" -> Some(""),
"@-a-c-@" -> Some("a-c"),
"@-" -> None,
"\"\"" -> None,
)

Expand Down

0 comments on commit 1fc03b3

Please sign in to comment.