Fix temporaries breaking (let ...) blocks, (gensym)
This commit is contained in:
@@ -1 +0,0 @@
|
|||||||
(print (explain explain))
|
|
||||||
+16
-6
@@ -19,14 +19,16 @@
|
|||||||
(assert (= '(2 3 4 2 3 4) `(,@glob1 ,@glob1)))
|
(assert (= '(2 3 4 2 3 4) `(,@glob1 ,@glob1)))
|
||||||
(assert (= '((((2 3 4)))) `(((,glob1)))))
|
(assert (= '((((2 3 4)))) `(((,glob1)))))
|
||||||
|
|
||||||
(defmacro debug (expression)
|
|
||||||
(print "DEBUG:" expression)
|
|
||||||
expression
|
|
||||||
)
|
|
||||||
|
|
||||||
; those are prelude, but defined in lysp itself:
|
; those are prelude, but defined in lysp itself:
|
||||||
|
|
||||||
(debug
|
(print "The previously printed expression is AFTER this one in the code")
|
||||||
|
(compile-debug
|
||||||
|
(when #t
|
||||||
|
(print "a")
|
||||||
|
(print "b")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(runtime-debug
|
||||||
(when #t
|
(when #t
|
||||||
(print "a")
|
(print "a")
|
||||||
(print "b")
|
(print "b")
|
||||||
@@ -43,3 +45,11 @@
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
; catch macro
|
||||||
|
(print "Failing in a catch block...")
|
||||||
|
(catch
|
||||||
|
(print a)
|
||||||
|
e (print "Caught an error:" e)
|
||||||
|
)
|
||||||
|
|
||||||
|
(print "... doesn't fail the execution")
|
||||||
|
|||||||
@@ -267,6 +267,29 @@ impl CompileContext {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn guard_argument(&mut self) {
|
||||||
|
let depth = self.scope_depth as isize;
|
||||||
|
self.locals.push(Local {
|
||||||
|
name: "".into(),
|
||||||
|
depth,
|
||||||
|
is_captured: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn unguard_argument(&mut self) {
|
||||||
|
let guard = self
|
||||||
|
.locals
|
||||||
|
.pop()
|
||||||
|
.expect("unguard_argument() called with an empty locals stack");
|
||||||
|
let stack_index = self.locals.len();
|
||||||
|
if guard.name.as_ref() != "" {
|
||||||
|
panic!(
|
||||||
|
"unguard_argument(): the local is not a guard: {:?} at stack index {}",
|
||||||
|
guard.name, stack_index,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn push_scope(&mut self) {
|
pub fn push_scope(&mut self) {
|
||||||
self.scope_depth += 1;
|
self.scope_depth += 1;
|
||||||
if self.options.trace_compile {
|
if self.options.trace_compile {
|
||||||
|
|||||||
@@ -53,13 +53,22 @@ impl Compile for CallExpression {
|
|||||||
if instruction == Instruction::Call {
|
if instruction == Instruction::Call {
|
||||||
let callee = self.callee.compile(cx)?;
|
let callee = self.callee.compile(cx)?;
|
||||||
cx.push(callee)?;
|
cx.push(callee)?;
|
||||||
|
cx.guard_argument();
|
||||||
}
|
}
|
||||||
for expression in self.arguments.iter() {
|
for expression in self.arguments.iter() {
|
||||||
let value = expression.compile(cx)?;
|
let value = expression.compile(cx)?;
|
||||||
cx.push(value)?;
|
cx.push(value)?;
|
||||||
|
cx.guard_argument();
|
||||||
}
|
}
|
||||||
cx.emit(instruction);
|
cx.emit(instruction);
|
||||||
cx.emit(argument_count);
|
cx.emit(argument_count);
|
||||||
|
let mut unguard_count = usize::from(argument_count);
|
||||||
|
if instruction == Instruction::Call {
|
||||||
|
unguard_count += 1;
|
||||||
|
}
|
||||||
|
for _ in 0..unguard_count {
|
||||||
|
cx.unguard_argument();
|
||||||
|
}
|
||||||
Ok(CompileValue::Stack)
|
Ok(CompileValue::Stack)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -121,7 +121,7 @@ impl Expression {
|
|||||||
_ => Self::map_or(CallExpression::parse(cons, value), Expression::Call),
|
_ => Self::map_or(CallExpression::parse(cons, value), Expression::Call),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Value::Keyword(_) => todo!("Error here"),
|
Value::Keyword(keyword) => todo!("Error here: keyword {keyword}"),
|
||||||
Value::Closure(_) => todo!("Error here"),
|
Value::Closure(_) => todo!("Error here"),
|
||||||
Value::Function(_) => todo!("Error here"),
|
Value::Function(_) => todo!("Error here"),
|
||||||
Value::NativeFunction(_) => todo!("Error here"),
|
Value::NativeFunction(_) => todo!("Error here"),
|
||||||
|
|||||||
+66
-4
@@ -1,8 +1,70 @@
|
|||||||
(defmacro when (condition &rest body)
|
; Convenience flow control macros
|
||||||
`(if ,condition (progn ,@body))
|
(defmacro when (condition body-head &rest body)
|
||||||
|
"If condition is true, evaluates the expressions in body, otherwise returns nil"
|
||||||
|
`(if ,condition (progn ,body-head ,@body))
|
||||||
)
|
)
|
||||||
|
|
||||||
(defmacro unless (condition &rest body)
|
(defmacro unless (condition body-head &rest body)
|
||||||
`(if (not ,condition) (progn ,@body))
|
"If condition is false, evaluates the expressions in body, otherwise returns nil"
|
||||||
|
`(if (not ,condition) (progn ,body-head ,@body))
|
||||||
)
|
)
|
||||||
|
|
||||||
|
; Result handling functions
|
||||||
|
(defun result/ok? (x)
|
||||||
|
"Returns #t if x is an ok"
|
||||||
|
(= 'ok (car x))
|
||||||
|
)
|
||||||
|
(defun result/err? (x)
|
||||||
|
"Returns #t if x is an error"
|
||||||
|
(= 'err (car x))
|
||||||
|
)
|
||||||
|
(defun result/map (f x)
|
||||||
|
"If x is an ok, applies f to its value, otherwise does nothing"
|
||||||
|
(if (result/ok? x)
|
||||||
|
`(ok ,(f (cadr x)))
|
||||||
|
x
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(defun result/map-err (f x)
|
||||||
|
"If x is an error, applies f to its value, otherwise does nothing"
|
||||||
|
(if (result/err? x)
|
||||||
|
`(err ,(f (cadr x)))
|
||||||
|
x
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
; Convenience error handling macros
|
||||||
|
(defmacro catch (expression error-symbol handler)
|
||||||
|
"Evaluates expression, running the handler if evaluation fails, introducing error-symbol as error"
|
||||||
|
(let (eval-result-symbol (gensym))
|
||||||
|
`(let (,eval-result-symbol (eval (quote ,expression)))
|
||||||
|
(cond
|
||||||
|
((result/ok? ,eval-result-symbol) (cadr ,eval-result-symbol))
|
||||||
|
(&otherwise
|
||||||
|
(let (,error-symbol (cadr ,eval-result-symbol))
|
||||||
|
,handler
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
(defmacro compile-debug (expression)
|
||||||
|
"Prints the input expression during macro expansion/compile time and evaluates the expression in runtime"
|
||||||
|
(print expression)
|
||||||
|
expression
|
||||||
|
)
|
||||||
|
(defmacro runtime-debug (expression)
|
||||||
|
"Prints the input expression and evaluates it in runtime"
|
||||||
|
`(progn
|
||||||
|
(print (quote ,expression))
|
||||||
|
,expression
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
; Convenience list functions
|
||||||
|
(defun cadr (x) "Alias for (car (cdr x))" (car (cdr x)))
|
||||||
|
(defun cdar (x) "Alias for (cdr (car x))" (cdr (car x)))
|
||||||
|
(defun caddr (x) "Alias for (car (cdr (cdr x)))" (car (cdr (cdr x))))
|
||||||
|
(defun cadar (x) "Alias for (car (cdr (car x)))" (car (cdr (car x))))
|
||||||
|
|||||||
+16
-1
@@ -1,4 +1,12 @@
|
|||||||
use std::{borrow::Borrow, cell::RefCell, collections::HashMap, fmt, hash::Hash, rc::Rc};
|
use std::{
|
||||||
|
borrow::Borrow,
|
||||||
|
cell::RefCell,
|
||||||
|
collections::HashMap,
|
||||||
|
fmt,
|
||||||
|
hash::Hash,
|
||||||
|
rc::Rc,
|
||||||
|
sync::atomic::{AtomicU32, Ordering},
|
||||||
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
error::MachineError,
|
error::MachineError,
|
||||||
@@ -22,6 +30,7 @@ pub struct Environment {
|
|||||||
globals: RefCell<HashMap<IdentifierValue, Value>>,
|
globals: RefCell<HashMap<IdentifierValue, Value>>,
|
||||||
macros: RefCell<HashMap<IdentifierValue, Macro>>,
|
macros: RefCell<HashMap<IdentifierValue, Macro>>,
|
||||||
parent: Option<Rc<Environment>>,
|
parent: Option<Rc<Environment>>,
|
||||||
|
gensym_index: AtomicU32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Environment {
|
impl Environment {
|
||||||
@@ -32,6 +41,12 @@ impl Environment {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn gensym(&self) -> IdentifierValue {
|
||||||
|
// TODO do this in a root environment?
|
||||||
|
let index = self.gensym_index.fetch_add(1, Ordering::SeqCst);
|
||||||
|
format!("___gensym{index}").into()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn defun_native<S, D, F>(&self, identifier: S, docstring: D, function: F) -> Value
|
pub fn defun_native<S, D, F>(&self, identifier: S, docstring: D, function: F) -> Value
|
||||||
where
|
where
|
||||||
S: Into<IdentifierValue>,
|
S: Into<IdentifierValue>,
|
||||||
|
|||||||
@@ -6,6 +6,9 @@ use crate::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
pub fn load(env: &Rc<Environment>) {
|
pub fn load(env: &Rc<Environment>) {
|
||||||
|
env.defun_native("gensym", "Provides an unique symbol name", |_, env, _| {
|
||||||
|
Ok(env.gensym().into())
|
||||||
|
});
|
||||||
env.defun_native(
|
env.defun_native(
|
||||||
"explain",
|
"explain",
|
||||||
"Provides an explanation for a given value",
|
"Provides an explanation for a given value",
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ use crate::{
|
|||||||
env::Environment,
|
env::Environment,
|
||||||
machine::Machine,
|
machine::Machine,
|
||||||
value::{
|
value::{
|
||||||
BooleanValue, BytecodeFunction, ClosureValue, ConsCell, NativeFunction, NativeValue,
|
BooleanValue, BytecodeFunction, ClosureValue, ConsCell, IdentifierValue,
|
||||||
NumberValue, StringValue, Vector,
|
NativeFunction, NativeValue, NumberValue, StringValue, Vector,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@@ -126,6 +126,12 @@ impl From<Vec<u8>> for Value {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<IdentifierValue> for Value {
|
||||||
|
fn from(value: IdentifierValue) -> Self {
|
||||||
|
Value::Identifier(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl TryFromValue<'_> for AnyFunction {
|
impl TryFromValue<'_> for AnyFunction {
|
||||||
fn try_from_value(value: &'_ Value) -> Result<Self, ValueConversionError> {
|
fn try_from_value(value: &'_ Value) -> Result<Self, ValueConversionError> {
|
||||||
match value {
|
match value {
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ impl_keyword! {
|
|||||||
Break => "break",
|
Break => "break",
|
||||||
Continue => "continue",
|
Continue => "continue",
|
||||||
Declare => "declare",
|
Declare => "declare",
|
||||||
|
Error => "&error",
|
||||||
// Cons => "cons",
|
// Cons => "cons",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user