├── package ├── example.tcl ├── test.tcl ├── impork.tcl ├── README.md └── scaffolder.tcl ├── Package.swift ├── Sources ├── stopwatch.swift ├── impork-test.swift └── main.swift ├── Makefile └── README.md /package/example.tcl: -------------------------------------------------------------------------------- 1 | # 2 | # Apply the scaffolder to itself to test its output 3 | # 4 | source scaffolder.tcl 5 | 6 | foreach proc [::swift::enumerate_procs ::swift] { 7 | puts [::swift::gen $proc] 8 | } 9 | 10 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:3.1 2 | 3 | import PackageDescription 4 | 5 | let package = Package( 6 | name: "SwiftTclDemo", 7 | dependencies: [ 8 | .Package(url: "https://github.com/flightaware/swift-tcl.git", Version(1,0,0)) 9 | ] 10 | ) 11 | 12 | -------------------------------------------------------------------------------- /package/test.tcl: -------------------------------------------------------------------------------- 1 | # 2 | # Test code for swift-tcl scaffold generator 3 | # 4 | if [file exists scaffolder.tcl] { 5 | source scaffolder.tcl 6 | proc hint {args} { 7 | uplevel 1 ::swift::hint {*}$args 8 | } 9 | } else { 10 | proc hint {args} {} 11 | } 12 | 13 | source impork.tcl 14 | 15 | puts [::swift::gen impork] 16 | 17 | -------------------------------------------------------------------------------- /package/impork.tcl: -------------------------------------------------------------------------------- 1 | 2 | proc impork {file {first 1} {step 1}} { 3 | if [catch {open $file} status] { 4 | return {} 5 | } 6 | set fp $status 7 | set contents [read $fp] 8 | close $fp 9 | set result {} 10 | set ln $first 11 | foreach line [split $contents "\n"] { 12 | lappend result $ln $line 13 | incr ln $step 14 | } 15 | return $result 16 | } 17 | -------------------------------------------------------------------------------- /Sources/stopwatch.swift: -------------------------------------------------------------------------------- 1 | // 2 | // stopwatch.swift 3 | // tcl-swift-bridge 4 | // 5 | // Created by Peter da Silva on 9/16/16. 6 | // Copyright © 2016 FlightAware. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | class stopwatch { 12 | var start: TimeInterval 13 | 14 | init() { 15 | start = ProcessInfo.processInfo.systemUptime 16 | } 17 | 18 | func reset() { 19 | start = ProcessInfo.processInfo.systemUptime 20 | } 21 | 22 | func mark() -> TimeInterval { 23 | return ProcessInfo.processInfo.systemUptime - start 24 | } 25 | } 26 | 27 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | BUILD=./.build 2 | 3 | UNAME_S := $(shell uname -s) 4 | ifeq ($(UNAME_S),Linux) 5 | TCLVERSION=8.6 6 | CCFLAGS += -D LINUX 7 | TCLLIBPATH=/usr/lib 8 | TCLINCPATH=/usr/include 9 | EXTRA_SWIFTLINK= 10 | TARGET=$(BUILD) 11 | endif 12 | 13 | ifeq ($(UNAME_S),Darwin) 14 | TCLVERSION=8.6.6_2 15 | BREWROOT=/usr/local/Cellar 16 | CCFLAGS += -D OSX 17 | TCLLIBPATH=$(BREWROOT)/tcl-tk/$(TCLVERSION)/lib 18 | TCLINCPATH=$(BREWROOT)/tcl-tk/$(TCLVERSION)/include 19 | EXTRA_SWIFTLINK=-Xlinker -L/usr/local/lib 20 | TARGET=SwiftTclDemo.xcodeproj 21 | endif 22 | 23 | default: $(TARGET) 24 | 25 | build: $(BUILD) 26 | 27 | $(BUILD): Package.swift Makefile 28 | swift build $(EXTRA_SWIFTLINK) -Xlinker -L$(TCLLIBPATH) -Xlinker -ltcl8.6 -Xlinker -ltclstub8.6 -Xlinker -lz -Xcc -I$(TCLINCPATH) 29 | 30 | SwiftTclDemo.xcodeproj: Package.swift Makefile build 31 | @echo Generating Xcode project 32 | swift package -Xlinker -L/usr/local/lib -Xlinker -L$(TCLLIBPATH) -Xlinker -ltcl8.6 -Xlinker -ltclstub8.6 generate-xcodeproj 33 | @echo "NOTE: You will need to manually set the working directory for the SwiftTclDemo scheme to the root directory of this tree." 34 | @echo "Thanks Apple" 35 | 36 | clean: 37 | rm -rf Package.pins .build SwiftTclDemo.xcodeproj 38 | 39 | test: build 40 | .build/debug/SwiftTclDemo 41 | -------------------------------------------------------------------------------- /Sources/impork-test.swift: -------------------------------------------------------------------------------- 1 | // 2 | // impork-test.swift 3 | // tcl-swift-bridge 4 | // 5 | // Created by Peter da Silva on 5/25/16. 6 | // Copyright © 2016 FlightAware. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import Tcl8_6 11 | import SwiftTcl 12 | 13 | func import_file(_ Interp: TclInterp, file: String) throws { 14 | try Interp.rawEval(list: ["source", file]) 15 | } 16 | 17 | func impork(_ Interp: TclInterp) { 18 | // let file: String = "../../../../../../../../git/swift-tcl/package/impork.tcl" // *cries* 19 | let file: String = "./package/impork.tcl" // *cries* 20 | do { 21 | try import_file(Interp, file: file) 22 | 23 | let array = try Interp.newArray("imporked", string: tcl_impork(Interp, file: file)) 24 | for (num, line) in array { 25 | print("\(num)\t\(try line.get() as String)") 26 | } 27 | } catch { 28 | print(error) 29 | } 30 | } 31 | 32 | // tcl_impork 33 | // Wrapper for impork 34 | func tcl_impork (_ springboardInterp: TclInterp, file: String, first: Int = 1, step: Int = 1) throws -> String { 35 | let vec = springboardInterp.newObject() 36 | try vec.lappend("impork") 37 | try vec.lappend(file) 38 | try vec.lappend(first) 39 | try vec.lappend(step) 40 | Tcl_EvalObjEx(springboardInterp.interp, vec.get(), 0) 41 | return try springboardInterp.getResult() 42 | } 43 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # swift-tcl-demo 2 | Swift executable combining Tcl and Swift 3 | 4 | ### Building and Installing 5 | This program uses several Swift modules as supporting libraries. 6 | These need to be compiled and linked into shared libraries. 7 | Then, the libraries need to be installed into platform specific locations on the clang compilers linker path. 8 | 9 | #### C helpers in libtclrefcount8.6.a 10 | This only installs a static library. The Tcl bindings are really compiled by the modules using the library. 11 | ``` 12 | git clone swift-tcl8.6 13 | make install 14 | ``` 15 | 16 | #### Swift module SwiftTcl libSwiftTcl.so 17 | This will install libSwiftTcl.so. If your platform is not supported, then 18 | copy the libSwiftTcl.so to the required directory. Run ldconfig on Linux machines. 19 | ``` 20 | git clone swift-tcl 21 | make install 22 | ``` 23 | 24 | #### Swift application SwiftTclDemo 25 | This will run the demo program as a test. 26 | ``` 27 | git clone swift-tcl-demo 28 | make test 29 | ``` 30 | 31 | #### All-in-one download and builds 32 | Download all the of repositories 33 | ``` 34 | git clone https://github.com/flightaware/swift-tcl8.6.git 35 | git clone https://github.com/flightaware/swift-tcl.git 36 | git clone https://github.com/flightaware/swift-tcl-demo.git 37 | git clone https://github.com/flightaware/swift-tcl-extension-demo.git 38 | ``` 39 | Build/Install or Build/Test 40 | ``` 41 | make -C swift-tcl8.6 install 42 | make -C swift-tcl install 43 | make -C swift-tcl-demo test 44 | make -C swift-tcl-extension-demo test 45 | ``` 46 | -------------------------------------------------------------------------------- /package/README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | In the packages directory is scaffolder.tcl. It has code to marshall all the procs (swift::enumerate_procs). swift::gen generates a Swift function definition for the proc by examining its arguments and default values. 4 | 5 | For a given proc name, swift::gen attempts to infer the data types of the arguments by examining their defaults and emits a Swift function declaration that will invoke the Tcl springboard so that the Tcl proc is a native function in Swift. 6 | 7 | It can recognize Int, Double, Bool and String. 8 | 9 | There are a few problems, though… 10 | 11 | * Tcl developers tend to use 0 for default values for booleans so we guess Int instead of Bool. 12 | * If a function argument doesn’t take a default value then we just say it’s String. 13 | * We can pretty much see if the proc returns something but we only guess that it’s a String. 14 | 15 | Consequently there is a hinting system. Right now you can say “swift::hint photos_display_hot_rating starWidth Int -> String” 16 | 17 | What it takes as an argument is the proc name and then key-value pairs for the overrides for any proc arguments. The special string “->” defines the return type. 18 | 19 | I think these hints ultimately belong in comments in the source code. 20 | 21 | I have been toying with that possibly not every proc needs to be directly accessible from Swift (but maybe it would be best if it did?). I am also toying with the idea that you might bite the bullet and include a full Swift declaration for the proc inside the comments. 22 | 23 | ```tcl 24 | proc flightaware_photos_displayWidget {compare sort {limit 6} {context default} {style default} {photos_period 0} {dryrun 0}} {...} 25 | ``` 26 | 27 | 28 | ``` 29 | % swift::gen flightaware_photos_displayWidget 30 | func flightaware_photos_displayWidget (compare: String, sort: String, limit: Int = 6, context: String = "default", style: String = "default", photos_period: Int = 0, dryrun: Int = 0 -> String) { 31 | return tcl_springboard(springboardInterp, "flightaware_photos_displayWidget", string_to_tclobjp(compare), string_to_tclobjp(sort), Tcl_NewLongObj(limit), string_to_tclobjp(context), string_to_tclobjp(style), Tcl_NewLongObj(photos_period), Tcl_NewLongObj(dryrun)) 32 | } 33 | ``` 34 | 35 | In the above example *dryrun* should have been a Bool, consequently we tell the hinter... ``` % swift::hint flightaware_photos_displayWidget dryrun Bool ``` to produce 36 | 37 | ```tcl 38 | func flightaware_photos_displayWidget (compare: String, sort: String, limit: Int = 6, context: String = "default", style: String = "default", photos_period: Int = 0, dryrun: Bool = 0 -> String) { 39 | return tcl_springboard(springboardInterp, "flightaware_photos_displayWidget", string_to_tclobjp(compare), string_to_tclobjp(sort), Tcl_NewLongObj(limit), string_to_tclobjp(context), string_to_tclobjp(style), Tcl_NewLongObj(photos_period), Tcl_NewBooleanObj(dryrun ? 1 : 0)) 40 | } 41 | ``` 42 | 43 | A tricky issue is going to be passing Swift objects around in Tcl. I think it will be possible to accept objects possibly as the AnyObject type and get the object type as a string from Swift. Definitely there is a way to get the unsafeAddressOf something so an instance of an object that in Swift may not have any kind of name can have a name in Tcl consisting of the object type concatenated with the address of the object as a string, a lot like Swig does for bringing C and C++ stuff to Tcl in an automated way. 44 | -------------------------------------------------------------------------------- /package/scaffolder.tcl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | namespace eval ::swift { 6 | variable hints 7 | 8 | # hint 9 | # 10 | # swift::hint photos_display_hot_rating starWidth Int -> String 11 | proc hint {proc args} { 12 | variable hints 13 | 14 | set hints($proc) $args 15 | } 16 | 17 | # 18 | # guess_default_type - given a string try to suss out what 19 | # data type it is. first see if it is a strict int, then 20 | # see if it is a strict double, then see if it is a 21 | # string boolean. If it wasn't one of those then say it is a string. 22 | # 23 | proc guess_default_type {defaultValue} { 24 | if {[string is int -strict $defaultValue]} { 25 | return Int 26 | } 27 | 28 | if {[string is double -strict $defaultValue]} { 29 | return Double 30 | } 31 | 32 | if {[string is boolean -strict $defaultValue]} { 33 | return Bool 34 | } 35 | 36 | 37 | return String 38 | } 39 | 40 | # 41 | # does_proc_return_something - meatball check to see if a 42 | # tcl proc returns a value. 43 | # 44 | proc does_proc_return_something {proc} { 45 | set body [info body $proc] 46 | 47 | return [regexp {return } $body] 48 | } 49 | 50 | # 51 | # gen - generate interface functions 52 | # 53 | proc gen {proc} { 54 | variable hints 55 | 56 | set args [info args $proc] 57 | 58 | if {[info exists hints($proc)]} { 59 | array set myHints $hints($proc) 60 | } 61 | 62 | set swift_name tcl::$proc 63 | regsub -all "::*" $swift_name "_" swift_name 64 | set string "\n// $swift_name\n// Wrapper for $proc\nfunc $swift_name (springboardInterp: TclInterp" 65 | 66 | puts stderr $args 67 | foreach arg $args { 68 | append string ", " 69 | 70 | if {![info default $proc $arg default]} { 71 | unset -nocomplain default 72 | } 73 | 74 | # if there's a hint for the type, use that, 75 | # else if there's a default value try to 76 | # sniff the type out of that else say 77 | # it's a String 78 | if {[info exists myHints($arg)]} { 79 | set type $myHints($arg) 80 | } elseif {[info exists default]} { 81 | set type [guess_default_type $default] 82 | } else { 83 | set type String 84 | } 85 | set myTypes($arg) $type 86 | 87 | append string "$arg: $type" 88 | 89 | if {[info exists default]} { 90 | if {$type == "String"} { 91 | append string " = \"$default\"" 92 | } else { 93 | append string " = $default" 94 | } 95 | } 96 | } 97 | 98 | append string ") throws" 99 | 100 | if {[info exists myHints(->)]} { 101 | append string " -> $myHints(->)" 102 | set return_type "$myHints(->)" 103 | } else { 104 | if {[does_proc_return_something $proc]} { 105 | append string " -> String" 106 | set return_type "String" 107 | } 108 | } 109 | 110 | append string " {\n" 111 | 112 | set body {} 113 | lappend body "let vec = springboardInterp.newObject()" 114 | lappend body "try vec.lappend(\"$proc\")" 115 | 116 | foreach arg $args { 117 | lappend body "try vec.lappend($arg)" 118 | } 119 | 120 | lappend body "Tcl_EvalObjEx(springboardInterp.interp, vec.get(), 0)" 121 | if [info exists return_type] { 122 | lappend body "return try springboardInterp.getResult()" 123 | } 124 | append string " [join $body "\n "]\n" 125 | append string "}" 126 | 127 | 128 | 129 | return $string 130 | } 131 | 132 | # 133 | # enumerate_procs - recursively enumerate all procs within a namespace and 134 | # all of its descendant namespaces (defaulting to the top-level namespace), 135 | # returning them as a list 136 | # 137 | proc enumerate_procs {{ns ::}} { 138 | set list [info procs ${ns}::*] 139 | 140 | foreach childNamespace [namespace children $ns] { 141 | lappend list {*}[enumerate_procs $childNamespace] 142 | } 143 | 144 | return $list 145 | } 146 | 147 | } 148 | 149 | 150 | -------------------------------------------------------------------------------- /Sources/main.swift: -------------------------------------------------------------------------------- 1 | // 2 | // main.swift 3 | // tcl-swift-play 4 | // 5 | // Created by Karl Lehenbauer on 4/6/16. 6 | // Copyright © 2016 FlightAware. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import Tcl8_6 11 | import SwiftTcl 12 | 13 | print("Hello, World!") 14 | print("Starting tests") 15 | 16 | let interp = TclInterp() 17 | 18 | if let result: String = try? interp.eval(code: "puts {Hey stinky}; return hijinks") { 19 | print("interpreter returned '\(result)'") 20 | } else { 21 | print("interpreter failed") 22 | } 23 | 24 | print(interp.result) 25 | 26 | if let result: Int = try? interp.eval(code: "expr 1 + 4") { 27 | print("interpreter returned '\(result)'") 28 | } else { 29 | print("interpreter failed") 30 | } 31 | 32 | var xo = interp.newObject(5) 33 | let xy = interp.newObject("hi mom") 34 | print(try xy.get() as String) 35 | xy.set("hi dad") 36 | print(try xy.get() as String) 37 | let xz = interp.newObject(5.5) 38 | if let xz2: Int = try? xz.get() { 39 | print(xz2) 40 | } 41 | let x5 = interp.newObject(5) 42 | try print(x5.get() as Double) 43 | 44 | var stooges = interp.newObject("Larry Curly Moe") 45 | for stooge in stooges { 46 | if let name = stooge.stringValue { 47 | print(name) 48 | } 49 | } 50 | 51 | var brothers = interp.newObject(["Groucho", "Harpo", "Chico"]) 52 | try brothers.lappend("Karl") 53 | if let julius:String = brothers[0] { 54 | print("Julius is \(julius)") 55 | } 56 | 57 | // List eval test 58 | try interp.rawEval(list: ["set", "a", "{illegal {string"]) 59 | try interp.rawEval(code: "puts [list a = $a]") 60 | 61 | func foo (interp: TclInterp, objv: [TclObj]) -> String { 62 | print("foo baby foo baby foo baby foo") 63 | return "" 64 | } 65 | 66 | func avg (interp: TclInterp, objv: [TclObj]) -> Double { 67 | var sum = 0.0 68 | var num = 0 69 | for obj in objv[1...objv.count-1] { 70 | guard let val: Double = try? obj.get() else {continue} 71 | sum += val 72 | num += 1 73 | } 74 | return(sum / Double(num)) 75 | } 76 | 77 | interp.createCommand(named: "foo", using: foo) 78 | 79 | do { 80 | try interp.rawEval(code: "foo") 81 | } 82 | 83 | interp.createCommand(named: "avg", using: avg) 84 | do { 85 | try interp.rawEval(code: "puts \"the average is [avg 1 2 3 4 5 6 7 8 9 10 77]\"") 86 | } 87 | 88 | try interp.rawEval(code: "puts \"the average is [avg 1 2 3 4 5 foo 7 8 9 10 77]\"") 89 | 90 | let EARTH_RADIUS_MILES = 3963.0 91 | 92 | func fa_degrees_radians (_ degrees: Double) -> Double { 93 | return (degrees * Double.pi / 180); 94 | } 95 | 96 | func fa_latlongs_to_distance (_ lat1: Double, lon1: Double, lat2: Double, lon2:Double) -> Double { 97 | let dLat = fa_degrees_radians (lat2 - lat1) 98 | let dLon = fa_degrees_radians (lon2 - lon1) 99 | 100 | 101 | let lat1 = fa_degrees_radians (lat1) 102 | let lat2 = fa_degrees_radians (lat2) 103 | 104 | let sin2 = sin (dLat / 2) * sin (dLat / 2) 105 | let a = sin2 + sin (dLon / 2) * sin (dLon / 2) * cos (lat1) * cos (lat2) 106 | let c = 2 * atan2 (sqrt (a), sqrt (1 - a)) 107 | var distance = EARTH_RADIUS_MILES * c 108 | 109 | // if result was not a number 110 | if (distance.isNaN) { 111 | distance = 0 112 | } 113 | 114 | return distance 115 | } 116 | 117 | func fa_latlongs_to_distance_cmd (interp: TclInterp, objv: [TclObj]) throws -> Double { 118 | if (objv.count != 5) { 119 | throw TclError.wrongNumArgs(nLeadingArguments: 0, message: "lat0 lon0 lat1 lon1") 120 | } 121 | 122 | let lat1: Double = try objv[1].getAsArg(named: "lat1") 123 | let lon1: Double = try objv[2].getAsArg(named: "lon1") 124 | let lat2: Double = try objv[3].getAsArg(named: "lat2") 125 | let lon2: Double = try objv[4].getAsArg(named: "lon2") 126 | 127 | let distance = fa_latlongs_to_distance(lat1, lon1: lon1, lat2: lat2, lon2: lon2) 128 | return distance 129 | } 130 | 131 | interp.createCommand(named: "fa_latlongs_to_distance", using: fa_latlongs_to_distance_cmd) 132 | 133 | 134 | do { 135 | try interp.rawEval(code: "puts \"distance from KIAH to KSEA is [fa_latlongs_to_distance 29.9844444 -95.3414444 47.4498889 -122.3117778]\"") 136 | } 137 | 138 | print("importing a swift array") 139 | var ints: [Int] = [0, 1, 2, 3, 4, 5, 6, 7, 9, 8, 10] 140 | var intListObj = interp.newObject(ints) 141 | print(ints) 142 | print(try intListObj.get() as String) 143 | print("") 144 | 145 | let sarray = ["zero","one","two","three","four"] 146 | print("Testing ranges and indexes on \(sarray)") 147 | let xarray = interp.newObject(sarray) 148 | print(" xarray.lrange(1...3) = \(String(describing: try xarray.lrange(1...3) as [String]))") 149 | print(" xarray.lrange(-3 ... -1) = \(String(describing: try xarray.lrange(-3 ... -1) as [String]))") 150 | print(" xarray.lindex(1) = \(try xarray.lindex(1) as String)") 151 | print(" xarray.lindex(-1) = \(try xarray.lindex(-1) as String)") 152 | print("Testing subscripts") 153 | print(" xarray[0] = \(xarray[0] as String?)") 154 | print(" xarray[0...2] = \(xarray[0...2] as [String]?)") 155 | print(" xarray as String = \(try xarray.get() as String)") 156 | try xarray.linsert(5, list: ["five"]) 157 | print(" after insert at end: xarray as String = \(try xarray.get() as String)") 158 | try xarray.lreplace(0...2, list: ["0", "uno", "II"]) 159 | print(" after replace at beginning: xarray as String = \(try xarray.get() as String)") 160 | xarray[0...2] = ["ZERO", "ONE", "TWO"] 161 | xarray[3] = "(3)" 162 | print(" after subscript assignment: xarray as String = \(try xarray.get() as String)") 163 | xarray[4...4] = ["4", "four", "IV", "[d]"] 164 | print(" after subscript assignment changing length: xarray as String = \(try xarray.get() as String)") 165 | xarray[5...7] = [] as [String] 166 | print(" after subscript assignment deleting elements: xarray as String = \(try xarray.get() as String)") 167 | xarray[0] = false 168 | xarray[1...4] = [1, 2, 3, 4] 169 | xarray[5] = 5.0 170 | print(" after subscript assignment of typed values: xarray as String = \(try xarray.get() as String)") 171 | print("\nTesting generator") 172 | var list = "" 173 | var sum = 0.0 174 | var count = 0 175 | for obj in xarray { 176 | if let v: Double = try? obj.get() { 177 | if list == "" { 178 | list = "{" + String(v) 179 | } else { 180 | list = list + ", " + String(v) 181 | } 182 | sum += v 183 | count += 1 184 | } 185 | } 186 | list += "}" 187 | print("sum of \(list) is \(sum), average is \(sum / Double(count))") 188 | 189 | print("Testing variable access") 190 | try interp.rawEval(code: "set fred 1"); 191 | if let value: String = interp.get(variable: "fred") { 192 | print(" Value of 'fred' is \(value)"); 193 | } 194 | if let value: String = interp.get(variable: "barney") { 195 | print(" Value of 'barney' is \(value)"); 196 | } else { 197 | print(" There is no 'barney'"); 198 | } 199 | 200 | let testdict = ["name": "Nick", "age": "32", "role": "hustler"] 201 | print("\nTesting array type on \(testdict)") 202 | if let character = try? interp.newArray("character", dict: testdict) { 203 | print("character[\"name\"] as String = \(character["name"] as String?)") 204 | print("character.names() = \(try character.names())") 205 | print("character.get() = \(try character.get() as [String: String])") 206 | 207 | print("\nModifying character") 208 | character["name"] = "Nick Wilde" 209 | character["animal"] = "fox" 210 | character["role"] = "cop" 211 | character["movie"] = "Zootopia" 212 | print("character[\"name\"] as String = \(character["name"] as String?)") 213 | print("character.names() = \(try character.names())") 214 | print("character.get() = \(try character.get() as [String: String])") 215 | 216 | print("\nsubst test") 217 | print(try interp.subst("character(name) = $character(name)")) 218 | 219 | print("\ngenerator test") 220 | for (key, value) in character { 221 | try print("character[\"\(key)\"] = \(value.get() as String)") 222 | } 223 | } else { 224 | print("Could not initialize array from dictionary.") 225 | } 226 | 227 | print("\ndigging variables out of the Tcl interpreter") 228 | var autoPath: String = try! interp.get(variable: "auto_path") 229 | print("auto_path is '\(autoPath)'") 230 | 231 | let tclVersion: Double = try! interp.get(variable: "tcl_version") 232 | print("Tcl version is \(tclVersion)") 233 | print("") 234 | 235 | print("sticking something extra into the tcl_platform array") 236 | try! interp.set(variable: "tcl_platform", element: "swift", value: "enabled") 237 | 238 | do {try interp.rawEval(code: "array get tcl_platform")} 239 | var dict: [String:String] = try! interp.resultObj.get() 240 | print(dict) 241 | var version = dict["osVersion"]! 242 | print("Your OS is \(dict["os"]!), running version \(version)") 243 | 244 | var machine: String = interp.get(variable: "tcl_platform", element: "machine")! 245 | var byteOrder: String = interp.get(variable: "tcl_platform", element: "byteOrder")! 246 | print("Your machine is \(machine) and your byte order is \(byteOrder)") 247 | print("") 248 | 249 | print("intentionally calling a swift extension with a bad argument") 250 | let _ = try? interp.rawEval(code: "puts \"distance from KIAH to KSEA is [fa_latlongs_to_distance 29.9844444 -95.3414444 crash -122.3117778]\"") 251 | let _ = try? interp.rawEval(code: "puts \"distance from KIAH to KSEA is [fa_latlongs_to_distance 29.9844444 -95.3414444]\"") 252 | 253 | // Comparing speed of operations. 254 | var a: [String] = [] 255 | for i in 1...100000 { 256 | a += [String(i)] 257 | } 258 | 259 | let timer = stopwatch() 260 | var i = 0 261 | var s: String = "" 262 | for e in a { 263 | s = e 264 | i += 1 265 | } 266 | print("Took \(timer.mark())s final \(i)\(s)") 267 | 268 | timer.reset() 269 | a.forEach { 270 | s = $0 271 | i += 1 272 | } 273 | print("Took \(timer.mark())s final \(i)\(s)") 274 | 275 | timer.reset() 276 | for e in a { 277 | s = e 278 | i += 1 279 | } 280 | print("Took \(timer.mark())s final \(i)\(s)") 281 | 282 | 283 | // Testing generated Tcl code 284 | print("") 285 | print("Testing generated Swift wrapper") 286 | impork(interp) 287 | --------------------------------------------------------------------------------