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

Add maps; remove map emulation functionality from list; function and tags now internally use maps instead of lists

This commit is contained in:
Étienne Fildadut 2022-09-09 21:39:37 +09:00
parent bac5cdde01
commit 95462391e3
20 changed files with 699 additions and 139 deletions

View file

@ -5,6 +5,7 @@ return [[
:number="number"
:string="string"
:list="list"
:map="map"
:pair="pair"
:function reference="function reference"
:variable reference="variable reference"

View file

@ -1,4 +1,4 @@
local truthy, anselme, compare, is_of_type, identifier_pattern, format_identifier, find, get_variable, mark_as_modified, set_variable, check_mutable, copy, mark_constant
local truthy, anselme, compare, is_of_type, identifier_pattern, format_identifier, find, get_variable, mark_as_modified, set_variable, check_mutable, copy, mark_constant, hash
local lua_functions
lua_functions = {
@ -173,18 +173,24 @@ lua_functions = {
["()(l::list, i::number)"] = {
mode = "unannotated raw",
value = function(l, i)
return l.value[i.value] or { type = "nil", value = nil }
local index = i.value
if index < 0 then index = #l.value + 1 + index end
if index > #l.value or index == 0 then return nil, "list index out of bounds" end
return l.value[index] or { type = "nil", value = nil }
end
},
["()(l::list, i::string)"] = {
mode = "unannotated raw",
["()(l::map, k)"] = {
mode = "raw",
value = function(l, i)
for _, v in ipairs(l.value) do
if v.type == "pair" and compare(v.value[1], i) then
return v.value[2]
end
local lv = l.type == "annotated" and l.value[1] or l
local h, err = hash(i)
if not h then return nil, err end
local v = lv.value[h]
if v then
return v[2]
else
return { type = "nil", value = nil }
end
return { type = "nil", value = nil }
end
},
-- index assignment
@ -194,30 +200,34 @@ lua_functions = {
local lv = l.type == "annotated" and l.value[1] or l
local iv = i.type == "annotated" and i.value[1] or i
if lv.constant then return nil, "can't change the contents of a constant list" end
lv.value[iv.value] = v
local index = iv.value
if index < 0 then index = #lv.value + 1 + index end
if index > #lv.value + 1 or index == 0 then return nil, "list assignment index out of bounds" end
lv.value[index] = v
mark_as_modified(anselme.running.state, lv.value)
return v
end
},
["()(l::list, k::string) := v"] = {
["()(l::map, k) := v::nil"] = {
mode = "raw",
value = function(l, k, v)
local lv = l.type == "annotated" and l.value[1] or l
local kv = k.type == "annotated" and k.value[1] or k
if lv.constant then return nil, "can't change the contents of a constant list" end
-- update index
for _, x in ipairs(lv.value) do
if x.type == "pair" and compare(x.value[1], kv) then
x.value[2] = v
mark_as_modified(anselme.running.state, x.value) -- FIXME i thought pairs were immutable...
return v
end
end
-- new index
table.insert(lv.value, {
type = "pair",
value = { kv, v }
})
if lv.constant then return nil, "can't change the contents of a constant map" end
local h, err = hash(k)
if not h then return nil, err end
lv.value[h] = nil
mark_as_modified(anselme.running.state, lv.value)
return v
end
},
["()(l::map, k) := v"] = {
mode = "raw",
value = function(l, k, v)
local lv = l.type == "annotated" and l.value[1] or l
if lv.constant then return nil, "can't change the contents of a constant map" end
local h, err = hash(k)
if not h then return nil, err end
lv.value[h] = { k, v }
mark_as_modified(anselme.running.state, lv.value)
return v
end
@ -435,7 +445,7 @@ local functions = {
package.loaded[...] = functions
local icommon = require((...):gsub("stdlib%.functions$", "interpreter.common"))
truthy, compare, is_of_type, get_variable, mark_as_modified, set_variable, check_mutable, mark_constant = icommon.truthy, icommon.compare, icommon.is_of_type, icommon.get_variable, icommon.mark_as_modified, icommon.set_variable, icommon.check_mutable, icommon.mark_constant
truthy, compare, is_of_type, get_variable, mark_as_modified, set_variable, check_mutable, mark_constant, hash = icommon.truthy, icommon.compare, icommon.is_of_type, icommon.get_variable, icommon.mark_as_modified, icommon.set_variable, icommon.check_mutable, icommon.mark_constant, icommon.hash
local pcommon = require((...):gsub("stdlib%.functions$", "parser.common"))
identifier_pattern, format_identifier, find = pcommon.identifier_pattern, pcommon.format_identifier, pcommon.find
anselme = require((...):gsub("stdlib%.functions$", "anselme"))

View file

@ -1,4 +1,4 @@
local format, to_lua, from_lua, events, anselme, escape
local format, to_lua, from_lua, events, anselme, escape, hash, mark_constant, update_hashes
local types = {}
types.lua = {
@ -36,7 +36,9 @@ types.lua = {
},
table = {
to_anselme = function(val)
local is_map = false
local l = {}
local m = {}
for _, v in ipairs(val) do
local r, e = from_lua(v)
if not r then return r, e end
@ -44,20 +46,33 @@ types.lua = {
end
for k, v in pairs(val) do
if not l[k] then
is_map = true
local kv, ke = from_lua(k)
if not k then return k, ke end
local vv, ve = from_lua(v)
if not v then return v, ve end
table.insert(l, {
type = "pair",
value = { kv, vv }
})
local h, err = hash(kv)
if not h then return nil, err end
m[h] = { kv, vv }
end
end
return {
type = "list",
value = l
}
if is_map then
for i, v in ipairs(l) do
local key = { type = "number", value = i }
local h, err = hash(key)
if not h then return nil, err end
m[h] = { key, v }
end
return {
type = "map",
value = m
}
else
return {
type = "list",
value = l
}
end
end
}
}
@ -69,7 +84,11 @@ types.anselme = {
end,
to_lua = function()
return nil
end
end,
hash = function()
return "nil()"
end,
mark_constant = function() end,
},
number = {
format = function(val)
@ -77,7 +96,11 @@ types.anselme = {
end,
to_lua = function(val)
return val
end
end,
hash = function(val)
return ("n(%s)"):format(val)
end,
mark_constant = function() end,
},
string = {
format = function(val)
@ -85,9 +108,14 @@ types.anselme = {
end,
to_lua = function(val)
return val
end
end,
hash = function(val)
return ("s(%s)"):format(val)
end,
mark_constant = function() end,
},
list = {
mutable = true,
format = function(val)
local l = {}
for _, v in ipairs(val) do
@ -99,25 +127,74 @@ types.anselme = {
end,
to_lua = function(val)
local l = {}
-- handle non-pair before pairs as LuaJIT's table.insert will always insert after the last element even if there are some nil before unlike PUC
for _, v in ipairs(val) do
if v.type ~= "pair" then
local s, e = to_lua(v)
if not s and e then return s, e end
table.insert(l, s)
end
end
for _, v in ipairs(val) do
if v.type == "pair" then
local k, ke = to_lua(v.value[1])
if not k and ke then return k, ke end
local x, xe = to_lua(v.value[2])
if not x and xe then return x, xe end
l[k] = x
end
local s, e = to_lua(v)
if not s and e then return s, e end
table.insert(l, s)
end
return l
end,
hash = function(val)
local l = {}
for _, v in ipairs(val) do
local s, e = hash(v)
if not s then return s, e end
table.insert(l, s)
end
return ("l(%s)"):format(table.concat(l, ","))
end,
mark_constant = function(v)
v.constant = true
for _, item in ipairs(v.value) do
mark_constant(item)
end
end
},
map = {
mutable = true,
format = function(val)
local l = {}
for _, v in pairs(val) do
local ks, ke = format(v[1])
if not ks then return ks, ke end
local vs, ve = format(v[2])
if not vs then return vs, ve end
table.insert(l, ("%s=%s"):format(ks, vs))
end
table.sort(l)
return ("{%s}"):format(table.concat(l, ", "))
end,
to_lua = function(val)
local l = {}
for _, v in pairs(val) do
local kl, ke = to_lua(v[1])
if not kl and ke then return kl, ke end
local xl, xe = to_lua(v[2])
if not xl and xe then return xl, xe end
l[kl] = xl
end
return l
end,
hash = function(val)
local l = {}
for _, v in pairs(val) do
local ks, ke = hash(v[1])
if not ks then return ks, ke end
local vs, ve = hash(v[2])
if not vs then return vs, ve end
table.insert(l, ("%s=%s"):format(ks, vs))
end
table.sort(l)
return ("m(%s)"):format(table.concat(l, ","))
end,
mark_constant = function(v)
v.constant = true
for _, val in pairs(v.value) do
mark_constant(val[1])
mark_constant(val[2])
end
update_hashes(v)
end,
},
pair = {
format = function(val)
@ -133,7 +210,18 @@ types.anselme = {
local v, ve = to_lua(val[2])
if not v and ve then return v, ve end
return { [k] = v }
end
end,
hash = function(val)
local k, ke = hash(val[1])
if not k then return k, ke end
local v, ve = hash(val[2])
if not v then return v, ve end
return ("p(%s=%s)"):format(k, v)
end,
mark_constant = function(v)
mark_constant(v.value[1])
mark_constant(v.value[2])
end,
},
annotated = {
format = function(val)
@ -147,7 +235,18 @@ types.anselme = {
local k, ke = to_lua(val[1])
if not k and ke then return k, ke end
return k
end
end,
hash = function(val)
local k, ke = hash(val[1])
if not k then return k, ke end
local v, ve = hash(val[2])
if not v then return v, ve end
return ("a(%s::%s)"):format(k, v)
end,
mark_constant = function(v)
mark_constant(v.value[1])
mark_constant(v.value[2])
end,
},
["function reference"] = {
format = function(val)
@ -157,27 +256,49 @@ types.anselme = {
return ("&%s"):format(table.concat(val, ", "))
end
end,
to_lua = nil
to_lua = nil,
hash = function(val)
return ("&f(%s)"):format(table.concat(val, ", "))
end,
mark_constant = function() end,
},
["variable reference"] = {
format = function(val)
return ("&%s"):format(val)
end,
to_lua = nil
to_lua = nil,
hash = function(val)
return ("&v(%s)"):format(val)
end,
mark_constant = function() end,
},
object = {
mutable = true,
format = function(val)
local attributes = {}
for name, v in pairs(val.attributes) do
table.insert(attributes, ("%s=%s"):format(name:gsub("^"..escape(val.class)..".", ""), format(v)))
end
if #attributes > 0 then
table.sort(attributes)
return ("%%%s(%s)"):format(val.class, table.concat(attributes, ", "))
else
return ("%%%s"):format(val.class)
end
end,
to_lua = nil
to_lua = nil,
hash = function(val)
local attributes = {}
for name, v in pairs(val.attributes) do
table.insert(attributes, ("%s=%s"):format(name:gsub("^"..escape(val.class)..".", ""), format(v)))
end
table.sort(attributes)
return ("%%(%s;%s)"):format(val.class, table.concat(attributes, ","))
end,
mark_constant = function(v)
v.constant = true
end,
},
-- internal types
["event buffer"] = {
@ -191,7 +312,7 @@ types.anselme = {
package.loaded[...] = types
local common = require((...):gsub("stdlib%.types$", "interpreter.common"))
format, to_lua, from_lua, events = common.format, common.to_lua, common.from_lua, common.events
format, to_lua, from_lua, events, hash, mark_constant, update_hashes = common.format, common.to_lua, common.from_lua, common.events, common.hash, common.mark_constant, common.update_hashes
anselme = require((...):gsub("stdlib%.types$", "anselme"))
escape = require((...):gsub("stdlib%.types$", "parser.common")).escape