diff options
Diffstat (limited to 'containers.moon')
| -rw-r--r-- | containers.moon | 99 |
1 files changed, 99 insertions, 0 deletions
diff --git a/containers.moon b/containers.moon new file mode 100644 index 0000000..deb5684 --- /dev/null +++ b/containers.moon @@ -0,0 +1,99 @@ +-- This file contains container classes, i.e. Lists, Dicts, and Sets +{:insert,:remove,:concat} = table +{:repr, :stringify, :equivalent, :nth_to_last, :size} = require 'utils' + +local list, dict + +-- List and Dict classes to provide basic equality/tostring functionality for the tables +-- used in Nomsu. This way, they retain a notion of whether they were originally lists or dicts. +_list_mt = + __eq:equivalent + -- Could consider adding a __newindex to enforce list-ness, but would hurt performance + __tostring: => + "["..concat([repr(b) for b in *@], ", ").."]" + __lt: (other)=> + assert type(@) == 'table' and type(other) == 'table', "Incompatible types for comparison" + for i=1,math.max(#@, #other) + if not @[i] and other[i] then return true + elseif @[i] and not other[i] then return false + elseif @[i] < other[i] then return true + elseif @[i] > other[i] then return false + return false + __le: (other)=> + assert type(@) == 'table' and type(other) == 'table', "Incompatible types for comparison" + for i=1,math.max(#@, #other) + if not @[i] and other[i] then return true + elseif @[i] and not other[i] then return false + elseif @[i] < other[i] then return true + elseif @[i] > other[i] then return false + return true + __add: (other)=> + ret = list[x for x in *@] + for x in *other + insert(ret, x) + return ret + __index: + add_1: insert, append_1: insert + add_1_at_index_2: (t,x,i)-> insert(t,i,x) + at_index_1_add_2: insert + pop: remove, remove_last: remove, remove_index_1: remove + last: (=> @[#@]), first: (=> @[1]) + _1_st_to_last:nth_to_last, _1_nd_to_last:nth_to_last + _1_rd_to_last:nth_to_last, _1_th_to_last:nth_to_last + has_1: (item)=> + for x in *@ + if x == item + return true + return false + index_of_1: (item)=> + for i,x in ipairs @ + if x == item + return i + return nil + +list = (t)-> setmetatable(t, _list_mt) + +walk_items = (i)=> + i = i + 1 + k, v = next(@table, @key) + if k != nil + @key = k + return i, dict{key:k, value:v} + +_dict_mt = + __eq:equivalent + __len:size + __tostring: => + "{"..concat(["#{repr(k)}: #{repr(v)}" for k,v in pairs @], ", ").."}" + __ipairs: => walk_items, {table:@, key:nil}, 0 + __band: (other)=> + dict{k,v for k,v in pairs(@) when other[k] != nil} + __bor: (other)=> + ret = {k,v for k,v in pairs(@)} + for k,v in pairs(other) + if ret[k] == nil then ret[k] = v + return dict(ret) + __bxor: (other)=> + ret = {k,v for k,v in pairs(@)} + for k,v in pairs(other) + if ret[k] == nil then ret[k] = v + else ret[k] = nil + return dict(ret) + __add: (other)=> + ret = {k,v for k,v in pairs(@)} + for k,v in pairs(other) + if ret[k] == nil then ret[k] = v + else ret[k] += v + return dict(ret) + __sub: (other)=> + ret = {k,v for k,v in pairs(@)} + for k,v in pairs(other) + if ret[k] == nil then ret[k] = -v + else ret[k] -= v + return dict(ret) +dict = (t)-> setmetatable(t, _dict_mt) + +for i,entry in ipairs(dict({x:99})) + assert(i == 1 and entry.key == "x" and entry.value == 99, "ipairs compatibility issue") + +return {:list, :dict} |
