/
builder.rb
65 lines (53 loc) · 1.81 KB
/
builder.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
# frozen_string_literal: true
module RuboCop
module AST
class NodePattern
# Responsible to build the AST nodes for `NodePattern`
#
# Doc on how this fits in the compiling process:
# /doc/modules/ROOT/pages/node_pattern.md
class Builder
def emit_capture(capture_token, node)
return node if capture_token.nil?
emit_unary_op(:capture, capture_token, node)
end
def emit_atom(type, value)
n(type, [value])
end
def emit_unary_op(type, _operator = nil, *children)
n(type, children)
end
def emit_list(type, _begin, children, _end)
n(type, children)
end
def emit_call(type, selector, args = nil)
_begin_t, arg_nodes, _end_t = args
n(type, [selector, *arg_nodes])
end
def emit_union(begin_t, pattern_lists, end_t)
if pattern_lists.size == 1 # {a b c} => [[a, b, c]] => [a, b, c]
children = pattern_lists.first
raise NodePattern::Invalid, 'A union can not be empty' if children.empty?
else # { a b | c } => [[a, b], [c]] => [s(:subsequence, a, b), c]
children = pattern_lists.map do |list|
emit_subsequence(list)
end
end
type = set_optimizable?(children) ? :set : :union
emit_list(type, begin_t, children, end_t)
end
def emit_subsequence(node_list)
return node_list.first if node_list.size == 1 # Don't put a single child in a subsequence
emit_list(:subsequence, nil, node_list, nil)
end
private
def set_optimizable?(children)
children.all?(&:literal?)
end
def n(type, *args)
Node::MAP[type].new(type, *args)
end
end
end
end
end