mirror of
https://github.com/TelegramMessenger/Telegram-iOS.git
synced 2026-07-05 19:28:46 +02:00
SwiftTL: thread apiPrefix, drop dead CLI flags and LegacyOrderParser
Preparation for layered schema generation. Threads apiPrefix: String through CodeGenerator.generate / generateMainFile / generateImplFile / typeReferenceRepresentation so the output's namespace name can come from the --api-prefix=<prefix> CLI flag rather than a hard-coded "Api". Drops the --stub-functions and --print-constructors=N-M flags (both unused) and the LegacyOrderParser.swift file (obsolete migration helper that re-parsed hand-emitted Api0.swift). No behavior change for the flat Api*.swift output when --api-prefix=Api (the default). Enables the upcoming layered secret- scheme pipeline to reuse the same generator helpers. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
25ddc21780
commit
bb29084392
4 changed files with 44 additions and 231 deletions
|
|
@ -87,7 +87,7 @@ private struct CodeWriter {
|
|||
}
|
||||
}*/
|
||||
|
||||
private func typeReferenceRepresentation(_ type: Resolver.TypeReference) -> String {
|
||||
private func typeReferenceRepresentation(_ apiPrefix: String, _ type: Resolver.TypeReference) -> String {
|
||||
switch type {
|
||||
case .int32:
|
||||
return "Int32"
|
||||
|
|
@ -106,13 +106,13 @@ private func typeReferenceRepresentation(_ type: Resolver.TypeReference) -> Stri
|
|||
case .boolTrue:
|
||||
return "bool"
|
||||
case let .bareVector(elementType):
|
||||
return "[\(typeReferenceRepresentation(elementType))]"
|
||||
return "[\(typeReferenceRepresentation(apiPrefix, elementType))]"
|
||||
case let .boxedVector(elementType):
|
||||
return "[\(typeReferenceRepresentation(elementType))]"
|
||||
return "[\(typeReferenceRepresentation(apiPrefix, elementType))]"
|
||||
case let .bareConstructor(typeName, _):
|
||||
return "Api.\(typeName)"
|
||||
return "\(apiPrefix).\(typeName)"
|
||||
case let .boxedType(typeName):
|
||||
return "Api.\(typeName)"
|
||||
return "\(apiPrefix).\(typeName)"
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -184,22 +184,22 @@ enum CodeGenerator {
|
|||
}
|
||||
}
|
||||
|
||||
static func generate(types: [Resolver.SumType], functions: [Resolver.Function], constructorOrder: [(typeName: QualifiedName, constructorName: String)], typeOrder: [(types: [(typeName: QualifiedName, constructorNames: [String])], functions: [QualifiedName])], stubFunctions: Bool = false) throws -> [String: String] {
|
||||
static func generate(apiPrefix: String, types: [Resolver.SumType], functions: [Resolver.Function], constructorOrder: [(typeName: QualifiedName, constructorName: String)], typeOrder: [(types: [(typeName: QualifiedName, constructorNames: [String])], functions: [QualifiedName])]) throws -> [String: String] {
|
||||
var files: [String: String] = [:]
|
||||
|
||||
var functions = functions
|
||||
functions.append(Resolver.Function(name: QualifiedName(namespace: "help", value: "test"), id: UInt32(bitPattern: -1058929929), arguments: [], result: .boxedType(QualifiedName(namespace: nil, value: "Bool"))))
|
||||
|
||||
files["Api0.swift"] = try generateMainFile(types: types, functions: functions, constructorOrder: constructorOrder)
|
||||
files["\(apiPrefix)0.swift"] = try generateMainFile(apiPrefix: apiPrefix, types: types, functions: functions, constructorOrder: constructorOrder)
|
||||
|
||||
for index in 0 ..< typeOrder.count {
|
||||
files["Api\(index + 1).swift"] = try generateImplFile(types: types, functions: functions, typeOrder: typeOrder[index], stubFunctions: stubFunctions)
|
||||
files["\(apiPrefix)\(index + 1).swift"] = try generateImplFile(apiPrefix: apiPrefix, types: types, functions: functions, typeOrder: typeOrder[index])
|
||||
}
|
||||
|
||||
return files
|
||||
}
|
||||
|
||||
private static func generateMainFile(types: [Resolver.SumType], functions: [Resolver.Function], constructorOrder: [(typeName: QualifiedName, constructorName: String)]) throws -> String {
|
||||
private static func generateMainFile(apiPrefix: String, types: [Resolver.SumType], functions: [Resolver.Function], constructorOrder: [(typeName: QualifiedName, constructorName: String)]) throws -> String {
|
||||
var writer = CodeWriter()
|
||||
|
||||
writer.line()
|
||||
|
|
@ -218,7 +218,7 @@ enum CodeGenerator {
|
|||
}
|
||||
}
|
||||
|
||||
writer.line("public enum Api {")
|
||||
writer.line("public enum \(apiPrefix) {")
|
||||
writer.indent()
|
||||
for namespace in namespaces.sorted(by: { $0 < $1 }) {
|
||||
writer.line("public enum \(namespace) {}")
|
||||
|
|
@ -258,7 +258,7 @@ enum CodeGenerator {
|
|||
for (_, constructor) in type.constructors {
|
||||
if constructor.name.value == constructorName {
|
||||
found = true
|
||||
writer.line("dict[\(Int32(bitPattern: constructor.id))] = { return Api.\(type.name).parse_\(constructor.name.value)($0) }")
|
||||
writer.line("dict[\(Int32(bitPattern: constructor.id))] = { return \(apiPrefix).\(type.name).parse_\(constructor.name.value)($0) }")
|
||||
break
|
||||
}
|
||||
}
|
||||
|
|
@ -274,7 +274,7 @@ enum CodeGenerator {
|
|||
|
||||
writer.line()
|
||||
|
||||
writer.line("public extension Api {")
|
||||
writer.line("public extension \(apiPrefix) {")
|
||||
writer.indent()
|
||||
|
||||
writer.line("static func parse(_ buffer: Buffer) -> Any? {")
|
||||
|
|
@ -344,7 +344,7 @@ enum CodeGenerator {
|
|||
writer.dedent()
|
||||
writer.line("} else {")
|
||||
writer.indent()
|
||||
writer.line("if let item = Api.parse(reader, signature: signature) as? T {")
|
||||
writer.line("if let item = \(apiPrefix).parse(reader, signature: signature) as? T {")
|
||||
writer.indent()
|
||||
writer.line("array.append(item)")
|
||||
writer.dedent()
|
||||
|
|
@ -378,7 +378,7 @@ enum CodeGenerator {
|
|||
throw CodeGenerationError(text: "Type \(typeName) not found")
|
||||
}
|
||||
|
||||
writer.line("case let _1 as Api.\(type.name):")
|
||||
writer.line("case let _1 as \(apiPrefix).\(type.name):")
|
||||
writer.indent()
|
||||
writer.line("_1.serialize(buffer, boxed)")
|
||||
writer.dedent()
|
||||
|
|
@ -398,7 +398,7 @@ enum CodeGenerator {
|
|||
return writer.output()
|
||||
}
|
||||
|
||||
private static func generateImplFile(types: [Resolver.SumType], functions: [Resolver.Function], typeOrder: (types: [(typeName: QualifiedName, constructorNames: [String])], functions: [QualifiedName]), stubFunctions: Bool) throws -> String {
|
||||
private static func generateImplFile(apiPrefix: String, types: [Resolver.SumType], functions: [Resolver.Function], typeOrder: (types: [(typeName: QualifiedName, constructorNames: [String])], functions: [QualifiedName])) throws -> String {
|
||||
var writer = CodeWriter()
|
||||
|
||||
var typeMap: [QualifiedName: Resolver.SumType] = [:]
|
||||
|
|
@ -407,7 +407,7 @@ enum CodeGenerator {
|
|||
}
|
||||
|
||||
for (typeName, constructorNames) in typeOrder.types {
|
||||
writer.line("public extension Api\(typeName.namespace.flatMap { "." + $0 } ?? "") {")
|
||||
writer.line("public extension \(apiPrefix)\(typeName.namespace.flatMap { "." + $0 } ?? "") {")
|
||||
writer.indent()
|
||||
|
||||
guard let type = typeMap[typeName] else {
|
||||
|
|
@ -448,7 +448,7 @@ enum CodeGenerator {
|
|||
}
|
||||
|
||||
let fieldName = argument.name.camelCasedAndEscaped
|
||||
let fieldType = typeReferenceRepresentation(argument.type) + (argument.condition != nil ? "?" : "")
|
||||
let fieldType = typeReferenceRepresentation(apiPrefix, argument.type) + (argument.condition != nil ? "?" : "")
|
||||
|
||||
if !fieldsString.isEmpty {
|
||||
fieldsString.append("\n")
|
||||
|
|
@ -509,7 +509,7 @@ enum CodeGenerator {
|
|||
|
||||
argumentsString.append(argument.name.camelCased)
|
||||
argumentsString.append(": ")
|
||||
argumentsString.append(typeReferenceRepresentation(argument.type))
|
||||
argumentsString.append(typeReferenceRepresentation(apiPrefix, argument.type))
|
||||
if argument.condition != nil {
|
||||
argumentsString.append("?")
|
||||
}
|
||||
|
|
@ -522,13 +522,6 @@ enum CodeGenerator {
|
|||
writer.line()
|
||||
writer.line("public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {")
|
||||
writer.indent()
|
||||
if stubFunctions {
|
||||
writer.line("#if DEBUG")
|
||||
writer.line("preconditionFailure()")
|
||||
writer.line("#else")
|
||||
writer.line("error")
|
||||
writer.line("#endif")
|
||||
} else {
|
||||
writer.line("switch self {")
|
||||
|
||||
for constructor in sortedConstructors {
|
||||
|
|
@ -608,20 +601,12 @@ enum CodeGenerator {
|
|||
}
|
||||
|
||||
writer.line("}")
|
||||
} // end if !stubFunctions
|
||||
writer.dedent()
|
||||
writer.line("}")
|
||||
|
||||
writer.line()
|
||||
writer.line("public func descriptionFields() -> (String, [(String, ConstructorParameterDescription)]) {")
|
||||
writer.indent()
|
||||
if stubFunctions {
|
||||
writer.line("#if DEBUG")
|
||||
writer.line("preconditionFailure()")
|
||||
writer.line("#else")
|
||||
writer.line("error")
|
||||
writer.line("#endif")
|
||||
} else {
|
||||
writer.line("switch self {")
|
||||
|
||||
for constructor in sortedConstructors {
|
||||
|
|
@ -673,7 +658,6 @@ enum CodeGenerator {
|
|||
}
|
||||
|
||||
writer.line("}")
|
||||
} // end if !stubFunctions for descriptionFields
|
||||
writer.dedent()
|
||||
writer.line("}")
|
||||
|
||||
|
|
@ -682,14 +666,6 @@ enum CodeGenerator {
|
|||
for constructor in sortedConstructors {
|
||||
writer.line("public static func parse_\(constructor.name.value)(_ reader: BufferReader) -> \(typeName.value)? {")
|
||||
writer.indent()
|
||||
if stubFunctions {
|
||||
writer.line("#if DEBUG")
|
||||
writer.line("preconditionFailure()")
|
||||
writer.line("#else")
|
||||
writer.line("error")
|
||||
writer.line("#endif")
|
||||
} else {
|
||||
|
||||
if constructor.arguments.contains(where: { if case .boolTrue = $0.type { return false } else { return true } }) {
|
||||
var argumentIndex = 0
|
||||
var argumentCheckString = ""
|
||||
|
|
@ -699,7 +675,7 @@ enum CodeGenerator {
|
|||
continue
|
||||
}
|
||||
|
||||
writer.line("var _\(argumentIndex + 1): \(typeReferenceRepresentation(argument.type))?")
|
||||
writer.line("var _\(argumentIndex + 1): \(typeReferenceRepresentation(apiPrefix, argument.type))?")
|
||||
|
||||
if let condition = argument.condition {
|
||||
guard let fieldIndex = constructor.arguments.filter({ if case .boolTrue = $0.type { return false } else { return true } }).firstIndex(where: { $0.name == condition.fieldName }) else {
|
||||
|
|
@ -708,11 +684,11 @@ enum CodeGenerator {
|
|||
|
||||
writer.line("if Int(_\(fieldIndex + 1)!) & Int(1 << \(condition.bitIndex)) != 0 {")
|
||||
writer.indent()
|
||||
try generateFieldParsing(writer: &writer, typeMap: typeMap, argument: argument, argumentAccessor: "_\(argumentIndex + 1)")
|
||||
try generateFieldParsing(apiPrefix: apiPrefix, writer: &writer, typeMap: typeMap, argument: argument, argumentAccessor: "_\(argumentIndex + 1)")
|
||||
writer.dedent()
|
||||
writer.line("}")
|
||||
} else {
|
||||
try generateFieldParsing(writer: &writer, typeMap: typeMap, argument: argument, argumentAccessor: "_\(argumentIndex + 1)")
|
||||
try generateFieldParsing(apiPrefix: apiPrefix, writer: &writer, typeMap: typeMap, argument: argument, argumentAccessor: "_\(argumentIndex + 1)")
|
||||
}
|
||||
|
||||
if !argumentCheckString.isEmpty {
|
||||
|
|
@ -753,9 +729,9 @@ enum CodeGenerator {
|
|||
writer.line("if \(argumentCheckString) {")
|
||||
writer.indent()
|
||||
if useStructPattern && !argumentCollectionString.isEmpty {
|
||||
writer.line("return Api.\(typeName).\(constructor.name.value)(Cons_\(constructor.name.value)(\(argumentCollectionString)))")
|
||||
writer.line("return \(apiPrefix).\(typeName).\(constructor.name.value)(Cons_\(constructor.name.value)(\(argumentCollectionString)))")
|
||||
} else {
|
||||
writer.line("return Api.\(typeName).\(constructor.name.value)\(argumentCollectionString.isEmpty ? "" : "(\(argumentCollectionString))")")
|
||||
writer.line("return \(apiPrefix).\(typeName).\(constructor.name.value)\(argumentCollectionString.isEmpty ? "" : "(\(argumentCollectionString))")")
|
||||
}
|
||||
writer.dedent()
|
||||
writer.line("}")
|
||||
|
|
@ -765,10 +741,9 @@ enum CodeGenerator {
|
|||
writer.dedent()
|
||||
writer.line("}")
|
||||
} else {
|
||||
writer.line("return Api.\(typeName).\(constructor.name.value)")
|
||||
writer.line("return \(apiPrefix).\(typeName).\(constructor.name.value)")
|
||||
}
|
||||
|
||||
} // end if !stubFunctions
|
||||
writer.dedent()
|
||||
writer.line("}")
|
||||
}
|
||||
|
|
@ -781,7 +756,7 @@ enum CodeGenerator {
|
|||
|
||||
if !typeOrder.functions.isEmpty {
|
||||
for functionName in typeOrder.functions {
|
||||
writer.line("public extension Api.functions\(functionName.namespace.flatMap { "." + $0 } ?? "") {")
|
||||
writer.line("public extension \(apiPrefix).functions\(functionName.namespace.flatMap { "." + $0 } ?? "") {")
|
||||
writer.indent()
|
||||
|
||||
var foundFunction: Resolver.Function?
|
||||
|
|
@ -807,13 +782,13 @@ enum CodeGenerator {
|
|||
|
||||
argumentsString.append(argument.name.camelCasedAndEscaped)
|
||||
argumentsString.append(": ")
|
||||
argumentsString.append(typeReferenceRepresentation(argument.type))
|
||||
argumentsString.append(typeReferenceRepresentation(apiPrefix, argument.type))
|
||||
if argument.condition != nil {
|
||||
argumentsString.append("?")
|
||||
}
|
||||
}
|
||||
|
||||
writer.line("static func \(function.name.value)(\(argumentsString)) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<\(typeReferenceRepresentation(function.result))>) {")
|
||||
writer.line("static func \(function.name.value)(\(argumentsString)) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<\(typeReferenceRepresentation(apiPrefix, function.result))>) {")
|
||||
writer.indent()
|
||||
writer.line("let buffer = Buffer()")
|
||||
writer.line("buffer.appendInt32(\(Int32(bitPattern: function.id)))")
|
||||
|
|
@ -847,12 +822,12 @@ enum CodeGenerator {
|
|||
argumentSerializationString.append("(\"\(argument.name.camelCasedAndEscaped)\", ConstructorParameterDescription(\(argument.name.camelCasedAndEscaped)))")
|
||||
}
|
||||
|
||||
writer.line("return (FunctionDescription(name: \"\(function.name)\", parameters: [\(argumentSerializationString)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> \(typeReferenceRepresentation(function.result))? in")
|
||||
writer.line("return (FunctionDescription(name: \"\(function.name)\", parameters: [\(argumentSerializationString)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> \(typeReferenceRepresentation(apiPrefix, function.result))? in")
|
||||
writer.indent()
|
||||
writer.line("let reader = BufferReader(buffer)")
|
||||
writer.line("var result: \(typeReferenceRepresentation(function.result))?")
|
||||
writer.line("var result: \(typeReferenceRepresentation(apiPrefix, function.result))?")
|
||||
|
||||
try generateFieldParsing(writer: &writer, typeMap: typeMap, argument: Resolver.Argument(name: "result", type: function.result, condition: nil), argumentAccessor: "result")
|
||||
try generateFieldParsing(apiPrefix: apiPrefix, writer: &writer, typeMap: typeMap, argument: Resolver.Argument(name: "result", type: function.result, condition: nil), argumentAccessor: "result")
|
||||
|
||||
writer.line("return result")
|
||||
writer.dedent()
|
||||
|
|
@ -904,7 +879,7 @@ enum CodeGenerator {
|
|||
}
|
||||
}
|
||||
|
||||
private static func generateFieldParsing(writer: inout CodeWriter, typeMap: [QualifiedName: Resolver.SumType], argument: Resolver.Argument, argumentAccessor: String) throws {
|
||||
private static func generateFieldParsing(apiPrefix: String, writer: inout CodeWriter, typeMap: [QualifiedName: Resolver.SumType], argument: Resolver.Argument, argumentAccessor: String) throws {
|
||||
switch argument.type {
|
||||
case .int32:
|
||||
writer.line("\(argumentAccessor) = reader.readInt32()")
|
||||
|
|
@ -961,11 +936,11 @@ enum CodeGenerator {
|
|||
if case .boxedVector = argument.type {
|
||||
writer.line("if let _ = reader.readInt32() {")
|
||||
writer.indent()
|
||||
writer.line("\(argumentAccessor) = Api.parseVector(reader, elementSignature: \(elementSignature), elementType: \(typeReferenceRepresentation(elementType)).self)")
|
||||
writer.line("\(argumentAccessor) = \(apiPrefix).parseVector(reader, elementSignature: \(elementSignature), elementType: \(typeReferenceRepresentation(apiPrefix, elementType)).self)")
|
||||
writer.dedent()
|
||||
writer.line("}")
|
||||
} else {
|
||||
writer.line("\(argumentAccessor) = Api.parseVector(reader, elementSignature: \(elementSignature), elementType: \(typeReferenceRepresentation(elementType)).self)")
|
||||
writer.line("\(argumentAccessor) = \(apiPrefix).parseVector(reader, elementSignature: \(elementSignature), elementType: \(typeReferenceRepresentation(apiPrefix, elementType)).self)")
|
||||
}
|
||||
case let .bareConstructor(typeName, name):
|
||||
guard let type = typeMap[typeName] else {
|
||||
|
|
@ -974,11 +949,11 @@ enum CodeGenerator {
|
|||
guard let constructor = type.constructors[name] else {
|
||||
throw CodeGenerationError(text: "Type \(typeName) not found")
|
||||
}
|
||||
writer.line("\(argumentAccessor) = Api.parse(reader, signature: \(Int32(bitPattern: constructor.id)) as? \(typeReferenceRepresentation(argument.type))")
|
||||
writer.line("\(argumentAccessor) = \(apiPrefix).parse(reader, signature: \(Int32(bitPattern: constructor.id)) as? \(typeReferenceRepresentation(apiPrefix, argument.type))")
|
||||
case .boxedType:
|
||||
writer.line("if let signature = reader.readInt32() {")
|
||||
writer.indent()
|
||||
writer.line("\(argumentAccessor) = Api.parse(reader, signature: signature) as? \(typeReferenceRepresentation(argument.type))")
|
||||
writer.line("\(argumentAccessor) = \(apiPrefix).parse(reader, signature: signature) as? \(typeReferenceRepresentation(apiPrefix, argument.type))")
|
||||
writer.dedent()
|
||||
writer.line("}")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,8 +31,6 @@ enum DescriptionParser {
|
|||
var functionLines: [String] = []
|
||||
|
||||
let skipPrefixes: [String] = [
|
||||
//"boolFalse#bc799737 = Bool;",
|
||||
//"boolTrue#997275b5 = Bool;",
|
||||
"true#3fedd339 = True;",
|
||||
"vector#1cb5c415 {t:Type} # [ t ] = Vector t;",
|
||||
"error#c4b9f9bb code:int text:string = Error;",
|
||||
|
|
|
|||
|
|
@ -1,128 +0,0 @@
|
|||
import Foundation
|
||||
|
||||
enum LegacyOrderParser {
|
||||
struct LegacyOrderParsingError: Error, CustomStringConvertible {
|
||||
var text: String
|
||||
|
||||
var description: String {
|
||||
return self.text
|
||||
}
|
||||
}
|
||||
|
||||
static func parseConstructorOrder(data: String) throws -> [(typeName: QualifiedName, constructorName: String)] {
|
||||
let lines = data.split(separator: "\n")
|
||||
|
||||
var result: [(typeName: QualifiedName, constructorName: String)] = []
|
||||
|
||||
for line in lines {
|
||||
if let startRange = line.range(of: " = { return Api."), let endRange = line.range(of: "($0) }", options: [.backwards], range: nil) {
|
||||
let parseString = line[startRange.upperBound ..< endRange.lowerBound]
|
||||
let components = parseString.components(separatedBy: ".parse_")
|
||||
if components.count != 2 {
|
||||
continue
|
||||
}
|
||||
|
||||
result.append((QualifiedName(string: components[0]), components[1]))
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
static func parseTypeOrder(data: String) throws -> (types: [(typeName: QualifiedName, constructorNames: [String])], functions: [QualifiedName]) {
|
||||
var resultTypes: [(typeName: QualifiedName, constructorNames: [String])] = []
|
||||
var resultFunctions: [QualifiedName] = []
|
||||
|
||||
let namespaces = data.components(separatedBy: "public extension Api {\n")
|
||||
|
||||
enum ParseSection {
|
||||
case types
|
||||
case functions
|
||||
}
|
||||
|
||||
for namespaceData in namespaces {
|
||||
if namespaceData.isEmpty {
|
||||
continue
|
||||
}
|
||||
guard let firstNewline = namespaceData.range(of: "\n") else {
|
||||
throw LegacyOrderParsingError(text: "No newline in the beginning of the namespace section")
|
||||
}
|
||||
let namespaceName: String?
|
||||
let namespaceContentData: String
|
||||
let parseSection: ParseSection
|
||||
if let prefixRange = namespaceData.range(of: " public enum ", options: [], range: namespaceData.startIndex ..< firstNewline.lowerBound), prefixRange.lowerBound == namespaceData.startIndex {
|
||||
namespaceName = nil
|
||||
namespaceContentData = namespaceData
|
||||
parseSection = .types
|
||||
} else if let prefixRange = namespaceData.range(of: " indirect public enum ", options: [], range: namespaceData.startIndex ..< firstNewline.lowerBound), prefixRange.lowerBound == namespaceData.startIndex {
|
||||
namespaceName = nil
|
||||
namespaceContentData = namespaceData
|
||||
parseSection = .types
|
||||
} else if let prefixRange = namespaceData.range(of: " public struct functions {", options: [], range: namespaceData.startIndex ..< firstNewline.lowerBound), prefixRange.upperBound == firstNewline.lowerBound {
|
||||
namespaceName = nil
|
||||
namespaceContentData = namespaceData
|
||||
parseSection = .functions
|
||||
} else {
|
||||
guard let prefixRange = namespaceData.range(of: "public struct ", options: [], range: namespaceData.startIndex ..< firstNewline.lowerBound), prefixRange.lowerBound == namespaceData.startIndex else {
|
||||
throw LegacyOrderParsingError(text: "Missing header prefix in the beginning of the namespace section")
|
||||
}
|
||||
guard let trailerRange = namespaceData.range(of: " {", options: [], range: prefixRange.upperBound ..< firstNewline.lowerBound) else {
|
||||
throw LegacyOrderParsingError(text: "Missing trailing suffix in the beginning of the namespace section")
|
||||
}
|
||||
namespaceName = String(namespaceData[prefixRange.upperBound ..< trailerRange.lowerBound])
|
||||
namespaceContentData = String(namespaceData[firstNewline.upperBound...])
|
||||
parseSection = .types
|
||||
}
|
||||
|
||||
let namespaceContentLines = namespaceContentData.split(separator: "\n")
|
||||
|
||||
switch parseSection {
|
||||
case .types:
|
||||
var currentType: (typeName: QualifiedName, constructorNames: [String])?
|
||||
for line in namespaceContentLines {
|
||||
if let typePrefixRange = line.range(of: " public enum "), typePrefixRange.lowerBound == line.startIndex, let typeSuffixRange = line.range(of: ": TypeConstructorDescription {"), typeSuffixRange.upperBound == line.endIndex {
|
||||
let typeName = String(line[typePrefixRange.upperBound ..< typeSuffixRange.lowerBound])
|
||||
if let currentType = currentType {
|
||||
resultTypes.append(currentType)
|
||||
}
|
||||
currentType = (QualifiedName(namespace: namespaceName, value: typeName), [])
|
||||
} else if let typePrefixRange = line.range(of: " indirect public enum "), typePrefixRange.lowerBound == line.startIndex, let typeSuffixRange = line.range(of: ": TypeConstructorDescription {"), typeSuffixRange.upperBound == line.endIndex {
|
||||
let typeName = String(line[typePrefixRange.upperBound ..< typeSuffixRange.lowerBound])
|
||||
if let currentType = currentType {
|
||||
resultTypes.append(currentType)
|
||||
}
|
||||
currentType = (QualifiedName(namespace: namespaceName, value: typeName), [])
|
||||
} else if currentType != nil, let constructorPrefixRange = line.range(of: " case "), constructorPrefixRange.lowerBound == line.startIndex {
|
||||
let constructorName: String
|
||||
if let bracketRange = line.range(of: "(") {
|
||||
constructorName = String(line[constructorPrefixRange.upperBound ..< bracketRange.lowerBound])
|
||||
} else {
|
||||
constructorName = String(line[constructorPrefixRange.upperBound...])
|
||||
}
|
||||
currentType?.constructorNames.append(constructorName)
|
||||
}
|
||||
}
|
||||
if let currentType = currentType {
|
||||
resultTypes.append(currentType)
|
||||
}
|
||||
case .functions:
|
||||
var currentNamespace: String?
|
||||
for line in namespaceContentLines {
|
||||
if let namespacePrefixRange = line.range(of: " public struct "), namespacePrefixRange.lowerBound == line.startIndex, let namespaceSuffixRange = line.range(of: " {"), namespaceSuffixRange.upperBound == line.endIndex {
|
||||
currentNamespace = String(line[namespacePrefixRange.upperBound ..< namespaceSuffixRange.lowerBound])
|
||||
} else if let functionPrefixRange = line.range(of: " public static func "), functionPrefixRange.lowerBound == line.startIndex {
|
||||
let functionName: String
|
||||
if let bracketRange = line.range(of: "(") {
|
||||
functionName = String(line[functionPrefixRange.upperBound ..< bracketRange.lowerBound])
|
||||
} else {
|
||||
functionName = String(line[functionPrefixRange.upperBound...])
|
||||
}
|
||||
resultFunctions.append(QualifiedName(namespace: currentNamespace, value: functionName))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (resultTypes, resultFunctions)
|
||||
}
|
||||
}
|
||||
|
|
@ -27,26 +27,15 @@ if CommandLine.arguments.count < 3 {
|
|||
|
||||
let schemeFilePath = CommandLine.arguments[1]
|
||||
let outputDirectoryPath = CommandLine.arguments[2]
|
||||
var apiPrefix = "Api"
|
||||
|
||||
var stubFunctions = false
|
||||
var printConstructorsRange: (start: Int, end: Int)? = nil
|
||||
for arg in CommandLine.arguments {
|
||||
if arg == "--stub-functions" {
|
||||
stubFunctions = true
|
||||
}
|
||||
if arg.hasPrefix("--print-constructors=") {
|
||||
let value = String(arg.dropFirst("--print-constructors=".count))
|
||||
let parts = value.split(separator: "-")
|
||||
if parts.count == 2, let start = Int(parts[0]), let end = Int(parts[1]) {
|
||||
if start > end {
|
||||
print("Error: Invalid range for --print-constructors: start (\(start)) must be <= end (\(end))")
|
||||
exit(1)
|
||||
}
|
||||
printConstructorsRange = (start, end)
|
||||
} else {
|
||||
print("Error: Invalid format for --print-constructors. Expected: --print-constructors=N-M (e.g., --print-constructors=0-10)")
|
||||
exit(1)
|
||||
}
|
||||
for arg in CommandLine.arguments[3...] {
|
||||
if arg.hasPrefix("--api-prefix=") {
|
||||
let value = String(arg.dropFirst("--api-prefix=".count))
|
||||
apiPrefix = value
|
||||
} else {
|
||||
print("Error: Unknown argument: \(arg)")
|
||||
exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -67,27 +56,6 @@ do {
|
|||
|
||||
let sortedTypes = resolvedTypes.sorted(by: { $0.name < $1.name })
|
||||
|
||||
if let range = printConstructorsRange {
|
||||
print("--- CONSTRUCTORS ---")
|
||||
for (index, type) in sortedTypes.enumerated() {
|
||||
if index >= range.start && index < range.end {
|
||||
for constructor in type.constructors.values.sorted(by: { $0.name < $1.name }) {
|
||||
let storedArguments = constructor.arguments.filter {
|
||||
if case .boolTrue = $0.type { return false }
|
||||
return true
|
||||
}
|
||||
if !storedArguments.isEmpty {
|
||||
let fieldNames = storedArguments.map { $0.name.camelCased }
|
||||
print("\(constructor.name.value):\(fieldNames.joined(separator: ","))")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
print("--- END CONSTRUCTORS ---")
|
||||
print("Total types: \(sortedTypes.count)")
|
||||
exit(0)
|
||||
}
|
||||
|
||||
for type in sortedTypes {
|
||||
for constructor in type.constructors.values.sorted(by: { $0.name < $1.name }) {
|
||||
constructorOrder.append((type.name, constructor.name.value))
|
||||
|
|
@ -118,7 +86,7 @@ do {
|
|||
|
||||
try FileManager.default.createDirectory(at: URL(fileURLWithPath: outputDirectoryPath), withIntermediateDirectories: true, attributes: nil)
|
||||
|
||||
let generatedFiles = try CodeGenerator.generate(types: resolvedTypes, functions: resolvedFunctions, constructorOrder: constructorOrder, typeOrder: typeOrder, stubFunctions: stubFunctions)
|
||||
let generatedFiles = try CodeGenerator.generate(apiPrefix: apiPrefix, types: resolvedTypes, functions: resolvedFunctions, constructorOrder: constructorOrder, typeOrder: typeOrder)
|
||||
|
||||
for (name, fileData) in generatedFiles {
|
||||
let filePath = URL(fileURLWithPath: outputDirectoryPath).appendingPathComponent(name).path
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue