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
|
# File 'lib/arugula/parser.rb', line 28
def consume
tok = pattern.slice!(0)
peek = pattern.chr
if tok.nil?
fail 'shouldnt happen'
elsif tok == '[' && !characterclass_type?
push_part(:characterclass)
elsif tok == '-' &&
characterclass_type? &&
state.parts.last.class.type == :literal &&
peek != ']'
literal = state.parts.pop
push_part(:range, literal.literal, peek)
pattern.slice!(0)
elsif tok == ']' && characterclass_type?
pop_part
elsif tok == '^' && characterclass_type? && state.parts.empty?
characterclass_part = pop_part
wrap_state(:not)
@states << characterclass_part
elsif tok == '$'
push_part(:eol)
elsif tok == '^'
push_part(:sol)
elsif tok == '\\'
tok = pattern.slice!(0)
case tok
when nil
fail 'unterminated escape sequence'
when *MetacharacterPart::MATCHERS.keys.map(&:to_s)
push_part(:metacharacter, tok)
else
push_part(:literal, tok)
end
elsif characterclass_type?
push_part(:literal, tok)
elsif tok == '('
push_capture
elsif tok == ')'
pop_part until capture_type?
pop_part
elsif tok == '|'
pop_part until state == @states.first || or_type? || capture_type?
wrap_state(:or) unless or_type?
push_part(:and)
elsif tok == '.'
push_part(:dot)
elsif tok == '*'
wrap_state(:star)
elsif tok == '+'
wrap_state(:plus)
elsif tok == '?'
wrap_state(:question)
elsif tok == '{'
before_comma = ''
after_comma = ''
until pattern.chr == ',' || pattern.chr == '}'
before_comma << pattern.slice!(0)
end
if pattern.chr == ','
pattern.slice!(0)
else
after_comma = before_comma
end
after_comma << pattern.slice!(0) until pattern.chr == '}'
pattern.slice!(0) if pattern.chr == '}'
before = before_comma.empty? ? 0 : before_comma.to_i
after = after_comma.empty? ? Float::INFINITY : after_comma.to_i
wrap_state(:quantifier, before, after)
else
push_part(:literal, tok)
end
end
|