1
0
Fork 0
mirror of https://github.com/Reuh/anselme.git synced 2025-10-27 16:49:31 +00:00

Prefix type checkers with "is", stdlib cleanup

This commit is contained in:
Étienne Fildadut 2024-01-06 15:00:08 +01:00
parent 98917c2ca4
commit 7f71569e07
25 changed files with 163 additions and 160 deletions

View file

@ -7,7 +7,7 @@ local block_identifier = Identifier:new("_")
return {
{
"attached block", "(level::number=1, keep return=false)",
"attached block", "(level::is number=1, keep return=false)",
function(state, level, keep_return)
-- level 2: env of the function that called the function that called attached block
local env = calling_environment_manager:get_level(state, level:to_lua(state)+1)
@ -25,7 +25,7 @@ return {
end
},
{
"attached block", "(level::number=1, keep return=false, default)",
"attached block", "(level::is number=1, keep return=false, default)",
function(state, level, keep_return, default)
-- level 2: env of the function that called the function that called attached block
local env = calling_environment_manager:get_level(state, level:to_lua(state)+1)

View file

@ -1,4 +0,0 @@
return [[
:@$is(t) $(x) x!type == t
:@$equal(x) $(y) x == y
]]

View file

@ -1,6 +1,6 @@
return [[
/* For loop */
:@$for(symbol::symbol, var, block=attached block(keep return=true))
:@$for(symbol::is symbol, var, block=attached block(keep return=true))
:iterator = iter(var)
:value = iterator()
:name = symbol!to string
@ -12,11 +12,12 @@ return [[
r
/* Range iterables */
:@is range = is("range")
:@$range(stop)
[1, stop, 1]!type("range")
:@$range(start, stop, step=1)
[start, stop, step]!type("range")
:@$iter(range::is("range"))
:@$iter(range::is range)
:v = range!value
:start = v(1)
:stop = v(2)
@ -34,8 +35,7 @@ return [[
return(i-step)
/* List/tuple iterables */
:tuple or list = $(x) x!type == "tuple" | x!type == "list"
:@$iter(tuple::tuple or list)
:@$iter(tuple::is sequence)
:n = tuple!len
:i = 0
$
@ -44,7 +44,7 @@ return [[
return(tuple(i))
/* Table */
:@$iter(table::table)
:@$iter(table::is table)
:s = table!to struct
iter(s)
]]

View file

@ -4,13 +4,13 @@ local assert0 = require("anselme.common").assert0
return {
{
"defined", "(c::function, s::string)",
"defined", "(c::is function, s::is string)",
function(state, c, s)
return Boolean:new(c.scope:defined_in_current(state, s:to_identifier()))
end
},
{
"has upvalue", "(c::function, s::string)",
"has upvalue", "(c::is function, s::is string)",
function(state, c, s)
return Boolean:new(c.scope:defined(state, s:to_identifier()))
end
@ -25,7 +25,7 @@ return {
end
},
{
"_._", "(c::function, s::string) = v",
"_._", "(c::is function, s::is string) = v",
function(state, c, s, v)
local identifier = s:to_identifier()
assert0(c.scope:defined(state, identifier), ("no variable %q defined in closure"):format(s.string))
@ -34,7 +34,7 @@ return {
end
},
{
"_._", "(c::function, s::symbol) = v",
"_._", "(c::is function, s::is symbol) = v",
function(state, c, s, v)
state.scope:push(c.scope)
local r = Definition:new(s, v):eval(state)

View file

@ -9,7 +9,7 @@ local function load(state, l)
for _, m in ipairs(l) do
local mod = require("anselme.stdlib."..m)
if type(mod) == "string" then
parser(mod, m..".ans"):eval(state)
parser(mod, "stdlib/"..m..".ans"):eval(state)
else
define_lua(state, mod)
end
@ -22,8 +22,8 @@ return function(main_state)
"tag",
"conditionals",
"base",
"types",
"boot",
"typed",
"type check",
"number",
"string",
"symbol",

View file

@ -5,58 +5,58 @@ return {
{ "pi", Number:new(math.pi) },
{
"_<_", "(a::number, b::number)",
"_<_", "(a::is number, b::is number)",
function(state, a, b)
if a.number < b.number then return b
else return Boolean:new(false)
end
end
},
{ "_<_", "(a::equal(false), b::number)", function(state, a, b) return Boolean:new(false) end },
{ "_<_", "(a::equal(false), b::is number)", function(state, a, b) return Boolean:new(false) end },
{
"_<=_", "(a::number, b::number)",
"_<=_", "(a::is number, b::is number)",
function(state, a, b)
if a.number <= b.number then return b
else return Boolean:new(false)
end
end
},
{ "_<=_", "(a::equal(false), b::number)", function(state, a, b) return Boolean:new(false) end },
{ "_<=_", "(a::equal(false), b::is number)", function(state, a, b) return Boolean:new(false) end },
{
"_>_", "(a::number, b::number)",
"_>_", "(a::is number, b::is number)",
function(state, a, b)
if a.number > b.number then return b
else return Boolean:new(false)
end
end
},
{ "_>_", "(a::equal(false), b::number)", function(state, a, b) return Boolean:new(false) end },
{ "_>_", "(a::equal(false), b::is number)", function(state, a, b) return Boolean:new(false) end },
{
"_>=_", "(a::number, b::number)",
"_>=_", "(a::is number, b::is number)",
function(state, a, b)
if a.number >= b.number then return b
else return Boolean:new(false)
end
end
},
{ "_>=_", "(a::equal(false), b::number)", function(state, a, b) return Boolean:new(false) end },
{ "_+_", "(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, 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, b::number)", function(state, a, b) return Number:new(math.floor(a.number / b.number)) end },
{ "_%_", "(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 },
{ "_>=_", "(a::equal(false), b::is number)", function(state, a, b) return Boolean:new(false) end },
{ "_+_", "(a::is number, b::is number)", function(state, a, b) return Number:new(a.number + b.number) end },
{ "_-_", "(a::is number, b::is number)", function(state, a, b) return Number:new(a.number - b.number) end },
{ "_*_", "(a::is number, b::is number)", function(state, a, b) return Number:new(a.number * b.number) end },
{ "_/_", "(a::is number, b::is number)", function(state, a, b) return Number:new(a.number / b.number) end },
{ "_//_", "(a::is number, b::is number)", function(state, a, b) return Number:new(math.floor(a.number / b.number)) end },
{ "_%_", "(a::is number, b::is number)", function(state, a, b) return Number:new(a.number % b.number) end },
{ "_^_", "(a::is number, b::is number)", function(state, a, b) return Number:new(a.number ^ b.number) end },
{ "-_", "(a::is 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", "(min::is number, max::is number)", function(state, min, max) return Number:new(math.random(min.number, max.number)) end },
{ "rand", "(max::is number)", function(state, max) return Number:new(math.random(max.number)) end },
{ "rand", "()", function(state) return Number:new(math.random()) end },
{ "floor", "(x::number)", function(state, x) return Number:new(math.floor(x.number)) end },
{ "ceil", "(x::number)", function(state, x) return Number:new(math.ceil(x.number)) end },
{ "floor", "(x::is number)", function(state, x) return Number:new(math.floor(x.number)) end },
{ "ceil", "(x::is number)", function(state, x) return Number:new(math.ceil(x.number)) end },
{
"round", "(x::number, increment=1)",
"round", "(x::is number, increment=1)",
function(state, x, increment)
local n = x.number / increment.number
if n >= 0 then

View file

@ -5,13 +5,13 @@ return {
{ "_:_", "(name, value)", function(state, a, b) return Pair:new(a,b) end },
{
"name", "(pair::pair)",
"name", "(pair::is pair)",
function(state, pair)
return pair.name
end
},
{
"value", "(pair::pair)",
"value", "(pair::is pair)",
function(state, pair)
return pair.value
end

View file

@ -6,13 +6,13 @@ local calling_environment_manager = require("anselme.state.calling_environment_m
return {
{
"from", "(function::function, anchor::anchor)",
"from", "(function::is function, anchor::is anchor)",
function(state, func, anchor)
return func:resume(state, anchor)
end
},
{
"from", "(function::function, anchor::nil)",
"from", "(function::is function, anchor::is nil)",
function(state, func)
return func:call(state, ArgumentTuple:new())
end
@ -24,7 +24,7 @@ return {
end
},
{
"resuming", "(level::number=0)",
"resuming", "(level::is number=0)",
function(state, level)
local env = calling_environment_manager:get_level(state, level:to_lua(state)+1)
state.scope:push(env)

View file

@ -6,9 +6,9 @@ return [[
:resume target = ()
fn.:check = $(anchor::anchor)
fn.:check = $(anchor::is anchor)
fn.reached(anchor) = (fn.reached(anchor) | 0) + 1
fn.:checkpoint = $(anchor::anchor, on resume=attached block(default=()))
fn.:checkpoint = $(anchor::is anchor, on resume=attached block(default=()))
if(on resume)
fn.current checkpoint = anchor
if(resume target == anchor | resuming(4))
@ -38,14 +38,14 @@ return [[
:@$_!(s::is script)
s!value!
:@$_._(s::is script, k::string)
:@$_._(s::is script, k::is string)
(s!value).fn.(k)
:@$_._(s::is script, k::string) = val
:@$_._(s::is script, k::is string) = val
(s!value).fn.(k) = val
:@$_._(s::is script, k::symbol) = val
:@$_._(s::is script, k::is symbol) = val
(s!value).fn.(k) = val
:@$from(s::is script, a::anchor)
:@$from(s::is script, a::is anchor)
s.current checkpoint = a
return(s!)
:@$from(s::is script)
@ -53,7 +53,7 @@ return [[
return(s!)
/* Additionnal helpers */
:@$ cycle(l::tuple)
:@$ cycle(l::is tuple)
:i = 2
while($i <= l!len)
if(l(i).run < l(1).run)
@ -61,7 +61,7 @@ return [[
i += 1
l(1)!
:@$ next(l::tuple)
:@$ next(l::is tuple)
:i = 1
while($i <= l!len)
if(l(i).run == 0)
@ -69,6 +69,6 @@ return [[
i += 1
l(i-1)!
:@$ random(l::tuple)
:@$ random(l::is tuple)
l(rand(1, l!len))!
]]

View file

@ -3,9 +3,9 @@ local ast = require("anselme.ast")
local String, Number = ast.String, ast.Number
return {
{ "_+_", "(a::string, b::string)", function(state, a, b) return String:new(a.string .. b.string) end },
{ "_+_", "(a::is string, b::is string)", function(state, a, b) return String:new(a.string .. b.string) end },
{
"len", "(s::string)",
"len", "(s::is string)",
function(state, s)
return Number:new(utf8.len(s.string))
end

View file

@ -4,25 +4,25 @@ local Nil, List, Table, Number, LuaFunction, ParameterTuple, Boolean = ast.Nil,
return {
-- tuple
{
"*_", "(t::tuple)",
"*_", "(t::is tuple)",
function(state, tuple)
return List:new(state, tuple)
end
},
{
"_!", "(l::tuple, i::number)",
"_!", "(l::is tuple, i::is number)",
function(state, l, i)
return l:get(i.number)
end
},
{
"len", "(l::tuple)",
"len", "(l::is tuple)",
function(state, l)
return Number:new(l:len())
end
},
{
"find", "(l::tuple, value)",
"find", "(l::is tuple, value)",
function(state, l, v)
local i = l:find(v)
if i then
@ -35,26 +35,26 @@ return {
-- list
{
"_!", "(l::list, i::number)",
"_!", "(l::is list, i::is number)",
function(state, l, i)
return l:get(state, i.number)
end
},
{
"_!", "(l::list, i::number) = value",
"_!", "(l::is list, i::is number) = value",
function(state, l, i, v)
l:set(state, i.number, v)
return Nil:new()
end
},
{
"len", "(l::list)",
"len", "(l::is list)",
function(state, l)
return Number:new(l:len(state))
end
},
{
"find", "(l::list, value)",
"find", "(l::is list, value)",
function(state, l, v)
local i = l:find(state, v)
if i then
@ -65,35 +65,35 @@ return {
end
},
{
"insert", "(l::list, value)",
"insert", "(l::is list, value)",
function(state, l, v)
l:insert(state, v)
return Nil:new()
end
},
{
"insert", "(l::list, position::number, value)",
"insert", "(l::is list, position::is number, value)",
function(state, l, position, v)
l:insert(state, position.number, v)
return Nil:new()
end
},
{
"remove", "(l::list)",
"remove", "(l::is list)",
function(state, l)
l:remove(state)
return Nil:new()
end
},
{
"remove", "(l::list, position::number)",
"remove", "(l::is list, position::is number)",
function(state, l, position)
l:remove(state, position.number)
return Nil:new()
end
},
{
"to tuple", "(l::list)",
"to tuple", "(l::is list)",
function(state, l)
return l:to_tuple(state)
end
@ -101,25 +101,25 @@ return {
-- struct
{
"*_", "(s::struct)",
"*_", "(s::is struct)",
function(state, struct)
return Table:new(state, struct)
end
},
{
"_!", "(s::struct, key)",
"_!", "(s::is struct, key)",
function(state, s, k)
return s:get(k)
end
},
{
"has", "(s::struct, key)",
"has", "(s::is struct, key)",
function(state, s, k)
return Boolean:new(s:has(k))
end
},
{
"iter", "(s::struct)",
"iter", "(s::is struct)",
function(state, struct)
local iter = struct:iter()
return LuaFunction:new(ParameterTuple:new(), function()
@ -132,26 +132,26 @@ return {
-- table
{
"_!", "(t::table, key)",
"_!", "(t::is table, key)",
function(state, t, key)
return t:get(state, key)
end
},
{
"_!", "(t::table, key) = value",
"_!", "(t::is table, key) = value",
function(state, t, key, value)
t:set(state, key, value)
return Nil:new()
end
},
{
"has", "(t::table, key)",
"has", "(t::is table, key)",
function(state, t, k)
return Boolean:new(t:has(state, k))
end
},
{
"to struct", "(t::table)",
"to struct", "(t::is table)",
function(state, t)
return t:to_struct(state)
end

View file

@ -1,7 +1,7 @@
return {
{
"to string", "(symbol::symbol)",
"to string", "(symbol::is symbol)",
function(state, sym)
return sym:to_string()
end

View file

@ -9,7 +9,7 @@ local resume_manager = require("anselme.state.resume_manager")
return {
-- text
{
"_+_", "(a::text, b::text)",
"_+_", "(a::is text, b::is text)",
function(state, a, b)
local r = Text:new()
for _, e in ipairs(a.list) do
@ -22,7 +22,7 @@ return {
end
},
{
"_!", "(txt::text)",
"_!", "(txt::is text)",
function(state, text)
event_manager:write(state, text)
return Nil:new()
@ -31,7 +31,7 @@ return {
-- choice
{
"_|>_", "(txt::text, fn)",
"_|>_", "(txt::is text, fn)",
function(state, text, func)
if func:contains_current_resume_target(state) then
func:call(state, ArgumentTuple:new())

View file

@ -0,0 +1,26 @@
return [[
:@$is(t) $(x) x!type == t
:@$equal(x) $(y) x == y
:@is nil = is("nil")
:@is number = is("number")
:@is string = is("string")
:@is boolean = is("boolean")
:@is symbol = is("symbol")
:@is anchor = is("anchor")
:@is pair = is("pair")
:@is text = is("text")
:@is sequence = $(x) x!type == "tuple" | x!type == "list"
:@is tuple = is("tuple")
:@is list = is("list")
:@is map = $(x) x!type == "struct" | x!type == "table"
:@is struct = is("struct")
:@is table = is("table")
:@is function = is("function")
:@is overload = is("overload")
:@is callable = $(x) x!type == "overload" | x!type == "function" | x!type == "lua function" | x!type == "quote"
]]

43
anselme/stdlib/typed.lua Normal file
View file

@ -0,0 +1,43 @@
local ast = require("anselme.ast")
local ArgumentTuple, String, Typed = ast.ArgumentTuple, ast.String, ast.Typed
return {
{
"_::_", "(value, check)",
function(state, value, check)
local r = check:call(state, ArgumentTuple:new(value))
if r:truthy() then
return value
else
error(("type check failure: %s does not satisfy %s"):format(value:format(state), check:format(state)), 0)
end
end
},
{
"type", "(value)",
function(state, v)
if v.type == "typed" then
return v.type_expression
else
return String:new(v.type)
end
end
},
{
"type", "(value, type)",
function(state, v, t)
return Typed:new(v, t)
end
},
{
"value", "(value)",
function(state, v)
if v.type == "typed" then
return v.expression
else
return v
end
end
},
}

View file

@ -1,62 +0,0 @@
local ast = require("anselme.ast")
local ArgumentTuple, Boolean, String, Typed = ast.ArgumentTuple, ast.Boolean, ast.String, ast.Typed
return {
{
"_::_", "(value, check)",
function(state, value, check)
local r = check:call(state, ArgumentTuple:new(value))
if r:truthy() then
return value
else
error(("type check failure: %s does not satisfy %s"):format(value:format(state), check:format(state)), 0)
end
end
},
{
"type", "(value)",
function(state, v)
if v.type == "typed" then
return v.type_expression
else
return String:new(v.type)
end
end
},
{
"type", "(value, type)",
function(state, v, t)
return Typed:new(v, t)
end
},
{
"value", "(value)",
function(state, v)
if v.type == "typed" then
return v.expression
else
return v
end
end
},
{ "nil", "(x)", function(state, x) return Boolean:new(x.type == "nil") end },
{ "number", "(x)", function(state, x) return Boolean:new(x.type == "number") end },
{ "string", "(x)", function(state, x) return Boolean:new(x.type == "string") end },
{ "boolean", "(x)", function(state, x) return Boolean:new(x.type == "boolean") end },
{ "symbol", "(x)", function(state, x) return Boolean:new(x.type == "symbol") end },
{ "anchor", "(x)", function(state, x) return Boolean:new(x.type == "anchor") end },
{ "text", "(x)", function(state, x) return Boolean:new(x.type == "text") end },
{ "pair", "(x)", function(state, x) return Boolean:new(x.type == "pair") end },
{ "tuple", "(x)", function(state, x) return Boolean:new(x.type == "tuple") end },
{ "list", "(x)", function(state, x) return Boolean:new(x.type == "list") end },
{ "struct", "(x)", function(state, x) return Boolean:new(x.type == "struct") end },
{ "table", "(x)", function(state, x) return Boolean:new(x.type == "table") end },
{ "function", "(x)", function(state, x) return Boolean:new(x.type == "function") end },
{ "overload", "(x)", function(state, x) return Boolean:new(x.type == "overload") end },
{ "callable", "(x)", function(state, x) return Boolean:new(x.type == "overload" or x.type == "function" or x.type == "lua function" or x.type == "quote") end },
}

View file

@ -76,9 +76,9 @@ local function run(path, interactive)
local state = anselme:new()
state:load_stdlib()
state:define("interrupt", "(code::string)", function(state, code) state:interrupt(code:to_lua(state), "interrupt") return ast.Nil:new() end, true)
state:define("interrupt", "(code::is string)", function(state, code) state:interrupt(code:to_lua(state), "interrupt") return ast.Nil:new() end, true)
state:define("interrupt", "()", function(state) state:interrupt() return ast.Nil:new() end, true)
state:define("wait", "(duration::number)", function(duration) coroutine.yield("wait", duration) end)
state:define("wait", "(duration::is number)", function(duration) coroutine.yield("wait", duration) end)
state:define("run in new branch", "(code)", function(code)
local parallel_state = state:branch()
write_output("--# parallel script #--")
@ -87,7 +87,7 @@ local function run(path, interactive)
write_output("--# main script #--")
end)
state:define("serialize", "(value)", function(state, value) return ast.String:new(value:serialize(state)) end, true)
state:define("deserialize", "(str::string)", function(state, str) return ast.abstract.Node:deserialize(state, str.string) end, true)
state:define("deserialize", "(str::is string)", function(state, str) return ast.abstract.Node:deserialize(state, str.string) end, true)
local run_state = state:branch()
@ -123,7 +123,7 @@ end
if not arg[1] or arg[1] == "update" then
-- display an animated loading indicator
local loading = {
loop = { "", "", "", "", "", "", "", "" },
loop = { "", "", "", "", "", "", "", "" },
loop_pos = 1,
erase_code = "",

View file

@ -1,7 +1,7 @@
:$ a - b
return("generic minus")
:$ a::string - b::string
:$ a::is string - b::is string
return(a + " minus " + b)
| {2-5}

View file

@ -7,7 +7,7 @@
|v={v}
a = v
:$ f(p) = v::string
:$ f(p) = v::is string
|v2={v}
a = p

View file

@ -1,8 +1,8 @@
:$ a(x::number)
:$ a(x::is number)
return(x + 2)
:$ x
:$ a(x::string)
:$ a(x::is string)
return(x + "heh")
|{a("plop")}

View file

@ -1,7 +1,7 @@
:$ fn(x::number)
:$ fn(x::is number)
|x
:$ fn(a::number)
:$ fn(a::is number)
|a
fn(5)

View file

@ -1,7 +1,7 @@
:$ fn(x::number)
:$ fn(x::is number)
|x
:$ fn(a::string="o")
:$ fn(a::is string="o")
|a
fn("s")
@ -10,10 +10,10 @@ fn(5)
fn()
:$ g(n="s", a::number=5)
:$ g(n="s", a::is number=5)
return("gn")
:$ g(n="s", a::string="lol")
:$ g(n="s", a::is string="lol")
return("gs")
|{g(n="k", a="l")}

View file

@ -1,7 +1,7 @@
:$ fn(x::number)
:$ fn(x::is number)
|x
:$ fn(a::string)
:$ fn(a::is string)
|a
fn("s")

View file

@ -1,6 +1,6 @@
:f = ()
_
:$_+_(a::string, b)
:$_+_(a::is string, b)
"{a}{b}"
:a=1

View file

@ -1,7 +1,7 @@
:$ -f
return("generic minus")
:$ -f::string
:$ -f::is string
return("minus "+f)
|{-5}