mirror of
https://github.com/Reuh/anselme.git
synced 2025-10-28 00:59:31 +00:00
Final test batch and associated fixes
This commit is contained in:
parent
050c84921c
commit
43a745a7a9
66 changed files with 1233 additions and 51 deletions
|
|
@ -38,6 +38,9 @@ Closure = Runtime(Overloadable) {
|
|||
format_parameters = function(self, state)
|
||||
return self.func.parameters:format(state)
|
||||
end,
|
||||
hash_parameters = function(self)
|
||||
return self.func.parameters:hash()
|
||||
end,
|
||||
call_dispatched = function(self, state, args)
|
||||
local calling_environment = state.scope:capture()
|
||||
state.scope:push(self.scope)
|
||||
|
|
|
|||
|
|
@ -40,6 +40,9 @@ Function = Overloadable {
|
|||
format_parameters = function(self, state)
|
||||
return self.parameters:format(state)
|
||||
end,
|
||||
hash_parameters = function(self)
|
||||
return self.parameters:hash()
|
||||
end,
|
||||
call_dispatched = function(self, state, args)
|
||||
state.scope:push()
|
||||
args:bind_parameter_tuple(state, self.parameters)
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ List = ast.abstract.Runtime {
|
|||
end,
|
||||
|
||||
len = function(self, state)
|
||||
return #self.branched:get(state).list
|
||||
return self.branched:get(state):len()
|
||||
end,
|
||||
iter = function(self, state)
|
||||
return ipairs(self.branched:get(state).list)
|
||||
|
|
|
|||
|
|
@ -20,6 +20,10 @@ LuaFunction = ast.abstract.Runtime(Overloadable) {
|
|||
fn(self.parameters, ...)
|
||||
end,
|
||||
|
||||
_hash = function(self)
|
||||
return ("%s<%s;%s>"):format(self.type, self.parameters:hash(), tostring(self.func))
|
||||
end,
|
||||
|
||||
_format = function(self, ...)
|
||||
if self.parameters.assignment then
|
||||
return "$"..self.parameters:format(...).."; <lua function>"
|
||||
|
|
@ -37,6 +41,9 @@ LuaFunction = ast.abstract.Runtime(Overloadable) {
|
|||
format_parameters = function(self, state)
|
||||
return self.parameters:format(state)
|
||||
end,
|
||||
hash_parameters = function(self)
|
||||
return self.parameters:hash()
|
||||
end,
|
||||
call_dispatched = function(self, state, args)
|
||||
local lua_args = { state }
|
||||
|
||||
|
|
|
|||
|
|
@ -1,17 +1,25 @@
|
|||
local ast = require("anselme.ast")
|
||||
local assert0 = require("anselme.common").assert0
|
||||
|
||||
local Overload
|
||||
Overload = ast.abstract.Node {
|
||||
type = "overload",
|
||||
_evaluated = true,
|
||||
|
||||
list = nil,
|
||||
list = nil, -- list of Overloadable
|
||||
_signatures = nil, -- map {[parameter hash]=true} of call signatures already registered in this overload
|
||||
|
||||
init = function(self, ...)
|
||||
self.list = { ... }
|
||||
self.list = {}
|
||||
self._signatures = {}
|
||||
for _, fn in ipairs{...} do
|
||||
self:insert(fn)
|
||||
end
|
||||
end,
|
||||
insert = function(self, val) -- only for construction
|
||||
assert0(not self._signatures[val:hash_parameters()], ("a function with parameters %s is already defined in the overload"):format(val:format_parameters()))
|
||||
table.insert(self.list, val)
|
||||
self._signatures[val:hash_parameters()] = true
|
||||
end,
|
||||
|
||||
_format = function(self, ...)
|
||||
|
|
|
|||
|
|
@ -60,6 +60,9 @@ Tuple = ast.abstract.Node {
|
|||
if index < 0 then index = #self.list + 1 + index end
|
||||
if index > #self.list or index == 0 then error("tuple index out of bounds", 0) end
|
||||
return self.list[index]
|
||||
end,
|
||||
len = function(self)
|
||||
return #self.list
|
||||
end
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -16,6 +16,10 @@ return ast.abstract.Node {
|
|||
format_parameters = function(self, state)
|
||||
return self:format(state)
|
||||
end,
|
||||
-- return string
|
||||
hash_parameters = function(self)
|
||||
return self:hash()
|
||||
end,
|
||||
|
||||
-- can be called either after a successful :dispatch or :compatible_with_arguments
|
||||
call_dispatched = function(self, state, args)
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ local parser = require("anselme.parser")
|
|||
local binser = require("anselme.lib.binser")
|
||||
local assert0 = require("anselme.common").assert0
|
||||
local anselme
|
||||
local Identifier
|
||||
|
||||
local State
|
||||
State = class {
|
||||
|
|
@ -90,6 +91,18 @@ State = class {
|
|||
define_local = function(self, name, value, func, raw_mode)
|
||||
self.scope:define_lua(name, value, func, raw_mode)
|
||||
end,
|
||||
--- Returns true if `name` (string) is defined in the global scope.
|
||||
--- Returns false otherwise.
|
||||
defined = function(self, name)
|
||||
self.scope:push_global()
|
||||
local r = self:defined_local(name)
|
||||
self.scope:pop()
|
||||
return r
|
||||
end,
|
||||
--- Same as `:defined`, but check if the variable is defined in the current scope.
|
||||
defined_local = function(self, name)
|
||||
return self.scope:defined(Identifier:new(name))
|
||||
end,
|
||||
|
||||
--- For anything more advanced, you can directly access the current scope stack stored in `state.scope`.
|
||||
-- See [state/ScopeStack.lua](../state/ScopeStack.lua) for details; the documentation is not as polished as this file but you should still be able to find your way around.
|
||||
|
|
@ -160,7 +173,7 @@ State = class {
|
|||
self.scope:reset()
|
||||
type, data = "error", type
|
||||
end
|
||||
if coroutine.status(self._coroutine) == "dead" then
|
||||
if self._coroutine and coroutine.status(self._coroutine) == "dead" then
|
||||
self._coroutine = nil
|
||||
end
|
||||
return type, data
|
||||
|
|
@ -171,8 +184,11 @@ State = class {
|
|||
--
|
||||
-- If `code` is 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.
|
||||
--
|
||||
-- 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)
|
||||
assert(self:active(), "trying to interrupt but no script is currently active")
|
||||
local called_from_script = self:state() == "running"
|
||||
if code then
|
||||
self._coroutine = coroutine.create(function()
|
||||
local r = assert0(self:eval_local(code, source))
|
||||
|
|
@ -184,6 +200,7 @@ State = class {
|
|||
self.scope:reset()
|
||||
self._coroutine = nil
|
||||
end
|
||||
if called_from_script then coroutine.yield("interrupt") end
|
||||
end,
|
||||
|
||||
--- Evaluate an expression in the global scope.
|
||||
|
|
@ -221,5 +238,7 @@ State = class {
|
|||
|
||||
package.loaded[...] = State
|
||||
anselme = require("anselme")
|
||||
local ast = require("anselme.ast")
|
||||
Identifier = ast.Identifier
|
||||
|
||||
return State
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
local ast = require("anselme.ast")
|
||||
local ArgumentTuple, Boolean = ast.ArgumentTuple, ast.Boolean
|
||||
local ArgumentTuple, Boolean, Nil = ast.ArgumentTuple, ast.Boolean, ast.Nil
|
||||
|
||||
local resume_manager = require("anselme.state.resume_manager")
|
||||
|
||||
|
|
@ -47,4 +47,11 @@ return {
|
|||
return resume_manager:get(state)
|
||||
end
|
||||
},
|
||||
{
|
||||
"merge branch", "()",
|
||||
function(state)
|
||||
state:merge()
|
||||
return Nil:new()
|
||||
end
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,4 +46,8 @@ return {
|
|||
{ "_%_", "(a::number, b::number)", function(state, a, b) return Number:new(a.number % b.number) end },
|
||||
{ "_^_", "(a::number, b::number)", function(state, a, b) return Number:new(a.number ^ b.number) end },
|
||||
{ "-_", "(a::number)", function(state, a) return Number:new(-a.number) end },
|
||||
|
||||
{ "rand", "(min::number, max::number)", function(state, min, max) return Number:new(math.random(min.number, max.number)) end },
|
||||
{ "rand", "(max::number)", function(state, max) return Number:new(math.random(max.number)) end },
|
||||
{ "rand", "()", function(state) return Number:new(math.random()) end },
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,31 +1,34 @@
|
|||
return [[
|
||||
:@script = $(name, fn)
|
||||
:¤t checkpoint => "{name}.checkpoint"!persist(false)
|
||||
:&reached => "{name}.reached"!persist(*{})
|
||||
fn.:¤t checkpoint => "{name}.checkpoint"!persist(false)
|
||||
fn.:&reached => "{name}.reached"!persist(*{})
|
||||
fn.:&run => "{name}.run"!persist(0)
|
||||
|
||||
:resumed from = ()
|
||||
|
||||
fn.:check = $(anchor::anchor)
|
||||
reached(anchor) = (reached(anchor) | 0) + 1
|
||||
fn.reached(anchor) = (fn.reached(anchor) | 0) + 1
|
||||
fn.:checkpoint = $(anchor::anchor)
|
||||
current checkpoint = anchor
|
||||
fn.current checkpoint = anchor
|
||||
resumed from != anchor ~
|
||||
reached(anchor) = (reached(anchor) | 0) + 1
|
||||
fn.reached(anchor) = (fn.reached(anchor) | 0) + 1
|
||||
merge branch!
|
||||
fn.:checkpoint = $(anchor::anchor, on resume::function)
|
||||
current checkpoint = anchor
|
||||
fn.current checkpoint = anchor
|
||||
resumed from == anchor | resuming(1) ~
|
||||
on resume!
|
||||
~
|
||||
reached(anchor) = (reached(anchor) | 0) + 1
|
||||
fn.reached(anchor) = (fn.reached(anchor) | 0) + 1
|
||||
merge branch!
|
||||
|
||||
:f = $
|
||||
current checkpoint ~
|
||||
resumed from = current checkpoint
|
||||
fn!resume(current checkpoint)
|
||||
fn.current checkpoint ~
|
||||
resumed from = fn.current checkpoint
|
||||
fn!resume(fn.current checkpoint)
|
||||
~
|
||||
resumed from = ()
|
||||
fn!
|
||||
run += 1
|
||||
f.:&run => "{name}.run"!persist(0)
|
||||
fn.run += 1
|
||||
|
||||
f!type("script")
|
||||
|
||||
|
|
@ -35,18 +38,11 @@ return [[
|
|||
s!value!
|
||||
|
||||
:@$_._(s::is script, k::string)
|
||||
:v = s!value
|
||||
v.fn!has upvalue(k) ~
|
||||
@v.fn.(k)
|
||||
~
|
||||
@v.(k)
|
||||
|
||||
@(s!value).fn.(k)
|
||||
:@$_._(s::is script, k::string) = val
|
||||
:v = s!value
|
||||
v.fn!has upvalue(k) ~
|
||||
v.fn.(k) = val
|
||||
~
|
||||
v.(k) = val
|
||||
(s!value).fn.(k) = val
|
||||
:@$_._(s::is script, k::symbol) = val
|
||||
(s!value).fn.(k) = val
|
||||
|
||||
:@$from(s::is script, a::anchor)
|
||||
s.current checkpoint = a
|
||||
|
|
@ -54,4 +50,24 @@ return [[
|
|||
:@$from(s::is script)
|
||||
s.current checkpoint = ()
|
||||
@s!
|
||||
|
||||
((Additionnal helpers))
|
||||
:@$ cycle(l::tuple)
|
||||
:i = 2
|
||||
i <= l!len ~?
|
||||
l(i).run < l(1).run ~
|
||||
@l(i)!
|
||||
i += 1
|
||||
l(1)!
|
||||
|
||||
:@$ next(l::tuple)
|
||||
:i = 1
|
||||
i <= l!len ~?
|
||||
l(i).run == 0 ~
|
||||
@l(i)!
|
||||
i += 1
|
||||
l(i-1)!
|
||||
|
||||
:@$ random(l::tuple)
|
||||
l(rand(1, l!len))!
|
||||
]]
|
||||
|
|
@ -15,6 +15,12 @@ return {
|
|||
return l:get(i.number)
|
||||
end
|
||||
},
|
||||
{
|
||||
"len", "(l::tuple)",
|
||||
function(state, l)
|
||||
return Number:new(l:len())
|
||||
end
|
||||
},
|
||||
|
||||
-- list
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue