Решение на Логически изрази от Камен Младенов

Обратно към всички решения

Към профила на Камен Младенов

Резултати

  • 7 точки от тестове
  • 2 бонус точки
  • 9 точки общо
  • 7 успешни тест(а)
  • 13 неуспешни тест(а)

Код

#![allow(warnings)]
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Expr {
Atom(char),
Not(Box<Expr>),
And(Vec<Expr>),
Or(Vec<Expr>),
}
macro_rules! expr {
(atom ( $c:literal ) ) => {
Expr::Atom($c)
};
(not ( $name:tt $e:tt ) ) => {
Expr::Not(Box::new( expr!($name$e) ))
};
(and ( $($name:tt $e:tt),* ) ) => {
Expr::And(vec![$( expr!($name$e) ),*])
};
(or ( $($name:tt $e:tt),* ) ) => {
Expr::Or(vec![$( expr!($name$e) ),*])
};
}
#[derive(Debug, PartialEq, Eq)]
pub enum ParseError {
UnexpectedExpr,
UnexpectedUnaryOp,
UnexpectedBinOp,
UnexpectedParen,
UnexpectedEnd,
}
/// Парсър за прост израз, който не съдържа скоби
pub struct SimpleExprParser {
top_atom: Option<Expr>,
top_op: Option<Expr>,
top_op_char: char,
bot_op: Option<Expr>,
bot_op_char: char,
}
impl SimpleExprParser {
pub fn new() -> SimpleExprParser {
SimpleExprParser {
top_atom: None,
top_op: None,
top_op_char: '_',
bot_op: None,
bot_op_char: '_',
}
}
/// Приема атом.
///
/// `c` ще бъде валиден символ за атом.
/// В противен случай можете да panic-нете (няма да се тества)
pub fn push_atom(&mut self, c: char) -> Result<(), ParseError> {
if (self.top_op_char == '!' || self.top_op_char == '_') && self.top_atom.is_some() {
return Err(ParseError::UnexpectedExpr);
}
if self.top_op_char == '!' {
let Expr::Not(ptr) = self.top_op.as_mut().unwrap() else { unreachable!() };
*(*ptr) = Expr::Atom(c);
if self.bot_op.is_some() {
match self.bot_op.as_mut().unwrap() {
Expr::And(vec) | Expr::Or(vec) => vec.push(self.top_op.take().unwrap()),
Expr::Not(ptr) => {
let mut ptr = ptr;
loop {
if let Expr::Atom(_) = **ptr {
**ptr = self.top_op.take().unwrap();
break;
}
match ptr.as_mut() {
Expr::Not(ptro) => ptr = ptro,
_ => unreachable!(),
}
}
},
_ => unreachable!(),
}
self.top_op = self.bot_op.take();
self.top_op_char = self.bot_op_char;
}
}
else if self.top_op.is_some() {
match self.top_op.as_mut().unwrap() {
Expr::And(vec) | Expr::Or(vec) => vec.push(Expr::Atom(c)),
_ => unreachable!(),
}
}
self.top_atom = Some(Expr::Atom(c));
Ok(())
}
fn take_single_expr(&mut self) -> Expr {
if self.bot_op.is_some() {
self.bot_op_char = '_';
self.bot_op.take().unwrap()
}
else {
self.top_atom.take().unwrap()
}
}
/// Приема символ за операция.
///
/// `op` ще бъде едно от '&', '|', '!'.
/// В противен случай можете да panic-нете (няма да се тества)
pub fn push_op(&mut self, op: char) -> Result<(), ParseError> {
if op != '!' && self.top_atom.is_none() {
return Err(ParseError::UnexpectedBinOp);
}
if self.top_op_char == op && self.top_atom.is_some() {
return Ok(());
}
if self.bot_op.is_some() {
match self.bot_op.as_mut().unwrap() {
Expr::And(vec) | Expr::Or(vec) => vec.push(self.top_op.take().unwrap()),
Expr::Not(ptr) => *(*ptr) = self.top_op.take().unwrap(),
_ => unreachable!(),
}
}
else {
self.bot_op = self.top_op.take();
self.bot_op_char = self.top_op_char;
}
self.top_op = Some(match op {
'&' => Expr::And(vec![self.take_single_expr()]),
'|' => Expr::Or(vec![self.take_single_expr()]),
'!' => Expr::Not(Box::new(Expr::Atom('_'))),
_ => unreachable!(),
});
self.top_op_char = op;
self.top_atom = None;
Ok(())
}
/// Завършва парсването и връща построения израз.
pub fn finish(self) -> Result<Expr, ParseError> {
if self.bot_op.is_some() || self.top_atom.is_none() {
Err(ParseError::UnexpectedEnd)
}
else {
self.top_op.or(self.top_atom).ok_or(ParseError::UnexpectedEnd)
}
}
}
macro_rules! test_sep {
( $( $call:tt $args:tt ).+ , $acall:tt $aargs:tt ) => {
{
let mut sep = SimpleExprParser::new();
$(
let _ = sep.$call$args.unwrap();
)+
let res = sep.finish().unwrap();
assert_eq!(res, expr!($acall$aargs));
}
};
( ! $( $call:tt $args:tt ).+ ) => {
'fails: {
let mut sep = SimpleExprParser::new();
$(
if sep.$call$args.is_err() {
break 'fails;
}
)+
sep.finish().expect_err("Invalid expression was passed, but it was successfully parsed");
}
};
}
#[test]
fn simple_parser() {
test_sep!(push_atom('A'), atom('A'));
test_sep!(push_op('!').push_atom('A'), not(atom('A')));
test_sep!(push_op('!').push_op('!').push_atom('A'), not(not(atom('A'))));
test_sep!(push_op('!').push_op('!').push_op('!').push_atom('A'), not(not(not(atom('A')))));
// test_sep!(push_op('!').push_op('!').push_op('!').push_atom('A').push_op('&').push_op('!').push_op('!').push_op('!').push_atom('B'), and(not(not(not(atom('A')))), not(not(not(atom('B'))))));
test_sep!(push_atom('A').push_op('&').push_atom('B'), and(atom('A'), atom('B')));
test_sep!(push_atom('A').push_op('|').push_atom('B'), or(atom('A'), atom('B')));
test_sep!(push_atom('A').push_op('&').push_atom('B').push_op('&').push_atom('C'), and(atom('A'), atom('B'), atom('C')));
test_sep!(push_atom('A').push_op('|').push_atom('B').push_op('|').push_atom('C'), or(atom('A'), atom('B'), atom('C')));
test_sep!(push_op('!').push_atom('A').push_op('&').push_atom('B').push_op('&').push_op('!').push_atom('C'), and(not(atom('A')), atom('B'), not(atom('C'))));
test_sep!(push_op('!').push_atom('A').push_op('|').push_atom('B').push_op('|').push_op('!').push_atom('C'), or(not(atom('A')), atom('B'), not(atom('C'))));
test_sep!(!push_op('!'));
test_sep!(!push_op('&'));
test_sep!(!push_op('|'));
test_sep!(!push_atom('A').push_atom('B'));
test_sep!(!push_op('!').push_op('!'));
test_sep!(!push_op('!').push_op('&'));
test_sep!(!push_op('!').push_op('|'));
test_sep!(!push_op('&').push_op('&'));
test_sep!(!push_op('|').push_op('|'));
test_sep!(!push_op('&').push_op('|'));
test_sep!(!push_op('|').push_op('&'));
test_sep!(!push_op('&').push_op('|'));
test_sep!(!push_op('!').push_atom('A').push_atom('B'));
test_sep!(!push_op('&').push_atom('A').push_atom('B'));
test_sep!(!push_op('|').push_atom('A').push_atom('B'));
test_sep!(!push_atom('A').push_op('&'));
test_sep!(!push_atom('A').push_op('|'));
}
/// Парсър за пълния израз
pub struct ExprParser {
stack: Vec<Expr>,
brace_depth: usize,
}
impl ExprParser {
pub fn new() -> ExprParser {
ExprParser {
stack: Vec::new(),
brace_depth: 0,
}
}
/// Приема атом.
///
/// `c` ще бъде валиден символ за атом.
/// В противен случай можете да panic-нете (няма да се тества)
pub fn push_atom(&mut self, c: char) -> Result<(), ParseError> {
if self.stack.is_empty() {
self.stack.push(Expr::Atom(c));
}
if let Some(Expr::Atom(_)) = self.stack.last() {
return Err(ParseError::UnexpectedExpr);
}
let top = self.stack.pop();
self.stack.push(Expr::Atom(c));
self.stack.push(top.unwrap());
Ok(())
}
/// Приема символ за операция.
///
/// `op` ще бъде едно от '&', '|', '!'.
/// В противен случай можете да panic-нете (няма да се тества)
pub fn push_op(&mut self, op: char) -> Result<(), ParseError> {
todo!()
}
/// Приема отваряща скоба.
pub fn open_paren(&mut self) -> Result<(), ParseError> {
todo!()
}
/// Приема затваряща скоба.
pub fn close_paren(&mut self) -> Result<(), ParseError> {
todo!()
}
/// Завършва парсването и връща построения израз.
pub fn finish(self) -> Result<Expr, ParseError> {
todo!()
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Value {
True,
False,
Expr(Expr),
}
pub fn eval(expr: &Expr, truthy: &[char], falsy: &[char]) -> Value {
todo!()
}
fn main() {
println!("Hello, world!");
}
#[test]
fn expr_macro() {
assert_eq!(
expr!(atom('m')),
Expr::Atom('m')
);
assert_eq!(
expr!(not(atom('a'))),
Expr::Not(Box::new(Expr::Atom('a')))
);
assert_eq!(
expr!(and(atom('a'), not(atom('b')), atom('c'))),
Expr::And(vec![
Expr::Atom('a'),
Expr::Not(Box::new(Expr::Atom('b'))),
Expr::Atom('c'),
])
);
assert_eq!(
expr!(or(atom('a'), not(atom('b')), atom('c'))),
Expr::Or(vec![
Expr::Atom('a'),
Expr::Not(Box::new(Expr::Atom('b'))),
Expr::Atom('c'),
])
);
assert_eq!(
expr!(or(and(atom('A'), not(atom('B'))), not(and(atom('C'), atom('D'))))),
Expr::Or(vec![
Expr::And(vec![
Expr::Atom('A'),
Expr::Not(Box::new(Expr::Atom('B'))),
]),
Expr::Not(Box::new(Expr::And(vec![
Expr::Atom('C'),
Expr::Atom('D'),
]))),
])
);
}

Лог от изпълнението

Compiling solution v0.1.0 (/tmp/d20241224-258381-g3ta0h/solution)
warning: variable does not need to be mutable
   --> tests/solution_test.rs:306:13
    |
306 |         let mut parser = SimpleExprParser::new();
    |             ----^^^^^^
    |             |
    |             help: remove this `mut`
    |
    = note: `#[warn(unused_mut)]` on by default

warning: `solution` (test "solution_test") generated 1 warning
    Finished test [unoptimized + debuginfo] target(s) in 1.68s
     Running tests/solution_test.rs (target/debug/deps/solution_test-1428e1090729d165)

running 20 tests
test solution_test::test_eval_full ... FAILED
test solution_test::test_error_paren_mismatched ... FAILED
test solution_test::test_eval_not_and_or ... FAILED
test solution_test::test_eval_partial ... FAILED
test solution_test::test_eval_unwrap_and_or ... FAILED
test solution_test::test_eval_unwrap_nested ... FAILED
test solution_test::test_paren_around_expr ... FAILED
test solution_test::test_paren_expr_priority ... FAILED
test solution_test::test_paren_nested ... FAILED
test solution_test::test_paren_not ... FAILED
test solution_test::test_paren_surrounded ... FAILED
test solution_test::test_parser_alternating_ops ... ok
test solution_test::test_parser_and_or ... ok
test solution_test::test_parser_atom ... ok
test solution_test::test_parser_error_unexpected_end ... ok
test solution_test::test_parser_errors_basic ... FAILED
test solution_test::test_parser_expr_and_not ... ok
test solution_test::test_parser_multiple_atoms_same_op ... ok
test solution_test::test_parser_multiple_not ... FAILED
test solution_test::test_parser_not ... ok

failures:

---- solution_test::test_eval_full stdout ----
thread '<unnamed>' panicked at 'not yet implemented', src/lib.rs:278:5
thread 'solution_test::test_eval_full' panicked at 'called `Option::unwrap()` on a `None` value', tests/solution_test.rs:371:5

---- solution_test::test_error_paren_mismatched stdout ----
thread '<unnamed>' panicked at 'not yet implemented', src/lib.rs:261:9
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
thread 'solution_test::test_error_paren_mismatched' panicked at 'called `Option::unwrap()` on a `None` value', tests/solution_test.rs:325:5

---- solution_test::test_eval_not_and_or stdout ----
thread '<unnamed>' panicked at 'not yet implemented', src/lib.rs:278:5
thread 'solution_test::test_eval_not_and_or' panicked at 'called `Option::unwrap()` on a `None` value', tests/solution_test.rs:387:5

---- solution_test::test_eval_partial stdout ----
thread '<unnamed>' panicked at 'not yet implemented', src/lib.rs:278:5
thread 'solution_test::test_eval_partial' panicked at 'called `Option::unwrap()` on a `None` value', tests/solution_test.rs:409:5

---- solution_test::test_eval_unwrap_and_or stdout ----
thread '<unnamed>' panicked at 'not yet implemented', src/lib.rs:278:5
thread 'solution_test::test_eval_unwrap_and_or' panicked at 'called `Option::unwrap()` on a `None` value', tests/solution_test.rs:456:5

---- solution_test::test_eval_unwrap_nested stdout ----
thread '<unnamed>' panicked at 'not yet implemented', src/lib.rs:278:5
thread 'solution_test::test_eval_unwrap_nested' panicked at 'called `Option::unwrap()` on a `None` value', tests/solution_test.rs:479:5

---- solution_test::test_paren_around_expr stdout ----
thread '<unnamed>' panicked at 'not yet implemented', src/lib.rs:256:9
thread 'solution_test::test_paren_around_expr' panicked at 'called `Option::unwrap()` on a `None` value', tests/solution_test.rs:176:5

---- solution_test::test_paren_expr_priority stdout ----
thread '<unnamed>' panicked at 'called `Result::unwrap()` on an `Err` value: UnexpectedExpr', tests/solution_test.rs:199:47
thread 'solution_test::test_paren_expr_priority' panicked at 'called `Result::unwrap()` on an `Err` value: UnexpectedExpr', tests/solution_test.rs:197:5

---- solution_test::test_paren_nested stdout ----
thread '<unnamed>' panicked at 'not yet implemented', src/lib.rs:251:9
thread 'solution_test::test_paren_nested' panicked at 'called `Option::unwrap()` on a `None` value', tests/solution_test.rs:252:5

---- solution_test::test_paren_not stdout ----
thread '<unnamed>' panicked at 'called `Result::unwrap()` on an `Err` value: UnexpectedExpr', tests/solution_test.rs:218:48
thread 'solution_test::test_paren_not' panicked at 'called `Result::unwrap()` on an `Err` value: UnexpectedExpr', tests/solution_test.rs:216:5

---- solution_test::test_paren_surrounded stdout ----
thread '<unnamed>' panicked at 'called `Result::unwrap()` on an `Err` value: UnexpectedExpr', tests/solution_test.rs:237:61
thread 'solution_test::test_paren_surrounded' panicked at 'called `Result::unwrap()` on an `Err` value: UnexpectedExpr', tests/solution_test.rs:235:5

---- solution_test::test_parser_errors_basic stdout ----
thread '<unnamed>' panicked at 'assertion failed: matches!(parser.push_op(\'!\'), Err(_))', tests/solution_test.rs:278:9
thread 'solution_test::test_parser_errors_basic' panicked at 'called `Option::unwrap()` on a `None` value', tests/solution_test.rs:265:5

---- solution_test::test_parser_multiple_not stdout ----
thread '<unnamed>' panicked at 'assertion failed: `(left == right)`
  left: `Or([Atom('A'), Not(Atom('_')), Not(Atom('B'))])`,
 right: `Or([Atom('A'), Not(Not(Atom('B')))])`', tests/solution_test.rs:147:9
thread 'solution_test::test_parser_multiple_not' panicked at 'assertion failed: `(left == right)`
  left: `Or([Atom('A'), Not(Atom('_')), Not(Atom('B'))])`,
 right: `Or([Atom('A'), Not(Not(Atom('B')))])`', tests/solution_test.rs:140:5


failures:
    solution_test::test_error_paren_mismatched
    solution_test::test_eval_full
    solution_test::test_eval_not_and_or
    solution_test::test_eval_partial
    solution_test::test_eval_unwrap_and_or
    solution_test::test_eval_unwrap_nested
    solution_test::test_paren_around_expr
    solution_test::test_paren_expr_priority
    solution_test::test_paren_nested
    solution_test::test_paren_not
    solution_test::test_paren_surrounded
    solution_test::test_parser_errors_basic
    solution_test::test_parser_multiple_not

test result: FAILED. 7 passed; 13 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

error: test failed, to rerun pass `--test solution_test`

История (1 версия и 0 коментара)

Камен качи първо решение на 22.12.2024 21:50 (преди 9 месеца)