Super INI is an INI preprocessor, the output produced can be parsed by even the most basic of INI/config parsers, while still allowing a higher level of expression and safety checking.
It was designed with applications that use large INI files in mind, such as games, where INI files are more straight forward to parse and can have a lower memory footprint than other text formats.
; change compiler settings
[] :: internal, setenv
output = out.ini
sorted = True
[Weapons] :: abstract :damage :level
[Eirlithrad] :: inline :Weapons
damage: i32 = 275
level: u8 = 18
[Melltith] :: eval, inline :Weapons
damage: i32 = 355
level := Eirlithrad::level * 2 - 10[Weapons]
Eirlithrad=275 18
Melltith=355 26The Super INI compiler is a single Python file with no library dependencies (Python's built-in sys and collections module are the only required imports)
python3 super_ini.py input_file [output_file]--help | -h: display help and exit--dump: print compiled output
[] :: include :file0 :file1Parse and include other files to the main output.
File paths that do not exist, or cause an IOError while reading will fail with error code E08:
error[E08]: missing input file `file0`
--> items.ini:1 []_: int = 780 ; arbitrarily sized integer
_: i8 = 0b01111111 ; 8bit signed integer
_: i16 = 32767 ; 16bit signed integer
_: i32 = 0xFFFF ; 32bit signed integer
_: i64 = -722 ; 64bit signed integer
_: u8 = 255 ; 8bit unsigned integer
_: float = 3.14159 ; arbitrarily sized floating point number
_: f32 = 1.28e5 ; 32bit floating point number
_: str = hello world ; a string literal
_: bool = False ; True or FalseEnsure the assigned value is of a specific type.
Values that do not match the specified type will fail with error code E07:
[Melltith]
damage: i32 = "355"error[E07]: incorrect type, expected i32
--> items.ini:2 [Melltith][] :: include
:file0
:file1
[Torlunn]
description =
Purchased from Scoia'tael merchant in unmarked camp,
east of Ferry Station in the back of the cave by the
Distellery in SkelligeContinuation lines must be indented to signify they are not another sequence, and should instead be appended to previous line.
Under indented lines will fail with error code E00:
[Torlunn]
description =
Purchased from Scoia'tael merchant in unmarked camp,
east of Ferry Station in the back of the cave by the
Distellery in Skelligeerror[E00]: undefined sequence `Distellery in Skellige`
--> items.ini:5 [Torlunn][constants]
max_damage: i32 = 475
[Harpy]
damage = constants::max_damageReplace a literal with a constant from another scope.
Unresolvable references will print a warning with code W00 or W01 depending on which part of the reference could not be resolved:
[Koviri Cutlass]
damage = constants::min_damagewarning[W01]: could not look up key reference `min_damage`
--> items.ini:2 [Koviri Cutlass][Constants] :: internal
max_level: u8 = 46
[Tir Tochair Blade]
key = Constants::max_level[Tir Tochair Blade]
key=46Any scope marked as internal will not be compiled.
[constants] :: eval
max_u8 = 2**8 - 1[constants]
max_u8=255Any scope marked as eval will have the value of its keys evaluated.
[Weapon] :: internal, abstract :damage :level
[Weeper] :: as :Weapon
damage: i32 = 370
level: u8 = 31A scope that implements another is forced to classify the abstract keys from the scope it implements:
[Weapon] :: internal, abstract :damage :level
[Weeper] :: as :Weapon
damage: i32 = 370
; missing `level` key, this will not compileIf a required key is not classified, the compiler will fail with an error code E06:
error[E06]: must classify key from abstract scope: `level`
--> items.ini:3 [Weeper]This ensures that if the compiled INI file is being used for deserialization, missing keys will be caught early on instead of causing a runtime error.
[Weapons] :: abstract :damage :level
[Disglair] :: inline :Weapons
damage: i32 = 215
level: u8 = 12[Weapons]
Disglair=215 12This is useful in code that uses an INI file to look up function pointers and pass it several arguments. Inlining essentially allows for named parameters in the Super INI file.
Scopes marked as inline will also be automatically marked as internal
Just like as, inline will cause the compiler to fail with the error code E06 if an abstract key is missing from the inline scope.
[] :: internal, setenv
output = out.ini
sorted = TrueItems defined in a scope that is marked as setenv will be used to update the compiler's global environment.
Terminology used in the Super INI compiler (super_ini.py)
or key, value pairs, are defined as a key string followed by an equals sign, followed by it's value. Items are generally placed explicitly inside a scope, otherwise they will be implicitly placed inside the [__global__] scope.
key = value
key := value
key: str = valueWhen a key is assigned a value it is known internally as a classification.
are containers for key, value pairs, and are defined as a character string enclosed in square brackets
[scope]
key = valueInternally a scope defines its key, value pairs.
are used to refer to values placed else where in the document, it is defined as a scope identifier followed by the SCOPE_RESOLUTION_OPERATOR (::) followed by a key identifier. References are resolved during the second stage of parsing, once all scopes are in the look up table.
PI := constants::PIScope objects are stored in the global LUT.
Items defined in a scope are stored in that scope object's local LUT.
# example of how super INI is structured within python
local_lut = OrderedDict()
local_lut['key'] = Value('value', type='str', trace=stack_trace)
global_lut = OrderedDict()
global_lut['scope_id'] = Scope('scope_id', lut=local_lut, trace=stack_trace)are called after all scopes have been parsed into the global LUT. A closure receives a reference to the scope that implements the closure (caller), and can directly modify the scope object's local LUT.
Closure calls are defined in the scope header
; here the `inline` closure will be called and passed the argument `Weapons`
[Eirlithrad] :: inline :Weaponsare essentially keys without a value, they are used to specify the type of a key, and closure arguments.
; `:Weapons` is a symbol
[Eirlithrad] :: inline :Weapons
; `:i32` is a symbol
damage: i32 = 355
; can also be written as
damage :i32 = 355