Lever is a general purpose programming language, in the Perl/Python/Ruby group, with built-in support for GUI applications, including OpenGL, and a packaging feature that makes it easy to distribute applications.
It's easy to add support for external 'C' libraries and the interface is relatively fast.
The language itself is extensible and modifiable and, in general, there is an emphasis on practicality.
Using C libraries in your Lever code is so clean that it is optional to write wrappers for them.
sdl = api.library("libSDL2") sdl.Init(sdl.INIT_EVERYTHING) sdl.Quit()
Lever has semi-automatic utilities to parse C files, clean them and translate them into .json -formatted headers that provide you with everything to use the libraries you need.
It also has headers for OpenGL4, although they have been generated directly from Khronos specifications.
blen = ffi.automem(ffi.uint) gl.getObjectParameterivARB(obj, gl.OBJECT_INFO_LOG_LENGTH_ARB, blen) gl.getShaderiv(obj, gl.INFO_LOG_LENGTH, blen) log = ffi.automem(ffi.ubyte, blen.to) gl.getInfoLogARB(obj, blen.to, null, log) print(log.str)
Combine this with rest of the features, and you get so incredibly simple programs that do incredibly complex things. For example, check this implementation of Logo out.
There's no global object in lever that holds all the loaded modules. Instead the loaded modules are kept in module scopes. It is first-class loaded-modules handling! You can stack module scopes over others. There's 15 lines to plugin system or live coding from here:
plugins = ModuleScope(dir ++ "path/to/plugins", %"import".scope) plugins_importer = Import(plugins.local, plugins)
And you can get rid of your scope when you like, to get all your modules to reload.
Async code looks so ugly, were you using callbacks, async/await or promises to do it. Except in Lever. In lever it looks prettier than your sync code.
If you call it with a function, it calls the function after a while.
test = (): print("5 second hello!") sleep(5, test) sleep(1) print("1 second hello")
But you can also call it with...
test = (parent): parent.switch() # switches back print("4 second hello!") dat = greenlet(test) dat.switch(getcurrent()) # goes to run test. # now we have a greenlet that hasn't returned. sleep(4, dat) # that inserted it into an event loop, cool?
That's right, greenlets! This is how any event emitter works in lever. You don't need to worry whether it should be callbacks or greenlets. You can either wait for event or pass a callback and things keep working.
What if you stuck your app to wait for an event, but the event source is removed and the waiting code should release file handle? No problem. The event source schedules 'Discard' -exception thrown to the greenlet, that makes your waiting code to gracefully exit.
There is more in-depth documentation in the repository, including internal documentation for the runtime.
Author knows by initial tests, that Lever is slightly slower than Python. There's performance.text detailing out how it is intended to achieve better performance out of Lever.
Lever is licensed under the MIT license.
Website maintained by Lever community.