require 'spec_helper'
RSpec.describe('Conditional parsing') do
specify('parse conditional') do
regexp = /(?a)(?()T|F)/
root = RP.parse(regexp, 'ruby/2.0')
exp = root[1]
expect(exp).to be_a(Conditional::Expression)
expect(exp.type).to eq :conditional
expect(exp.token).to eq :open
expect(exp.to_s).to eq '(?()T|F)'
expect(exp.reference).to eq 'A'
end
specify('parse conditional condition') do
regexp = /(?a)(?()T|F)/
root = RP.parse(regexp, 'ruby/2.0')
exp = root[1].condition
expect(exp).to be_a(Conditional::Condition)
expect(exp.type).to eq :conditional
expect(exp.token).to eq :condition
expect(exp.to_s).to eq '()'
expect(exp.reference).to eq 'A'
expect(exp.referenced_expression.to_s).to eq '(?a)'
end
specify('parse conditional condition with number ref') do
regexp = /(a)(?(1)T|F)/
root = RP.parse(regexp, 'ruby/2.0')
exp = root[1].condition
expect(exp).to be_a(Conditional::Condition)
expect(exp.type).to eq :conditional
expect(exp.token).to eq :condition
expect(exp.to_s).to eq '(1)'
expect(exp.reference).to eq 1
expect(exp.referenced_expression.to_s).to eq '(a)'
end
specify('parse conditional nested groups') do
regexp = /((a)|(b)|((?(2)(c(d|e)+)?|(?(3)f|(?(4)(g|(h)(i)))))))/
root = RP.parse(regexp, 'ruby/2.0')
expect(root.to_s).to eq regexp.source
group = root.first
expect(group).to be_instance_of(Group::Capture)
alt = group.first
expect(alt).to be_instance_of(Alternation)
expect(alt.length).to eq 3
expect(alt.map(&:first)).to all(be_a Group::Capture)
subgroup = alt[2].first
conditional = subgroup.first
expect(conditional).to be_instance_of(Conditional::Expression)
expect(conditional.length).to eq 3
expect(conditional[0]).to be_instance_of(Conditional::Condition)
expect(conditional[0].to_s).to eq '(2)'
condition = conditional.condition
expect(condition).to be_instance_of(Conditional::Condition)
expect(condition.to_s).to eq '(2)'
branches = conditional.branches
expect(branches.length).to eq 2
expect(branches).to be_instance_of(Array)
end
specify('parse conditional nested') do
regexp = /(a(b(c(d)(e))))(?(1)(?(2)d|(?(3)e|f))|(?(4)(?(5)g|h)))/
root = RP.parse(regexp, 'ruby/2.0')
expect(root.to_s).to eq regexp.source
{
1 => [2, root[1]],
2 => [2, root[1][1][0]],
3 => [2, root[1][1][0][2][0]],
4 => [1, root[1][2][0]],
5 => [2, root[1][2][0][1][0]]
}.each do |index, example|
branch_count, exp = example
expect(exp).to be_instance_of(Conditional::Expression)
expect(exp.condition.to_s).to eq "(#{index})"
expect(exp.branches.length).to eq branch_count
end
end
specify('parse conditional nested alternation') do
regexp = /(a)(?(1)(b|c|d)|(e|f|g))(h)(?(2)(i|j|k)|(l|m|n))|o|p/
root = RP.parse(regexp, 'ruby/2.0')
expect(root.to_s).to eq regexp.source
expect(root.first).to be_instance_of(Alternation)
[
[3, 'b|c|d', root[0][0][1][1][0][0]],
[3, 'e|f|g', root[0][0][1][2][0][0]],
[3, 'i|j|k', root[0][0][3][1][0][0]],
[3, 'l|m|n', root[0][0][3][2][0][0]]
].each do |example|
alt_count, alt_text, exp = example
expect(exp).to be_instance_of(Alternation)
expect(exp.to_s).to eq alt_text
expect(exp.alternatives.length).to eq alt_count
end
end
specify('parse conditional extra separator') do
regexp = /(?a)(?()T|)/
root = RP.parse(regexp, 'ruby/2.0')
branches = root[1].branches
expect(branches.length).to eq 2
seq_1, seq_2 = branches
[seq_1, seq_2].each do |seq|
expect(seq).to be_a(Sequence)
expect(seq.type).to eq :expression
expect(seq.token).to eq :sequence
end
expect(seq_1.to_s).to eq 'T'
expect(seq_2.to_s).to eq ''
end
specify('parse conditional quantified') do
regexp = /(foo)(?(1)\d|(\w)){42}/
root = RP.parse(regexp, 'ruby/2.0')
conditional = root[1]
expect(conditional).to be_quantified
expect(conditional.quantifier.to_s).to eq '{42}'
expect(conditional.to_s).to eq '(?(1)\\d|(\\w)){42}'
expect(conditional.branches.any?(&:quantified?)).to be false
end
specify('parse conditional branch content quantified') do
regexp = /(foo)(?(1)\d{23}|(\w){42})/
root = RP.parse(regexp, 'ruby/2.0')
conditional = root[1]
expect(conditional).not_to be_quantified
expect(conditional.branches.any?(&:quantified?)).to be false
expect(conditional.branches[0][0]).to be_quantified
expect(conditional.branches[0][0].quantifier.to_s).to eq '{23}'
expect(conditional.branches[1][0]).to be_quantified
expect(conditional.branches[1][0].quantifier.to_s).to eq '{42}'
end
specify('parse conditional excessive branches') do
regexp = '(?a)(?()T|F|X)'
expect { RP.parse(regexp, 'ruby/2.0') }.to raise_error(Conditional::TooManyBranches)
end
end