Module: CommandSearch::Parser

Defined in:
lib/command_search/parser.rb

Class Method Summary collapse

Class Method Details

.clean!(ast) ⇒ Object



104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
# File 'lib/command_search/parser.rb', line 104

def clean!(ast)
  return unless ast.any?
  if ast[0][:type] == :colon || ast[0][:type] == :compare
    r_merge!(ast, 0)
  end
  if ast[-1][:type] == :colon || ast[-1][:type] == :compare
    l_merge!(ast, ast.length - 1)
  end
  i = 1
  while i < ast.length - 1
    next i += 1 unless ast[i][:type] == :colon || ast[i][:type] == :compare
    if ast[i + 1][:type] == :minus
      r_merge!(ast, i + 1)
    elsif ![:str, :number, :quote].include?(ast[i - 1][:type])
      r_merge!(ast, i)
    elsif ![:str, :number, :quote].include?(ast[i + 1][:type])
      l_merge!(ast, i)
    else
      i += 1
    end
  end
end

.cluster_cmds!(ast) ⇒ Object



29
30
31
32
33
34
35
36
37
38
39
40
# File 'lib/command_search/parser.rb', line 29

def cluster_cmds!(ast)
  i = 1
  while i < ast.length - 1
    type = ast[i][:type]
    next i += 1 unless type == :colon || type == :compare
    ast[(i - 1)..(i + 1)] = {
      type: type,
      nest_op: ast[i][:value],
      value: [ast[i - 1], ast[i + 1]]
    }
  end
end

.cluster_not!(ast) ⇒ Object



61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
# File 'lib/command_search/parser.rb', line 61

def cluster_not!(ast)
  i = ast.length
  while i > 0
    i -= 1
    type = ast[i][:type]
    cluster_not!(ast[i][:value]) if type == :and
    next unless type == :minus
    if i == ast.length - 1
      ast.delete_at(i)
      next
    end
    ast[i][:type] = :not
    ast[i][:value] = [ast[i + 1]]
    ast.delete_at(i + 1)
  end
end

.cluster_or!(ast) ⇒ Object



42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# File 'lib/command_search/parser.rb', line 42

def cluster_or!(ast)
  i = 0
  while i < ast.length
    type = ast[i][:type]
    cluster_or!(ast[i][:value]) if type == :and || type == :not
    next i += 1 unless type == :pipe
    if i == 0 || i == ast.length - 1
      ast.delete_at(i)
      next
    end
    val = [ast[i - 1], ast[i + 1]]
    cluster_or!(val)
    ast[i][:type] = :or
    ast[i][:value] = val
    ast.delete_at(i + 1)
    ast.delete_at(i - 1)
  end
end

.group_parens!(ast) ⇒ Object



5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# File 'lib/command_search/parser.rb', line 5

def group_parens!(ast)
  i = 0
  opening_idxs = []
  while i < ast.length
    next i += 1 unless ast[i][:type] == :paren
    if ast[i][:value] == '('
      opening_idxs.push(i)
      ast.delete_at(i)
      next
    end
    ast.delete_at(i)
    opening = opening_idxs.pop()
    next unless opening
    val = ast.slice(opening, i - opening)
    if val.count > 1
      ast[opening..(i - 1)] = { type: :and, value: val }
      i -= val.length
      next
    elsif val.count == 1
      ast[opening] = val.first
    end
  end
end

.l_merge!(ast, i) ⇒ Object



97
98
99
100
101
102
# File 'lib/command_search/parser.rb', line 97

def l_merge!(ast, i)
  ast[i][:type] = :str
  return unless ast[i - 1] && ast[i - 1][:type] == :str
  ast[i][:value] = ast[i - 1][:value] + ast[i][:value]
  ast.delete_at(i - 1)
end

.parse!(ast) ⇒ Object



127
128
129
130
131
132
133
134
135
# File 'lib/command_search/parser.rb', line 127

def parse!(ast)
  clean!(ast)
  unchain!(ast)
  cluster_cmds!(ast)
  group_parens!(ast)
  cluster_not!(ast)
  cluster_or!(ast)
  ast
end

.r_merge!(ast, i) ⇒ Object



90
91
92
93
94
95
# File 'lib/command_search/parser.rb', line 90

def r_merge!(ast, i)
  ast[i][:type] = :str
  return unless ast[i + 1] && ast[i + 1][:type] == :str
  ast[i][:value] = ast[i][:value] + ast[i + 1][:value]
  ast.delete_at(i + 1)
end

.unchain!(ast) ⇒ Object



78
79
80
81
82
83
84
85
86
87
88
# File 'lib/command_search/parser.rb', line 78

def unchain!(ast)
  i = 1
  while i < ast.length - 3
    left = ast[i][:type]
    right = ast[i + 2][:type]
    i += 1
    next unless left == :colon || left == :compare
    next unless right == :colon || right == :compare
    ast.insert(i, ast[i].clone())
  end
end