Skip to content

Handle atoms as things to be wrapped in One #413

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

Merged
merged 1 commit into from
Jun 21, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
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
110 changes: 79 additions & 31 deletions Sources/_StringProcessing/PrintAsPattern.swift
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ extension PrettyPrinter {
print("/* TODO: conditional */")

case let .quantification(amount, kind, child):
let amount = amount.ast._patternBase
let amountStr = amount.ast._patternBase
var kind = kind.ast?._patternBase ?? ""

// If we've updated our quantification behavior, then use that. This
Expand All @@ -137,10 +137,10 @@ extension PrettyPrinter {
kind = quantificationBehavior._patternBase
}

var blockName = "\(amount)(\(kind))"
var blockName = "\(amountStr)(\(kind))"

if kind == ".eager" {
blockName = "\(amount)"
blockName = "\(amountStr)"
}

// Special case single child character classes for repetition nodes.
Expand All @@ -152,6 +152,20 @@ extension PrettyPrinter {
// One(.digit)
// }
//
func printAtom(_ pattern: String) {
indent()

if kind != ".eager" {
blockName.removeLast()
output("\(blockName), ")
} else {
output("\(blockName)(")
}

output("\(pattern))")
terminateLine()
}

func printSimpleCCC(
_ ccc: DSLTree.CustomCharacterClass
) {
Expand All @@ -169,23 +183,42 @@ extension PrettyPrinter {
terminateLine()
}

switch child {
case let .customCharacterClass(ccc):
if ccc.isSimplePrint {
printSimpleCCC(ccc)
return
}

break
case let .convertedRegexLiteral(.customCharacterClass(ccc), _):
if ccc.isSimplePrint {
printSimpleCCC(ccc)
return
// We can only do this for Optionally, ZeroOrMore, and OneOrMore. Cannot
// do it right now for Repeat.
if amount.ast.supportsInlineComponent {
switch child {
case let .atom(a):
if let pattern = a._patternBase(&self), pattern.canBeWrapped {
printAtom(pattern.0)
return
}

break
case let .customCharacterClass(ccc):
if ccc.isSimplePrint {
printSimpleCCC(ccc)
return
}

break

case let .convertedRegexLiteral(.atom(a), _):
if let pattern = a._patternBase(&self), pattern.canBeWrapped {
printAtom(pattern.0)
return
}

break
case let .convertedRegexLiteral(.customCharacterClass(ccc), _):
if ccc.isSimplePrint {
printSimpleCCC(ccc)
return
}

break
default:
break
}

break
default:
break
}

printBlock(blockName) { printer in
Expand All @@ -199,7 +232,11 @@ extension PrettyPrinter {
}

if let pattern = a._patternBase(&self) {
print(pattern)
if pattern.canBeWrapped {
print("One(\(pattern.0))")
} else {
print(pattern.0)
}
}

case .trivia:
Expand Down Expand Up @@ -391,9 +428,9 @@ extension PrettyPrinter {
if let lhs = lhs._patternBase(&self), let rhs = rhs._patternBase(&self) {
indent()
output("(")
output(lhs)
output(lhs.0)
output("...")
output(rhs)
output(rhs.0)
output(")")
}

Expand Down Expand Up @@ -939,6 +976,15 @@ extension AST.Quantification.Amount {
case let .range(n, m): return "Repeat(\(n.value)...\(m.value))"
}
}

var supportsInlineComponent: Bool {
switch self {
case .zeroOrMore: return true
case .oneOrMore: return true
case .zeroOrOne: return true
default: return false
}
}
}

extension AST.Quantification.Kind {
Expand Down Expand Up @@ -1033,33 +1079,35 @@ extension DSLTree.CustomCharacterClass {
}

extension DSLTree.Atom {
func _patternBase(_ printer: inout PrettyPrinter) -> String? {
func _patternBase(
_ printer: inout PrettyPrinter
) -> (String, canBeWrapped: Bool)? {
switch self {
case .any:
return ".any"
return (".any", true)

case let .char(c):
return String(c)._quoted
return (String(c)._quoted, false)

case let .scalar(s):
let hex = String(s.value, radix: 16, uppercase: true)
return "\\u{\(hex)}"._quoted
return ("\\u{\(hex)}"._quoted, false)

case let .unconverted(a):
if a.ast.isUnprintableAtom {
return "#/\(a.ast._regexBase)/#"
return ("#/\(a.ast._regexBase)/#", false)
} else {
return a.ast._dslBase.0
return a.ast._dslBase
}

case .assertion(let a):
return a.ast._patternBase
return (a.ast._patternBase, false)

case .backreference(_):
return "/* TOOD: backreferences */"
return ("/* TOOD: backreferences */", false)

case .symbolicReference:
return "/* TOOD: symbolic references */"
return ("/* TOOD: symbolic references */", false)

case .changeMatchingOptions(let matchingOptions):
for add in matchingOptions.ast.adding {
Expand Down
21 changes: 9 additions & 12 deletions Tests/RegexTests/RenderDSLTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -56,20 +56,17 @@ extension RenderDSLTests {

try testConversion(#"\d+"#, """
Regex {
OneOrMore {
.digit
}
OneOrMore(.digit)
}
""")

try testConversion(#":\d:"#, """
Regex {
":"
One(.digit)
":"
}
""")
try XCTExpectFailure("Invalid leading dot syntax in non-initial position") {
try testConversion(#":\d:"#, """
Regex {
":"
CharacterClass.digit
":"
}
""")
}
}

func testOptions() throws {
Expand Down