- You can import enums into a scope with
<using> - You can convert between enums and strings with Lua
- You can have
<comptime>enums - Enums can be used as namespaces, similar to records
You can import enums into a scope
Consider:
local Days = @enum{
Sunday = 0,
Monday,
Tuesday,
Wednesday,
Thursday,
Friday,
Saturday
}
function Days.isworkday(d: Days)
switch d
case Days.Sunday, Days.Saturday then return true
else return false
end
end
check(Days.isworkday(Days.Sunday))This isn't bad at all, but in worse code you can locally drop the Days. prefix:
function Days.isworkday(d: Days) local any_name <using> = Days switch d case Sunday, Saturday then return true else return false end end
You can convert between enums and strings with Lua
Nelua doesn't bake in a string conversion for enums, but you can synthesize such functions as needed:
require 'string'
local M = @record{}
local M.WordForm = @enum{
ru_adj_superlative = 0,
ru_adj_comparative,
ru_verb_participle_passive_present,
ru_verb_participle_passive_past,
ru_base,
-- there are 60 of these
}
function M.WordForm.parse(s: string): M.WordForm
## for _, field in ipairs(M.value.metafields.WordForm.value.fields) do
if s == #[field.name]# then return M.WordForm.#|field.name|# end
## end
assert(false, string.format('invalid wordform: %s', s))
return 0
end
function M.WordForm.show(wf: M.WordForm): string
## for _, field in ipairs(M.value.metafields.WordForm.value.fields) do
if wf == M.WordForm.#|field.name|# then return #[field.name]# end
## end
assert(false, 'invalid M.WordForm')
return ''
end
check(M.WordForm.parse('ru_base') == M.WordForm.ru_base)
check(M.WordForm.ru_adj_superlative:show() == 'ru_adj_superlative')You can have <comptime> enums
Consider:
local Duration = @enum{ s = 1, m, h, d, ms, us }
local function sleepunits(value: number, unit: Duration <comptime>)
## local units = { 1, 60, 3600, 86400, 1/1000, 1/1000000 }
print('faking sleep for: ', value * #[units[unit.value]]#)
end
sleepunits(3, Duration.h)
sleepunits(2, Duration.h)
sleepunits(3, Duration.ms)This compiles to:
void sleep_units_sleepunits_1(double value, nlniltype unit) {
nelua_print_1(((nlstring){(uint8_t*)"faking sleep for: ", 18}), (value * 3600));
}
void sleep_units_sleepunits_2(double value, nlniltype unit) {
nelua_print_1(((nlstring){(uint8_t*)"faking sleep for: ", 18}), (value * 0.001));
}
int nelua_main(int argc, char** argv) {
sleep_units_sleepunits_1(3.0, NELUA_NIL);
sleep_units_sleepunits_1(2.0, NELUA_NIL);
sleep_units_sleepunits_2(3.0, NELUA_NIL);
return 0;
}Enums can be used as namespaces, similar to records
local Days = @enum{
Sunday = 0,
Monday,
Tuesday,
Wednesday,
Thursday,
Friday,
Saturday
}
## Days.value.fields.Sunday.is_weekend = true
## Days.value.fields.Saturday.is_weekend = true
function Days.is_weekday(self: Days)
return self ~= Days.Sunday and self ~= Days.Saturday
end
## for _, day in ipairs({'Sunday', 'Saturday'}) do
check(not Days.#|day|#:is_weekday())
## end
## for i, day in ipairs(Days.value.fields) do
## if not day.is_weekend then
check(Days.#|day.name|#:is_weekday())
## end
## endHere you can see
- metadata added to enum values, visible only to Lua
- a function defined in an enum namespace
- the way to define a 'method' that takes its received by value instead of by pointer
- exhaustive generation of tests, albeit, longer than less clear than just writing the tests manually