1 --[[--------------------------------------------------------------------
5 Miscellaneous algorithms that don't belong anywhere else.
7 --------------------------------------------------------------------]]--
9 function newobject(class
)
11 setmetatable(obj
, class
)
17 -- each(foo): returns an iterator; if the object supports the each method,
18 -- call that, otherwise return an iterator for a plain array.
19 function each(array_or_eachable_obj
)
20 if array_or_eachable_obj
.class
then
21 return array_or_eachable_obj
:each()
23 local array
= array_or_eachable_obj
27 if array
[i
] then return array
[i
] else return nil end
32 function table_shallow_eql(tbl1
, tbl2
)
33 for k
,v
in pairs(tbl1
) do
34 if tbl1
[k
] ~= tbl2
[k
] then return false end
36 for k
,v
in pairs(tbl2
) do
37 if tbl1
[k
] ~= tbl2
[k
] then return false end
42 -- traverses a graph of some sort -- caller provides a function that gives
43 -- children of the current node.
44 function breadth_first_traversal(obj
, children_func
)
45 local seen
= Set
:new
{obj
}
46 local queue
= Queue
:new(obj
)
47 while not queue
:isempty() do
48 local node
= queue
:dequeue()
49 children
= children_func(node
) or {}
50 for child_node
in each(children
) do
51 if seen
:contains(child_node
) == false then
53 queue
:enqueue(child_node
)
60 function depth_first_traversal(obj
, children_func
)
61 local seen
= Set
:new
{obj
}
62 local stack
= Stack
:new()
64 depth_first_traversal_helper(obj
, children_func
, stack
, seen
)
67 function depth_first_traversal_helper(obj
, children_func
, stack
, seen
)
68 children
= children_func(obj
, stack
) or {}
69 for child
in each(children
) do
70 if seen
:contains(child
) then
71 error("You gave me a left-recursive grammar you bastard! Obj: " .. serialize(obj
) .. ", Child: " .. serialize(child
) .. ", Stack:" .. serialize(stack
:to_array()))
72 elseif seen
:contains(child
) == false then
75 depth_first_traversal_helper(child
, children_func
, stack
, seen
)
81 -- all ints within each IntSet are assumed to be equivalent.
82 -- Given this, return a new list of IntSets, where each IntSet
83 -- returned is considered equivalent across ALL IntSets.
84 function equivalence_classes(int_sets
)
89 for int_set
in each(int_sets
) do
90 if int_set
.negated
then int_set
= int_set
:invert() end
91 for range
in each(int_set
.list
) do
92 table.insert(events
, {range
.low
, BEGIN
, int_set
})
93 table.insert(events
, {range
.high
+1, END
, int_set
})
97 local cmp_events
= function(a
, b
)
99 return b
[2] < a
[2] -- END events should go before BEGIN events
105 table.sort(events
, cmp_events
)
107 local nested_regions
= Set
:new()
108 local last_offset
= nil
110 for event
in each(events
) do
111 local offset
, event_type
, int_set
= unpack(event
)
113 if last_offset
and last_offset
< offset
and (not nested_regions
:isempty()) then
114 local hk
= nested_regions
:hash_key()
115 classes
[hk
] = classes
[hk
] or IntSet
:new()
116 classes
[hk
]:add(Range
:new(last_offset
, offset
-1))
119 if event_type
== BEGIN
then
120 nested_regions
:add(int_set
)
122 nested_regions
:remove(int_set
)
128 for hk
, int_set
in pairs(classes
) do
129 table.insert(ret
, int_set
)
134 function str_join(list
, separator
)
136 for i
, string in ipairs(list
) do
139 str
= str
.. separator