swift-4.0.2-RELEASE
来てた。String
は StringProtocol
だけど Number
は Numeric
なんですね… https://developer.apple.com/documentation/swift/numericStringProtocol
以外の XxxProtocol
って何があります?IteratorProtocol
普通にわすれてたw NSObjectProtocol
なんてあるのかぁ(白目public protocol NSObjectProtocol {
ってなってるのに、実際の動きは public protocol NSObjectProtocol: class {
なんじゃあないのっていうのが各所で浮き出てくる (edited)Iterator
っていう 名前衝突を避けたくてそうなった感があるけどね・・・@objc
つけたらclass
矯正されるのと同じ感じですかね@objc
明示ルール出来たのにNSObjectProtocol
はそうじゃないっていうのもねinherits
、何かの型がprotocolに準拠している場合は conforms
、多分これで問題ないかと…?Int
は型だから protocol
に Conforms To
ですねStatus
を abstract class
で定義できたらなぁとすごい思うstruct StackArray<value Size: Int> { ... }
var a = StackArray<2>() a.0 // ok a.1 // ok a.2 // compile error
(edited)enum Status { case NotReady case Ready } class Something<value T: Status> { /*中身は同じでOK*/ }
(edited)value T: Status
になってるのか。 (edited)Status
が protocol
じゃダメなんだっけ? sealed にできない?- Now you can define a “dependent type”, for example ModuloInteger<P>, where P is the integer value that defines the type. - Like this, you’ll have: —> MI<2>: {0, 1}, where 1 + 1 = 0. —> MI<3>: {0, 1, 2}, where 1 + 1 = 2, and 2 • 2 = 1
Status
が protocol
でもダメってことはないですが、Something<NotReady>.createInstance()
で書かないといけないのがイケてないですねVector<2>
とか Matrix<4, 4>
とかやりたい。reserveCapacity
とか考えなくて済むstruct MultiArray<T, let Dimensions: Int> { // specify the number of dimensions to the array subscript (indices: Int...) -> T { get { require(indices.count == Dimensions) // ... } }
(edited)struct Real { ... } extension Real : ConstructibleFrom<Float> { init(_ value: Float) { ... } } extension Real : ConstructibleFrom<Double> { init(_ value: Double) { ... } }
サンプルも Rust の From trait と似てるenum
でstate
パターン、無理やりRawValue
に振る舞いを実装して見た https://gist.github.com/norio-nomura/65db97c4786851bc368a8d68834fb31b (edited)RawRepresentable
で実装where T: Ready
で書くと問題ないけど、where T == Ready
で書くと Something.createInstance()
の直後でも変換の補完で .shout()
が出るのなんで?(もちろんコンパイルエラーにはなるけど…)$ swift generate.swift
で実行しているだけなんや。%{ let intTypes = [8,16,32,64] }% % for intType in intTypes { % for sign in ["", "U"] { /// Extension that adds a few additional functionalities to ${sign}Int${intType} extension ${sign}Int${intType} { /// Returns a ${sign}Int${intType} with all ones % if sign == "" { public static var allOnes: Int${intType} { return Int${intType}(bitPattern: UInt${intType}.max) } % } else { public static var allOnes: UInt${intType} { return UInt${intType}.max } % } } % } % }
-alpha
とか -beta
つけるのオススメ。end
とか Python じゃないし。-swift-version 3
を渡してるかどうかは #if swift(>=3.2.2)
で判定。 (edited)[omochi@omochi-iMac gysb (master *+=)]$ cat Examples/include.swift.gysb %! include_code("libs/*.swift") % aaa=${aaa()} bbb=${bbb()} [omochi@omochi-iMac gysb (master *+=)]$ swift run gysb Examples/include.swift.gysb aaa=999 bbb=777
%!
と include_code を追加したのでなんとかなるmaster *+=
ってなんやて思ったけどプロンプトだった%! swift_package("Package.swift")
とか定義しておくと SPM の executable として実行するような機能を作ったら対応できそう。%{...}
の中にimportは書けないのか[omochi@omochi-iMac gysb (master=)]$ swift run gysb --compile Examples/include.swift.gysb func write(_ s: String) { print(s, terminator: "") } func aaa() -> Int { return 999 } func bbb() -> Int { return 777 } write("aaa=") write(String(describing: aaa())) write("\n") write("bbb=") write(String(describing: bbb())) write("\n")
.gysb
インプットから.swift
のString
を作れるAPIがあると、swift test
の度に.swift
を生成する事ができる様になります。 (edited)#comment(lib, "GL.h")
ってかいてリンク指定できるみたいな。 (edited)*.c
をパッケージ内に持ってて、SwiftPMにClangモジュールとしてビルドしてもらってます。Run Script Phase
を使えるからCLIでいいけど、SwiftPMはビルドプロセスに入れられないのがネックだね。vapor build
の手前に処理を差し込む方法ないのって問い合わせたらねえって言われた (edited)vapor cloud deploy
するとリモートでチェックアウトして vapor build
が動くんだけどその手前でコードジェネレータ動かしてもらわないと成果物コミットしてないから当然コンパイル通らないPackage.swift
の内容を切り替え、GYSB=1 swift test
でコード生成し、swift test
で生成したコードを利用する方法を思いついた。swift test --filter Generate
とテストするモジュールを制限しても全てをビルドしようとするから、未生成なコードに依存する部分がビルド出来なくてダメだった。// swift-tools-version:4.0 import PackageDescription import Foundation let package: Package if ProcessInfo.processInfo.environment["GYSB"] != nil { package = Package( name: "Generate", dependencies: [ .package(url: "https://github.com/omochi/gysb.git", .branch("master")), ], targets: [ .testTarget(name: "Generate", dependencies: ["GysbKit"], path: "Tests/GenerateTests") ] ) } else { package = Package( name: "Example", products: [ .library(name: "Example", targets: ["Example"]), .library(name: "Generated", targets: ["Generated"]), ], targets: [ .target(name: "Example", dependencies: ["Generated"]), .target(name: "Generated", dependencies: []), .testTarget(name: "ExampleTests", dependencies: ["Example"]), ] ) }
$ tree . ├── Package.resolved ├── Package.swift ├── README.md ├── Sources │ ├── Example │ │ └── BuildPhase.swift │ └── Generated │ └── vector.swift └── Tests ├── ExampleTests │ └── ExampleTests.swift ├── GenerateTests │ └── GenerateVectorTests.swift └── LinuxMain.swift
こんな感じ (edited)Package.swift
でYams
をビルドして、それを.gysb
の中でインポートしようとしてるのだけど、うまくいかないな。Test Case '-[GysbWithYamsTests.GysbWithYamsTests testExample]' started. process execution failure path=[/usr/bin/swift] arg[0]=[/var/folders/kt/2mwy9b_56_7993x190pl_1fh0000gn/T/vector_49IokLMk.swift] arg[1]=[-L] arg[2]=[/Users/norio/github/GysbWithYams/.build/x86_64-apple-macosx10.10/debug] statusCode=[1] stderr= /var/folders/kt/2mwy9b_56_7993x190pl_1fh0000gn/T/vector_49IokLMk.swift:4:9: error: no such module 'Yams' import Yams ^ Test Case '-[GysbWithYamsTests.GysbWithYamsTests testExample]' passed (0.438 seconds).
$ /usr/bin/swift /var/folders/kt/2mwy9b_56_7993x190pl_1fh0000gn/T/vector_49IokLMk.swift
return try execCapture(path: swiftPath, arguments: [path, "-L", "/Users/norio/github/GysbWithYams/.build/x86_64-apple-macosx10.10/debug"])
(edited) -F <value> Add directory to framework search path
-l
も必要だったかはよくわからない-I…
,-L…
,-F…
つけても、YamsのPackage.swift
でライブラリtypeを.static
や.dynamic
にして-lYams
つけてもダメだ。 path=[/usr/bin/swift] arg[0]=[/var/folders/kt/2mwy9b_56_7993x190pl_1fh0000gn/T/vector_NwwoI7hu.swift] arg[1]=[-I] arg[2]=[/Users/norio/github/GysbWithYams/.build/x86_64-apple-macosx10.10/debug] arg[3]=[-F] arg[4]=[/Users/norio/github/GysbWithYams/.build/x86_64-apple-macosx10.10/debug] arg[5]=[-L] arg[6]=[/Users/norio/github/GysbWithYams/.build/x86_64-apple-macosx10.10/debug] arg[7]=[-lYams] statusCode=[1] stderr= /var/folders/kt/2mwy9b_56_7993x190pl_1fh0000gn/T/vector_NwwoI7hu.swift:4:9: error: no such module 'Yams' import Yams
(edited).dynamic
にして、以下のオプションをswift
に渡したらいけた。 return try execCapture(path: swiftPath, arguments: [ "-I", "/Users/norio/github/GysbWithYams/.build/x86_64-apple-macosx10.10/debug", "-L", "/Users/norio/github/GysbWithYams/.build/x86_64-apple-macosx10.10/debug", "-lYams", path, ])
% import Foundation % import Yams % guard let yaml = try Yams.compose(yaml: String(contentsOf: URL(fileURLWithPath: "TestResources/vector/vector.yml"))) else { fatalError() } % let vars = yaml.array().flatMap { $0.string } % for n in 2...4 { struct Vector${n} { % for i in 0..<n { var ${vars[i]}: Float % } } % }
swift run gysb
が通る状態?// swift-tools-version:4.0 import PackageDescription let package = Package( name: "GysbWithYams", dependencies: [ .package(url: "https://github.com/omochi/gysb.git", .branch("master")), .package(url: "https://github.com/jpsim/Yams.git", .branch("master")), ], targets: [ .testTarget( name: "GysbWithYamsTests", dependencies: ["GysbKit", "Yams"]), ] )
class GysbWithYamsTests: XCTestCase { func testExample() { do { let driver = Driver.init(path: "TestResources/vector/vector.swift.gyb") let actual = try driver.render(to: .render) print(actual) } catch { print(error) } } static var allTests = [ ("testExample", testExample), ] }
(edited)libYams.a
かlibYams.dylib
が無いとダメですね。type: .static
でも本当はいけると思うのですが、swiftc
がクラッシュしてしまいダメでしたが。.o
達を直接リンクします。 (edited)swift test -v
とかしてみるとコンパイラの起動オプションを見られます。type: .dynamic
にするとswift build --static-swift-stdlib
とかしてもそれらのライブラリはダイナミックリンクされるみたいだから、今後は使い勝手が悪くなると避けられるんじゃないかな? (edited).dynamic
なライブラリを同じパッケージ内のexecutableターゲットから使う場合は問題ないのですが、依存しているパッケージから使った場合、それらはフルパスでリンクされてしまい、ポータブルなexecutableではなくなってしまいます。 $ otool -L ./.build/x86_64-apple-macosx10.10/debug/gysbClient ./.build/x86_64-apple-macosx10.10/debug/gysbClient: /System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation (compatibility version 150.0.0, current version 1445.12.0) /Users/norio/github/GysbWithYams/.build/x86_64-apple-macosx10.10/debug/libGysbKit.dylib (compatibility version 0.0.0, current version 0.0.0) /usr/lib/libobjc.A.dylib (compatibility version 1.0.0, current version 228.0.0) /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1252.0.0)
(edited)prefix operator > prefix func >(value: String) { print(value) } let intTypes = [8, 16, 32, 64] for intType in intTypes { for sign in ["", "U"] { >""" /// Extension that adds a few additional functionalities to \(sign)Int\(intType) extension \(sign)Int\(intType) { /// Returns a \(sign)Int\(intType) with all ones """ if sign == "" { >""" public static var allOnes:Int\(intType) { return Int\(intType)(bitPattern: UInt\(intType).max) } """ } else { >""" public static var allOnes:UInt\(intType) { return UInt\(intType).max } """ } >""" } """ } }
(edited)%{ intTypes = [8,16,32,64] }% % for intType in intTypes: % for sign in ['','U']: /// Extension that adds a few additional functionalities to ${sign}Int${intType} extension ${sign}Int${intType} { /// Returns a ${sign}Int${intType} with all ones %if sign == '': public static var allOnes:Int${intType} { return Int${intType}(bitPattern: UInt${intType}.max) } %else: public static var allOnes:UInt${intType} { return UInt${intType}.max } %end } %end %end
ManifestoGenerator
とか出来てる!w https://github.com/omochi/gysb/blob/master/Sources/GysbSwiftConfig/ManifestoGenerator.swift%! swift_config("gysb_swift_config.json") %{ import Foundation import Yams let yamlPath = URL.init(fileURLWithPath: "data.yml") let yamlStr = try! String(contentsOf: yamlPath, encoding: .utf8) let yaml = try Yams.compose(yaml: yamlStr)! let fields: [String] = yaml.array().map { $0.string! } }% struct Data { % for field in fields { var ${field}: String % } }
{ "packageDependencies": [ { "url": "https://github.com/jpsim/Yams.git", "requirement": { "identifier": "0.5.0", "type": "exact" } }, ], "targetDependencies": [ { "name": "Yams" } ] }
%! swift_config()
の指定は1ファイルだけがする。%! swift_config("gysb_swift_config.json")
gysb.json
はどこにあるんだ?ってなっちゃうんですよね%! import("https://github.com/jpsim/Yams.git")
とかするとswift_config()
に渡すjson相当のものが自動で生成される様にするとか。%! import("https://github.com/jpsim/Yams.git") とかするとswift_config()に渡すjson相当のものが自動で生成される様にするとか。
これの問題点は、パッケージ名からターゲット名がわからないことimport
使えるんだっけ?libSwiftPM
が気軽に使えれば「リポジトリからPackage.swiftを解釈して〜」とか簡単に出来そうなのに… https://github.com/apple/swift-package-manager/blob/master/Package.swift#L19%! swift_config("gysb_swift_config.json")
brew install gysb
できる様になると良いね。%! swift_config
以外に %! include_code
っていうマクロ命令もあってswift_config
書く場合と同じでgysb Sources/Foo/*.gysb Sources/Bar/*.gysb
gysb src/
で再帰的にgysb さがすの??gysb -r src/
とか明示的にした方が良さそうな気も。gysb.josn
も全部適用で良さそう。 (edited)gysb Sources/Foo/*.gysb Sources/Bar/*.gysb
みたいなことがしたいんじゃないの?swift_config
を導入せずに gysb.json を置く方式にするのであれば、一つのディレクトリの中で設定を切り替えることはできないという意味です。Sources/Foo/gysb.json Sources/Bar/gysb.json
Souces/gysb.json
と Sources/Foo/gysb.json
をマージ、 Souces/gysb.json
と Sources/Bar/gysb.json
して 2 回実行 Souces/gysb.json Sources/Foo/gysb.json Sources/Bar/gysb.json
Foo/gysb.json
等に記述することを想定)Foo
, Bar
以下のすべての gysb ファイルに対して 1 回で実行 Souces/gysb.json
%! swift_conifig
はやめてディレクトリ遡り探索の gysb.json にしようと思います%!
という複雑性を持ち込まなくてよさそう。% func foo() { FooFooFoo % } % for _ in 0..<3 { % foo() % }
FooFooFoo FooFooFoo FooFooFoo
func taxRate() -> Float { return 1.08 }
%{ func taxRate() -> Float { return 1.08 } }
metalib.swift.gysb
とかになる。Sources/foo/a.swift.gysb // こいつが それを読みに行く Sources/foo/metalib/metalib.swift.gysb
$ gysb --source-dir Sources
を実行すると・・・Sources/foo/metalib/metalib.swift.gysb
が 処理対象になって、 自分を自分の上部にincludeしようとして、無限ループして壊れる。func taxRate()
みたいな、ちょっとしたやつ。%!
的な構文は避けられなさそう。%!
から逃げられないですね%! include("path/to/file")
の行をそのファイルの中身で展開するだけ。{% include footer.html %}
{% include {{ page.my_variable }} %}
% for i in 0..<10 { %! include("file\(i).gysbi") % }
%!
のマクロ言語はテンプレート処理系の前段にあるとしていますinclude
を関数として実装できないかな?write
するgysbi
ファイルに対して gysb
を実行して得られた文字列を挿入すれば。%!
も排除できる。brew
のバイナリ配布、sourcery
がSwiftPMでビルドしたものを使ってる。 https://github.com/Homebrew/homebrew-core/blob/master/Formula/sourcery.rbbottles do ... end
にバイナリの置き場所書けば対応で、省略すればインストール先でビルド必要な認識でした。 (edited)[swift-evolution] update on forum Ted Kremenek via swift-evolution The decision to move to a forum was announced a while ago, and it hasn’t appeared yet. I think we will be making the move soon and I wanted to provide some reasons why it was delayed and what comes next. ... My hope is that process will start in December.
yaml ならいけるかもしれませんが、 gysb の実行に YAML パーサが必要になって依存が生まれてしまいそう・・・
一応書いておくと、YamsはCodable
をサポートしたYAMLパーサです。Yams自身には外部ライブラリ依存はなくて、利用実績としてはSwiftLintが.swiftlint.yml
のパースに使っています。$(brew --repository homebrew/core) git remote add omochi https://github.com/omochi/homebrew-core.git
したら、次のコマンドでformula作成: brew create https://github.com/omochi/gysb/archive/0.8.6.tar.gz
して、出来たgysb.rb
のdepends_on
, def install
, test do
を https://github.com/Homebrew/homebrew-core/blob/master/Formula/sourcery.rb 辺りを参考に設定して、 brew install --verbose --debug gysb
でインストールテストして、 cd $(brew --repo homebrew/core) git checkout -b gysb git add Formula/gysb.rb git commit git push https://github.com/omochi/homebrew-core/ gysb
してPR、って感じかな?Makefile
とか不要。class Gysb < Formula desc "Generate your swifty boilerplate" homepage "" url "https://github.com/omochi/gysb/archive/0.8.6.tar.gz" sha256 "139fd7225442c74e943b32716158a3ea5bd438241372a3cf913fd5313793248e" depends_on :xcode => ["9.0", :build] def install system "swift", "build", "--disable-sandbox", "-c", "release", "-Xswiftc", "-static-stdlib" bin.install ".build/x86_64-apple-macosx10.10/release/gysb" end test do # `test do` will create, run in and delete a temporary directory. # # This test will fail and we won't accept that! For Homebrew/homebrew-core # this will need to be a test that verifies the functionality of the # software. Run the test with `brew test gysb`. Options passed # to `brew install` such as `--HEAD` also need to be provided to `brew test`. # # The installed folder is not in the path, so use the entire path to any # executables being tested: `system "#{bin}/program", "do", "something"`. system "true" end end
test do
にsystem "true"
とか書いたけど、そこは真面目に書き換えないといけない。sourcery --version
で返すかどうか、かな。+struct ParameterizedStruct<T> { + mutating func takesFunctionWithGenericReturnType(_ f: (Int) -> T) {} +}
これがArrayに相当してるのかgit tag --contains cf9a09e18dba7a7fe0506381589fbf0f4bb99a98
で何も出ない。swift-DEVELOPMENT-SNAPSHOT-2017-11-21-a
出てる。func processPo<X: ConstPo>(po: X, process: (X.Element) -> Void) {
これでokconst
の場合と違って、型ごと CostoPo
を満たさないといけないの微妙そう。struct
じゃダメ? Swift の class
は二級市民だと思ってる。View
に対応した ViewModel を struct
で作って渡すとか?View
自体を操作する関数だとダメだけど。const
にしたいくらいだから View
から情報をとりたいだけに見える)enum Hoge { case fuga(Int) case piyo(Int) var count: Int { switch self { case .fuga(let count), .piyo(let count): // <- ここ return count } } }
let count
だからいける?protocol ProtocolA {} enum Hoge { case fuga(ProtocolA) case piyo(ProtocolA) var count: ProtocolA { switch self { case .fuga(let count), .piyo(let count): return count } } }
Playground execution failed: error: MyPlayground.playground:5:24: error: matching a protocol value in multiple patterns is not yet supported; use separate cases instead case .fuga(let count), .piyo(let count): ^
protocol ProtocolA {} enum Hoge<T: ProtocolA> { case fuga(T) case piyo(T) var count: T { switch self { case .fuga(let count), .piyo(let count): return count } } }
let a: Int? = 42 if case let a? = a { print(a) }
int *a = ...; *a = 42;
って書くのと似てるよね。 (edited)*a
が int
型というのと、 a?
が Int
型というのが。a?
は Int 型ではないですよねa?
は Optional<Int> だからこそ a
の部分だけが Int
a?
は Int?
で a
が Int
か。*a
が int
で a
は int *
。protocol ProtocolA {} enum Hoge<T: ProtocolA> { case fuga(T) case piyo(T) func value<T>() -> T { switch self { case .fuga(let value), .piyo(let value): return value } } }
error: MyPlayground.playground:6:20: error: cannot convert return expression of type 'T' to return type 'T' return value ^~~~~ as! T
typealias Tuple = (Int, String) enum Hoge { case fuga(Int) case piyo(Tuple) var value: Int { switch self { case .fuga(let value), .piyo((let value, _)): return value } } }
case let [first, second, third]:
みたいな。error: MyPlayground.playground:6:20: error: cannot convert return expression of type 'T' to return type 'T' return value ^~~~~ as! T
これは真っ当なエラーでは…Token
と tok
と Tok
が出てきて、Tok
の定義が全然見つからないと思ったら Token
型のフィールド名が Tok
だった・・・tok
は enumsnake_case_
ですね、他のC++プロダクトをそんなに読んでないのでわからないですがCMake -G Xcode
Tok
でジャンプできたぞw--release-debuginfo --xcode
でビルドしたらclang: error: no such file or directory: '/Users/omochi/work/swift-source/build/Xcode-RelWithDebInfoAssert/cmark-macosx-x86_64/src/Debug/libcmark.a'
と出ていて (edited)/Users/omochi/work/swift-source/build/Xcode-RelWithDebInfoAssert/cmark-macosx-x86_64/src/RelWithDebInfo/libcmark.a
--release-debuginfo
なのに cmark は --debug
で参照しちゃっててうまくいってないみたいなんですけど--xcode
は作業用、 ninja でビルド するのが良いのか? release-debuginfo があまりメンテナンスされていないので、 release にするのが良いのか? とか、どうなんでしょう