Share
Embed
Transcript
27 slides
-
SwiftSyntax͓͞Β͍ • SwiftίϯύΠϥ෦ʹɺ৽͘͠៉ྷʹ࡞Γ͞ΕͨύʔαϞ δϡʔϧ libSyntax ͕͋Δ • ίʔυฤूͳͲΛߟྀͨ͠APIΛ࣋ͭ • ͦΕΛSwift͔Β͏ͨΊͷϥΠϒϥϦ͕
SwiftSyntax 1 • SwiftPMύοέʔδͱͯ͠ఏڙ 1 https://github.com/apple/swift-syntax 5 -
ύʔαຊମผ • SwiftSyntax ͋͘·Ͱͨͩͷ libSyntax ͷSwiftϒϦο δ • libSyntax XcodeͱҰॹʹ
→ ࣮ߦڥʹΑͬͯόʔ δϣϯ͕ҟͳΔ • SwiftSyntax ͷόʔδϣϯΛݻఆͰ͖ͯɺ࣮ߦڥͷ libSyntax ͷόʔδϣϯ͕ݻఆͰ͖ͳ͍ 7 -
ղܾํ๏ • libSyntax Ұॹʹ͢Δ • SwiftPMͷ binary target ͳΒɺxcframework ͷதʹ
libSyntax ΛຒΊࠐΊΔ • ͍ͭͰʹιʔε෦ͷϏϧυ࣌ؒΧοτͰ͖Δ 9 -
BinarySwiftSyntax 2 • SwiftSyntaxΛϏϧυ͢ΔxcodeprojΛ࡞ • खݩͷXcode͔Β libSyntax Λநग़ $ cp
"$(xcode-select -p)"/Toolchains/XcodeDefault.xctoolchain /usr/lib/swift/macosx/lib_InternalSwiftSyntaxParser.dylib SwiftSyntax/Deps • xcframeworkʹ͢Δ $ xcodebuild archive \ -project SwiftSyntax.xcodeproj \ CODE_SIGN_IDENTITY="" \ CODE_SIGNING_REQUIRED=NO \ CODE_SIGNING_ALLOWED=NO $ xcodebuild -create-xcframework \ -framework build/UninstalledProducts/macosx/SwiftSyntax.framework \ -output dist/Xcode12.5/SwiftSyntax.xcframework 2 https://github.com/omochi/BinarySwiftSyntax 10 -
؆୯ʹ͑Δ // package.swift let package = Package(name: "foo", products: [
.executable(name: "foo", targets: ["foo"]) ], dependencies: [ .package(url: "https://github.com/omochi/BinarySwiftSyntax", branch: "main") ], targets: [ .target(name: "foo", dependencies: [ // v ͜͜ͰόʔδϣϯࢦఆͰ͖Δ .product(name: "SwiftSyntax-Xcode13.0", package: "BinarySwiftSyntax") ]) ] ) // main.swift import SwiftSyntax let sourceFile: SourceFileSyntax = try SyntaxParser.parse(source: source) 12 -
let file = try SyntaxParser.parse(source: source) for statement in file.statements
{ if let structDecl = statement.item.as(StructDeclSyntax.self) { ... } } • .item ? • .as(StructDeclSyntax.self) ? 16 -
for decl in structDecl.members.members { if let varDecl = decl.decl.as(VariableDeclSyntax.self)
{ ... } } • .members.members ? • decl.decl ? • .as(VariableDeclSyntax.self) ? 17 -
• SwiftSyntaxߏจϨϕϧͷϥΠϒϥϦͳͷͰɺࣗ༝දݱ ೳྗ͕ߴ͍͕ɺͦͷෳࡶͰ͍͠ • C++͚ʹ࡞ͬͨ libSyntax ͱͷϒϦοδͷؔͰ(?)ઃܭ ʹΫη͕͋Δ • ߏจϨϕϧͷϥΠϒϥϦͳͷͰɺܕใͷ໊લղܾͳͲɺҙ
ຯϨϕϧαϙʔτ͞Εͳ͍ • ༻్ʹԠͨ͡ϥΠϒϥϦΛҰͭڬΜͰ͍͍ͨ 19 -
SwiftTypeReader 4 • SwiftSyntaxΛϥοϓͯ͠ɺܕใΛѻ͍͍͢APIͰఏڙ͢ ΔϥΠϒϥϦ • ܕҎ֎ͷใ (ؔͷຊจͳͲ) ѻΘͳ͍ 4
https://github.com/omochi/SwiftTypeReader 20 -
func testSimple() throws { let result = try XCTReadTypes(""" struct
S { var a: Int? } """ ) let s = try XCTUnwrap(result.module.types[safe: 0]?.struct) XCTAssertEqual(s.name, "S") XCTAssertEqual(s.location, Location([.module(name: "main")])) XCTAssertEqual(s.storedProperties.count, 1) let a = try XCTUnwrap(s.storedProperties[safe: 0]) XCTAssertEqual(a.name, "a") let aType = try XCTUnwrap(a.type().struct) XCTAssertEqual(aType.module?.name, "Swift") XCTAssertEqual(aType.name, "Optional") XCTAssertEqual(try aType.genericArguments().count, 1) let aWrappedType = try XCTUnwrap(aType.genericArguments()[safe: 0]?.struct) XCTAssertEqual(aWrappedType.module?.name, "Swift") XCTAssertEqual(aWrappedType.name, "Int") } • .storedProperties 21 -
func testEnum() throws { let result = try XCTReadTypes(""" enum
E { case a case b(Int) case c(x: Int, y: Int) } """ ) let e = try XCTUnwrap(result.module.types[safe: 0]?.enum) do { let c = try XCTUnwrap(e.caseElements[safe: 0]) XCTAssertEqual(c.name, "a") } do { let c = try XCTUnwrap(e.caseElements[safe: 1]) XCTAssertEqual(c.name, "b") let x = try XCTUnwrap(c.associatedValues[safe: 0]) XCTAssertNil(x.name) XCTAssertEqual(try x.type().name, "Int") } do { let c = try XCTUnwrap(e.caseElements[safe: 2]) XCTAssertEqual(c.name, "c") let x = try XCTUnwrap(c.associatedValues[safe: 0]) XCTAssertEqual(x.name, "x") XCTAssertEqual(try x.type().name, "Int") let y = try XCTUnwrap(c.associatedValues[safe: 1]) XCTAssertEqual(y.name, "y") XCTAssertEqual(try y.type().name, "Int") } } • .caseElements • .associatedValues 22 -
func testGenericParameter() throws { let result = try XCTReadTypes(""" struct
S<T> { var a: T } """ ) let s = try XCTUnwrap(result.module.types[safe: 0]?.struct) XCTAssertEqual(s.name, "S") XCTAssertEqual(s.genericParameters.count, 1) let t = try XCTUnwrap(s.genericParameters[safe: 0]) XCTAssertEqual(t.name, "T") XCTAssertEqual(s.storedProperties.count, 1) let a = try XCTUnwrap(s.storedProperties[safe: 0]) XCTAssertEqual(a.name, "a") let at = try XCTUnwrap(a.type().genericParameter) XCTAssertEqual( at.location, Location([ .module(name: "main"), .type(name: "S") ]) ) } • .genericParameter.location 23 -
ར༻ྫ: SE0295Polyfill 5 • SE-0295 (enumͷcodableରԠ) Λίʔυੜ͢ΔϥΠϒϥϦ • Swift5.5 ͕ϦϦʔε͞ΕͨͷͰطʹҾୀ
5 https://github.com/omochi/SE0295Polyfill 24 -
extension Command { enum CodingKeys: Swift.CodingKey { case load case
store } enum LoadCodingKey: Swift.CodingKey { case key } enum StoreCodingKey: Swift.CodingKey { case key case value } } extension Command { public func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) switch self { case .load(key: let key): var nestedContainer = container.nestedContainer(keyedBy: LoadCodingKey.self, forKey: .load) try nestedContainer.encode(key, forKey: .key) case .store(key: let key, value: let value): var nestedContainer = container.nestedContainer(keyedBy: StoreCodingKey.self, forKey: .store) try nestedContainer.encode(key, forKey: .key) try nestedContainer.encode(value, forKey: .value) } } } extension Command { public init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) if container.allKeys.count != 1 { let context = DecodingError.Context( codingPath: container.codingPath, debugDescription: "Invalid number of keys found, expected one." ) throw DecodingError.typeMismatch(Command.self, context) } switch container.allKeys.first.unsafelyUnwrapped { case .load: let nestedContainer = try container.nestedContainer(keyedBy: LoadCodingKey.self, forKey: .load) let key = try nestedContainer.decode(String.self, forKey: .key) self = .load(key: key) case .store: let nestedContainer = try container.nestedContainer(keyedBy: StoreCodingKey.self, forKey: .store) let key = try nestedContainer.decode(String.self, forKey: .key) let value = try nestedContainer.decode(Int.self, forKey: .value) self = .store(key: key, value: value) } } } 26