Download raw

[[
This is a concept for defining Wesnoth Formula Language functions that have a Lua implementation, rather than a C++ implementation. The specification is as follows:

- Each function must return two values - first, the actual value to be returned by the function, and second, a string describing the type of the value. It may be possible to deduce the second return value in many cases, but at least for numbers it's required.
- When compiling a Lua function to WFL, the implementation will examine the function's parameter names. Any trailing parameters whose name end in '_opt' will be treated as optional; the WFL function's minimum parameters will be equal to the number of preceding parameters, and the WFL function's maximum parameters will be equal to the total number of parameters, except, if the Lua function is declared as variadic, in which case the WFL function accepts any number of parameters.
- The WFL function's name is, unsurprisingly, the key to which it is assigned in the function table.

The values passed to a WFL function are in fact not actual values but instead callable userdata, similar to that returned by wesnoth.compile_formula. You can pass a table of variables that will be visible when evaluating that parameter. Unlike the callable returned by wesnoth.compile_formula, passing a function table would not be supported.

An optional parameter that did not get passed in the WFL will be set to nil, rather than a callable that returns nil. (A callable returning nil would of course be possible if the formula itself evaluated to null.)
]]

function no_args()
	return 'Hello world!', 'string'
end

function one_arg(n)
	return n() + 1, 'int'
end

function one_or_two_args(n1, n2_opt)
	if n2_opt then
		return n1() + n2_opt(), 'int'
	else
		return n1() * 2, 'int'
	end
end

function at_least_two_args(a, b, ...)
	local initial = a() .. ' ' .. b()
	for i, v in ipairs(table.pack(...)) do
		initial = initial .. ' ' .. v()
	end
	return initial, 'string'
end

function filter(tbl, filt)
	local result = {}
	for i, v in ipairs(tbl()) do
		table.insert(result, filt(v))
	end
	return result, 'list'
end

local fcn_table = wesnoth.compile_formula_functions{
	world = no_args,
	increment = one_arg,
	sum_or_double = one_or_two_args,
	words = at_least_two_args
}

-- Possibly allow compiling in additional functions afterwards
fcn_table.my_filter = filter

-- Evaluates to the string 'Hello world!'
wesnoth.eval_formula("world()", fcn_table)
-- Evaluates to 6
wesnoth.eval_formula("increment(5)", fcn_table)
-- Evaluates to 7
wesnoth.eval_formula("sum_or_double(3,4)", fcn_table)
-- Evaluates to 8
wesnoth.eval_formula("sum_or_double(4)", fcn_table)
-- Evaluates to the string 'one two three four five'
wesnoth.eval_formula("words('one', 'two', 'three', 'four', 'five')", fcn_table)
-- Evaluates to the list [2.0, 5.6, 7.8]
wesnoth.eval_formula("my_filter([1,2.0,3,'four',5.6,6,7.8], type(self) == 'decimal')", fcn_table)