Leaf - A scripting language for Elm

I’m proud to annouce Leaf (Orasund/leaf-lang) - A multi paradigm scripting language for Elm. It is designed to be extendable to fit your needs.

Leaf is

  • dynamically typed
  • extendable (by normal Elm functions)
  • based on Lua with a few features taken from Rust
  • context sensitive (similar to Ports in Elm)
  • small (50KB of pure Elm code)

Checkout the interactive documentation :wink: I’ve spent twice as much time on the documentation as on the actual implementation, so I hope you like it.

Future Plans

The next step will be to work on a package to write nice error messages like in spectreconsole/errata or like in the Elm compiler.

My future plans with Leaf are mostly to keep improving the documentation. I have no plans to add features to it - It’s extendable for a reason. I have a few ideas how one could add additional types (like Maybe or Result) but these will properly stay private projects.

26 Likes

I don’t understand the ‘why’ - What problem does this solve?

I guess you ask why scripting and not why leaf. In my case, I use scripting (schelme) in order to provide serializable customization of some calculations in the UIs.

I’d love to see an example of this in the wild if you have anything OSS.

The reason I needed such a language is that I’m building a card-game. In this game, the users should be able to add their own cards. To do so, I need a scripting language.

I needed a language that was very accessible, - scheme and lisp don’t do the job. That’s why I decided to write my own.

2 Likes

This is great work! The docs are nice, and hopefully I’ll find the time to try Leaf with my traffic simulation project, Liikennematto.

I have been thinking about how to implement “game levels” or save games. The idea is to allow someone (at least myself) to easily create tilemaps and place cars to the world.

I have a World record that holds everything that changes over time, like cars, the road network and buildings. I’m currently using plain Elm fixtures to build the Worlds by hand, and those fixtures are used in tests. It’s a bit cumbersome. I would like to choose one of those fixtures or other pre-defined scenarios (which savegames happen to be, too) in Liikennematto by using some kind of menu.

2 Likes

Very cool. One small suggestion for the docs: if you mean for this to be very accessible, I would consider not using ligatures in the doc font to turn -> into an arrow, it could confuse some if they’re not already familiar with the convention.

2 Likes

Nice work! I am trying to use this for a random thing and got stuck on syntax. I feel I tried everything and looked through the source but for the life of me I can not understand how accessing values in objects work. :smiley:

So:

mut a = { helloWorld : null,
  favoriteNumber : 42
};

a.favoriteNumber

Parser error: Expecting End at row:5 col:2

How would I access the value in key favoriteNumber?

Hi there, Leaf does not come with a standard lib, so you have to write the getter yourself:

get : String -> Dict String Value -> Value
get field obj =
    obj
        |> Dict.get field
        |> Maybe.withDefault NullVal


main : Html msg
main =
    let
        context =
            [ get
                |> Leaf.binaryFun (Leaf.typed Leaf.asString)
                    (Leaf.typed Leaf.asObject)
                |> Leaf.field "get"
            ]
                |> Dict.fromList
    in
    Html.text <|
        case Leaf.run context script of
            Ok ( value, _ ) ->
                value |> Leaf.toString

            Err err ->
                "Error:" ++ err

(Ellie)