1
0
Fork 0
mirror of https://github.com/Reuh/anselme.git synced 2025-10-27 16:49:31 +00:00
anselme/stdlib/functions.lua
2020-05-24 20:31:09 +02:00

334 lines
7.6 KiB
Lua

local truthy, eval, find_function_variant, anselme
local function rewrite_assignement(fqm, state, arg, explicit_call)
local op, e = find_function_variant(fqm:match("^(.*)%=$"), state, arg, true)
if not op then return op, e end
local ass, err = find_function_variant(":=", state, { type = "list", left = arg.left, right = op }, explicit_call)
if not ass then return ass, err end
return ass
end
local functions
functions = {
-- discard left
[";"] = {
{
arity = 2, mode = "raw",
value = function(a, b) return b end
}
},
-- assignement
[":="] = {
{
arity = 2, mode = "custom",
check = function(state, args)
local left, right = args[1], args[2]
if left.type ~= "variable" then
return nil, ("assignement expected a variable as a left argument but received a %s"):format(left.type)
end
if left.return_type and right.return_type and left.return_type ~= right.return_type then
return nil, ("trying to assign a %s value to a %s variable"):format(right.return_type, left.return_type)
end
return right.return_type or true
end,
value = function(state, exp)
local arg = exp.argument
local name = arg.left.name
local right, righte = eval(state, arg.right)
if not right then return right, righte end
state.variables[name] = right
return right
end
}
},
["+="] = {
{ rewrite = rewrite_assignement }
},
["-="] = {
{ rewrite = rewrite_assignement }
},
["*="] = {
{ rewrite = rewrite_assignement }
},
["/="] = {
{ rewrite = rewrite_assignement }
},
["//="] = {
{ rewrite = rewrite_assignement }
},
["%="] = {
{ rewrite = rewrite_assignement }
},
["^="] = {
{ rewrite = rewrite_assignement }
},
-- comparaison
["="] = {
{
arity = 2, return_type = "number", mode = "raw",
value = function(a, b)
return {
type = "number",
value = (a.type == b.type and a.value == b.value) and 1 or 0
}
end
}
},
["!="] = {
{
arity = 2, return_type = "number", mode = "raw",
value = function(a, b)
return {
type = "number",
value = (a.type == b.type and a.value == b.value) and 0 or 1
}
end
}
},
[">"] = {
{
arity = 2, types = { "number", "number" }, return_type = "number",
value = function(a, b) return a > b end
}
},
["<"] = {
{
arity = 2, types = { "number", "number" }, return_type = "number",
value = function(a, b) return a < b end
}
},
[">="] = {
{
arity = 2, types = { "number", "number" }, return_type = "number",
value = function(a, b) return a >= b end
}
},
["<="] = {
{
arity = 2, types = { "number", "number" }, return_type = "number",
value = function(a, b) return a <= b end
}
},
-- arithmetic
["+"] = {
{
arity = 2, types = { "number", "number" }, return_type = "number",
value = function(a, b) return a + b end
},
{
arity = 2, types = { "string", "string" }, return_type = "string",
value = function(a, b) return a .. b end
}
},
["-"] = {
{
arity = 2, types = { "number", "number" }, return_type = "number",
value = function(a, b) return a - b end
},
{
arity = 1, types = { "number" }, return_type = "number",
value = function(a) return -a end
}
},
["*"] = {
{
arity = 2, types = { "number", "number" }, return_type = "number",
value = function(a, b) return a * b end
}
},
["/"] = {
{
arity = 2, types = { "number", "number" }, return_type = "number",
value = function(a, b) return a / b end
}
},
["//"] = {
{
arity = 2, types = { "number", "number" }, return_type = "number",
value = function(a, b) return math.floor(a / b) end
}
},
["^"] = {
{
arity = 2, types = { "number", "number" }, return_type = "number",
value = function(a, b) return a ^ b end
}
},
-- boolean
["!"] = {
{
arity = 1, return_type = "number", mode = "raw",
value = function(a)
return {
type = "number",
value = truthy(a) and 0 or 1
}
end
}
},
["&"] = {
{
arity = 2, return_type = "number", mode = "custom",
value = function(state, exp)
local left, lefte = eval(state, exp.left)
if not left then return left, lefte end
if truthy(left) then
local right, righte = eval(state, exp.right)
if not right then return right, righte end
if truthy(right) then
return {
type = "number",
value = 1
}
end
end
return {
type = "number",
value = 0
}
end
}
},
["|"] = {
{
arity = 2, return_type = "number", mode = "raw",
value = function(state, exp)
local left, lefte = eval(state, exp.left)
if not left then return left, lefte end
if truthy(left) then
return {
type = "number",
value = 1
}
end
local right, righte = eval(state, exp.right)
if not right then return right, righte end
return {
type = "number",
value = truthy(right) and 1 or 0
}
end
}
},
-- pair
[":"] = {
{
arity = 2, return_type = "pair", mode = "raw",
value = function(a, b)
return {
type = "pair",
value = { a, b }
}
end
}
},
-- index
["("] = {
{
arity = 2, types = { "list", "number" }, mode = "raw",
value = function(a, b)
return a.value[b.value] or { type = "nil", value = nil }
end
}
},
-- list methods
len = {
{
arity = 1, types = { "list" }, return_type = "number", mode = "raw", -- raw to count pairs in the list
value = function(a)
return {
type = "number",
value = #a.value
}
end
}
},
insert = {
{
arity = 2, types = { "list" }, return_type = "list", mode = "raw",
value = function(a, v)
table.insert(a.value, v)
return a
end
},
{
arity = 3, types = { "list", "number" }, return_type = "list", mode = "raw",
value = function(a, k, v)
table.insert(a.value, k.value, v)
return a
end
}
},
remove = {
{
arity = 1, types = { "list" }, return_type = "list", mode = "raw",
value = function(a)
table.remove(a.value)
return a
end
},
{
arity = 2, types = { "list", "number" }, return_type = "list", mode = "raw",
value = function(a, k)
table.remove(a.value, k.value)
return a
end
}
},
rand = {
{
arity = 0, return_type = "number",
value = function()
return math.random()
end
},
{
arity = 1, types = { "number" }, return_type = "number",
value = function(a)
return math.random(a)
end
},
{
arity = 2, types = { "number", "number" }, return_type = "number",
value = function(a, b)
return math.random(a, b)
end
}
},
cycle = function(...)
local l = {...}
local f, fseen = l[1], assert(anselme.running:eval(l[1]..".👁️", anselme.running:current_namespace()))
for j=2, #l do
local seen = assert(anselme.running:eval(l[j]..".👁️", anselme.running:current_namespace()))
if seen < fseen then
f = l[j]
break
end
end
return anselme.running:run(f, anselme.running:current_namespace())
end,
random = function(...)
local l = {...}
return anselme.running:run(l[math.random(1, #l)], anselme.running:current_namespace())
end,
next = function(...)
local l = {...}
local f = l[#l]
for j=1, #l-1 do
local seen = assert(anselme.running:eval(l[j]..".👁️", anselme.running:current_namespace()))
if seen == 0 then
f = l[j]
break
end
end
return anselme.running:run(f, anselme.running:current_namespace())
end
}
package.loaded[...] = functions
truthy = require((...):gsub("stdlib%.functions$", "interpreter.common")).truthy
eval = require((...):gsub("stdlib%.functions$", "interpreter.expression"))
find_function_variant = require((...):gsub("stdlib%.functions$", "parser.common")).find_function_variant
anselme = require((...):gsub("stdlib%.functions$", "anselme"))
return functions