Решение на Basic BASIC от Никола Ласков

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

Към профила на Никола Ласков

Резултати

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

Код

use std::{io::{self, Write, Read}, collections::HashMap};
#[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: Read, W: Write> {
input: R,
output: &'a mut W,
lines:HashMap<String,String>,
variables:HashMap<String,String>,
}
impl<'a,R: Read, W: Write> Interpreter<'a,R, W > {
pub fn new(input: R, output: &'a mut W) -> Self{
return Interpreter{
input,
output,
lines:HashMap::new(),
variables:HashMap::new(),
}
}
}
impl<'a,R: Read, W: Write> Interpreter<'a,R, W> {
pub fn add(&mut self, code: &str) -> Result<(), InterpreterError> {
let res:Vec<&str> = code.split(" ").collect();
let com:Vec<&str> = code.splitn(2," ").collect();
//Error checker
let test = res[0].parse::<u16>();
match test {
Ok(_) => (),
Err(_) => return Err(InterpreterError::SyntaxError { code:code.to_string() }),
}
if res[1] == "READ" {
if res.len()!=3 {return Err(InterpreterError::SyntaxError { code:code.to_string() });}
let chars:Vec<_> = res[2].chars().collect();
if chars[0].is_lowercase(){return Err(InterpreterError::SyntaxError { code:code.to_string() });}
}
else if res[1] == "PRINT"{
if res.len()!=3 {return Err(InterpreterError::SyntaxError { code:code.to_string() });}
}
else if res[1] == "GOTO" {
if res.len()!= 3 {return Err(InterpreterError::SyntaxError { code:code.to_string() });}
let test = res[2].parse::<u16>();
match test {
Ok(_) => (),
Err(_) => return Err(InterpreterError::SyntaxError { code:code.to_string() }),
}
}
else if res[1] == "IF" {
if res.len()!= 7 {return Err(InterpreterError::SyntaxError { code:code.to_string() });}
if !(res[3] == ">" || res[3] == "=" || res[3] == "<") {
return Err(InterpreterError::SyntaxError { code:code.to_string() });
}
if res[5]!="GOTO" {
return Err(InterpreterError::SyntaxError { code:code.to_string() });
}
let test = res[6].parse::<u16>();
match test {
Ok(_) => (),
Err(_) => return Err(InterpreterError::SyntaxError { code:code.to_string() }),
}
}else{
return Err(InterpreterError::SyntaxError { code:code.to_string() });
}
self.lines.insert(String::from(com[0]),String::from(com[1]));
return Ok(());
}
}
impl<'a,R: Read, W: Write> Interpreter<'a,R, W> {
/// Оценява `value` като стойност в контекста на интерпретатора:
///
/// - Ако `value` е низ, който започва с главна буква (съгласно `char::is_uppercase`), търсим
/// дефинирана променлива с това име и връщаме нейната стойност.
/// -> Ако няма такава, връщаме `InterpreterError::UnknownVariable` с това име.
/// - Ако `value` е валидно u16 число, връщаме числото
/// -> Иначе, връщаме `InterpreterError::NotANumber` с тази стойност
///
pub fn eval_value(&self, value: &str) -> Result<u16, InterpreterError> {
let char_vec: Vec<char> = value.chars().collect();
let ch = char_vec[0];
if ch.is_uppercase(){
if self.variables.contains_key(value){
return Ok(self.variables.get(value).unwrap().to_string().parse::<u16>().unwrap());
}
else{
return Err(InterpreterError::UnknownVariable{name:String::from(value)});
}
}
match value.parse::<u16>(){
Ok(x) => return Ok(x),
Err(_) => return Err(InterpreterError::NotANumber{value:value.to_string()})
}
}
}
impl<'a,R: Read, W: Write> Interpreter<'a,R, W> {
/// Функцията започва да изпълнява редовете на програмата в нарастващ ред. Ако стигне до GOTO,
/// скача на съответния ред и продължава от него в нарастващ ред. Когато вече няма ред с
/// по-голямо число, функцията свършва и връща `Ok(())`.
///
/// Вижте по-долу за отделните команди и какви грешки могат да върнат.
///
pub fn run(&mut self) -> Result<(), InterpreterError> {
let mut buffer = String::new();
let res = self.input.read_to_string(&mut buffer);
match res {
Ok(_) => (),
Err(x) => return Err(InterpreterError::IoError(x))
}
let mut input = buffer.split("\n");
let mut keys: Vec<_> =self.lines.keys().collect();
keys.sort();
let mut i=0;
while i < keys.len(){
let x:Vec<_> = self.lines.get(keys[i]).unwrap().split(" ").collect();
print!("{:?}\n",x);
if x[0] == "READ"{
let text = input.next().unwrap();
self.variables.insert(x[1].to_string(), text.to_string());
}
else if x[0] == "PRINT"{
let temp = self.eval_value(x[1]);
match temp {
Ok(_)=>(),
Err(_) => return Err(InterpreterError::RuntimeError{line_number:keys[i].parse::<u16>().unwrap(),message:"Error".to_string()})
}
let temp = temp.unwrap().to_string();
let temp = format!("{}{}",temp,"\n");
let res = self.output.write(temp.as_bytes());
match res {
Ok(_) => (),
Err(x) => return Err(InterpreterError::IoError(x))
}
}
else if x[0] == "GOTO"{
let previous_i = i;
for j in 0..keys.len(){
if keys[j] == x[1]{
i = j;
}
}
if i == previous_i{
return Err(InterpreterError::RuntimeError{line_number:keys[i].parse::<u16>().unwrap(),message:"Error".to_string()})
}
continue;
}
else if x[0] == "IF"{
let var1 = self.eval_value(x[1]).unwrap();
let var2= self.eval_value(x[3]).unwrap();
match x[2] {
"=" => if var1 == var2{
let previous_i = i;
for j in 0..keys.len(){
if keys[j] == x[5]{
i = j;
break;
}
}
if i == previous_i{
return Err(InterpreterError::RuntimeError{line_number:keys[i].parse::<u16>().unwrap(),message:"Error".to_string()})
}
continue;
},
"<" => if var1 < var2{
let previous_i = i;
for j in 0..keys.len(){
if keys[j] == x[5]{
i = j;
break;
}
}
if i == previous_i{
return Err(InterpreterError::RuntimeError{line_number:keys[i].parse::<u16>().unwrap(),message:"Error".to_string()})
}
continue;
},
_ => if var1 > var2{
let previous_i = i;
for j in 0..keys.len(){
if keys[j] == x[5]{
i = j;
break;
}
}
if i == previous_i{
return Err(InterpreterError::RuntimeError{line_number:keys[i].parse::<u16>().unwrap(),message:"Error".to_string()})
}
continue;
}
}
}
i = i+1;
}
return Ok(());
}
}

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

Compiling solution v0.1.0 (/tmp/d20230111-3772066-158gudn/solution)
    Finished test [unoptimized + debuginfo] target(s) in 1.47s
     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_print ... ok
test solution_test::test_basic_input ... ok
test solution_test::test_erroring_goto ... ok
test solution_test::test_basic_read ... ok
test solution_test::test_io_error_read ... ok
test solution_test::test_io_error_write ... ok
test solution_test::test_full_program ... FAILED
test solution_test::test_line_order_and_overwriting ... ok
test solution_test::test_print_cyrillic ... FAILED
test solution_test::test_print_vars_and_strings ... FAILED
test solution_test::test_syntax_errors_1 ... FAILED
test solution_test::test_runtime_errors ... FAILED
test solution_test::test_syntax_errors_2 ... ok

failures:

---- solution_test::test_full_program stdout ----
["READ", "Guess"]
["PRINT", "too_high"]
thread '<unnamed>' panicked at 'called `Result::unwrap()` on an `Err` value: RuntimeError { line_number: 100, message: "Error" }', tests/solution_test.rs:245:31
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
thread 'solution_test::test_full_program' panicked at 'called `Result::unwrap()` on an `Err` value: RuntimeError { line_number: 100, message: "Error" }', tests/solution_test.rs:230:5

---- solution_test::test_print_cyrillic stdout ----
["READ", "Щ"]
["READ", "Юнак"]
["PRINT", "Щ"]
["PRINT", "Юнак"]
["PRINT", "евала"]
thread '<unnamed>' panicked at 'called `Result::unwrap()` on an `Err` value: RuntimeError { line_number: 50, message: "Error" }', tests/solution_test.rs:171:31
thread 'solution_test::test_print_cyrillic' panicked at 'called `Result::unwrap()` on an `Err` value: RuntimeError { line_number: 50, message: "Error" }', tests/solution_test.rs:160:5

---- solution_test::test_print_vars_and_strings stdout ----
["READ", "A"]
["READ", "Abc"]
["PRINT", "A"]
["PRINT", "Abc"]
["PRINT", "abc"]
thread '<unnamed>' panicked at 'called `Result::unwrap()` on an `Err` value: RuntimeError { line_number: 50, message: "Error" }', tests/solution_test.rs:151:31
thread 'solution_test::test_print_vars_and_strings' panicked at 'called `Result::unwrap()` on an `Err` value: RuntimeError { line_number: 50, message: "Error" }', tests/solution_test.rs:140: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:260: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 ----
["PRINT", "13"]
["PRINT", "A"]
["READ", "A"]
["READ", "B"]
["READ", "C"]
thread '<unnamed>' panicked at 'Expression Ok(()) does not match the pattern "Err(InterpreterError::RuntimeError { line_number: 40, .. })"', tests/solution_test.rs:315:9
thread 'solution_test::test_runtime_errors' panicked at 'Expression Ok(()) does not match the pattern "Err(InterpreterError::RuntimeError { line_number: 40, .. })"', tests/solution_test.rs:301:5


failures:
    solution_test::test_full_program
    solution_test::test_print_cyrillic
    solution_test::test_print_vars_and_strings
    solution_test::test_runtime_errors
    solution_test::test_syntax_errors_1

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`

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

Никола качи първо решение на 10.01.2023 10:53 (преди 5 месеца)

Никола качи решение на 10.01.2023 12:03 (преди 5 месеца)

use std::{io::{self, Write, Read}, collections::HashMap};
#[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: Read, W: Write> {
input: R,
output: &'a mut W,
lines:HashMap<String,String>,
variables:HashMap<String,String>,
}
impl<'a,R: Read, W: Write> Interpreter<'a,R, W > {
pub fn new(input: R, output: &'a mut W) -> Self{
return Interpreter{
input,
output,
lines:HashMap::new(),
variables:HashMap::new(),
}
}
}
impl<'a,R: Read, W: Write> Interpreter<'a,R, W> {
pub fn add(&mut self, code: &str) -> Result<(), InterpreterError> {
let res:Vec<&str> = code.split(" ").collect();
let com:Vec<&str> = code.splitn(2," ").collect();
//Error checker
let test = res[0].parse::<u16>();
match test {
Ok(_) => (),
Err(_) => return Err(InterpreterError::SyntaxError { code:code.to_string() }),
}
if res[1] == "READ" {
if res.len()!=3 {return Err(InterpreterError::SyntaxError { code:code.to_string() });}
let chars:Vec<_> = res[2].chars().collect();
if chars[0].is_lowercase(){return Err(InterpreterError::SyntaxError { code:code.to_string() });}
}
else if res[1] == "PRINT"{
if res.len()!=3 {return Err(InterpreterError::SyntaxError { code:code.to_string() });}
}
else if res[1] == "GOTO" {
if res.len()!= 3 {return Err(InterpreterError::SyntaxError { code:code.to_string() });}
let test = res[2].parse::<u16>();
match test {
Ok(_) => (),
Err(_) => return Err(InterpreterError::SyntaxError { code:code.to_string() }),
}
}
else if res[1] == "IF" {
if res.len()!= 7 {return Err(InterpreterError::SyntaxError { code:code.to_string() });}
if !(res[3] == ">" || res[3] == "=" || res[3] == "<") {
return Err(InterpreterError::SyntaxError { code:code.to_string() });
}
if res[5]!="GOTO" {
return Err(InterpreterError::SyntaxError { code:code.to_string() });
}
let test = res[6].parse::<u16>();
match test {
Ok(_) => (),
Err(_) => return Err(InterpreterError::SyntaxError { code:code.to_string() }),
}
}else{
return Err(InterpreterError::SyntaxError { code:code.to_string() });
}
self.lines.insert(String::from(com[0]),String::from(com[1]));
return Ok(());
}
}
impl<'a,R: Read, W: Write> Interpreter<'a,R, W> {
/// Оценява `value` като стойност в контекста на интерпретатора:
///
/// - Ако `value` е низ, който започва с главна буква (съгласно `char::is_uppercase`), търсим
/// дефинирана променлива с това име и връщаме нейната стойност.
/// -> Ако няма такава, връщаме `InterpreterError::UnknownVariable` с това име.
/// - Ако `value` е валидно u16 число, връщаме числото
/// -> Иначе, връщаме `InterpreterError::NotANumber` с тази стойност
///
pub fn eval_value(&self, value: &str) -> Result<u16, InterpreterError> {
let char_vec: Vec<char> = value.chars().collect();
let ch = char_vec[0];
if ch.is_uppercase(){
if self.variables.contains_key(value){
return Ok(self.variables.get(value).unwrap().to_string().parse::<u16>().unwrap());
}
else{
return Err(InterpreterError::UnknownVariable{name:String::from(value)});
}
}
match value.parse::<u16>(){
Ok(x) => return Ok(x),
Err(_) => return Err(InterpreterError::NotANumber{value:value.to_string()})
}
}
}
impl<'a,R: Read, W: Write> Interpreter<'a,R, W> {
/// Функцията започва да изпълнява редовете на програмата в нарастващ ред. Ако стигне до GOTO,
/// скача на съответния ред и продължава от него в нарастващ ред. Когато вече няма ред с
/// по-голямо число, функцията свършва и връща `Ok(())`.
///
/// Вижте по-долу за отделните команди и какви грешки могат да върнат.
///
pub fn run(&mut self) -> Result<(), InterpreterError> {
let mut buffer = String::new();
let res = self.input.read_to_string(&mut buffer);
match res {
Ok(_) => (),
Err(x) => return Err(InterpreterError::IoError(x))
}
let mut input = buffer.split("\n");
let mut keys: Vec<_> =self.lines.keys().collect();
keys.sort();
let mut i=0;
while i < keys.len(){
let x:Vec<_> = self.lines.get(keys[i]).unwrap().split(" ").collect();
print!("{:?}\n",x);
if x[0] == "READ"{
let text = input.next().unwrap();
self.variables.insert(x[1].to_string(), text.to_string());
}
else if x[0] == "PRINT"{
let temp = self.eval_value(x[1]);
match temp {
Ok(_)=>(),
Err(_) => return Err(InterpreterError::RuntimeError{line_number:keys[i].parse::<u16>().unwrap(),message:"Error".to_string()})
}
let temp = temp.unwrap().to_string();
+ let temp = format!("{}{}",temp,"\n");
let res = self.output.write(temp.as_bytes());
match res {
Ok(_) => (),
Err(x) => return Err(InterpreterError::IoError(x))
}
}
else if x[0] == "GOTO"{
let previous_i = i;
for j in 0..keys.len(){
if keys[j] == x[1]{
i = j;
}
}
if i == previous_i{
return Err(InterpreterError::RuntimeError{line_number:keys[i].parse::<u16>().unwrap(),message:"Error".to_string()})
}
continue;
}
else if x[0] == "IF"{
let var1 = self.eval_value(x[1]).unwrap();
let var2= self.eval_value(x[3]).unwrap();
match x[2] {
"=" => if var1 == var2{
let previous_i = i;
for j in 0..keys.len(){
if keys[j] == x[5]{
i = j;
break;
}
}
if i == previous_i{
return Err(InterpreterError::RuntimeError{line_number:keys[i].parse::<u16>().unwrap(),message:"Error".to_string()})
}
continue;
},
"<" => if var1 < var2{
let previous_i = i;
for j in 0..keys.len(){
if keys[j] == x[5]{
i = j;
break;
}
}
if i == previous_i{
return Err(InterpreterError::RuntimeError{line_number:keys[i].parse::<u16>().unwrap(),message:"Error".to_string()})
}
continue;
},
_ => if var1 > var2{
let previous_i = i;
for j in 0..keys.len(){
if keys[j] == x[5]{
i = j;
break;
}
}
if i == previous_i{
return Err(InterpreterError::RuntimeError{line_number:keys[i].parse::<u16>().unwrap(),message:"Error".to_string()})
}
continue;
}
}
}
i = i+1;
}
return Ok(());
}
}