Interact with Swift on Pharo
SwiftPlayground-Pharo
Run Swift with the Pharo Swift Playground, interoperate with Pharo, inspect output and Swift ASTs.
- Pharo 7.0 reference platform.
- Requires macOS 10.14.5 (or later) or GNU/Linux (tested with Ubuntu 14.04, 64 bit).
- SeasideSwift should run on Windows with little to no modifications but has not been tested yet. See Running Pharo in Windows Subsystem for Linux (WSL) and Swift for Windows.
Installation
-
Install and setup the Swift tools for your environment:
- macOS: Install the Command Line Tools (macOS 10.14) for Xcode 10.2.1 (or later).
- GNU/Linux: Install Swift from swift.org.
-
In a Playground, evaluate:
Metacello new repository: 'github://brackendev/SwiftPlayground-Pharo'; baseline: 'SwiftPlayground'; onConflict: [ :ex | ex useIncoming ]; onUpgrade: [ :ex | ex useIncoming ]; onDowngrade: [ :ex | ex useLoaded ]; ignoreImage; load.
Usage
Swift Playground
Write, compile, run, and inspect output of Swift code via the Swift Playground (accessible via the Tools menu).
Important contextual menu items:
Do it
– Compile and run the selected Swift codeInspect it
– Compile and run the selected Swift code, inspect itPrint it
– Compile and run the selected Swift code, print it (TODO)
Additionally, the contextual menu item, Inspect AST
, returns the Swift AST for the selected Swift code. For example, print("Hello, World!")
returns:
(import_decl range=[Swift:1:1 - line:1:8] 'Foundation')
(top_level_code_decl range=[Swift:2:1 - line:2:22]
(brace_stmt range=[Swift:2:1 - line:2:22]
(call_expr type='<null>' arg_labels=_:
(unresolved_decl_ref_expr type='<null>' name=print function_ref=unapplied)
(paren_expr type='<null>'
(string_literal_expr type='<null>' encoding=utf8 value="Hello, World!" builtin_initializer=**NULL** initializer=**NULL**)))))
Inline Swift
Outside of the Swift Playground, Swift code can be executed within Pharo code by using the runSwift
string class extension. For example:
API Reference
Swift Output and ASTs
Pharo class extension methods can be used to compile, run, and view the AST of Swift code.
String class extension: runSwift
Returns a string representation of a Swift object from Swift code. Use Swift's print function within the Swift code for output to Pharo. For example:
swiftString := 'The five boxing wizards jump quickly' asLowercase asSwiftString.
('let (lowercased, alphabet) = (Set(', swiftString, '), "abcdefghijklmnopqrstuvwxyz")
print("\(!alphabet.contains { !lowercased.contains($0) })")') runSwift.
"Returns 'true'"
Tip: Simple Swift code does not require Swift's print function. For example:
'Array("ABCDE")' runSwift.
"Returns '["A", "B", "C", "D", "E"]'"
swiftArray := #(1 2 3 4 5) asSwiftArray.
(swiftArray, '.map{$0 * $0}.reduce(0, +)') runSwift.
"Returns '55'"
String class extension: swiftAST
Returns the Swift AST of Swift code.
Pharo Object to Swift String Serialization
Pharo class extension methods can be used as quick helpers to serialize Pharo objects to Swift psuedo-objects (string representations of Swift objects). For example, 'Hello, World!' asSwiftString
returns '"Hello, World!"'
.
In the code below, notice the usage of sentence
, asSwiftString
, and the swiftCode
string concatenation:
sentence := 'The five boxing wizards jump quickly' asLowercase asSwiftString.
swiftCode := ('
// Determine a pangram
let (sentenceSet, alphabet) = (Set(', sentence, '), "abcdefghijklmnopqrstuvwxyz")
print(!alphabet.contains {
!sentenceSet.contains($0)
})
').
swiftCode runSwift.
"Returns 'true'"
The following extension methods have been implemented (with examples). The examples are also availabe via the SPExamples
object.
Array class extension: asSwiftArray
Returns a string representation of a Swift object. Currently only handles one depth of booleans, numbers, and strings.
#(1 'A' 2 true 3 false) asSwiftArray.
"Returns '[1,"A",2,true,3,false]'"
Boolean class extension: asSwiftBoolean
Returns a string representation of a Swift object.
true asSwiftBoolean.
"Returns 'true'"
Dictionary class extension: asSwiftDictionary
Returns a string representation of a Swift object. Currently only handles one depth of booleans, numbers, and strings.
(Dictionary newFrom: {(1 -> 2). ('A' -> 3). (4 -> 'B'). (5 -> true). (false -> 'C'). ('D' -> 'E')}) asSwiftDictionary.
"Returns '[1:2,"A":3,4:"B",5:true,"D":"E",false:"C"]'"
String class extension: asSwiftString
Returns a string representation of a Swift object.
'Hello, World!' asSwiftString.
"Returns '"Hello, World!"'"
Swift Response String to Pharo Object Deserialization
(TODO)
Imports
The Apple Foundation framework is imported into Swift code automatically. To use other Apple frameworks with Swift code, use the Swift import
directive as needed.
Asynchronous Swift Code
To prevent asynchronous Swift code from exiting too early, use the Swift dispatchMain() function to never return and use the Swift exit() function to exit where appropriate.
For example, in the Swift code below, a Swift URLRequest network request session is started and then followed by dispatchMain()
so the program does not prematurely exit. In the session response closure exit(0)
is then called to exit the program.
let sessionConfig = URLSessionConfiguration.default
let session = URLSession(configuration: sessionConfig, delegate: nil, delegateQueue: nil)
var url = URL(string: "https://www.gravatar.com/4f64c9f81bb0d4ee969aaf7b4a5a6f40.json")
var request = URLRequest(url: url!)
request.httpMethod = "GET"
let task = session.dataTask(with: request, completionHandler: { data, response, error in
if let uError = error {
print(uError.localizedDescription) // Returns error string
} else if let uData = data, let string = String(data: uData, encoding: String.Encoding.utf8) {
print(string) // Returns response string
}
exit(0) // Exit after asynchronous work is complete
})
task.resume()
session.finishTasksAndInvalidate() // Start the network request session
dispatchMain() // Prevent premature exit
TODO
- [ ] Swift Playground
Print it
- [ ] Swift Playground syntax highlighting
- [ ] Swift response string to Pharo object deserialization
- [ ] Move documentation to the wiki
- [ ] Move to Spec2