1
0
Fork 0
mirror of https://github.com/Reuh/anselme.git synced 2025-10-27 16:49:31 +00:00
anselme/ast/Function.lua
Étienne Reuh Fildadut 56ed6c912b Replace checkpoint system
The previous system needed to store of the scope and full AST to build a Resumable object, which means that if persisted, updating the resumable script will have no effect.
The new system instead uses an anchor token and does not require any information besides the anchor name.
2023-12-27 17:06:35 +01:00

78 lines
2.2 KiB
Lua

-- note: functions only appear in non-evaluated nodes! once evaluated, they always become closures
local ast = require("ast")
local Overloadable = ast.abstract.Overloadable
local Closure, ReturnBoundary
local operator_priority = require("common").operator_priority
local Function
Function = Overloadable {
type = "function",
parameters = nil, -- ParameterTuple
expression = nil,
format_priority = operator_priority["$_"],
exports = nil, -- { [sym] = exp, ... }, exctracted from expression during :prepare
init = function(self, parameters, expression, exports)
self.parameters = parameters
self.expression = ReturnBoundary:new(expression)
self.exports = exports or {}
end,
_format = function(self, ...)
if self.parameters.assignment then
return "$"..self.parameters:format(...).."; "..self.expression:format_right(...)
else
return "$"..self.parameters:format(...).." "..self.expression:format_right(...)
end
end,
traverse = function(self, fn, ...)
fn(self.parameters, ...)
fn(self.expression, ...)
end,
compatible_with_arguments = function(self, state, args)
return args:match_parameter_tuple(state, self.parameters)
end,
format_parameters = function(self, state)
return self.parameters:format(state)
end,
call_compatible = function(self, state, args)
state.scope:push()
args:bind_parameter_tuple(state, self.parameters)
local exp = self.expression:eval(state)
state.scope:pop()
-- reminder: don't do any additionnal processing here as that won't be executed when resuming self.expression
-- instead wrap it in some additional node, like our friend ReturnBoundary
return exp
end,
_eval = function(self, state)
return Closure:new(Function:new(self.parameters:eval(state), self.expression, self.exports), state)
end,
_prepare = function(self, state)
state.scope:push_export() -- recreate scope context that will be created by closure
state.scope:push()
self.parameters:prepare(state)
self.expression:prepare(state)
state.scope:pop()
self.exports = state.scope:capture():list_exported(state)
state.scope:pop()
end,
}
package.loaded[...] = Function
Closure, ReturnBoundary = ast.Closure, ast.ReturnBoundary
return Function