145 lines
5.6 KiB
Ruby
145 lines
5.6 KiB
Ruby
require "ruby_algebra"
|
||
RSpec.describe RubyAlgebra::Parser do
|
||
# Хелпер для быстрой сборки ожидаемых многочленов в тестах
|
||
def build_poly(terms_array)
|
||
terms = terms_array.map do |t|
|
||
RubyAlgebra::Term.new(t[:coeff], t[:vars] || {})
|
||
end
|
||
RubyAlgebra::Polynomial.new(terms)
|
||
end
|
||
|
||
describe '.parse_polynomial' do
|
||
let(:tokenizer) { ->(str) { RubyAlgebra::Parser::Tokenizer.new(str) } }
|
||
|
||
it 'парсит простое число как константный многочлен' do
|
||
result = RubyAlgebra::Parser.parse_polynomial(tokenizer.call("42"))
|
||
expect(result).to eq(build_poly([{ coeff: 42 }]))
|
||
end
|
||
|
||
it 'парсит одиночную переменную' do
|
||
result = RubyAlgebra::Parser.parse_polynomial(tokenizer.call("x"))
|
||
expect(result).to eq(build_poly([{ coeff: 1, vars: { "x" => 1 } }]))
|
||
end
|
||
|
||
it 'парсит многочлен с несколькими термами и степенями' do
|
||
# 2x^2 + 3x - 5
|
||
result = RubyAlgebra::Parser.parse_polynomial(tokenizer.call("2x^2 + 3x - 5"))
|
||
expected = build_poly([
|
||
{ coeff: 2, vars: { "x" => 2 } },
|
||
{ coeff: 3, vars: { "x" => 1 } },
|
||
{ coeff: -5, vars: {} }
|
||
])
|
||
expect(result).to eq(expected)
|
||
end
|
||
|
||
it 'обрабатывает отрицательный первый терм' do
|
||
result = RubyAlgebra::Parser.parse_polynomial(tokenizer.call("-x + 1"))
|
||
expect(result).to eq(build_poly([
|
||
{ coeff: -1, vars: { "x" => 1 } },
|
||
{ coeff: 1 }
|
||
]))
|
||
end
|
||
end
|
||
|
||
describe '.parse_command' do
|
||
context 'Арифметические операции (взаимодействие многочленов)' do
|
||
it 'парсит команду сложения: C := A + B' do
|
||
cmd = RubyAlgebra::Parser.parse_command("C := A + B")
|
||
expect(cmd).to be_a(RubyAlgebra::AssignmentCommand)
|
||
expect(cmd.operation).to eq(:add)
|
||
expect(cmd.lhs).to eq("C")
|
||
expect(cmd.operand1).to eq("A")
|
||
expect(cmd.operand2).to eq("B")
|
||
end
|
||
|
||
it 'парсит команду вычитания: Result := P1 - P2' do
|
||
cmd = RubyAlgebra::Parser.parse_command("Result := P1 - P2")
|
||
expect(cmd.operation).to eq(:sub)
|
||
expect(cmd.operand1).to eq("P1")
|
||
expect(cmd.operand2).to eq("P2")
|
||
end
|
||
|
||
it 'парсит команду умножения: M := Poly1 * Poly2' do
|
||
cmd = RubyAlgebra::Parser.parse_command("M := Poly1 * Poly2")
|
||
expect(cmd.operation).to eq(:mult)
|
||
expect(cmd.operand1).to eq("Poly1")
|
||
expect(cmd.operand2).to eq("Poly2")
|
||
end
|
||
|
||
it 'парсит деление с остатком: Q, R := A / B' do
|
||
cmd = RubyAlgebra::Parser.parse_command("Q, R := A / B")
|
||
expect(cmd.operation).to eq(:div)
|
||
expect(cmd.lhs).to eq(["Q", "R"])
|
||
expect(cmd.operand1).to eq("A")
|
||
expect(cmd.operand2).to eq("B")
|
||
end
|
||
end
|
||
|
||
context 'Операции с числами (Scales)' do
|
||
it 'парсит умножение на число как :scale' do
|
||
cmd = RubyAlgebra::Parser.parse_command("A := B * 10")
|
||
expect(cmd.operation).to eq(:scale)
|
||
expect(cmd.operand2).to eq(10)
|
||
end
|
||
|
||
it 'парсит деление на число как :scale с инверсией' do
|
||
cmd = RubyAlgebra::Parser.parse_command("A := B / 2")
|
||
expect(cmd.operation).to eq(:scale)
|
||
expect(cmd.operand2).to eq(0.5)
|
||
end
|
||
end
|
||
|
||
context 'Специальные методы' do
|
||
it 'парсит дифференцирование: D := Diff(P, x)' do
|
||
cmd = RubyAlgebra::Parser.parse_command("D := Diff(P, x)")
|
||
expect(cmd.operation).to eq(:diff)
|
||
expect(cmd.operand1).to eq("P")
|
||
expect(cmd.operand2).to eq(["x"])
|
||
end
|
||
|
||
it 'парсит подстановку: S := Subs(P, x=2, y=3)' do
|
||
cmd = RubyAlgebra::Parser.parse_command("S := Subs(P, x=2, y=3)")
|
||
expect(cmd.operation).to eq(:subs)
|
||
expect(cmd.operand1).to eq("P")
|
||
expect(cmd.operand2).to eq({ "x" => 2, "y" => 3 })
|
||
end
|
||
end
|
||
|
||
it 'парсит команду вывода (Display)' do
|
||
cmd = RubyAlgebra::Parser.parse_command("A")
|
||
expect(cmd).to be_a(RubyAlgebra::DisplayCommand)
|
||
expect(cmd.item).to eq("A")
|
||
end
|
||
end
|
||
end
|
||
|
||
RSpec.describe RubyAlgebra::Interpreter do
|
||
let(:interpreter) { RubyAlgebra::Interpreter.new }
|
||
|
||
it 'выполняет цепочку: присваивание и сложение' do
|
||
# Создаем полиномы через парсер и выполняем команды через интерпретатор
|
||
p1_cmd = RubyAlgebra::Parser.parse_command("A := 2x")
|
||
p2_cmd = RubyAlgebra::Parser.parse_command("B := 3x + 1")
|
||
add_cmd = RubyAlgebra::Parser.parse_command("C := A + B")
|
||
|
||
interpreter.execute(p1_cmd)
|
||
interpreter.execute(p2_cmd)
|
||
result_str = interpreter.execute(add_cmd)
|
||
|
||
expect(result_str).to include("5x + 1")
|
||
end
|
||
|
||
it 'выполняет деление с остатком' do
|
||
# (x^2 - 1) / (x - 1) = x + 1, остаток 0
|
||
interpreter.execute(RubyAlgebra::Parser.parse_command("A := 1x^2 - 1"))
|
||
interpreter.execute(RubyAlgebra::Parser.parse_command("B := 1x - 1"))
|
||
|
||
# В вашей грамматике деление: Q, R := A / B
|
||
cmd = RubyAlgebra::Parser.parse_command("Q, R := A / B")
|
||
interpreter.execute(cmd)
|
||
|
||
expect(interpreter.execute(RubyAlgebra::Parser.parse_command("Q"))).to eq("1.0x + 1.0")
|
||
expect(interpreter.execute(RubyAlgebra::Parser.parse_command("R"))).to eq("0")
|
||
end
|
||
end
|