mirror of
https://github.com/teo3300/rust-mal.git
synced 2026-01-12 01:05:32 +01:00
Created core file
- keep core functions in a different file - I can return custom values UwU Signed-off-by: teo3300 <matteo.rogora@live.it>
This commit is contained in:
103
src/core.rs
Normal file
103
src/core.rs
Normal file
@ -0,0 +1,103 @@
|
||||
// This file should contain all the necessary function to define builtin functions
|
||||
|
||||
use crate::env::env_binds;
|
||||
use crate::printer::prt;
|
||||
use crate::types::{MalType, MalErr, MalRet};
|
||||
use crate::types::MalType::{Fun, MalFun, List};
|
||||
|
||||
use MalType::Int;
|
||||
|
||||
pub fn scream() -> MalRet {
|
||||
panic!("If this messagge occurs, something went terribly wrong")
|
||||
}
|
||||
|
||||
pub fn call_func(func: &MalType, args: &[MalType]) -> MalRet {
|
||||
match func {
|
||||
Fun(func, _) => func(args),
|
||||
MalFun {
|
||||
eval,
|
||||
params,
|
||||
ast,
|
||||
env,
|
||||
} => {
|
||||
let inner_env = env_binds(env.clone(), params, args)?;
|
||||
// It's fine to clone the environment here
|
||||
// since this is when the function is actually called
|
||||
match eval(ast, inner_env)? {
|
||||
List(list) => Ok(list.last().unwrap_or(&Nil).clone()),
|
||||
_ => scream(),
|
||||
}
|
||||
}
|
||||
_ => Err(MalErr::unrecoverable(
|
||||
format!("{:?} is not a function", prt(func)).as_str(),
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
fn if_number(val: &MalType) -> Result<isize, MalErr> {
|
||||
match val {
|
||||
Int(val) => Ok(*val),
|
||||
_ => Err(MalErr::unrecoverable(
|
||||
format!("{:?} is not a number", prt(&val)).as_str(),
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn arithmetic_op(set: isize, f: fn(isize, isize) -> isize, args: &[MalType]) -> MalRet {
|
||||
if args.is_empty() {
|
||||
return Ok(Int(set));
|
||||
}
|
||||
|
||||
let mut left = if_number(&args[0])?;
|
||||
if args.len() > 1 {
|
||||
let right = &args[1..];
|
||||
for el in right {
|
||||
left = f(left, if_number(el)?);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Int(left))
|
||||
}
|
||||
|
||||
use MalType::{Bool, Nil};
|
||||
|
||||
pub fn comparison_op(f: fn(isize, isize) -> bool, args: &[MalType]) -> MalRet {
|
||||
match args.len() {
|
||||
0 => Err(MalErr::unrecoverable(
|
||||
"Comparison requires at least 1 argument",
|
||||
)),
|
||||
_ => {
|
||||
let (left, rights) = car_cdr(args);
|
||||
let mut left = if_number(left)?;
|
||||
for right in rights {
|
||||
let right = if_number(right)?;
|
||||
if !f(left, right) {
|
||||
return Ok(Nil);
|
||||
}
|
||||
left = right;
|
||||
}
|
||||
Ok(Bool(true))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Extract the car and cdr from a list
|
||||
pub fn car_cdr(list: &[MalType]) -> (&MalType, &[MalType]) {
|
||||
(
|
||||
&list[0],
|
||||
if list.len() > 1 {
|
||||
&list[1..]
|
||||
} else {
|
||||
&list[0..0]
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
use std::process::exit;
|
||||
|
||||
pub fn core_exit(list: &[MalType]) -> MalRet {
|
||||
match car_cdr(list).0 {
|
||||
Int(val) => exit(*val as i32),
|
||||
_ => exit(-1)
|
||||
}
|
||||
}
|
||||
10
src/env.rs
10
src/env.rs
@ -1,3 +1,4 @@
|
||||
use crate::core::{arithmetic_op, comparison_op, core_exit};
|
||||
use crate::types::{MalErr, MalType::*};
|
||||
use crate::types::{MalMap, MalRet, MalType};
|
||||
use std::cell::RefCell;
|
||||
@ -91,18 +92,11 @@ pub fn env_binds(outer: Env, binds: &MalType, exprs: &[MalType]) -> Result<Env,
|
||||
}
|
||||
|
||||
use crate::types::MalType::{Fun, Str};
|
||||
use crate::types::{arithmetic_op, comparison_op};
|
||||
use std::process::exit;
|
||||
|
||||
pub fn scream() -> MalRet {
|
||||
panic!("If this messagge occurs, something went terribly wrong")
|
||||
}
|
||||
|
||||
pub fn env_init() -> Env {
|
||||
env_init!(None,
|
||||
"test" => Fun(|_| Ok(Str("This is a test function".to_string())), "Just a test function"),
|
||||
"quit" => Fun(|_| {exit(0)}, "Quits the program with success status (0)"),
|
||||
"help" => Fun(|_| {scream()}, "Gets information about the symbols"),
|
||||
"exit" => Fun(|a| {core_exit(a)}, "Quits the program with specified status"),
|
||||
"+" => Fun(|a| arithmetic_op(0, |a, b| a + b, a), "Returns the sum of the arguments"),
|
||||
"-" => Fun(|a| arithmetic_op(0, |a, b| a - b, a), "Returns the difference of the arguments"),
|
||||
"*" => Fun(|a| arithmetic_op(1, |a, b| a * b, a), "Returns the product of the arguments"),
|
||||
|
||||
31
src/eval.rs
31
src/eval.rs
@ -1,32 +1,9 @@
|
||||
use crate::env::{env_binds, env_get, env_new, env_set};
|
||||
use crate::env::{scream, Env};
|
||||
use crate::env::{env_get, env_new, env_set};
|
||||
use crate::env::Env;
|
||||
use crate::printer::prt;
|
||||
use crate::types::MalType::*;
|
||||
use crate::types::{car_cdr, MalErr};
|
||||
use crate::types::{MalArgs, MalMap, MalRet, MalType};
|
||||
|
||||
fn call_func(func: &MalType, args: &[MalType]) -> MalRet {
|
||||
match func {
|
||||
Fun(func, _) => func(args),
|
||||
MalFun {
|
||||
eval,
|
||||
params,
|
||||
ast,
|
||||
env,
|
||||
} => {
|
||||
let inner_env = env_binds(env.clone(), params, args)?;
|
||||
// It's fine to clone the environment here
|
||||
// since this is when the function is actually called
|
||||
match eval(ast, inner_env)? {
|
||||
List(list) => Ok(list.last().unwrap_or(&Nil).clone()),
|
||||
_ => scream(),
|
||||
}
|
||||
}
|
||||
_ => Err(MalErr::unrecoverable(
|
||||
format!("{:?} is not a function", prt(func)).as_str(),
|
||||
)),
|
||||
}
|
||||
}
|
||||
use crate::core::{car_cdr, call_func};
|
||||
use crate::types::{MalArgs, MalMap, MalRet, MalErr, MalType};
|
||||
|
||||
/// Resolve the first element of the list as the function name and call it
|
||||
/// with the other elements as arguments
|
||||
|
||||
@ -8,6 +8,7 @@ mod printer;
|
||||
mod reader;
|
||||
mod step4_if_fn_do;
|
||||
mod types;
|
||||
mod core;
|
||||
|
||||
use env::env_init;
|
||||
use parse_tools::{load_file, interactive};
|
||||
|
||||
63
src/types.rs
63
src/types.rs
@ -107,65 +107,4 @@ pub fn unescape_str(s: &str) -> String {
|
||||
.replace("\\\\", "\\")
|
||||
.replace("\\n", "\n")
|
||||
.replace("\\\"", "\"")
|
||||
}
|
||||
|
||||
/// Extract the car and cdr from a list
|
||||
pub fn car_cdr(list: &[MalType]) -> (&MalType, &[MalType]) {
|
||||
(
|
||||
&list[0],
|
||||
if list.len() > 1 {
|
||||
&list[1..]
|
||||
} else {
|
||||
&list[0..0]
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
use MalType::Int;
|
||||
|
||||
fn if_number(val: &MalType) -> Result<isize, MalErr> {
|
||||
match val {
|
||||
Int(val) => Ok(*val),
|
||||
_ => Err(MalErr::unrecoverable(
|
||||
format!("{:?} is not a number", prt(&val)).as_str(),
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn arithmetic_op(set: isize, f: fn(isize, isize) -> isize, args: &[MalType]) -> MalRet {
|
||||
if args.is_empty() {
|
||||
return Ok(Int(set));
|
||||
}
|
||||
|
||||
let mut left = if_number(&args[0])?;
|
||||
if args.len() > 1 {
|
||||
let right = &args[1..];
|
||||
for el in right {
|
||||
left = f(left, if_number(el)?);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Int(left))
|
||||
}
|
||||
|
||||
use MalType::{Bool, Nil};
|
||||
|
||||
pub fn comparison_op(f: fn(isize, isize) -> bool, args: &[MalType]) -> MalRet {
|
||||
match args.len() {
|
||||
0 => Err(MalErr::unrecoverable(
|
||||
"Comparison requires at least 1 argument",
|
||||
)),
|
||||
_ => {
|
||||
let (left, rights) = car_cdr(args);
|
||||
let mut left = if_number(left)?;
|
||||
for right in rights {
|
||||
let right = if_number(right)?;
|
||||
if !f(left, right) {
|
||||
return Ok(Nil);
|
||||
}
|
||||
left = right;
|
||||
}
|
||||
Ok(Bool(true))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user