Решение на Basic BASIC от Чудомир Ченков
Резултати
- 19 точки от тестове
- 0 бонус точки
- 19 точки общо
- 14 успешни тест(а)
- 1 неуспешни тест(а)
Код
use std::io::{self, Write, Read, BufRead, BufReader};
use std::collections::BTreeMap;
#[derive(Debug)]
pub enum InterpreterError {
IoError(io::Error),
UnknownVariable { name: String },
NotANumber { value: String },
SyntaxError { code: String },
RuntimeError { line_number: u16, message: String },
}
pub fn construct_runerr(line_number: &u16, message: &str) -> InterpreterError {
InterpreterError::RuntimeError {
line_number: *line_number,
message: message.to_string()
}
}
pub struct Interpreter<'a, R: Read, W: Write> {
input: BufReader<R>,
output: &'a mut W,
commands: BTreeMap<u16, Vec<&'a str>>,
variables: BTreeMap<&'a str, u16>
}
impl<'a, R: Read, W: Write> Interpreter<'a, R, W> {
pub fn new(input: R, output: &'a mut W) -> Self {
Interpreter {
input: BufReader::new(input),
output,
commands: BTreeMap::new(),
variables: BTreeMap::new()
}
}
pub fn add(&mut self, code: &'a str) -> Result<(), InterpreterError> {
let err = InterpreterError::SyntaxError { code: code.to_string() };
let mut args: Vec<&str> = code.split_whitespace().collect();
let line_num: u16;
let mut found_err = false;
match args[0].parse::<u16>() {
Ok(num) => line_num = num,
Err(_) => return Err(err)
}
match args[1] {
"PRINT" => found_err = found_err || args.len() != 3,
"READ" => found_err = found_err || args.len() != 3 || !args[2].chars().nth(0).unwrap().is_uppercase(),
"GOTO" => found_err = found_err || args.len() != 3 || args[2].parse::<u16>().is_err(),
"IF" => found_err = found_err || args.len() != 7 || args[5] != "GOTO" || args[6].parse::<u16>().is_err(),
_ => { }
}
if found_err {
return Err(err);
}
// remove line number from args
args.remove(0);
self.commands.insert(line_num, args);
Ok(())
}
pub fn eval_value(&self, value: &str) -> Result<u16, InterpreterError> {
if value.chars().nth(0).unwrap().is_uppercase() {
match self.variables.get(value) {
Some(num) => Ok(*num),
None => Err(InterpreterError::UnknownVariable { name: value.to_string() })
}
} else {
match value.parse::<u16>() {
Ok(num) => Ok(num),
Err(_err) => Err(InterpreterError::NotANumber { value: value.to_string() })
}
}
}
pub fn run(&mut self) -> Result<(), InterpreterError> {
let mut cmd_iter = self.commands.iter();
while let Some((line_number, args)) = cmd_iter.next() {
match args[0] {
"PRINT" => {
match self.eval_value(args[1]) {
Ok(num) => match self.output.write_all(&format!("{}\n", &num).as_bytes()) {
Err(err) => return Err(InterpreterError::IoError(err)),
_ => { }
},
Err(err) => match err {
InterpreterError::UnknownVariable { name } =>
return Err(construct_runerr(line_number, &format!("Unknown variable {}", name))),
InterpreterError::NotANumber { value } =>
match self.output.write_all(&format!("{}\n", value).as_bytes()) {
Err(err) => return Err(InterpreterError::IoError(err)),
_ => { }
},
_ => { }
}
};
},
"READ" => {
let mut buf = String::new();
match self.input.read_line(&mut buf) {
Ok(_size) => { },
Err(err) => return Err(InterpreterError::IoError(err))
};
match buf.trim().parse::<u16>() {
Ok(num) => self.variables.insert(args[1], num),
Err(_err) => return Err(construct_runerr(line_number, "Invalid value"))
};
},
"GOTO" => {
let goto_line = args[1].parse::<u16>().unwrap();
let mut prev_line: Option<u16> = None;
cmd_iter = self.commands.iter();
while let Some((ln, _)) = cmd_iter.next() {
if *ln == goto_line { break; }
prev_line = Some(*ln);
}
cmd_iter = self.commands.iter();
match prev_line {
Some(prev_ln) =>
if prev_ln != *self.commands.iter().next_back().unwrap().0 {
while let Some((ln, _)) = cmd_iter.next() {
if *ln == prev_ln { break; }
}
} else {
return Err(construct_runerr(line_number, "Invalid line number"))
},
None => { }
};
},
"IF" => {
let left: u16;
let right: u16;
match self.eval_value(args[1]) {
Ok(num) => left = num,
Err(_err) => return Err(construct_runerr(line_number, "Runtime error"))
};
match self.eval_value(args[3]) {
Ok(num) => right = num,
Err(_err) => return Err(construct_runerr(line_number, "Runtime error"))
};
let condition = match args[2] {
"<" => left < right,
">" => left > right,
"=" => left == right,
_ => false
};
if condition {
let goto_line = args[5].parse::<u16>().unwrap();
let mut prev_line: Option<u16> = None;
cmd_iter = self.commands.iter();
while let Some((ln, _)) = cmd_iter.next() {
if *ln == goto_line { break; }
prev_line = Some(*ln);
}
cmd_iter = self.commands.iter();
match prev_line {
Some(prev_ln) => {
if prev_ln != *self.commands.iter().next_back().unwrap().0 {
while let Some((ln, _)) = cmd_iter.next() {
if *ln == prev_ln { break; }
}
} else {
return Err(construct_runerr(line_number, "Invalid line number"))
}
},
None => { }
};
}
},
_ => { }
}
};
Ok(())
}
}
Лог от изпълнението
Compiling solution v0.1.0 (/tmp/d20230111-3772066-1aj2zcl/solution) 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_goto ... ok test solution_test::test_basic_if ... 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 ... ok test solution_test::test_io_error_write ... ok 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 ... ok test solution_test::test_runtime_errors ... ok test solution_test::test_syntax_errors_2 ... FAILED failures: ---- 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:294:9 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace 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_syntax_errors_2 test result: FAILED. 14 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s error: test failed, to rerun pass `--test solution_test`
История (3 версии и 0 коментара)
Чудомир качи решение на 10.01.2023 16:04 (преди над 2 години)
use std::io::{self, Write, Read, BufRead, BufReader};
use std::collections::BTreeMap;
#[derive(Debug)]
pub enum InterpreterError {
IoError(io::Error),
UnknownVariable { name: String },
NotANumber { value: String },
SyntaxError { code: String },
RuntimeError { line_number: u16, message: String },
}
pub fn construct_runerr(line_number: &u16, message: &str) -> InterpreterError {
InterpreterError::RuntimeError {
line_number: *line_number,
message: message.to_string()
}
}
pub struct Interpreter<'a, R: Read, W: Write> {
input: BufReader<R>,
output: &'a mut W,
commands: BTreeMap<u16, Vec<&'a str>>,
variables: BTreeMap<&'a str, u16>
}
impl<'a, R: Read, W: Write> Interpreter<'a, R, W> {
pub fn new(input: R, output: &'a mut W) -> Self {
Interpreter {
input: BufReader::new(input),
output,
commands: BTreeMap::new(),
variables: BTreeMap::new()
}
}
pub fn add(&mut self, code: &'a str) -> Result<(), InterpreterError> {
let err = InterpreterError::SyntaxError { code: code.to_string() };
let mut args: Vec<&str> = code.split_whitespace().collect();
let line_num: u16;
let mut found_err = false;
match args[0].parse::<u16>() {
Ok(num) => line_num = num,
Err(_) => return Err(err)
}
match args[1] {
"PRINT" => found_err = found_err || args.len() != 3,
"READ" => found_err = found_err || args.len() != 3 || !args[2].chars().nth(0).unwrap().is_uppercase(),
"GOTO" => found_err = found_err || args.len() != 3 || args[2].parse::<u16>().is_err(),
"IF" => found_err = found_err || args.len() != 7 || args[5] != "GOTO" || args[6].parse::<u16>().is_err(),
_ => { }
}
if found_err {
return Err(err);
}
// remove line number from args
args.remove(0);
self.commands.insert(line_num, args);
Ok(())
}
pub fn eval_value(&self, value: &str) -> Result<u16, InterpreterError> {
if value.chars().nth(0).unwrap().is_uppercase() {
match self.variables.get(value) {
Some(num) => Ok(*num),
None => Err(InterpreterError::UnknownVariable { name: value.to_string() })
}
} else {
match value.parse::<u16>() {
Ok(num) => Ok(num),
Err(_err) => Err(InterpreterError::NotANumber { value: value.to_string() })
}
}
}
pub fn run(&mut self) -> Result<(), InterpreterError> {
let mut cmd_iter = self.commands.iter();
while let Some((line_number, args)) = cmd_iter.next() {
match args[0] {
"PRINT" => {
match self.eval_value(args[1]) {
Ok(num) => match self.output.write_all(&format!("{}\n", &num).as_bytes()) {
Err(err) => return Err(InterpreterError::IoError(err)),
_ => { }
},
Err(err) => match err {
InterpreterError::UnknownVariable { name } =>
return Err(construct_runerr(line_number, &format!("Unknown variable {}", name))),
InterpreterError::NotANumber { value } =>
- match self.output.write_all(value.as_bytes()) {
+ match self.output.write_all(&format!("{}\n", value).as_bytes()) {
Err(err) => return Err(InterpreterError::IoError(err)),
_ => { }
},
_ => { }
}
};
},
"READ" => {
let mut buf = String::new();
match self.input.read_line(&mut buf) {
Ok(_size) => { },
Err(err) => return Err(InterpreterError::IoError(err))
};
match buf.trim().parse::<u16>() {
Ok(num) => self.variables.insert(args[1], num),
Err(_err) => return Err(construct_runerr(line_number, "Invalid value"))
};
},
"GOTO" => {
let goto_line = args[1].parse::<u16>().unwrap();
match cmd_iter.find(|&(ln, _ar)| *ln == goto_line) {
Some(_) => { },
None => return Err(construct_runerr(line_number, "Invalid line number"))
}
},
"IF" => {
let left: u16;
let right: u16;
match self.eval_value(args[1]) {
Ok(num) => left = num,
Err(_err) => return Err(construct_runerr(line_number, "Runtime error"))
};
match self.eval_value(args[3]) {
Ok(num) => right = num,
Err(_err) => return Err(construct_runerr(line_number, "Runtime error"))
};
let condition = match args[2] {
"<" => left < right,
">" => left > right,
"=" => left == right,
_ => false
};
if condition {
let goto_line = args[5].parse::<u16>().unwrap();
match cmd_iter.find(|&(ln, _ar)| *ln == goto_line) {
Some(_) => { },
None => return Err(construct_runerr(line_number, "Invalid line number"))
}
}
},
_ => { }
}
};
Ok(())
}
}
Чудомир качи решение на 10.01.2023 16:39 (преди над 2 години)
use std::io::{self, Write, Read, BufRead, BufReader};
use std::collections::BTreeMap;
#[derive(Debug)]
pub enum InterpreterError {
IoError(io::Error),
UnknownVariable { name: String },
NotANumber { value: String },
SyntaxError { code: String },
RuntimeError { line_number: u16, message: String },
}
pub fn construct_runerr(line_number: &u16, message: &str) -> InterpreterError {
InterpreterError::RuntimeError {
line_number: *line_number,
message: message.to_string()
}
}
pub struct Interpreter<'a, R: Read, W: Write> {
input: BufReader<R>,
output: &'a mut W,
commands: BTreeMap<u16, Vec<&'a str>>,
variables: BTreeMap<&'a str, u16>
}
impl<'a, R: Read, W: Write> Interpreter<'a, R, W> {
pub fn new(input: R, output: &'a mut W) -> Self {
Interpreter {
input: BufReader::new(input),
output,
commands: BTreeMap::new(),
variables: BTreeMap::new()
}
}
pub fn add(&mut self, code: &'a str) -> Result<(), InterpreterError> {
let err = InterpreterError::SyntaxError { code: code.to_string() };
let mut args: Vec<&str> = code.split_whitespace().collect();
let line_num: u16;
let mut found_err = false;
match args[0].parse::<u16>() {
Ok(num) => line_num = num,
Err(_) => return Err(err)
}
match args[1] {
"PRINT" => found_err = found_err || args.len() != 3,
"READ" => found_err = found_err || args.len() != 3 || !args[2].chars().nth(0).unwrap().is_uppercase(),
"GOTO" => found_err = found_err || args.len() != 3 || args[2].parse::<u16>().is_err(),
"IF" => found_err = found_err || args.len() != 7 || args[5] != "GOTO" || args[6].parse::<u16>().is_err(),
_ => { }
}
if found_err {
return Err(err);
}
// remove line number from args
args.remove(0);
self.commands.insert(line_num, args);
Ok(())
}
pub fn eval_value(&self, value: &str) -> Result<u16, InterpreterError> {
if value.chars().nth(0).unwrap().is_uppercase() {
match self.variables.get(value) {
Some(num) => Ok(*num),
None => Err(InterpreterError::UnknownVariable { name: value.to_string() })
}
} else {
match value.parse::<u16>() {
Ok(num) => Ok(num),
Err(_err) => Err(InterpreterError::NotANumber { value: value.to_string() })
}
}
}
pub fn run(&mut self) -> Result<(), InterpreterError> {
let mut cmd_iter = self.commands.iter();
while let Some((line_number, args)) = cmd_iter.next() {
match args[0] {
"PRINT" => {
match self.eval_value(args[1]) {
Ok(num) => match self.output.write_all(&format!("{}\n", &num).as_bytes()) {
Err(err) => return Err(InterpreterError::IoError(err)),
_ => { }
},
Err(err) => match err {
InterpreterError::UnknownVariable { name } =>
return Err(construct_runerr(line_number, &format!("Unknown variable {}", name))),
InterpreterError::NotANumber { value } =>
match self.output.write_all(&format!("{}\n", value).as_bytes()) {
Err(err) => return Err(InterpreterError::IoError(err)),
_ => { }
},
_ => { }
}
};
},
"READ" => {
let mut buf = String::new();
match self.input.read_line(&mut buf) {
Ok(_size) => { },
Err(err) => return Err(InterpreterError::IoError(err))
};
match buf.trim().parse::<u16>() {
Ok(num) => self.variables.insert(args[1], num),
Err(_err) => return Err(construct_runerr(line_number, "Invalid value"))
};
},
"GOTO" => {
let goto_line = args[1].parse::<u16>().unwrap();
+ let mut prev_line: Option<u16> = None;
- match cmd_iter.find(|&(ln, _ar)| *ln == goto_line) {
- Some(_) => { },
- None => return Err(construct_runerr(line_number, "Invalid line number"))
+ cmd_iter = self.commands.iter();
+
+ while let Some((ln, _)) = cmd_iter.next() {
+ if *ln == goto_line { break; }
+ prev_line = Some(*ln);
}
+
+ cmd_iter = self.commands.iter();
+
+ match prev_line {
+ Some(prev_ln) =>
+ if prev_ln != *self.commands.iter().next_back().unwrap().0 {
+ while let Some((ln, _)) = cmd_iter.next() {
+ if *ln == prev_ln { break; }
+ }
+ } else {
+ return Err(construct_runerr(line_number, "Invalid line number"))
+ },
+ None => { }
+ };
},
"IF" => {
let left: u16;
let right: u16;
match self.eval_value(args[1]) {
Ok(num) => left = num,
Err(_err) => return Err(construct_runerr(line_number, "Runtime error"))
};
match self.eval_value(args[3]) {
Ok(num) => right = num,
Err(_err) => return Err(construct_runerr(line_number, "Runtime error"))
};
let condition = match args[2] {
"<" => left < right,
">" => left > right,
"=" => left == right,
_ => false
};
if condition {
let goto_line = args[5].parse::<u16>().unwrap();
-
- match cmd_iter.find(|&(ln, _ar)| *ln == goto_line) {
- Some(_) => { },
- None => return Err(construct_runerr(line_number, "Invalid line number"))
+ let mut prev_line: Option<u16> = None;
+
+ cmd_iter = self.commands.iter();
+
+ while let Some((ln, _)) = cmd_iter.next() {
+ if *ln == goto_line { break; }
+ prev_line = Some(*ln);
}
+
+ cmd_iter = self.commands.iter();
+
+ match prev_line {
+ Some(prev_ln) => {
+ if prev_ln != *self.commands.iter().next_back().unwrap().0 {
+ while let Some((ln, _)) = cmd_iter.next() {
+ if *ln == prev_ln { break; }
+ }
+ } else {
+ return Err(construct_runerr(line_number, "Invalid line number"))
+ }
+ },
+ None => { }
+ };
}
},
_ => { }
}
};
Ok(())
}
-}
+}