Skip to content

lua-atmos/atmos

Repository files navigation

Atmos

Tests

Structured Event-Driven Concurrency for Lua

[ v0.5 | v0.4 | v0.3 | v0.2.1 | v0.1 ]

This is the unstable main branch. Please, switch to stable v0.5.

[ About | Hello World! | Install & Run | Environments | Documentation | Resources ]

About

Atmos is a programming library for Lua that reconciles Structured Concurrency, Event-Driven Programming, and Functional Streams, extending classical structured programming with three main functionalities:

  • Structured Deterministic Concurrency:
    • A task primitive with deterministic scheduling provides predictable behavior and safe abortion.
    • Structured primitives compose concurrent tasks with lexical scope (e.g., watching, every, par_or).
    • A tasks container primitive holds attached tasks and control their lifecycle.
  • Event Signaling Mechanisms:
    • An await primitive suspends a task and wait for events.
    • An emit primitive signals events and awake awaiting tasks.
  • Functional Streams (à la ReactiveX):
    • Functional combinators for lazy (infinite) lists.
    • Interoperability with tasks & events: tasks and events as streams, and streams as events.
    • Safe finalization of stateful (task-based) streams.

Atmos is inspired by synchronous programming languages like Céu and Esterel.

Hello World!

During 5 seconds, displays Hello World! every second:

require "atmos.env.clock"

call(function ()
    watching(clock{s=5}, function ()
        every(clock{s=1}, function ()
            print("Hello World!")
        end)
    end)
end)

We first import the builtin clock environment, which provides timers to applications. The call primitive receives a function with the application logic in Atmos, as follows:

  • The watching command will execute its inner function during 5 seconds.
  • The every loop will execute its inner function every second.
  • Once the watching terminates, the call returns back to Lua.

In Atmos, the lifetimes and schedules of tasks are determined by lexical structure. Tasks that would awake "simultaneously" instead do so in order of appearance in the source code. This enables reasoning about programs more statically based on the structure of the source code. Tasks that abort also abort their inner taks, which have a "last chance" to execute if applicable. Applying this to the above example:

  • On the first, second, third, and fourth second, every awakes and prints "Hello World!"
  • On the fifth second, watching and every are both scheduled to awake.
  • The every awakes before the enclosing watching, printing "Hello World!" for the fifth (and last) time.
  • Therefore, call returns after five seconds having printed "Hello World!" five times.

See the relevant section in the guide for other, more complex examples.

Now, the same specification, but using streams:

require "atmos.env.clock"
local S = require "atmos.streams"

call(function ()
    local s1 = S.from(clock{s=1})
        :tap(function()
            print("Hello World!")
        end)
    local s2 = S.from(clock{s=5}):take(1)
    S.paror(s1,s2):to() -- note that s1 comes before s2!
end)
  • s1 is a periodic 1-second stream that prints the message on every occurrence, through the tap combinator.
  • s2 is a periodic 5-seconds stream that terminates after its first occurrence, because of take(1).
  • S.paror merges the streams, terminating when either of them terminate.
  • to is a sink that starts and exhausts the full stream pipeline.

Install & Run

sudo luarocks --lua-version=5.4 install atmos 0.5
lua5.4 <lua-path>/atmos/env/clock/exs/hello.lua

You may also clone the repository and copy part of the source tree, as follows, into your Lua path (e.g., /usr/local/share/lua/5.4):

atmos
├── env/
│   ├── clock/
│   │   ├── exs/
│   │   │   ├── hello.lua
│   │   │   └── hello-rx.lua
│   │   └── init.lua
│   ├── iup/
│   │   ├── exs/
│   │   │   └── button-counter.lua
│   │   └── init.lua
│   ├── pico/
│   │   ├── exs/
│   │   │   └── click-drag-cancel.lua
│   │   └── init.lua
│   ├── sdl/
│   │   ├── exs/
│   │   │   ├── click-drag-cancel.lua
│   │   │   └── DejaVuSans.ttf
│   │   └── init.lua
│   └── socket/
│       ├── exs/
│       │   └── cli-srv.lua
│       └── init.lua
├── init.lua
├── run.lua
├── streams.lua
└── util.lua

Atmos depends on f-streams.

Environments

An environment is an external component that bridges input events from the real world into an Atmos application.

The standard distribution of Atmos provides the following environments:

  • atmos.env.clock: A simple pure-Lua environment that uses os.clock to issue timer events.
  • atmos.env.socket: An environment that relies on luasocket to provide network communication.
  • atmos.env.sdl: An environment that relies on lua-sdl2 to provide window, mouse, key, and timer events.
    • sudo luarocks --lua-version=5.4 install lua-sdl2 2.0
  • atmos.env.pico: An environment that relies on pico-sdl-lua as a simpler alternative do SDL.
    • sudo luarocks --lua-version=5.4 install pico-sdl 0.2
  • atmos.env.iup: An environment that relies on IUP (iup-lua) to provide graphical user interfaces (GUIs).

Documentation

Resources

About

Structured Event-Driven Concurrency for Lua

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Contributors 2

  •  
  •  

Languages