-
Notifications
You must be signed in to change notification settings - Fork 0
/
Tree.lua
130 lines (108 loc) · 2.33 KB
/
Tree.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
local Tree = torch.class("Tree")
function bracketTokenizer(s, f)
local pos = 1
while pos < (#s+1) do
local ch = s:sub(pos, pos)
if ch == '(' then
pos = pos + 1
f(ch)
elseif ch == ')' then
pos = pos + 1
f(ch)
elseif ch == ' ' then
pos = pos + 1
else
local start = pos
repeat
pos = pos + 1
ch = s:sub(pos, pos)
until pos >= (#s+1) or ch == ' ' or ch == '(' or ch == ')'
f(s:sub(start, pos-1))
end
end
f(nil)
end
function parseTree(tokenizer, createFn, dict)
repeat
tok = tokenizer()
if tok == '(' then
local name = tokenizer()
local tree = createFn(name)
tree.value = dict[name]
repeat
local child = parseTree(tokenizer, createFn, dict)
if child ~= nil then
tree:addChild(child)
end
until child == nil
return tree
elseif tok == ')' then
return nil
else
local tree = createFn(tok)
tree.value = dict[tok]
return tree
end
until tok == nil
end
function Tree:__init(name)
self.name = name
self.value = nil
self.children = {}
self.parent = nil
end
function Tree:addChild(child)
table.insert(self.children, child)
child.parent = self
end
function Tree:isLeaf(child)
return #self.children == 0
end
function Tree:filter(fn)
local results = {fn(self)}
for _, child in ipairs(self.children) do
local subtree = child:filter(fn)
for k, v in ipairs(subtree) do
table.insert(results, v)
end
end
return results
end
function Tree:apply(fn)
fn(self)
for _, child in ipairs(self.children) do
child:apply(fn)
end
end
function Tree:copy()
local treecopy = Tree.new(self.name)
for i, child in ipairs(self.children) do
local subcopy = child:copy()
treecopy:addChild(subcopy)
end
return treecopy
end
function Tree.parse(s, dict)
local tokenizer = coroutine.wrap(function () bracketTokenizer(s, coroutine.yield) end)
dict = dict or {}
return parseTree(tokenizer, Tree.new, dict)
end
function Tree:describe()
local result = nil
result = "(" .. self.name
for i, child in ipairs(self.children) do
if child:isLeaf() then
result = result .. " " .. child.name
else
result = result .. " " .. child:describe()
end
end
result = result .. ")"
return result
end
function Tree:__tostring__()
return self:describe()
end
-- local s = "(S (NP the dog) (VP attacks (NP the cat)))"
-- local tree = Tree.parse(s)
-- print(tree)