-
Notifications
You must be signed in to change notification settings - Fork 1
/
optimizers.go
109 lines (93 loc) · 2.51 KB
/
optimizers.go
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
package kowhai
import "strings"
type ParseTreeOptimizer interface {
Preprocess(node *ParseTreeNode) *ParseTreeNode
Postprocess(node *ParseTreeNode) *ParseTreeNode
}
// This optimization can be used to remove intermediate nodes that have
// only a single child.
type TrimWhenSingle struct {
AppliesTo []string
}
func (o TrimWhenSingle) Preprocess(node *ParseTreeNode) *ParseTreeNode {
return node
}
func (o TrimWhenSingle) Postprocess(node *ParseTreeNode) *ParseTreeNode {
if len(node.Children) != 1 {
return node
}
if node.Term.IsRule() {
r := node.Term.(*Rule)
if r == nil {
return node
}
for _, a := range o.AppliesTo {
if a == r.String() {
node.Children[0].Parent = node.Parent
return node.Children[0]
}
}
}
return node
}
// The optimization removes parse nodes thar derive from rules
// that were created by the grammar operators (+, ?, *, |)
type RemoveSyntheticNodes struct {
}
func (o RemoveSyntheticNodes) Preprocess(node *ParseTreeNode) *ParseTreeNode {
return node
}
func (o RemoveSyntheticNodes) Postprocess(node *ParseTreeNode) *ParseTreeNode {
if len(node.Children) == 0 {
return node
}
node.Children = o.GetNaturalChildren(node)
return node
}
func (o RemoveSyntheticNodes) GetNaturalChildren(node *ParseTreeNode) (children []*ParseTreeNode) {
for _, c := range node.Children {
if c.Term.IsRule() {
r := c.Term.(*Rule)
if r == nil {
children = append(children, c)
continue
}
if strings.HasPrefix(r.name, "OR_") || strings.HasPrefix(r.name, "STAR_") || strings.HasPrefix(r.name, "OPT_") || strings.HasPrefix(r.name, "PLUS_") {
for _, rp := range c.Children {
rp.Parent = node
}
children = append(children, o.GetNaturalChildren(c)...)
continue
}
}
children = append(children, c)
}
return
}
// This optimization handles child nodes that overlap (due to partial parse trees)
// Generally applying this optimization makes the resulting parse tree easier to understand
type OverlappingChildren struct {
}
func (o OverlappingChildren) Preprocess(node *ParseTreeNode) *ParseTreeNode {
if len(node.Children) < 2 {
return node
}
curr := node.Children[0]
for _, c := range node.Children[1:] {
if c.Overlaps(curr) {
for _, rp := range curr.Children {
rp.Parent = c
}
c.Children = append(curr.Children, c.Children...)
curr.Children = nil
}
curr = c
}
return node
}
func (o OverlappingChildren) Postprocess(node *ParseTreeNode) *ParseTreeNode {
if node.Term.IsRule() && node.Children == nil {
return nil
}
return node
}