Skip to content

Commit

Permalink
fix: using closures instead of function pointers
Browse files Browse the repository at this point in the history
  • Loading branch information
ali77gh committed Jun 5, 2024
1 parent 916134b commit aab82f5
Show file tree
Hide file tree
Showing 9 changed files with 103 additions and 38 deletions.
2 changes: 1 addition & 1 deletion src/builtin_function/assign.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ mod tests {

#[test]
fn assign_value_and_variable() {
let mut runtime = Runtime::new(|_| {}, || "".to_string());
let mut runtime = Runtime::new(Box::new(|_| {}), Box::new(|| "".to_string()));

assign(
&mut runtime,
Expand Down
2 changes: 1 addition & 1 deletion src/builtin_function/control_flow/new_tag.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ mod tests {

#[test]
fn new_tag_test() {
let mut runtime = Runtime::new(|_| {}, || "".to_string());
let mut runtime = Runtime::new(Box::new(|_| {}), Box::new(|| "".to_string()));

new_tag(
&mut runtime,
Expand Down
15 changes: 12 additions & 3 deletions src/builtin_function/debugger/dump.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,22 @@ use crate::{
};

pub fn dump(runtime: &mut Runtime, executable: &ExecutableLine) -> Result<()> {
runtime.std_out(format!("------- Memory dump line: {}", executable.line_number).as_str());
let mut result = String::new();
for variable in runtime.variables.iter() {
let name = variable.0;
let value = variable.1;
runtime.std_out(format!("{} -> ${}", value.to_string(), name).as_str())
result.push_str(format!("{} -> ${}\n", value.to_string(), name).as_str())
}
runtime.std_out("------- Memory dump ends");
result.pop();
runtime.std_out(
format!(
"------- Memory dump line: {} -------",
executable.line_number
)
.as_str(),
);
runtime.std_out(&result);
runtime.std_out("------- Memory dump ends -------");

Ok(())
}
4 changes: 2 additions & 2 deletions src/builtin_function/std_io/input.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::builtin_function::utils::returns;
use crate::common::data_type::DataType;
use crate::common::errors::Result;
use crate::builtin_function::utils::returns;
use crate::{common::executable::ExecutableLine, runtime::Runtime};

pub fn input(runtime: &mut Runtime, executable: &ExecutableLine) -> Result<()> {
Expand All @@ -19,7 +19,7 @@ mod tests {

#[test]
fn input_test() {
let mut runtime = Runtime::new(|_| {}, || "test".to_string());
let mut runtime = Runtime::new(Box::new(|_| {}), Box::new(|| "test".to_string()));

input(
&mut runtime,
Expand Down
20 changes: 10 additions & 10 deletions src/builtin_function/std_io/println.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::common::errors::Result;
use crate::builtin_function::utils::param_to_datatype;
use crate::common::errors::Result;
use crate::{common::executable::ExecutableLine, runtime::Runtime};

pub fn println(runtime: &mut Runtime, executable: &ExecutableLine) -> Result<()> {
Expand All @@ -23,10 +23,10 @@ mod tests {
#[test]
fn print_string() {
let mut runtime = Runtime::new(
|x| {
Box::new(|x| {
assert_eq!(x, "test");
},
|| "".to_string(),
}),
Box::new(|| "".to_string()),
);

println(
Expand All @@ -44,10 +44,10 @@ mod tests {
#[test]
fn print_int() {
let mut runtime = Runtime::new(
|x| {
Box::new(|x| {
assert_eq!(x, "2");
},
|| "".to_string(),
}),
Box::new(|| "".to_string()),
);

println(
Expand All @@ -65,10 +65,10 @@ mod tests {
#[test]
fn print_many() {
let mut runtime = Runtime::new(
|x| {
Box::new(|x| {
assert_eq!(x, "2, false");
},
|| "".to_string(),
}),
Box::new(|| "".to_string()),
);

println(
Expand Down
59 changes: 56 additions & 3 deletions src/runners/eval.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,12 @@ use crate::compile::parser::Parser;
use crate::compile::preprocessor::Preprocessor;
use crate::runtime::Runtime;

pub fn eval(code: String, std_out: fn(&str), std_in: fn() -> String, on_error: fn(ChapError)) {
pub fn eval<'a>(
code: String,
std_out: Box<dyn FnMut(&str) + 'a>,
std_in: Box<dyn FnMut() -> String + 'a>,
mut on_error: impl FnMut(ChapError),
) {
let mut runtime = match make_runtime(code, std_out, std_in) {
Ok(rt) => rt,
Err(e) => {
Expand All @@ -30,7 +35,11 @@ pub fn eval(code: String, std_out: fn(&str), std_in: fn() -> String, on_error: f
}
}

fn make_runtime(code: String, std_out: fn(&str), std_in: fn() -> String) -> Result<Runtime> {
fn make_runtime<'a>(
code: String,
std_out: Box<dyn FnMut(&str) + 'a>,
std_in: Box<dyn FnMut() -> String + 'a>,
) -> Result<Runtime<'a>> {
let mut preprocessor = Preprocessor::default();
let mut parser = Parser::default();
let mut runtime = Runtime::new(std_out, std_in);
Expand All @@ -51,10 +60,54 @@ fn make_runtime(code: String, std_out: fn(&str), std_in: fn() -> String) -> Resu

#[cfg(test)]
mod tests {
use crate::common::errors::ChapError;

use super::eval;

#[test]
fn test_eval() {
eval("3".to_string(), |_| {}, || "".to_string(), |_| {});
eval(
"3".to_string(),
Box::new(|_| {}),
Box::new(|| "".to_string()),
|_| {},
);
}

#[test]
fn test_eval_closure() {
let input = "INPUT".to_string();
let mut output = "".to_string();

eval(
"input -> $a; $a -> print".to_string(),
Box::new(|out| {
output = out.to_string();
}),
Box::new(|| {
return input.clone();
}),
|_| {},
);
assert_eq!(input, output);
}

#[test]
fn test_eval_error() {
let mut error: Option<ChapError> = None;
eval(
"a".to_string(),
Box::new(|_| {}),
Box::new(|| {
return "".to_string();
}),
|e| {
error = Some(e);
},
);

if let None = error {
assert!(false, "error not happened");
}
}
}
8 changes: 4 additions & 4 deletions src/runners/file_executor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,16 @@ pub fn file_executor(file_name: &str) {
let code = read_to_string(file_name).unwrap();
eval(
code,
|msg| {
Box::new(|msg| {
println!("{}", msg);
},
|| {
}),
Box::new(|| {
let mut buffer = String::new();
let stdin = io::stdin(); // We get `Stdin` here.
stdin.read_line(&mut buffer).unwrap();
buffer = buffer.replace('\n', "").trim().to_string();
buffer
},
}),
|e| {
e.exit_with_error();
},
Expand Down
6 changes: 3 additions & 3 deletions src/runners/repl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ pub fn start_repl() {
let mut reader = DefaultEditor::new().unwrap(); // TODO: handle error

let mut runtime = Runtime::new(
|msg| {
Box::new(|msg| {
println!("{}", msg);
},
|| String::from(""),
}),
Box::new(|| String::from("")),
);

loop {
Expand Down
25 changes: 14 additions & 11 deletions src/runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,20 @@ use crate::common::errors::Result;
use crate::common::executable::ExecutableLine;
use std::collections::HashMap;

pub struct Runtime {
pub struct Runtime<'a> {
pub executables: Vec<ExecutableLine>,
pub variables: HashMap<String, DataType>, // <variable name, variable value>
pub tags: HashMap<String, usize>, // <tag name, index in executables vector>
pub current_line: usize,
pub std_out: fn(&str),
pub std_in: fn() -> String,
pub std_out: Box<dyn FnMut(&str) + 'a>,
pub std_in: Box<dyn FnMut() -> String + 'a>,
}

impl Runtime {
pub fn new(std_out: fn(&str), std_in: fn() -> String) -> Self {
impl<'a> Runtime<'a> {
pub fn new(
std_out: Box<dyn FnMut(&str) + 'a>,
std_in: Box<dyn FnMut() -> String + 'a>,
) -> Self {
Self {
executables: vec![],
variables: HashMap::new(),
Expand Down Expand Up @@ -43,11 +46,11 @@ impl Runtime {
Ok(())
}

pub fn std_out(&self, msg: &str) {
pub fn std_out(&mut self, msg: &str) {
(self.std_out)(msg);
}

pub fn std_in(&self) -> String {
pub fn std_in(&mut self) -> String {
(self.std_in)()
}
}
Expand All @@ -61,7 +64,7 @@ mod tests {

#[test]
fn simple_execution_test() {
let mut rt = Runtime::new(|_| {}, || "".to_string());
let mut rt = Runtime::new(Box::new(|_| {}), Box::new(|| "".to_string()));

assert_eq!(rt.current_line, 0);
rt.on_new_line(ExecutableLine::new(
Expand All @@ -82,10 +85,10 @@ mod tests {
#[test]
fn runtime_std_test() {
let mut rt = Runtime::new(
|x| {
Box::new(|x| {
assert_eq!(x, "the text");
},
|| "the text".to_string(),
}),
Box::new(|| "the text".to_string()),
);

rt.on_new_line(ExecutableLine::new(
Expand Down

0 comments on commit aab82f5

Please sign in to comment.