1
0
Fork 0
mirror of https://github.com/Reuh/anselme.git synced 2025-10-27 08:39:30 +00:00

[api] allow adding tags when running/evaluating

This commit is contained in:
Étienne Fildadut 2024-11-11 10:23:21 +01:00
parent ed7fe34853
commit 876135401c
3 changed files with 39 additions and 26 deletions

View file

@ -1,5 +1,6 @@
local expression_to_ast = require("anselme.parser.expression.to_ast") local expression_to_ast = require("anselme.parser.expression.to_ast")
local utf8 = utf8 or require("lua-utf8")
local ast = require("anselme.ast") local ast = require("anselme.ast")
local PartialScope, Block, Call, Identifier = ast.PartialScope, ast.Block, ast.Call, ast.Identifier local PartialScope, Block, Call, Identifier = ast.PartialScope, ast.Block, ast.Call, ast.Identifier

View file

@ -7,11 +7,11 @@ local tag_manager = require("anselme.state.tag_manager")
local event_manager = require("anselme.state.event_manager") local event_manager = require("anselme.state.event_manager")
local translation_manager = require("anselme.state.translation_manager") local translation_manager = require("anselme.state.translation_manager")
local persistent_manager = require("anselme.state.persistent_manager") local persistent_manager = require("anselme.state.persistent_manager")
local uuid = require("anselme.common").uuid
local parser = require("anselme.parser") local parser = require("anselme.parser")
local binser = require("anselme.lib.binser") local binser = require("anselme.lib.binser")
local assert0 = require("anselme.common").assert0 local common = require("anselme.common")
local operator_priority = require("anselme.common").operator_priority local uuid, assert0, operator_priority = common.uuid, common.assert0, common.operator_priority
local to_anselme = require("anselme.common.to_anselme")
local anselme local anselme
local Identifier, Return, Node local Identifier, Return, Node
@ -178,12 +178,13 @@ State = class {
--- Load a script in this branch. It will become the active script. --- Load a script in this branch. It will become the active script.
-- --
-- `code` is the code string or AST to run. If `code` is a string, `source` is the source name string to show in errors (optional). -- `code` is the code string or AST to run. If `code` is a string, `source` is the source name string to show in errors (optional).
-- `tags` is an optional Lua table; its content will be added to the tags for the duration of the script.
-- --
-- Note that this will only load the script; execution will only start by using the `:step` method. Will error if a script is already active in this State. -- Note that this will only load the script; execution will only start by using the `:step` method. Will error if a script is already active in this State.
run = function(self, code, source) run = function(self, code, source, tags)
assert(not self:active(), "a script is already active") assert(not self:active(), "a script is already active")
self._coroutine = coroutine.create(function() self._coroutine = coroutine.create(function()
local r = assert0(self:eval_local(code, source)) local r = assert0(self:eval_local(code, source, tags))
event_manager:complete_flush(self) event_manager:complete_flush(self)
if Return:is(r) then r = r.expression end if Return:is(r) then r = r.expression end
return "return", r return "return", r
@ -191,11 +192,11 @@ State = class {
end, end,
--- Same as `:run`, but read the code from a file. --- Same as `:run`, but read the code from a file.
-- `source` will be set as the file path. -- `source` will be set as the file path.
run_file = function(self, path) run_file = function(self, path, tags)
local f = assert(io.open(path, "r")) local f = assert(io.open(path, "r"))
local block = parser(f:read("a"), path) local block = parser(f:read("a"), path)
f:close() f:close()
return self:run(block) return self:run(block, nil, tags)
end, end,
--- When a script is active, will resume running it until the next event. --- When a script is active, will resume running it until the next event.
-- --
@ -218,16 +219,17 @@ State = class {
-- --
-- Will error if no script is active. -- Will error if no script is active.
-- --
-- If `code` is given, the script will not be disabled but instead will be immediately replaced with this new script. -- `code`, `source` and `tags` are all optional and have the same behaviour as in `:run`.
-- If they are given, the script will not be disabled but instead will be immediately replaced with this new script.
-- The new script will then be started on the next `:step` and will preserve the current scope. This can be used to trigger an exit function or similar in the active script. -- The new script will then be started on the next `:step` and will preserve the current scope. This can be used to trigger an exit function or similar in the active script.
-- --
-- If this is called from within a running script, this will raise an `interrupt` event in order to stop the current script execution. -- If this is called from within a running script, this will raise an `interrupt` event in order to stop the current script execution.
interrupt = function(self, code, source) interrupt = function(self, code, source, tags)
assert(self:active(), "trying to interrupt but no script is currently active") assert(self:active(), "trying to interrupt but no script is currently active")
local called_from_script = self:state() == "running" local called_from_script = self:state() == "running"
if code then if code then
self._coroutine = coroutine.create(function() self._coroutine = coroutine.create(function()
local r = assert0(self:eval_local(code, source)) local r = assert0(self:eval_local(code, source, tags))
event_manager:complete_flush(self) event_manager:complete_flush(self)
self.scope:reset() -- scope stack is probably messed up after the switch self.scope:reset() -- scope stack is probably messed up after the switch
if Return:is(r) then r = r.expression end if Return:is(r) then r = r.expression end
@ -244,19 +246,24 @@ State = class {
-- --
-- This can be called from outside a running script, but an error will be triggered the expression raise any event other than return. -- This can be called from outside a running script, but an error will be triggered the expression raise any event other than return.
-- --
-- `code` is the code string or AST to run. If `code` is a string, `source` is the source name string to show in errors (optional).
-- `tags` is an optional Lua table; its content will be added to the tags for the duration of the expression.
--
-- * returns AST in case of success. Run `:to_lua(state)` on it to convert to a Lua value. -- * returns AST in case of success. Run `:to_lua(state)` on it to convert to a Lua value.
-- * returns `nil, error message` in case of error. -- * returns `nil, error message` in case of error.
eval = function(self, code, source) eval = function(self, code, source, tags)
self.scope:push_global() self.scope:push_global()
local r, e = self:eval_local(code, source) local r, e = self:eval_local(code, source, tags)
self.scope:pop() self.scope:pop()
return r, e return r, e
end, end,
--- Same as `:eval`, but evaluate the expression in the current scope. --- Same as `:eval`, but evaluate the expression in the current scope.
eval_local = function(self, code, source) eval_local = function(self, code, source, tags)
if type(code) == "string" then code = parser(code, source) end if type(code) == "string" then code = parser(code, source) end
local stack_size = self.scope:size() local stack_size = self.scope:size()
if tags then tag_manager:push(self, to_anselme(tags)) end
local s, e = pcall(code.eval, code, self) local s, e = pcall(code.eval, code, self)
if tags then tag_manager:pop(self) end
if not s then if not s then
self.scope:reset(stack_size) self.scope:reset(stack_size)
return nil, e return nil, e

View file

@ -249,22 +249,23 @@ Returns `"inactive"` if no script is loaded.
_defined at line 171 of [anselme/state/State.lua](../anselme/state/State.lua):_ `state = function(self)` _defined at line 171 of [anselme/state/State.lua](../anselme/state/State.lua):_ `state = function(self)`
### :run (code, source) ### :run (code, source, tags)
Load a script in this branch. It will become the active script. Load a script in this branch. It will become the active script.
`code` is the code string or AST to run. If `code` is a string, `source` is the source name string to show in errors (optional). `code` is the code string or AST to run. If `code` is a string, `source` is the source name string to show in errors (optional).
`tags` is an optional Lua table; its content will be added to the tags for the duration of the script.
Note that this will only load the script; execution will only start by using the `:step` method. Will error if a script is already active in this State. Note that this will only load the script; execution will only start by using the `:step` method. Will error if a script is already active in this State.
_defined at line 183 of [anselme/state/State.lua](../anselme/state/State.lua):_ `run = function(self, code, source)` _defined at line 184 of [anselme/state/State.lua](../anselme/state/State.lua):_ `run = function(self, code, source, tags)`
### :run_file (path) ### :run_file (path, tags)
Same as `:run`, but read the code from a file. Same as `:run`, but read the code from a file.
`source` will be set as the file path. `source` will be set as the file path.
_defined at line 194 of [anselme/state/State.lua](../anselme/state/State.lua):_ `run_file = function(self, path)` _defined at line 195 of [anselme/state/State.lua](../anselme/state/State.lua):_ `run_file = function(self, path, tags)`
### :step () ### :step ()
@ -274,37 +275,41 @@ Will error if no script is active.
Returns `event type string, event data`. Returns `event type string, event data`.
_defined at line 205 of [anselme/state/State.lua](../anselme/state/State.lua):_ `step = function(self)` _defined at line 206 of [anselme/state/State.lua](../anselme/state/State.lua):_ `step = function(self)`
### :interrupt (code, source) ### :interrupt (code, source, tags)
Stops the currently active script. Stops the currently active script.
Will error if no script is active. Will error if no script is active.
If `code` is given, the script will not be disabled but instead will be immediately replaced with this new script. `code`, `source` and `tags` are all optional and have the same behaviour as in `:run`.
If they are given, the script will not be disabled but instead will be immediately replaced with this new script.
The new script will then be started on the next `:step` and will preserve the current scope. This can be used to trigger an exit function or similar in the active script. The new script will then be started on the next `:step` and will preserve the current scope. This can be used to trigger an exit function or similar in the active script.
If this is called from within a running script, this will raise an `interrupt` event in order to stop the current script execution. If this is called from within a running script, this will raise an `interrupt` event in order to stop the current script execution.
_defined at line 225 of [anselme/state/State.lua](../anselme/state/State.lua):_ `interrupt = function(self, code, source)` _defined at line 227 of [anselme/state/State.lua](../anselme/state/State.lua):_ `interrupt = function(self, code, source, tags)`
### :eval (code, source) ### :eval (code, source, tags)
Evaluate an expression in the global scope. Evaluate an expression in the global scope.
This can be called from outside a running script, but an error will be triggered the expression raise any event other than return. This can be called from outside a running script, but an error will be triggered the expression raise any event other than return.
`code` is the code string or AST to run. If `code` is a string, `source` is the source name string to show in errors (optional).
`tags` is an optional Lua table; its content will be added to the tags for the duration of the expression.
* returns AST in case of success. Run `:to_lua(state)` on it to convert to a Lua value. * returns AST in case of success. Run `:to_lua(state)` on it to convert to a Lua value.
* returns `nil, error message` in case of error. * returns `nil, error message` in case of error.
_defined at line 249 of [anselme/state/State.lua](../anselme/state/State.lua):_ `eval = function(self, code, source)` _defined at line 254 of [anselme/state/State.lua](../anselme/state/State.lua):_ `eval = function(self, code, source, tags)`
### :eval_local (code, source) ### :eval_local (code, source, tags)
Same as `:eval`, but evaluate the expression in the current scope. Same as `:eval`, but evaluate the expression in the current scope.
_defined at line 256 of [anselme/state/State.lua](../anselme/state/State.lua):_ `eval_local = function(self, code, source)` _defined at line 261 of [anselme/state/State.lua](../anselme/state/State.lua):_ `eval_local = function(self, code, source, tags)`
If you want to perform more advanced manipulation of the resulting AST nodes, look at the `ast` modules. If you want to perform more advanced manipulation of the resulting AST nodes, look at the `ast` modules.
In particular, every Node inherits the methods from [ast.abstract.Node](../ast/abstract/Node.lua). In particular, every Node inherits the methods from [ast.abstract.Node](../ast/abstract/Node.lua).
@ -312,4 +317,4 @@ Otherwise, each Node has its own module file defined in the [ast/](../ast) direc
--- ---
_file generated at 2024-11-09T17:00:43Z_ _file generated at 2024-11-11T09:22:49Z_