the toplevel
- You can run code on it
- You can have code run only if it's being run directly, and isn't getting
require()'d - You can have a main() if you really want it
- You can leave it to nelua CLI args to decide the entry point
- You can return to the OS from it
- You can close over toplevel variables
- You can allocate large objects in static memory
- You can get its filename
You can run code on it
The normal entrypoint of your program is the first line of the .nelua file that you passed to the compiler. Or the string passed to nelua's -i/--eval flag if that was provided. If all you do define variables and functions and then call main(), that's fine. If you define nothing but do all your work somehow, that's fine too, that could be a good script. If you define functions and never call any of them, that's fine too - that could be a good library.
Here's /bin/tac entirely on the toplevel:
require 'sequence' require 'io' local input: sequence(string) for line in io.lines() do input:push(line) end for i=1, #input do print(input:pop()) end
You can have code run only if it's being run directly, and isn't getting require()'d
This is a complete program that either prints 'hello world' as an executable, or returns a module as a library:
require 'string'
local M = @record{}
function M.greeting(who: string)
return string.format('Hello, %s!', who)
end
## if M.scope.parent.is_root then
local g <close> = M.greeting('world')
print(g)
## else
return M
## endYou can have a main() if you really want it
This is a complete Nelua program that prints 'hello' last. This is probably a bad idea. (confirmed: it breaks the 'arg' module without more work than shown here.)
print 'this still happens' local function hello() <entrypoint, cexport 'main'> print 'hello' end print 'this still happens before hello()'
You can leave it to nelua CLI args to decide the entry point
Here's a program that's any of /bin/true or /bin/false or /bin/hello depending on how it's compiled.
require 'C.stdlib'
local M = @record{}
function M.fail() C.exit(1) end
function M.succeed() C.exit(0) end
function M.hello() print 'hello' end
return M
Like so:
$ nelua -o false -i 'local m = require("entry") m.fail()'; ./false || echo 'it worked'
it worked
$ nelua -o true -i 'local m = require("entry") m.succeed()'; ./true && echo 'it worked'
it worked
$ nelua -i 'local m = require("entry") m.hello()'
hello
You can return to the OS from it
This is /bin/false in Nelua:
return 1
usage:
$ nelua -o false false.nelua $ ./false; echo $? 1
Generated C:
int nelua_main(int argc, char** argv) {
return 1;
}
int main(int argc, char** argv) {
return nelua_main(argc, argv);
}A practical reason to do this is that you've written some quick code without functions and you need to escape from a nested loop to end execution. You could do like this AoC entry and goto a label, but a return will work too.
You can close over toplevel variables
Paul Graham's accumulator generator: "The problem: Write a function foo that takes a number n and returns a function that takes a number i, and returns n incremented by i."
Without minding the details, here it is:
## function foo(name, n)
local n: number = #[n]#
local function #|name|#(i: number): number
n = n + i
return n
end
## end
## foo('from10', 10)
## foo('from100', 100)
assert(100 == from100(0))
assert( 60 == from10(50))
assert(110 == from100(10))
assert( 50 == from10(-10))
assert(210 == from100(100))You can allocate large objects in static memory
The cells array from the list3.nelua example works because local variables at the toplevel are generated as static variables, with memory initialized to zero by the OS when the process is created. If that line appeared in a function body the program would crash at runtime from a stack overflow:
local Cons = @record{ car: integer, cdr: *Cons }
## local function comma(s) s = string.gsub(s, ',', '') return tonumber(s) end
local function main()
local cells: [#[comma '100,000,000']#]Cons
print(#cells)
end
main()When run:
$ nelua toolarge.nelua
Segmentation fault
$ nelua -d toolarge.nelua
...
Program received signal SIGSEGV, Segmentation fault.
0x00005555555551e2 in toolarge_main () at /home/lua/.cache/nelua/toolarge.c:107
107 toolarge_Cons_arr100000000 cells = (toolarge_Cons_arr100000000){0};
You can get its filename
## print(require'nelua.utils.fs'.scriptname()) local a = 1 ## print(inspect(a.node:location()))