Skip to content

Commit

Permalink
Complete migration and rename println to print.
Browse files Browse the repository at this point in the history
- Add `addNewlines` to the initializers and default it to `false` to maintain
  the existing behavior.
- Update all apis to be just the `print` instead of `println`.
- Add a overload of `print` with an extra `newlines` argument to allow
  overriding on a per call basis.
  • Loading branch information
thomasvl committed Sep 8, 2022
1 parent a98ac39 commit 7a18afa
Show file tree
Hide file tree
Showing 9 changed files with 310 additions and 250 deletions.
112 changes: 86 additions & 26 deletions Sources/SwiftProtobufPluginLibrary/CodePrinter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -44,69 +44,125 @@ public struct CodePrinter {
/// of a line.
private var atLineStart = true

/// Initialize the printer to use the give indent.
public init(indent: String.UnicodeScalarView = " ".unicodeScalars) {
/// Keeps track of if a newline should be added after each string to the
/// print apis.
private let newlines: Bool

/// Initialize the printer for use.
///
/// - Parameters:
/// - indent: A string (usually spaces) to use for the indentation amount.
/// - newlines: A boolean indicating if every `print` and `printIndented`
/// should automatically add newlines to the end of the strings.
public init(
indent: String.UnicodeScalarView = " ".unicodeScalars,
addNewlines newlines: Bool = false
) {
contentScalars.reserveCapacity(CodePrinter.initialBufferSize)
singleIndent = indent
self.newlines = newlines
}

/// Initialize a new printer using the existing state from another printer.
///
/// This can be useful to use with generation subtasks, so see if they
/// actually generate something (via `isEmpty`) to then optionally add it
/// back into the parent with whatever surounding content.
///
/// This is most useful to then use `append` to add the new content.
///
/// - Parameter parent: The other printer to copy the configuration/state
/// from.
public init(_ parent: CodePrinter) {
self.init(parent, addNewlines: parent.newlines)
}

/// Initialize a printer using the existing indention information from
/// another CodePrinter.
/// Initialize a new printer using the existing state from another printer
/// but with support to control the behavior of `addNewlines`.
///
/// This can be useful to use with generation subtasks, so see if they
/// actually generate something (via `isEmpty`) to then optionally add it
/// back into the parent with whatever surounding content.
///
/// This is most useful to then use `append` to add the new content.
public init(_ parent: Self) {
self.init(indent: parent.singleIndent)
///
/// - Parameters:
/// - parent: The other printer to copy the configuration/state
/// from.
/// - newlines: A boolean indicating if every `print` and `printIndented`
/// should automatically add newlines to the end of the strings.
public init(_ parent: CodePrinter, addNewlines newlines: Bool) {
self.init(indent: parent.singleIndent, addNewlines: newlines)
indentation = parent.indentation
}

/// Writes the given strings to the printer.
/// Writes the given strings to the printer, adding a newline after each
/// string.
///
/// Newlines within the strings are honored and indentention is applied.
///
/// The `addNewlines` value from initializing the printer controls if
/// newlines are appended after each string.
///
/// If called with no strings, a blank line is added to the printer
/// (even is `addNewlines` was false at initialization of the printer.
///
/// - Parameter text: A variable-length list of strings to be printed.
public mutating func print(_ text: String...) {
for t in text {
printInternal(t.unicodeScalars)
if text.isEmpty {
contentScalars.append(CodePrinter.kNewline)
atLineStart = true
} else {
for t in text {
printInternal(t.unicodeScalars, addNewline: newlines)
}
}
}

/// Writes the given strings to the printer, adding a newline after
/// each string. If called with no strings, a blank line is added to the
/// printer.
/// Writes the given strings to the printer, optionally adding a newline
/// after each string. If called with no strings, a blank line is added to
/// the printer.
///
/// Newlines within the strings are honored and indentention is applied.
///
/// - Parameter text: A variable-length list of strings to be printed.
public mutating func println(_ text: String...) {
/// - Parameters
/// - text: A variable-length list of strings to be printed.
/// - newlines: Boolean to control adding newlines after each string. This
/// is an explicit override of the `addNewlines` value using to
/// initialize this `CodePrinter`.
public mutating func print(_ text: String..., newlines: Bool) {
if text.isEmpty {
assert(newlines,
"Disabling newlines with no strings doesn't make sense.")
contentScalars.append(CodePrinter.kNewline)
atLineStart = true
} else {
for t in text {
printInternal(t.unicodeScalars)
contentScalars.append(CodePrinter.kNewline)
atLineStart = true
printInternal(t.unicodeScalars, addNewline: newlines)
}
}
}

/// Indents, writes the given strings to the printer with a newline added
/// to each one, and then outdents.
/// Indents, writes the given strings to the printer, and then outdents.
///
/// Newlines within the strings are honored and indentention is applied.
///
/// The `addNewlines` value from initializing the printer controls if
/// newlines are appended after each string.
///
/// - Parameter text: A variable-length list of strings to be printed.
public mutating func printlnIndented(_ text: String...) {
public mutating func printIndented(_ text: String...) {
indent()
for t in text {
printInternal(t.unicodeScalars)
contentScalars.append(CodePrinter.kNewline)
atLineStart = true
printInternal(t.unicodeScalars, addNewline: newlines)
}
outdent()
}

private mutating func printInternal(_ scalars: String.UnicodeScalarView) {
private mutating func printInternal(
_ scalars: String.UnicodeScalarView,
addNewline: Bool
) {
for scalar in scalars {
// Indent at the start of a new line, unless it's a blank line.
if atLineStart && scalar != CodePrinter.kNewline {
Expand All @@ -115,6 +171,10 @@ public struct CodePrinter {
contentScalars.append(scalar)
atLineStart = (scalar == CodePrinter.kNewline)
}
if addNewline {
contentScalars.append(CodePrinter.kNewline)
atLineStart = true
}
}

/// Appended the content of another `CodePrinter`to this one.
Expand All @@ -124,9 +184,9 @@ public struct CodePrinter {
/// - indenting: Boolean, if the text being appended should be reindented
/// to the current state of this printer. If the `printer` was
/// initialized off of this printer, there isn't a need to reindent.
public mutating func append(_ printer: Self, indenting: Bool = false) {
public mutating func append(_ printer: CodePrinter, indenting: Bool = false) {
if indenting {
printInternal(printer.contentScalars)
printInternal(printer.contentScalars, addNewline: false)
} else {
contentScalars.append(contentsOf: printer.contentScalars)
atLineStart = printer.atLineStart
Expand Down
78 changes: 39 additions & 39 deletions Sources/protoc-gen-swift/EnumGenerator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -56,32 +56,32 @@ class EnumGenerator {
func generateMainEnum(printer p: inout CodePrinter) {
let visibility = generatorOptions.visibilitySourceSnippet

p.println(
p.print(
"",
"\(enumDescriptor.protoSourceComments())\(visibility)enum \(swiftRelativeName): \(namer.swiftProtobufModuleName).Enum {")
p.withIndentation { p in
p.println("\(visibility)typealias RawValue = Int")
p.print("\(visibility)typealias RawValue = Int")

// Cases/aliases
generateCasesOrAliases(printer: &p)

// Generate the default initializer.
p.println(
p.print(
"",
"\(visibility)init() {")
p.printlnIndented("self = \(namer.dottedRelativeName(enumValue: enumDescriptor.values.first!))")
p.println("}")
p.printIndented("self = \(namer.dottedRelativeName(enumValue: enumDescriptor.values.first!))")
p.print("}")

p.println()
p.print()
generateInitRawValue(printer: &p)

p.println()
p.print()
generateRawValueProperty(printer: &p)

maybeGenerateCaseIterable(printer: &p)

}
p.println(
p.print(
"",
"}")
}
Expand All @@ -90,27 +90,27 @@ class EnumGenerator {
guard enumDescriptor.hasUnknownPreservingSemantics else { return }

let visibility = generatorOptions.visibilitySourceSnippet
p.println(
p.print(
"",
"// The compiler won't synthesize support with the \(unrecognizedCaseName) case.",
"\(visibility)static let allCases: [\(swiftFullName)] = [")
p.withIndentation { p in
for v in mainEnumValueDescriptors {
let dottedName = namer.dottedRelativeName(enumValue: v)
p.println("\(dottedName),")
p.print("\(dottedName),")
}
}
p.println("]")
p.print("]")
}

func generateRuntimeSupport(printer p: inout CodePrinter) {
p.println(
p.print(
"",
"extension \(swiftFullName): \(namer.swiftProtobufModuleName)._ProtoNameProviding {")
p.withIndentation { p in
generateProtoNameProviding(printer: &p)
}
p.println("}")
p.print("}")
}

/// Generates the cases or statics (for alias) for the values.
Expand All @@ -121,18 +121,18 @@ class EnumGenerator {
for enumValueDescriptor in namer.uniquelyNamedValues(enum: enumDescriptor) {
let comments = enumValueDescriptor.protoSourceComments()
if !comments.isEmpty {
p.println()
p.print()
}
let relativeName = namer.relativeName(enumValue: enumValueDescriptor)
if let aliasOf = enumValueDescriptor.aliasOf {
let aliasOfName = namer.relativeName(enumValue: aliasOf)
p.println("\(comments)\(visibility)static let \(relativeName) = \(aliasOfName)")
p.print("\(comments)\(visibility)static let \(relativeName) = \(aliasOfName)")
} else {
p.println("\(comments)case \(relativeName) // = \(enumValueDescriptor.number)")
p.print("\(comments)case \(relativeName) // = \(enumValueDescriptor.number)")
}
}
if enumDescriptor.hasUnknownPreservingSemantics {
p.println("case \(unrecognizedCaseName)(Int)")
p.print("case \(unrecognizedCaseName)(Int)")
}
}

Expand All @@ -142,18 +142,18 @@ class EnumGenerator {
private func generateProtoNameProviding(printer p: inout CodePrinter) {
let visibility = generatorOptions.visibilitySourceSnippet

p.println("\(visibility)static let _protobuf_nameMap: \(namer.swiftProtobufModuleName)._NameMap = [")
p.print("\(visibility)static let _protobuf_nameMap: \(namer.swiftProtobufModuleName)._NameMap = [")
p.withIndentation { p in
for v in mainEnumValueDescriptorsSorted {
if v.aliases.isEmpty {
p.println("\(v.number): .same(proto: \"\(v.name)\"),")
p.print("\(v.number): .same(proto: \"\(v.name)\"),")
} else {
let aliasNames = v.aliases.map({ "\"\($0.name)\"" }).joined(separator: ", ")
p.println("\(v.number): .aliased(proto: \"\(v.name)\", aliases: [\(aliasNames)]),")
p.print("\(v.number): .aliased(proto: \"\(v.name)\", aliases: [\(aliasNames)]),")
}
}
}
p.println("]")
p.print("]")
}

/// Generates `init?(rawValue:)` for the enum.
Expand All @@ -162,21 +162,21 @@ class EnumGenerator {
private func generateInitRawValue(printer p: inout CodePrinter) {
let visibility = generatorOptions.visibilitySourceSnippet

p.println("\(visibility)init?(rawValue: Int) {")
p.print("\(visibility)init?(rawValue: Int) {")
p.withIndentation { p in
p.println("switch rawValue {")
p.print("switch rawValue {")
for v in mainEnumValueDescriptorsSorted {
let dottedName = namer.dottedRelativeName(enumValue: v)
p.println("case \(v.number): self = \(dottedName)")
p.print("case \(v.number): self = \(dottedName)")
}
if enumDescriptor.hasUnknownPreservingSemantics {
p.println("default: self = .\(unrecognizedCaseName)(rawValue)")
p.print("default: self = .\(unrecognizedCaseName)(rawValue)")
} else {
p.println("default: return nil")
p.print("default: return nil")
}
p.println("}")
p.print("}")
}
p.println("}")
p.print("}")
}

/// Generates the `rawValue` property of the enum.
Expand All @@ -199,25 +199,25 @@ class EnumGenerator {
(enumDescriptor.hasUnknownPreservingSemantics ? 1 : 0)
let useMultipleSwitches = neededCases > maxCasesInSwitch

p.println("\(visibility)var rawValue: Int {")
p.print("\(visibility)var rawValue: Int {")
p.withIndentation { p in
if useMultipleSwitches {
for (i, v) in mainEnumValueDescriptorsSorted.enumerated() {
if (i % maxCasesInSwitch) == 0 {
if i > 0 {
p.println(
p.print(
"default: break",
"}")
}
p.println("switch self {")
p.print("switch self {")
}
let dottedName = namer.dottedRelativeName(enumValue: v)
p.println("case \(dottedName): return \(v.number)")
p.print("case \(dottedName): return \(v.number)")
}
if enumDescriptor.hasUnknownPreservingSemantics {
p.println("case .\(unrecognizedCaseName)(let i): return i")
p.print("case .\(unrecognizedCaseName)(let i): return i")
}
p.println("""
p.print("""
default: break
}
Expand All @@ -226,18 +226,18 @@ class EnumGenerator {
fatalError()
""")
} else {
p.println("switch self {")
p.print("switch self {")
for v in mainEnumValueDescriptorsSorted {
let dottedName = namer.dottedRelativeName(enumValue: v)
p.println("case \(dottedName): return \(v.number)")
p.print("case \(dottedName): return \(v.number)")
}
if enumDescriptor.hasUnknownPreservingSemantics {
p.println("case .\(unrecognizedCaseName)(let i): return i")
p.print("case .\(unrecognizedCaseName)(let i): return i")
}
p.println("}")
p.print("}")
}

}
p.println("}")
p.print("}")
}
}
Loading

0 comments on commit 7a18afa

Please sign in to comment.