Решение на Basic BASIC от Николай Рангелов

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

Към профила на Николай Рангелов

Резултати

  • 13 точки от тестове
  • 0 бонус точки
  • 13 точки общо
  • 10 успешни тест(а)
  • 5 неуспешни тест(а)

Код

use std::io::{self, Write, Read, BufRead};
use std::io::BufReader;
use std::collections::BTreeMap;
use std::num::ParseIntError;
#[derive(Debug)]
pub enum InterpreterError {
IoError(io::Error),
UnknownVariable { name: String },
NotANumber { value: String },
SyntaxError { code: String },
RuntimeError { line_number: u16, message: String },
}
pub struct Interpreter<'a, R: std::io::Read, W: Write> {
input: BufReader<R>,
output: &'a mut W,
lines: BTreeMap<u16, String>,
variables: BTreeMap<String, u16>,
}
impl<'a, R: std::io::Read, W: Write> Interpreter<'a, R, W> {
pub fn new(_input: R, output: &'a mut W) -> Self {
return Self {input: BufReader::new(_input), output: output, lines: BTreeMap::new(), variables: BTreeMap::new()};
}
pub fn add(&mut self, code: &str) -> Result<(), InterpreterError> {
let commands: Vec<&str> = code.split(" ").collect::<Vec<&str>>();
if commands.len() < 3 {
return Err(InterpreterError::SyntaxError { code: code.to_string() });
}
let line_parsing_result: Result<u16, ParseIntError> = commands[0].parse::<u16>();
let line: u16 = match line_parsing_result {
Ok(number) => number,
Err(_) => return Err(InterpreterError::SyntaxError { code: code.to_string() }),
};
self.lines.insert(line, code.to_string());
return Ok(());
}
pub fn eval_value(&self, value: &str) -> Result<u16, InterpreterError> {
let value_parsing_result: Result<u16, ParseIntError> = value.parse::<u16>();
if char::is_uppercase(value.chars().nth(0).unwrap()) {
if self.variables.contains_key(value) {
return Ok(self.variables[value]);
} else {
return Err(InterpreterError::UnknownVariable { name: value.to_string() });
}
}
match value_parsing_result {
Ok(number) => return Ok(number),
_ => 1,
};
return Err(InterpreterError::NotANumber { value: value.to_string() });
}
pub fn run(&mut self) -> Result<(), InterpreterError> {
let k : Vec<&u16> = self.lines.keys().collect();
let mut i = 0;
while i < k.len() {
let line = *k.get(i).unwrap();
let instruction = self.lines.get(line).unwrap();
let commands: Vec<&str> = instruction.split(" ").collect::<Vec<&str>>();
let command: &str = commands[1];
if command == "PRINT" {
let mut to_be_printed: u16 = 0;
let newline: String = "\n".to_string();
if char::is_uppercase(commands[2].chars().nth(0).unwrap()) {
match self.eval_value(commands[2]) {
Ok(n) => to_be_printed = n,
Err(e) => return Err(InterpreterError::RuntimeError { line_number: *line, message: instruction.to_string()}),
};
self.output.write(to_be_printed.to_string().as_bytes());
self.output.write(newline.as_bytes());
} else {
self.output.write(commands[2].as_bytes());
self.output.write(newline.as_bytes());
}
}
if command == "READ" {
if char::is_uppercase(commands[2].chars().nth(0).unwrap()) {
let mut buf = String::new();
self.input.read_line(&mut buf);
buf.pop();
let new_int = match buf.parse::<u16>() {
Ok(n) => n,
Err(e) => return Err(InterpreterError::RuntimeError { line_number: *line, message: instruction.to_string()}),
};
self.variables.insert(commands[2].to_string(), new_int);
} else {
return Err(InterpreterError::RuntimeError { line_number: *line, message: instruction.to_string()});
}
}
let mut shouldimove = true;
if command == "GOTO" {
let new_int = match commands[2].parse::<u16>() {
Ok(n) => n,
Err(e) => return Err(InterpreterError::RuntimeError { line_number: *line, message: instruction.to_string()}),
};
let index = k.iter().position(|&r| *r == new_int);
if index == None {
return Err(InterpreterError::RuntimeError { line_number: *line, message: instruction.to_string() });
}
i = index.unwrap();
shouldimove = false;
}
if command == "IF" {
if (commands[3] == "<") {
if self.eval_value(commands[2]).unwrap() < self.eval_value(commands[4]).unwrap() {
let new_int = match commands[6].parse::<u16>() {
Ok(n) => n,
Err(e) => return Err(InterpreterError::RuntimeError { line_number: *line, message: instruction.to_string()}),
};
let index = k.iter().position(|&r| *r == new_int);
if index == None {
return Err(InterpreterError::RuntimeError { line_number: *line, message: instruction.to_string() });
}
i = index.unwrap();
shouldimove = false;
}
}
if (commands[3] == ">") {
if self.eval_value(commands[2]).unwrap() > self.eval_value(commands[4]).unwrap() {
let new_int = match commands[6].parse::<u16>() {
Ok(n) => n,
Err(e) => return Err(InterpreterError::RuntimeError { line_number: *line, message: instruction.to_string()}),
};
let index = k.iter().position(|&r| *r == new_int);
if index == None {
return Err(InterpreterError::RuntimeError { line_number: *line, message: instruction.to_string() });
}
i = index.unwrap();
shouldimove = false;
}
}
if (commands[3] == "=") {
if self.eval_value(commands[2]).unwrap() == self.eval_value(commands[4]).unwrap() {
let new_int = match commands[6].parse::<u16>() {
Ok(n) => n,
Err(e) => return Err(InterpreterError::RuntimeError { line_number: *line, message: instruction.to_string()}),
};
let index = k.iter().position(|&r| *r == new_int);
if index == None {
return Err(InterpreterError::RuntimeError { line_number: *line, message: instruction.to_string() });
}
i = index.unwrap();
shouldimove = false;
}
}
}
if shouldimove {
i += 1;
}
}
return Ok(());
}
}
fn main() {
let stdin = std::io::stdin();
let mut stdout = std::io::stdout();
let mut interpreter = Interpreter::new(stdin, &mut stdout);
interpreter.add("10 PRINT guess_a_number").unwrap();
interpreter.add("20 READ Guess").unwrap();
interpreter.add("30 IF Guess > 42 GOTO 100").unwrap();
interpreter.add("40 IF Guess < 42 GOTO 200").unwrap();
interpreter.add("50 IF Guess = 42 GOTO 300").unwrap();
interpreter.add("100 PRINT too_high").unwrap();
interpreter.add("110 GOTO 10").unwrap();
interpreter.add("200 PRINT too_low").unwrap();
interpreter.add("210 GOTO 10").unwrap();
interpreter.add("300 PRINT you_got_it!").unwrap();
interpreter.run().unwrap();
}

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

Compiling solution v0.1.0 (/tmp/d20230111-3772066-loj1rw/solution)
warning: unused import: `Read`
 --> src/lib.rs:1:28
  |
1 | use std::io::{self, Write, Read, BufRead};
  |                            ^^^^
  |
  = note: `#[warn(unused_imports)]` on by default

warning: unnecessary parentheses around `if` condition
   --> src/lib.rs:114:20
    |
114 |                 if (commands[3] == "<") {
    |                    ^                  ^
    |
    = note: `#[warn(unused_parens)]` on by default
help: remove these parentheses
    |
114 -                 if (commands[3] == "<") {
114 +                 if commands[3] == "<" {
    |

warning: unnecessary parentheses around `if` condition
   --> src/lib.rs:128:20
    |
128 |                 if (commands[3] == ">") {
    |                    ^                  ^
    |
help: remove these parentheses
    |
128 -                 if (commands[3] == ">") {
128 +                 if commands[3] == ">" {
    |

warning: unnecessary parentheses around `if` condition
   --> src/lib.rs:142:20
    |
142 |                 if (commands[3] == "=") {
    |                    ^                  ^
    |
help: remove these parentheses
    |
142 -                 if (commands[3] == "=") {
142 +                 if commands[3] == "=" {
    |

warning: value assigned to `to_be_printed` is never read
  --> src/lib.rs:69:25
   |
69 |                 let mut to_be_printed: u16 = 0;
   |                         ^^^^^^^^^^^^^
   |
   = help: maybe it is overwritten before being read?
   = note: `#[warn(unused_assignments)]` on by default

warning: unused variable: `e`
  --> src/lib.rs:75:29
   |
75 |                         Err(e) => return Err(InterpreterError::RuntimeError { line_number: *line, message: instruction.to_string()}),
   |                             ^ help: if this is intentional, prefix it with an underscore: `_e`
   |
   = note: `#[warn(unused_variables)]` on by default

warning: unused variable: `e`
  --> src/lib.rs:93:29
   |
93 |                         Err(e) => return Err(InterpreterError::RuntimeError { line_number: *line, message: instruction.to_string()}),
   |                             ^ help: if this is intentional, prefix it with an underscore: `_e`

warning: unused variable: `e`
   --> src/lib.rs:104:25
    |
104 |                     Err(e) => return Err(InterpreterError::RuntimeError { line_number: *line, message: instruction.to_string()}),
    |                         ^ help: if this is intentional, prefix it with an underscore: `_e`

warning: unused variable: `e`
   --> src/lib.rs:118:33
    |
118 | ...                   Err(e) => return Err(InterpreterError::RuntimeError { line_number: *line, message: instruction.to_string()}),
    |                           ^ help: if this is intentional, prefix it with an underscore: `_e`

warning: unused variable: `e`
   --> src/lib.rs:132:33
    |
132 | ...                   Err(e) => return Err(InterpreterError::RuntimeError { line_number: *line, message: instruction.to_string()}),
    |                           ^ help: if this is intentional, prefix it with an underscore: `_e`

warning: unused variable: `e`
   --> src/lib.rs:146:33
    |
146 | ...                   Err(e) => return Err(InterpreterError::RuntimeError { line_number: *line, message: instruction.to_string()}),
    |                           ^ help: if this is intentional, prefix it with an underscore: `_e`

warning: function `main` is never used
   --> src/lib.rs:165:4
    |
165 | fn main() {
    |    ^^^^
    |
    = note: `#[warn(dead_code)]` on by default

warning: unused `Result` that must be used
  --> src/lib.rs:77:21
   |
77 |                     self.output.write(to_be_printed.to_string().as_bytes());
   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |
   = note: this `Result` may be an `Err` variant, which should be handled
   = note: `#[warn(unused_must_use)]` on by default

warning: unused `Result` that must be used
  --> src/lib.rs:78:21
   |
78 |                     self.output.write(newline.as_bytes());
   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |
   = note: this `Result` may be an `Err` variant, which should be handled

warning: unused `Result` that must be used
  --> src/lib.rs:80:21
   |
80 |                     self.output.write(commands[2].as_bytes());
   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |
   = note: this `Result` may be an `Err` variant, which should be handled

warning: unused `Result` that must be used
  --> src/lib.rs:81:21
   |
81 |                     self.output.write(newline.as_bytes());
   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |
   = note: this `Result` may be an `Err` variant, which should be handled

warning: unused `Result` that must be used
  --> src/lib.rs:89:21
   |
89 |                     self.input.read_line(&mut buf);
   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |
   = note: this `Result` may be an `Err` variant, which should be handled

warning: `solution` (lib) generated 17 warnings
    Finished test [unoptimized + debuginfo] target(s) in 1.56s
     Running tests/solution_test.rs (target/debug/deps/solution_test-0edbea2040daef01)

running 15 tests
test solution_test::test_basic_if ... ok
test solution_test::test_basic_goto ... ok
test solution_test::test_basic_input ... ok
test solution_test::test_basic_print ... ok
test solution_test::test_basic_read ... ok
test solution_test::test_erroring_goto ... ok
test solution_test::test_full_program ... ok
test solution_test::test_io_error_read ... FAILED
test solution_test::test_io_error_write ... FAILED
test solution_test::test_line_order_and_overwriting ... ok
test solution_test::test_print_cyrillic ... ok
test solution_test::test_print_vars_and_strings ... ok
test solution_test::test_syntax_errors_1 ... FAILED
test solution_test::test_runtime_errors ... FAILED
test solution_test::test_syntax_errors_2 ... FAILED

failures:

---- solution_test::test_io_error_read stdout ----
thread '<unnamed>' panicked at 'Expression Err(RuntimeError { line_number: 20, message: "20 READ Oh_No" }) does not match the pattern "Err(InterpreterError::IoError(_))"', tests/solution_test.rs:352:9
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
thread 'solution_test::test_io_error_read' panicked at 'Expression Err(RuntimeError { line_number: 20, message: "20 READ Oh_No" }) does not match the pattern "Err(InterpreterError::IoError(_))"', tests/solution_test.rs:344:5

---- solution_test::test_io_error_write stdout ----
thread '<unnamed>' panicked at 'Expression Ok(()) does not match the pattern "Err(InterpreterError::IoError(_))"', tests/solution_test.rs:366:9
thread 'solution_test::test_io_error_write' panicked at 'Expression Ok(()) does not match the pattern "Err(InterpreterError::IoError(_))"', tests/solution_test.rs:358:5

---- solution_test::test_syntax_errors_1 stdout ----
thread '<unnamed>' panicked at 'Expression Ok(()) does not match the pattern "Err(InterpreterError::SyntaxError { .. })"', tests/solution_test.rs:259:9
thread 'solution_test::test_syntax_errors_1' panicked at 'Expression Ok(()) does not match the pattern "Err(InterpreterError::SyntaxError { .. })"', tests/solution_test.rs:254:5

---- solution_test::test_runtime_errors stdout ----
thread '<unnamed>' panicked at 'called `Result::unwrap()` on an `Err` value: UnknownVariable { name: "C" }', /tmp/d20230111-3772066-loj1rw/solution/src/lib.rs:143:94
thread 'solution_test::test_runtime_errors' panicked at 'called `Result::unwrap()` on an `Err` value: UnknownVariable { name: "C" }', tests/solution_test.rs:301:5

---- solution_test::test_syntax_errors_2 stdout ----
thread '<unnamed>' panicked at 'Expression Ok(()) does not match the pattern "Err(InterpreterError::SyntaxError { .. })"', tests/solution_test.rs:280:9
thread 'solution_test::test_syntax_errors_2' panicked at 'Expression Ok(()) does not match the pattern "Err(InterpreterError::SyntaxError { .. })"', tests/solution_test.rs:275:5


failures:
    solution_test::test_io_error_read
    solution_test::test_io_error_write
    solution_test::test_runtime_errors
    solution_test::test_syntax_errors_1
    solution_test::test_syntax_errors_2

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

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

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

Николай качи първо решение на 10.01.2023 16:23 (преди над 2 години)