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:
parent
bac5cdde01
commit
95462391e3
20 changed files with 699 additions and 139 deletions
|
|
@ -5,6 +5,7 @@ return [[
|
|||
:number="number"
|
||||
:string="string"
|
||||
:list="list"
|
||||
:map="map"
|
||||
:pair="pair"
|
||||
:function reference="function reference"
|
||||
:variable reference="variable reference"
|
||||
|
|
|
|||
|
|
@ -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"))
|
||||
|
|
|
|||
187
stdlib/types.lua
187
stdlib/types.lua
|
|
@ -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
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue