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.
Guides
Superior FFI
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 thisimplementation of Logo out.
Modules, without sys.modules
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.
Built-in eventloop with augmented concurrency
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.
Lever's got integrated libuv eventloop that implements its 'sleep' command, which is very much like 'setInterval' in javascript. Except that if you call it without a function, it waits:
sleep(2)
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.
Other Features
- Completely customizable syntax
- Dynamic typing
- RPython implemented runtime
- Lexical scoping
- Operator overloading via multimethods
- GLSL-like vector, matrix and quaternion math
- Growing library support for gamedev, virtual reality, audio and 3D graphics
- Partial Windows, SteamOS support
- Partial OpenGL 4 and Vulkan support
There is more in-depth documentation in the repository, including internal documentation for the runtime.
Performance
Author knows by initial tests, that Lever is slightly slower than Python. There'sperformance.text detailing out how it is intended to achieve better performance out of Lever.
License
Lever is licensed under the MIT license.
Download
Website maintained by Lever community.