Print elm-syntax declarations as swift code.
To try it out, you can
run this script.
import Elm.Parser
import ElmSyntaxToSwift
"""module Sample exposing (..)
plus2 : Int -> Int
plus2 n =
n + ([ 2 ] |> List.sum)
"""
|> Elm.Parser.parseToFile
|> Result.mapError (\_ -> "failed to parse elm source code")
|> Result.map
(\syntaxModule ->
[ syntaxModule ]
|> ElmSyntaxToSwift.modules
|> .declarations
|> ElmSyntaxToSwift.swiftDeclarationsToModuleString
)
-->
Ok """import Foundation
...
public enum Elm {
..some default declarations..
@Sendable public static func Sample_plus2(_ n: Double) -> Double {
Basics_add(n, List_sum(Array_toList([ 2.0 ])))
}
}
"""- not supported are
- ports that use non-json values like
port sendMessage : String -> Cmd msg, glsl elm/file,elm/http,elm/browser,elm-explorations/markdown,elm-explorations/webgl,elm-explorations/benchmarkTask,Process,Platform.Task,Platform.ProcessId,Platform.Router,Platform.sendToApp,Platform.sendToSelf,Random.generate,Time.now,Time.every,Time.here,Time.getZoneName,Bytes.getHostEndianness,Math.Matrix4(due to swift's standard library not exposing many simd types and operations available in apple's SDK)- extensible record types outside of module-level value/function declarations. For example, these declarations might not work:
Allowed is only record extension in module-level value/functions, annotated or not:
-- in variant value type Named rec = Named { rec | name : String } -- in let type, annotated or not let getName : { r | name : name } -> name
In the non-allowed cases listed above, we assume that you intended to use a regular record type with only the extension fields which can lead to swift compile errors if you actually pass in additional fields.userId : { u | name : String, server : Domain } -> String
- ports that use non-json values like
- dependencies cannot internally use the same module names as the transpiled project
- the resulting code might not be readable or even conventionally formatted and comments are not preserved
- web search is abysmal; literally the worst part of the language. Even querying excluding
-app -swiftui -ios -apple -xcode -taylor -ai -popular -ArgumentParseretc, prepare for a lot of shallowness, irrelevance, pain and disappointment. Swift's source code itself is also riddled with indirections etc so... best of luck :)
Please report any issues you notice <3
- it runs decently fast natively (and semi-officially as wasm)
- it's a kind-of superset of elm which makes transpiling easier
An example can be found in example-hello-world/.
In your elm project, add a file Sources/main.swift that uses Elm.swift:
print(Elm.YourModule_yourFunction("yourInput"))where Elm.YourModule_yourFunction(firstArgument)(secondArgument) is the transpiled elm function Your.Module.yourFunction firstArgument secondArgument. (If the value/function contains extensible records, search for Elm.YourModule_yourFunction__ to see the different specialized options)
You will find these types:
- elm
Bool(TrueorFalse) → swiftBool(trueorfalse),String→String,Array Float→Array<Double>,Set Float->Set<Double>,Dict Float String→Map<Double, String>,Never→Never - elm
Floats,Ints andnumber-variable typed values will be of typeDouble - elm
Chars will be of typeUnicodeScalar - elm unit
()will be of typeElm.Unitand can be constructed and matched with.Unit - elm tuples like
( Float, String )will be of typeElm.Tuple<Double, String>and can be constructed and matched with.Tuple(_, _)..firstand.secondaccess also works - elm triples like
( Float, Float, String )will be of typeElm.Triple<Double, Double, String>and can be constructed and matched with.Triple(_, _, _)..first,.secondand.thirdaccess also works - elm records like
{ y : Float, x : Float }will be of typeElm.Generated_x_y<Double, Double>with the fields sorted and can be constructed and matched withElm.Generated_x_y.Record(x: _, y: _).record.xaccess also works - a transpiled elm app does not run itself.
An elm main
Platform.workerprogram type will literally just consist of fieldsInit,UpdateandSubscriptionswhere subscriptions/commands are returned as a list ofElm.PlatformSub_SubSingle/Elm.PlatformCmd_CmdSinglewith possible elm subscriptions/commands in a choice type. It's then your responsibility as "the platform" to perform effects, create events and manage the state. For an example see example-worker-blocking/ & example-worker-async/
Compile the resulting swift to an executable:
swiftc Sources/main.swift Sources/Elm.swiftThe built executable can now be found at main; append -o your-path to set a different output path; append -O to enable optimizations like tail-call elimination.
When in a project that has a Package.swift, you can also use
swift buildIf something unexpected happened, please report an issue.