CLI arguments
Lit CLI has arguments, that you pass to it in order to manipulate its behaviour. You can get a list of them via --help
argument:
~ $ lit --help
lit [options] [files]
-o --output [file] Instead of running the file the compiled bytecode will be saved.
-n --native [file] Instead of running the file the compiled code will be embeded into a native runner.
-O[name] Enables given optimization. For the list of aviable optimizations run with -Ohelp
-D[name] Defines given symbol.
-e --eval [string] Runs the given code string.
-p --pass [args] Passes the rest of the arguments to the script.
-i --interactive Starts an interactive shell.
-d --dump Dumps all the bytecode chunks from the given file.
-t --time Measures and prints the compilation timings.
-h --help I wonder, what this option does.
If no code to run is provided, lit will try to run either main.lbc
or main.lit
and, if it fails, defaults to an interactive shell.
-o --output
This argument prevents CLI from executing provided code, instead it will be only compiled and saved to the given path. You can always run the saved bytecode later on:
lit main.lit -o main.lbc
lit main.lbc
.lbc
extension stands for lit bytecode. You can read more about it in the Bytecode section.
-n --native
This argument is similar to --output
, but instead of saving the raw bytecode it downloads lit sourcecode, compiles it with the bytecode embedded into a special runner.
Note: this option is only supported on linux for now.
-O -Oall -Ono-all
This argument controls optimization levels and separate optimizations. You can always get a hint with lit -Ohelp
. Here are all the supported optimization parameters:
Separate optimizations
You can tweak how lits optimizer behaves in great detail, here are the options that you can play around with:
constant-folding | Replaces constants in code with their values. |
literal-folding | Precalculates literal expressions (3 + 4 is replaced with 7). |
unused-var | Removes user-declared all variables, that were not used. |
unreachable-code | Removes code that will never be reached. |
empty-body | Removes loops with empty bodies. |
line-info | Removes line information from chunks to save on space. |
private-names | Removes names of the private locals from modules (they are indexed by id at runtime). |
c-for | Replaces for-in loops with c-style for loops where it can. |
To enable an optimization, for example line-info
, prefix it with just the -O
part:
lit main.lit -Oline-info
And to disable an optimization you need to prefix it with -Ono-
:
lit main.lit -Ono-line-info
Optimization levels
But before you start trying to tweak every single optimization option by hand, consider having a look at built-in optimization levels.
Level 0 | No optimizations (same as -Ono-all) |
Level 1 | Super light optimizations, sepcific to interactive shell. |
Level 2 | (default) Recommended optimization level for the development. |
Level 3 | Medium optimization, recommended for the release. |
Level 4 | (default for bytecode) Extreme optimization, throws out most of the variable/function names, used for bytecode compilation. |
To activate a level, prefix it with -O
:
lit main.lit -O3
-D
This argument defines a symbol as if you've inserted #define
into your code. Let's look at this example:
#ifdef DEBUG
print('Running in debug mode!')
#else
print('Running in release mode!')
#endif
Now if we run it without any additional parameters, we will see the release mode message. But if we run it with the -DDEBUG
:
~ $ lit -DDEBUG main.lit
Running in debug mode!
The code acts with the symbol definition in mind.
-e --eval
This is probably one of the most useful arguments out there, and it is very simple - it just runs the code you pass with it!
~ $ lit -e "print(32 * 2)"
64
-p --pass
This argument stops the parsing of arguments, and everything that is left will be passed to the script in the args
array:
~ $ lit -e "print(args)" --pass hello -e 32
[ "hello", "-e", 32 ]
-i --interactive
Launches an interactive shell, that allows you to input and execute code.
-d --dump
Instead of executing the compiled code lit will dump its contents and stop:
~ $ lit -d main.lit
^^ main ^^
constants:
0 "print"
1 10
2 1
text:
0000 1 GET_GLOBAL c0 ("print") 1
0001 | MOVE 2 c1 (10) 0
0002 | MOVE 3 c2 (1) 0
0003 | RANGE 2 3 2
0004 | CALL 1 2 1
0005 | LOAD_NULL 1 0 0
0006 | RETURN 1 1 0
hex:
0000401F 00404080 004080C0 0100C086 00808064 00000041 00004047
vv main vv
^^ main ^^
constants:
0 "print"
1 10
2 1
text:
print(1 .. 10)
0000 1 GET_GLOBAL c0 ("print") 1
0001 | MOVE 2 c1 (10) 0
0002 | MOVE 3 c2 (1) 0
0003 | RANGE 2 3 2
0004 | CALL 1 2 1
0005 | LOAD_NULL 1 0 0
0006 | RETURN 1 1 0
hex:
0000401F 00404080 004080C0 0100C086 00808064 00000041 00004047
vv main vv
To better understand what this all means you can refer to the Bytecode section.
-t --time
Lit will measure and display the time it takes it to read, preprocess, parse, optimize and emit the code:
~ $ lit main.lit -t
Reading source: 0.059ms
-----------------------
Preprocessing: 0.001ms
Parsing: 0.014ms
Optimization: 0.002ms
Emitting: 0.076ms
Total: 0.167ms
-----------------------
-h --help
Displays a tiny summary of everything said above.