-
-
Notifications
You must be signed in to change notification settings - Fork 25
/
Copy pathbuild_syntax_trie.rb
105 lines (81 loc) · 3.06 KB
/
build_syntax_trie.rb
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
module SnippetExtractor
module Extended
class BuildSyntaxTrie
include Mandate
initialize_with :rules
def call
trie = SyntaxTrie.new(Node.new({}, "", nil))
rules.each { |rule| add_rule(trie, rule) }
trie
end
def add_rule(trie, rule)
word = get_word_from_rule(rule)
set_next_node(trie.root, word, rule)
end
def get_word_from_rule(rule)
rule = rule.start_rule if rule.is_a? MultilineRule
rule.whole_word? ? " #{rule.word} " : rule.word
end
def set_next_node(node, word, rule)
return handle_rule_placement(node, rule) if word.empty?
handle_next_node(node, word, rule)
end
def handle_next_node(node, word, rule)
next_letter, next_node_type = get_info_for_next_node(word)
if next_node_type == RepeatNode && node.word.strip.empty?
raise "Mapping conflict: Trying to map #{rule} which has a repeating character before any character"
end
if node.mapping.key?(next_letter)
unless node.mapping[next_letter].instance_of?(next_node_type)
raise "Mapping conflict: #{node.word} and #{rule} have conflicting repeating rule on char #{next_letter}"
end
else
node.mapping[next_letter] = next_node_type.new({}, node.word + next_letter, nil)
end
set_next_node(node.mapping[next_letter], word[1..], rule)
end
def get_info_for_next_node(word)
next_letter = word[0]
next_node_type = next_letter == REPITITION_MODIFIER ? RepeatNode : Node
[next_letter, next_node_type]
end
def handle_rule_placement(node, rule)
return set_rule(node, rule) unless node.action
unless are_compatible?(node.action, rule)
raise "Mapping conflict: #{node.word} has action #{node.action}, but #{rule} tries to overwrite it"
end
merge_rule(node, rule)
end
def are_compatible?(action, rule)
case rule
when MultilineRule then multilines_compatible?(action, rule)
when SimpleRule then single_lines_compatible?(action, rule)
end
end
def multilines_compatible?(action, rule)
rule.is_a?(MultilineRule) && action.is_a?(Multi) && action.start_action == get_action_from(rule.start_rule)
end
def single_lines_compatible?(action, rule)
action == get_action_from(rule)
end
def set_rule(node, rule)
node.action = get_action_from(rule)
end
def merge_rule(node, rule)
# We only merge compatible multiline rules. Simple rules are only mergeable if they are the same
add_rule(node.action.syntax_trie, rule.end_rule) if node.action.is_a?(Multi)
end
def get_action_from(rule)
case rule
when MultilineRule then Multi.new(get_action_from(rule.start_rule), BuildSyntaxTrie.([rule.end_rule]))
when SimpleRule
if rule.skip_line?
Line.new(rule.word)
else
Just.new(rule.word)
end
end
end
end
end
end