lysp: fix (explain ...) for macros
This commit is contained in:
@@ -59,3 +59,10 @@
|
||||
)
|
||||
|
||||
(print "... doesn't fail the execution")
|
||||
|
||||
(defmacro nested-0 (x) `(list 2 ,x))
|
||||
(defmacro nested-1 (x) `(list 1 (nested-0 ,x)))
|
||||
(assert (= '(1 (2 3)) (nested-1 3)))
|
||||
|
||||
;; (explain ...) must work on macros
|
||||
(assert (explain and))
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
; TODO most of those could be ported to Rust for performance
|
||||
; TODO tail recursion
|
||||
(defun filter (f xs)
|
||||
"Returns a new list, formed from elements of xs matching predicate f"
|
||||
(cond
|
||||
((nil? xs) nil)
|
||||
((f (car xs)) (cons (car xs) (filter f (cdr xs))))
|
||||
@@ -38,30 +39,35 @@
|
||||
)
|
||||
)
|
||||
(defun map (f xs)
|
||||
"Returns a new list, with f applied to elements of xs"
|
||||
(if (cons? xs)
|
||||
(cons (f (car xs)) (map f (cdr xs)))
|
||||
nil
|
||||
)
|
||||
)
|
||||
(defun flatmap (f xs)
|
||||
"Returns a new list, with f applied to list elements of xs, then appended together"
|
||||
(let (ys nil)
|
||||
(while (cons? xs)
|
||||
(setq ys (append ys (f (car xs))))
|
||||
(setq xs (cdr xs)))
|
||||
ys))
|
||||
(defun fold (f acc xs)
|
||||
"Returns the value calculated by sequentially applying f to acc and each element of xs"
|
||||
(while (cons? xs)
|
||||
(setq acc (f acc (car xs)))
|
||||
(setq xs (cdr xs)))
|
||||
acc)
|
||||
|
||||
(defun reverse (xs)
|
||||
"Returns the reversed list"
|
||||
(let (ys nil)
|
||||
(while (cons? xs)
|
||||
(setq ys (cons (car xs) ys))
|
||||
(setq xs (cdr xs)))
|
||||
ys))
|
||||
(defun unzip (xs)
|
||||
"Converts a list of lists into a single-level list"
|
||||
(flatmap identity xs))
|
||||
|
||||
; Logic functions
|
||||
@@ -78,6 +84,7 @@
|
||||
)
|
||||
))
|
||||
(defmacro or (&rest forms)
|
||||
"Sequentially evaluates the forms, stopping and returning a form if it's trueish"
|
||||
;; (or x y z) -> (cond (x x) (y y) (z z) (&otherwise #t))
|
||||
(or_ forms))
|
||||
(defun and_ (forms)
|
||||
@@ -87,6 +94,7 @@
|
||||
(&otherwise `(if ,(car forms) ,(and_ (cdr forms))))
|
||||
))
|
||||
(defmacro and (&rest forms)
|
||||
"Sequentially evaluates the forms, returning the last form if all the forms are trueish"
|
||||
;; (and x y z) -> (if x (if y (if z z)))
|
||||
(and_ forms)
|
||||
)
|
||||
|
||||
@@ -32,8 +32,6 @@ impl MacroExpand for Value {
|
||||
| Self::Boolean(_)
|
||||
| Self::String(_)
|
||||
| Self::Keyword(_)
|
||||
// | Self::OpaqueValue(_)
|
||||
// | Self::BytecodeFunction(_)
|
||||
| Self::Quote(_)
|
||||
| Self::Closure(_)
|
||||
| Self::Function(_)
|
||||
@@ -43,7 +41,6 @@ impl MacroExpand for Value {
|
||||
| Self::HashTable(_)
|
||||
| Self::UnquoteSplice(_)
|
||||
| Self::Unquote(_) => Ok(self.clone()),
|
||||
// | Self::NativeFunction(_) => Ok(self.clone()),
|
||||
Self::Cons(cons) => {
|
||||
let ConsCell(car, cdr) = cons.as_ref();
|
||||
let car = car.macro_expand(vm, env, false)?;
|
||||
@@ -65,17 +62,20 @@ impl MacroExpand for Value {
|
||||
return Ok(Self::Cons(cons));
|
||||
};
|
||||
|
||||
match mac {
|
||||
Macro::Native(native) => {
|
||||
let result = native.invoke(vm, env, &args[..]).expect("TODO");
|
||||
Ok(result)
|
||||
}
|
||||
Macro::Bytecode(bytecode) => {
|
||||
let closure = ClosureValue { function: bytecode.clone(), upvalues: vec![] };
|
||||
let result = vm.evaluate_closure_args(env, closure, &args[..])?;
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
match mac {
|
||||
Macro::Native(native) => {
|
||||
let result = native.invoke(vm, env, &args[..]).expect("TODO");
|
||||
result.macro_expand(vm, env, tail)
|
||||
}
|
||||
Macro::Bytecode(bytecode) => {
|
||||
let closure = ClosureValue {
|
||||
function: bytecode.clone(),
|
||||
upvalues: vec![],
|
||||
};
|
||||
let result = vm.evaluate_closure_args(env, closure, &args[..])?;
|
||||
result.macro_expand(vm, env, tail)
|
||||
}
|
||||
}
|
||||
}
|
||||
Self::Quasi(value) => {
|
||||
let value = expand_quasiquote(value);
|
||||
|
||||
@@ -7,7 +7,7 @@ use crate::{
|
||||
error::MachineError,
|
||||
vm::{
|
||||
Value,
|
||||
env::Environment,
|
||||
env::{Environment, Macro},
|
||||
value::{Keyword, StringValue, convert::TryFromValue},
|
||||
},
|
||||
};
|
||||
@@ -55,9 +55,35 @@ pub fn load(env: &Rc<Environment>) {
|
||||
env.defun_native("gensym", "Provides an unique symbol name", |_, env, _| {
|
||||
Ok(env.gensym().into())
|
||||
});
|
||||
env.defun_native(
|
||||
env.defmacro_native(
|
||||
"explain",
|
||||
"Provides an explanation for a given value",
|
||||
|_, env, args| {
|
||||
let [argument] = args else {
|
||||
return Err(MachineError::InvalidArgumentCount);
|
||||
};
|
||||
if let Value::Identifier(identifier) = argument
|
||||
&& let Some(mac) = env.global_macro(identifier)
|
||||
{
|
||||
return match mac {
|
||||
Macro::Native(mac) => Ok(Value::String(
|
||||
format!("built-in macro {}: {}", mac.name(), mac.docstring()).into(),
|
||||
)),
|
||||
Macro::Bytecode(mac) => Ok(Value::String(
|
||||
format!("macro {}: {}", mac.name(), mac.docstring()).into(),
|
||||
)),
|
||||
};
|
||||
}
|
||||
|
||||
Ok(Value::list_or_nil([
|
||||
Value::Identifier("explain_".into()),
|
||||
argument.clone(),
|
||||
]))
|
||||
},
|
||||
);
|
||||
env.defun_native(
|
||||
"explain_",
|
||||
"Provides an explanation for a given value",
|
||||
|_, _, args| {
|
||||
let [argument] = args else {
|
||||
return Err(MachineError::InvalidArgumentCount);
|
||||
|
||||
Reference in New Issue
Block a user