mirror of
https://github.com/teo3300/rust-mal.git
synced 2026-01-12 01:05:32 +01:00
Moving a whole bunch of stuff in lisp
Signed-off-by: teo3300 <matteo.rogora@live.it>
This commit is contained in:
@ -1,7 +1,26 @@
|
||||
;; Previously in core.rs
|
||||
; Logic
|
||||
(def! not (fn* [x]
|
||||
(if x nil true)))
|
||||
|
||||
(def! and (fn* [a b]
|
||||
(if a
|
||||
b)))
|
||||
|
||||
(def! or (fn* [a b]
|
||||
(if a
|
||||
true
|
||||
b)))
|
||||
|
||||
(def! xor (fn* [a b]
|
||||
(if a
|
||||
(not b)
|
||||
b)))
|
||||
|
||||
; Other functions in core.rs
|
||||
(def! assert-eq (fn* [a b]
|
||||
(assert (= a b))))
|
||||
|
||||
(def! empty? (fn* [l]
|
||||
(= (count l) 0)))
|
||||
|
||||
|
||||
17
src/core.rs
17
src/core.rs
@ -1,6 +1,6 @@
|
||||
use std::env;
|
||||
|
||||
use crate::env::{arithmetic_op, car, comparison_op, env_new, env_set, mal_exit, Env};
|
||||
use crate::env::{any_zero, arithmetic_op, car, comparison_op, env_new, env_set, mal_exit, Env};
|
||||
|
||||
// This is the first time I implement a macro, and I'm copying it
|
||||
// so I will comment this a LOT
|
||||
@ -35,16 +35,17 @@ use crate::parse_tools::read_file;
|
||||
use crate::printer::pr_str;
|
||||
use crate::reader::{read_str, Reader};
|
||||
use crate::types::MalType::{Bool, Fun, Int, List, Nil, Str};
|
||||
use crate::types::{mal_assert, mal_assert_eq, mal_comp, MalArgs, MalErr};
|
||||
use crate::types::{mal_assert, mal_comp, MalArgs, MalErr};
|
||||
|
||||
pub fn ns_init() -> Env {
|
||||
env_init!(None,
|
||||
// That's it, you are all going to be simpler functions
|
||||
"test" => Fun(|_| Ok(Str("This is a test function".to_string())), "Just a test function"),
|
||||
"exit" => Fun(mal_exit, "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"),
|
||||
"/" => Fun(|a| arithmetic_op(1, |a, b| a / b, a), "Returns the division of the arguments"),
|
||||
"/" => Fun(|a| {any_zero(a)?; arithmetic_op(1, |a, b| a / b, a)}, "Returns the division of the arguments"),
|
||||
">" => Fun(|a| comparison_op(|a, b| a > b, a), "Returns true if the arguments are in strictly descending order, 'nil' otherwise"),
|
||||
"<" => Fun(|a| comparison_op(|a, b| a < b, a), "Returns true if the arguments are in strictly ascending order, 'nil' otherwise"),
|
||||
">=" => Fun(|a| comparison_op(|a, b| a >= b, a), "Returns true if the arguments are in descending order, 'nil' otherwise"),
|
||||
@ -57,13 +58,13 @@ pub fn ns_init() -> Env {
|
||||
"list?" => Fun(|a| Ok(Bool(a.iter().all(|el| matches!(el, List(_))))), "Return true if the first argument is a list, false otherwise"),
|
||||
// "empty?" => implemented through "count" in core.mal
|
||||
"count" => Fun(|a| Ok(Int(car(a)?.if_list()?.len() as isize)), "Return the number of elements in the first argument"),
|
||||
"and" => Fun(|a| Ok(Bool(a.iter().all(|a| !matches!(a, Nil | Bool(false))))), "Returns false if at least one of the arguments is 'false' or 'nil', true otherwise"),
|
||||
"or" => Fun(|a| Ok(Bool(a.iter().any(|a| !matches!(a, Nil | Bool(false))))), "Returns false if all the arguments are 'false' or 'nil', true otherwise"),
|
||||
"xor" => Fun(|a| Ok(Bool(a.iter().filter(|a| !matches!(a, Nil | Bool(false))).count() == 1)), "Returns true if one of the arguments is different from 'nil' or 'false', false otherwise"),
|
||||
// "not" => implemented throught "if" in core.mal
|
||||
// "and" => implemented through "if" in core.mal
|
||||
// "or" => implemented through "if" in core.mal
|
||||
// "xor" => implemented through "if" in core.mal
|
||||
// "not" => implemented through "if" in core.mal
|
||||
"=" => Fun(mal_comp, "Return true if the first two parameters are the same type and content, in case of lists propagate to all elements"),
|
||||
"assert" => Fun(mal_assert, "Return an error if assertion fails"),
|
||||
"assert-eq" => Fun(mal_assert_eq, "Return an error if arguments are not the same"),
|
||||
// "assert-eq" => implemented through "assert" in core.mal
|
||||
// Since the READ errors are Recoverable, when encountering one the reader continues appending to the previous status,
|
||||
// making unreasonable output, to solve this "upgrade" any kind of error in the inner "read_str" to an unrecoverable one, so the reader breaks the cycle
|
||||
"read-string" => Fun(|a| read_str(Reader::new().push(car(a)?.if_string()?)).map_err(MalErr::severe), "Tokenize and read the first argument"),
|
||||
|
||||
10
src/env.rs
10
src/env.rs
@ -106,6 +106,16 @@ pub fn call_func(func: &MalType, args: &[MalType]) -> CallRet {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn any_zero(list: &[MalType]) -> MalRet {
|
||||
if list
|
||||
.iter()
|
||||
.any(|x| if let MalType::Int(0) = x { true } else { false })
|
||||
{
|
||||
return Err(MalErr::unrecoverable("Attempting division by 0"));
|
||||
}
|
||||
return Ok(M::Nil);
|
||||
}
|
||||
|
||||
pub fn arithmetic_op(set: isize, f: fn(isize, isize) -> isize, args: &[MalType]) -> MalRet {
|
||||
Ok(M::Int(match args.len() {
|
||||
0 => set,
|
||||
|
||||
@ -14,8 +14,9 @@ fn eval_str(line: &str, env: &Env) -> MalRet {
|
||||
|
||||
pub fn set_home_path(env: &Env) {
|
||||
eval_str(
|
||||
"(or (def! MAL_HOME (env \"MAL_HOME\"))
|
||||
(def! MAL_HOME (str (env \"HOME\") \"/.config/mal\")))",
|
||||
"(if (env \"MAL_HOME\")
|
||||
(def! MAL_HOME (env \"MAL_HOME\"))
|
||||
(def! MAL_HOME (str (env \"HOME\") \"/.config/mal\")))",
|
||||
env,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
19
src/types.rs
19
src/types.rs
@ -120,25 +120,6 @@ pub fn mal_assert(args: &[MalType]) -> MalRet {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mal_assert_eq(args: &[MalType]) -> MalRet {
|
||||
let (car, cdr) = car_cdr(args)?;
|
||||
match mal_eq(car, cdr)? {
|
||||
M::Nil | M::Bool(false) => {
|
||||
let mut message = String::from("Assertion-eq failed: [");
|
||||
message.push_str(
|
||||
args.iter()
|
||||
.map(prt)
|
||||
.collect::<Vec<String>>()
|
||||
.join(" ")
|
||||
.as_str(),
|
||||
);
|
||||
message.push(']');
|
||||
Err(MalErr::unrecoverable(message.as_str()))
|
||||
}
|
||||
_ => Ok(M::Nil),
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Clone, Copy, Debug)]
|
||||
pub enum Severity {
|
||||
Recoverable,
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
(assert true)
|
||||
(assert (ok? 1))
|
||||
(assert-eq nil (ok? (1)))
|
||||
(assert-eq true (ok? 1))
|
||||
(ok? (assert true))
|
||||
(not (ok? (assert nil)))
|
||||
@ -9,23 +9,19 @@
|
||||
(assert (not (not true)))
|
||||
|
||||
; or
|
||||
(assert (not (or false)))
|
||||
(assert (or 1))
|
||||
(assert (or 1 nil false))
|
||||
(assert (or 1 1 1))
|
||||
(assert (or nil 1 false))
|
||||
(assert (not (or nil false)))
|
||||
(assert (not (or false nil)))
|
||||
(assert (not (or nil nil)))
|
||||
(assert (or 1 nil))
|
||||
(assert (or nil 1))
|
||||
(assert (or 1 1))
|
||||
|
||||
; and
|
||||
(assert (and 1))
|
||||
(assert (not (and nil)))
|
||||
(assert (and 1 1 1))
|
||||
(assert (not (and 1 nil false)))
|
||||
(assert (not (and nil false)))
|
||||
(assert (not (and nil nil)))
|
||||
(assert (not (and 1 nil)))
|
||||
(assert (not (and 1 nil)))
|
||||
(assert (and 1 1))
|
||||
|
||||
; xor
|
||||
(assert (not (xor nil false nil)))
|
||||
(assert (xor nil 1 nil false nil))
|
||||
(assert (not (xor nil 1 false 1)))
|
||||
(assert (not (xor 1 nil 1 1)))
|
||||
(assert (not (xor nil nil)))
|
||||
(assert (xor nil 1))
|
||||
(assert (xor 1 nil))
|
||||
(assert (not (xor 1 1)))
|
||||
Reference in New Issue
Block a user