mirror of
https://github.com/Reuh/anselme.git
synced 2025-10-27 16:49:31 +00:00
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.
78 lines
2.2 KiB
Lua
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
|