1 --[[--------------------------------------------------------------------
3 Gazelle: a system for building fast, reusable parsers
7 Miscellaneous algorithms that don't belong anywhere else.
9 Copyright (c) 2007-2008 Joshua Haberman. See LICENSE for details.
11 --------------------------------------------------------------------]]--
13 function newobject(class
)
15 setmetatable(obj
, class
)
21 -- each(foo): returns an iterator; if the object supports the each method,
22 -- call that, otherwise return an iterator for a plain array.
23 function each(array_or_eachable_obj
)
24 if array_or_eachable_obj
.class
then
25 return array_or_eachable_obj
:each()
27 local array
= array_or_eachable_obj
31 if array
[i
] then return array
[i
] else return nil end
36 function table_shallow_eql(tbl1
, tbl2
)
37 for k
,v
in pairs(tbl1
) do
38 if tbl1
[k
] ~= tbl2
[k
] then return false end
40 for k
,v
in pairs(tbl2
) do
41 if tbl1
[k
] ~= tbl2
[k
] then return false end
46 function table_copy(t
, max_depth
)
48 for k
, v
in pairs(t
) do
49 if max_depth
> 1 and type(v
) == "table" then
50 v
= table_copy(v
, max_depth
- 1)
57 function table_shallow_copy(t
)
58 return table_copy(t
, 1)
62 function get_unique_table_for(val
)
63 local string_table
= {}
64 for entry
in each(val
) do table.insert(string_table
, tostring(entry
)) end
65 local str
= table.concat(string_table
, "\136")
66 if not cache
[str
] then
67 cache
[str
] = table_shallow_copy(val
)
72 -- traverses a graph of some sort -- caller provides a function that gives
73 -- children of the current node.
74 function breadth_first_traversal(obj
, children_func
)
75 local seen
= Set
:new
{obj
}
76 local queue
= Queue
:new(obj
)
77 while not queue
:isempty() do
78 local node
= queue
:dequeue()
79 children
= children_func(node
) or {}
80 for child_node
in each(children
) do
81 if seen
:contains(child_node
) == false then
83 queue
:enqueue(child_node
)
90 function depth_first_traversal(obj
, children_func
)
91 local seen
= Set
:new
{obj
}
92 local stack
= Stack
:new()
94 depth_first_traversal_helper(obj
, children_func
, stack
, seen
)
97 function depth_first_traversal_helper(obj
, children_func
, stack
, seen
)
98 children
= children_func(obj
, stack
) or {}
99 for child
in each(children
) do
100 if not seen
:contains(child
) then
103 depth_first_traversal_helper(child
, children_func
, stack
, seen
)
109 -- all ints within each IntSet are assumed to be equivalent.
110 -- Given this, return a new list of IntSets, where each IntSet
111 -- returned is considered equivalent across ALL IntSets.
112 function equivalence_classes(int_sets
)
117 for int_set
in each(int_sets
) do
118 if int_set
.negated
then int_set
= int_set
:invert() end
119 for range
in each(int_set
.list
) do
120 table.insert(events
, {range
.low
, BEGIN
, int_set
})
121 table.insert(events
, {range
.high
+1, END
, int_set
})
125 local cmp_events
= function(a
, b
)
127 return b
[2] < a
[2] -- END events should go before BEGIN events
133 table.sort(events
, cmp_events
)
135 local nested_regions
= Set
:new()
136 local last_offset
= nil
138 for event
in each(events
) do
139 local offset
, event_type
, int_set
= unpack(event
)
141 if last_offset
and last_offset
< offset
and (not nested_regions
:isempty()) then
142 local hk
= nested_regions
:hash_key()
143 classes
[hk
] = classes
[hk
] or IntSet
:new()
144 classes
[hk
]:add(Range
:new(last_offset
, offset
-1))
147 if event_type
== BEGIN
then
148 nested_regions
:add(int_set
)
150 nested_regions
:remove(int_set
)
156 for hk
, int_set
in pairs(classes
) do
157 table.insert(ret
, int_set
)
162 function str_join(list
, separator
)
164 for i
, string in ipairs(list
) do
167 str
= str
.. separator