151 lines
4.7 KiB
Ruby
151 lines
4.7 KiB
Ruby
require 'spec_helper'
|
|
require 'dentaku/token'
|
|
require 'dentaku/parser'
|
|
|
|
describe Dentaku::Parser do
|
|
it 'is constructed from a token' do
|
|
token = Dentaku::Token.new(:numeric, 5)
|
|
node = described_class.new([token]).parse
|
|
expect(node.value).to eq 5
|
|
end
|
|
|
|
it 'performs simple addition' do
|
|
five = Dentaku::Token.new(:numeric, 5)
|
|
plus = Dentaku::Token.new(:operator, :add)
|
|
four = Dentaku::Token.new(:numeric, 4)
|
|
|
|
node = described_class.new([five, plus, four]).parse
|
|
expect(node.value).to eq 9
|
|
end
|
|
|
|
it 'compares two numbers' do
|
|
five = Dentaku::Token.new(:numeric, 5)
|
|
lt = Dentaku::Token.new(:comparator, :lt)
|
|
four = Dentaku::Token.new(:numeric, 4)
|
|
|
|
node = described_class.new([five, lt, four]).parse
|
|
expect(node.value).to eq false
|
|
end
|
|
|
|
it 'calculates unary percentage' do
|
|
five = Dentaku::Token.new(:numeric, 5)
|
|
mod = Dentaku::Token.new(:operator, :mod)
|
|
|
|
node = described_class.new([five, mod]).parse
|
|
expect(node.value).to eq 0.05
|
|
end
|
|
|
|
it 'performs multiple operations in one stream' do
|
|
five = Dentaku::Token.new(:numeric, 5)
|
|
plus = Dentaku::Token.new(:operator, :add)
|
|
four = Dentaku::Token.new(:numeric, 4)
|
|
times = Dentaku::Token.new(:operator, :multiply)
|
|
three = Dentaku::Token.new(:numeric, 3)
|
|
|
|
node = described_class.new([five, plus, four, times, three]).parse
|
|
expect(node.value).to eq 17
|
|
end
|
|
|
|
it 'respects order of operations' do
|
|
five = Dentaku::Token.new(:numeric, 5)
|
|
times = Dentaku::Token.new(:operator, :multiply)
|
|
four = Dentaku::Token.new(:numeric, 4)
|
|
plus = Dentaku::Token.new(:operator, :add)
|
|
three = Dentaku::Token.new(:numeric, 3)
|
|
|
|
node = described_class.new([five, times, four, plus, three]).parse
|
|
expect(node.value).to eq 23
|
|
end
|
|
|
|
it 'respects grouping by parenthesis' do
|
|
lpar = Dentaku::Token.new(:grouping, :open)
|
|
five = Dentaku::Token.new(:numeric, 5)
|
|
plus = Dentaku::Token.new(:operator, :add)
|
|
four = Dentaku::Token.new(:numeric, 4)
|
|
rpar = Dentaku::Token.new(:grouping, :close)
|
|
times = Dentaku::Token.new(:operator, :multiply)
|
|
three = Dentaku::Token.new(:numeric, 3)
|
|
|
|
node = described_class.new([lpar, five, plus, four, rpar, times, three]).parse
|
|
expect(node.value).to eq 27
|
|
end
|
|
|
|
it 'evaluates functions' do
|
|
fn = Dentaku::Token.new(:function, :if)
|
|
fopen = Dentaku::Token.new(:grouping, :open)
|
|
five = Dentaku::Token.new(:numeric, 5)
|
|
lt = Dentaku::Token.new(:comparator, :lt)
|
|
four = Dentaku::Token.new(:numeric, 4)
|
|
comma = Dentaku::Token.new(:grouping, :comma)
|
|
three = Dentaku::Token.new(:numeric, 3)
|
|
two = Dentaku::Token.new(:numeric, 2)
|
|
rpar = Dentaku::Token.new(:grouping, :close)
|
|
|
|
node = described_class.new([fn, fopen, five, lt, four, comma, three, comma, two, rpar]).parse
|
|
expect(node.value).to eq 2
|
|
end
|
|
|
|
it 'represents formulas with variables' do
|
|
five = Dentaku::Token.new(:numeric, 5)
|
|
times = Dentaku::Token.new(:operator, :multiply)
|
|
x = Dentaku::Token.new(:identifier, :x)
|
|
|
|
node = described_class.new([five, times, x]).parse
|
|
expect { node.value }.to raise_error(Dentaku::UnboundVariableError)
|
|
expect(node.value(x: 3)).to eq 15
|
|
end
|
|
|
|
it 'evaluates boolean expressions' do
|
|
d_true = Dentaku::Token.new(:logical, true)
|
|
d_and = Dentaku::Token.new(:combinator, :and)
|
|
d_false = Dentaku::Token.new(:logical, false)
|
|
|
|
node = described_class.new([d_true, d_and, d_false]).parse
|
|
expect(node.value).to eq false
|
|
end
|
|
|
|
it 'evaluates a case statement' do
|
|
case_start = Dentaku::Token.new(:case, :open)
|
|
x = Dentaku::Token.new(:identifier, :x)
|
|
case_when1 = Dentaku::Token.new(:case, :when)
|
|
one = Dentaku::Token.new(:numeric, 1)
|
|
case_then1 = Dentaku::Token.new(:case, :then)
|
|
two = Dentaku::Token.new(:numeric, 2)
|
|
case_when2 = Dentaku::Token.new(:case, :when)
|
|
three = Dentaku::Token.new(:numeric, 3)
|
|
case_then2 = Dentaku::Token.new(:case, :then)
|
|
four = Dentaku::Token.new(:numeric, 4)
|
|
case_close = Dentaku::Token.new(:case, :close)
|
|
|
|
node = described_class.new(
|
|
[case_start,
|
|
x,
|
|
case_when1,
|
|
one,
|
|
case_then1,
|
|
two,
|
|
case_when2,
|
|
three,
|
|
case_then2,
|
|
four,
|
|
case_close]).parse
|
|
expect(node.value(x: 3)).to eq(4)
|
|
end
|
|
|
|
it 'raises an error on parse failure' do
|
|
five = Dentaku::Token.new(:numeric, 5)
|
|
times = Dentaku::Token.new(:operator, :multiply)
|
|
minus = Dentaku::Token.new(:operator, :subtract)
|
|
|
|
expect {
|
|
described_class.new([five, times, minus]).parse
|
|
}.to raise_error(Dentaku::ParseError)
|
|
end
|
|
|
|
it "evaluates explicit 'NULL' as a Nil" do
|
|
null = Dentaku::Token.new(:null, nil)
|
|
node = described_class.new([null]).parse
|
|
expect(node.value).to eq(nil)
|
|
end
|
|
end
|