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

146 lines
3.9 KiB
Lua

local atypes, ltypes
local eval
local common
common = {
-- flush interpreter state to global state
merge_state = function(state)
local global_vars = state.interpreter.global_state.variables
for var, value in pairs(state.variables) do
global_vars[var] = value
state.variables[var] = nil
end
end,
-- returns a variable's value, evaluating a pending expression if neccessary
-- if you're sure the variable has already been evaluated, use state.variables[fqm] directly
-- return var
-- return nil, err
get_variable = function(state, fqm)
local var = state.variables[fqm]
if var.type == "pending definition" then
local v, e = eval(state, var.value.expression)
if not v then
return nil, ("%s; while evaluating default value for variable %q defined at %s"):format(e, fqm, var.value.source)
end
state.variables[fqm] = v
return v
else
return var
end
end,
-- check truthyness of an anselme value
truthy = function(val)
if val.type == "number" then
return val.value ~= 0
elseif val.type == "nil" then
return false
else
return true
end
end,
-- compare two anselme value for equality
compare = function(a, b)
if a.type ~= b.type then
return false
end
if a.type == "pair" or a.type == "type" then
return common.compare(a.value[1], b.value[1]) and common.compare(a.value[2], b.value[2])
elseif a.type == "list" then
if #a.value ~= #b.value then
return false
end
for i, v in ipairs(a.value) do
if not common.compare(v, b.value[i]) then
return false
end
end
return true
else
return a.value == b.value
end
end,
-- format a anselme value to something printable
-- does not call custom {}() functions, only built-in ones, so it should not be able to fail
-- str: if success
-- * nil, err: if error
format = function(val)
if atypes[val.type] and atypes[val.type].format then
return atypes[val.type].format(val.value)
else
return nil, ("no formatter for type %q"):format(val.type)
end
end,
-- lua value: if success (may be nil!)
-- * nil, err: if error
to_lua = function(val)
if atypes[val.type] and atypes[val.type].to_lua then
return atypes[val.type].to_lua(val.value)
else
return nil, ("no Lua exporter for type %q"):format(val.type)
end
end,
-- anselme value: if success
-- * nil, err: if error
from_lua = function(val)
if ltypes[type(val)] and ltypes[type(val)].to_anselme then
return ltypes[type(val)].to_anselme(val)
else
return nil, ("no Lua importer for type %q"):format(type(val))
end
end,
-- string: if success
-- * nil, err: if error
eval_text = function(state, text)
local s = ""
for _, item in ipairs(text) do
if type(item) == "string" then
s = s .. item
else
local v, e = eval(state, item)
if not v then return v, e end
v, e = common.format(v)
if not v then return v, e end
s = s .. v
end
end
return s
end,
-- specificity(number): if var is of type type
-- false: if not
is_of_type = function(var, type)
local depth = 1
-- var has a custom type
if var.type == "type" then
local var_type = var.value[2]
while true do
if common.compare(var_type, type) then -- same type
return depth
elseif var_type.type == "type" then -- compare parent type
depth = depth + 1
var_type = var_type.value[2]
else -- no parent, fall back on base type
depth = depth + 1
var = var.value[1]
break
end
end
end
-- var has a base type
return type.type == "string" and type.value == var.type and depth
end,
-- return a pretty printable type value for var
pretty_type = function(var)
if var.type == "type" then
return common.format(var.value[2])
else
return var.type
end
end
}
package.loaded[...] = common
local types = require((...):gsub("interpreter%.common$", "stdlib.types"))
atypes, ltypes = types.anselme, types.lua
eval = require((...):gsub("common$", "expression"))
return common