Add defmacro stubs

This commit is contained in:
2026-05-06 16:17:08 +03:00
parent 43938dee3c
commit 0c2d6c85bb
18 changed files with 314 additions and 98 deletions
+2
View File
@@ -1,5 +1,7 @@
;; vi:ft=lisp:sw=2:ts=2
(defun fun1 (a b) (+ a (* b 3)))
(assert-equal 2 (+ 1 #t #f))
(assert-equal "test1" (+ "test" 1))
(assert-equal "1test2" (+ 1 "test" 2))
+86 -31
View File
@@ -279,7 +279,7 @@ impl<'a> LocalBlock<'a> {
Ok(())
}
pub fn compile_statement(&mut self, expression: &Expression) -> Result<(), CompileError> {
pub fn compile_statement(&mut self, expression: &Rc<Expression>) -> Result<(), CompileError> {
let value = self.compile_expression(expression)?;
self.compile_drop(value)?;
Ok(())
@@ -318,7 +318,7 @@ impl<'a> LocalBlock<'a> {
fn compile_builtin_math_generic(
&mut self,
math: MathInstruction,
args: &[Expression],
args: &[Rc<Expression>],
) -> Result<CompileValue, CompileError> {
// TODO optimize
for arg in args.iter().rev() {
@@ -335,7 +335,7 @@ impl<'a> LocalBlock<'a> {
fn compile_call_builtin(
&mut self,
builtin: BuiltinFunction,
args: &[Expression],
args: &[Rc<Expression>],
) -> Result<CompileValue, CompileError> {
match builtin {
BuiltinFunction::Math(math) => self.compile_builtin_math_generic(math, args),
@@ -456,9 +456,9 @@ impl<'a> LocalBlock<'a> {
pub fn compile_expression(
&mut self,
expression: &Expression,
expression: &Rc<Expression>,
) -> Result<CompileValue, CompileError> {
match expression {
match expression.as_ref() {
Expression::Nil => Ok(CompileValue::Nil),
Expression::StringLiteral(value) => Ok(CompileValue::String(value.clone())),
Expression::BooleanLiteral(value) => Ok(CompileValue::Boolean(*value)),
@@ -471,6 +471,7 @@ impl<'a> LocalBlock<'a> {
Expression::Cond(condition) => self.compile_cond(condition),
Expression::Let(binding) => self.compile_let(binding),
Expression::Setq(setq) => self.compile_setq(setq),
Expression::Defmacro(_defmacro) => todo!(),
Expression::SyntaxError(_) => unreachable!(),
}
@@ -487,18 +488,52 @@ mod tests {
function::FunctionSignature,
module::CompilationModule,
syntax::{
CallExpression, CondExpression, CondExpressionArm, Expression, FunctionBody,
IfExpression, LambdaExpression,
CallExpression, CondExpression, CondExpressionArm, DefmacroExpression, Expression,
FunctionBody, IfExpression, LambdaExpression,
},
value::{CompileConstant, CompileValue},
},
vm::instruction::{Instruction, MathInstruction, U},
};
fn test_compile(
expression: &Expression,
) -> (CompilationModule, CompiledFunction, CompileValue) {
fn test_compile(expression: Expression) -> (CompilationModule, CompiledFunction, CompileValue) {
let mut module = CompilationModule::default();
module.define_macro(DefmacroExpression {
identifier: "test-macro-1".into(),
signature: FunctionSignature {
required_arguments: vec!["x".into()],
optional_arguments: vec![],
rest_argument: None,
},
body: FunctionBody {
head: vec![],
tail: Rc::new(Expression::Call(CallExpression {
callee: Rc::new(Expression::Identifier("test-macro-2".into())),
arguments: vec![
Rc::new(Expression::Identifier("x".into())),
Rc::new(Expression::IntegerLiteral(1)),
],
})),
},
});
module.define_macro(DefmacroExpression {
identifier: "test-macro-2".into(),
signature: FunctionSignature {
required_arguments: vec!["x".into(), "y".into()],
optional_arguments: vec![],
rest_argument: None,
},
body: FunctionBody {
head: vec![],
tail: Rc::new(Expression::Call(CallExpression {
callee: Rc::new(Expression::Identifier("+".into())),
arguments: vec![
Rc::new(Expression::Identifier("x".into())),
Rc::new(Expression::Identifier("y".into())),
],
})),
},
});
let mut function = FunctionBlock {
signature: FunctionSignature {
required_arguments: vec!["arg0".into()],
@@ -512,24 +547,41 @@ mod tests {
max_local_index: 0,
};
let mut local = LocalBlock::root(&mut function, &mut module);
let value = local.compile_expression(expression).unwrap();
let value = local.compile_expression(&Rc::new(expression)).unwrap();
(module, function.resolve_labels(), value)
}
#[test]
fn test_identity_compile() {
let (_, f, v) = test_compile(&Expression::IntegerLiteral(1));
let (_, f, v) = test_compile(Expression::IntegerLiteral(1));
assert!(f.instructions.is_empty());
assert_eq!(v, CompileValue::Integer(1));
}
#[test]
fn test_macro_expansion() {
let (_, f, v) = test_compile(Expression::Call(CallExpression {
callee: Rc::new(Expression::Identifier("test-macro-1".into())),
arguments: vec![Rc::new(Expression::IntegerLiteral(2))],
}));
assert_eq!(
&f.instructions,
&[
Instruction::PushInteger(U::truncate(1)),
Instruction::PushInteger(U::truncate(2)),
Instruction::Math(MathInstruction::Add, U::truncate(2)),
]
);
assert_eq!(v, CompileValue::Stack);
}
#[test]
fn test_comparison_compile() {
let (m, f, v) = test_compile(&Expression::Call(CallExpression {
let (m, f, v) = test_compile(Expression::Call(CallExpression {
callee: Rc::new(Expression::Identifier(">".into())),
arguments: vec![
Expression::Identifier("a".into()),
Expression::IntegerLiteral(1),
Rc::new(Expression::Identifier("a".into())),
Rc::new(Expression::IntegerLiteral(1)),
],
}));
let cs = m.constant_pool.into_map();
@@ -551,7 +603,7 @@ mod tests {
#[test]
fn test_if_compile() {
let (_, f, v) = test_compile(&Expression::If(IfExpression {
let (_, f, v) = test_compile(Expression::If(IfExpression {
condition: Rc::new(Expression::BooleanLiteral(false)),
if_true: Rc::new(Expression::IntegerLiteral(1)),
if_false: Some(Rc::new(Expression::IntegerLiteral(2))),
@@ -572,15 +624,15 @@ mod tests {
#[test]
fn test_cond_compile() {
let (_, f, v) = test_compile(&Expression::Cond(CondExpression {
let (_, f, v) = test_compile(Expression::Cond(CondExpression {
arms: vec![
CondExpressionArm {
condition: Expression::BooleanLiteral(false),
then: Expression::IntegerLiteral(1),
condition: Rc::new(Expression::BooleanLiteral(false)),
then: Rc::new(Expression::IntegerLiteral(1)),
},
CondExpressionArm {
condition: Expression::BooleanLiteral(true),
then: Expression::IntegerLiteral(2),
condition: Rc::new(Expression::BooleanLiteral(true)),
then: Rc::new(Expression::IntegerLiteral(2)),
},
],
otherwise_arm: Some(Rc::new(Expression::IntegerLiteral(3))),
@@ -606,7 +658,7 @@ mod tests {
#[test]
fn test_compile_lambda_returning_lambda() {
// ( ((lambda () (lambda (a b) (+ a b)))) 1 2 )
let (m, f, v) = test_compile(&Expression::Call(CallExpression {
let (m, f, v) = test_compile(Expression::Call(CallExpression {
callee: Rc::new(Expression::Call(CallExpression {
callee: Rc::new(Expression::Lambda(LambdaExpression {
signature: FunctionSignature {
@@ -627,8 +679,8 @@ mod tests {
tail: Rc::new(Expression::Call(CallExpression {
callee: Rc::new(Expression::Identifier("+".into())),
arguments: vec![
Expression::Identifier("a".into()),
Expression::Identifier("b".into()),
Rc::new(Expression::Identifier("a".into())),
Rc::new(Expression::Identifier("b".into())),
],
})),
},
@@ -637,7 +689,10 @@ mod tests {
})),
arguments: vec![],
})),
arguments: vec![Expression::IntegerLiteral(1), Expression::IntegerLiteral(2)],
arguments: vec![
Rc::new(Expression::IntegerLiteral(1)),
Rc::new(Expression::IntegerLiteral(2)),
],
}));
assert_eq!(
&f.instructions[..],
@@ -671,10 +726,10 @@ mod tests {
#[test]
fn test_compile_lambda() {
// (+ ((lambda (a) (+ a 1))) 2)
let (m, f, v) = test_compile(&Expression::Call(CallExpression {
let (m, f, v) = test_compile(Expression::Call(CallExpression {
callee: Rc::new(Expression::Identifier("+".into())),
arguments: vec![
Expression::Call(CallExpression {
Rc::new(Expression::Call(CallExpression {
callee: Expression::Lambda(LambdaExpression {
signature: FunctionSignature {
required_arguments: vec!["a".into()],
@@ -686,16 +741,16 @@ mod tests {
tail: Rc::new(Expression::Call(CallExpression {
callee: Rc::new(Expression::Identifier("+".into())),
arguments: vec![
Expression::Identifier("a".into()),
Expression::IntegerLiteral(1),
Rc::new(Expression::Identifier("a".into())),
Rc::new(Expression::IntegerLiteral(1)),
],
})),
},
})
.into(),
arguments: vec![],
}),
Expression::IntegerLiteral(2),
})),
Rc::new(Expression::IntegerLiteral(2)),
],
}));
assert_eq!(v, CompileValue::Stack);
+7 -2
View File
@@ -1,11 +1,11 @@
use std::collections::HashMap;
use std::{collections::HashMap, rc::Rc};
use crate::{
compile::{
block::{CompiledFunction, FunctionBlock},
error::CompileError,
function::FunctionSignature,
syntax::FunctionBody,
syntax::{DefmacroExpression, FunctionBody},
value::CompileConstant,
},
vm::{
@@ -19,11 +19,16 @@ use crate::{
pub struct CompilationModule {
pub(crate) constant_pool: Pool<CompileConstant, { ConstantId::BITS }>,
pub(crate) local_functions: HashMap<u32, CompiledFunction>,
macros: HashMap<Rc<str>, DefmacroExpression>,
local_function_index: u32,
root: Option<u32>,
}
impl CompilationModule {
pub fn define_macro(&mut self, defmacro: DefmacroExpression) {
self.macros.insert(defmacro.identifier.clone(), defmacro);
}
pub fn constant(&mut self, value: CompileConstant) -> Result<ConstantId, CompileError> {
match self.constant_pool.key(value) {
Some(key) => Ok(key),
+12 -12
View File
@@ -11,7 +11,7 @@ use crate::{
#[derive(Debug, PartialEq)]
pub struct Assignment {
pub identifier: Rc<str>,
pub value: Expression,
pub value: Rc<Expression>,
}
#[derive(Debug, PartialEq)]
@@ -154,12 +154,12 @@ mod tests {
]);
let e = Expression::parse(&v).unwrap();
assert_eq!(
e,
Expression::Let(LetExpression {
e.as_ref(),
&Expression::Let(LetExpression {
sequential: false,
bindings: vec![Assignment {
identifier: "a".into(),
value: Expression::IntegerLiteral(1)
value: Rc::new(Expression::IntegerLiteral(1))
},],
body: FunctionBody {
head: vec![],
@@ -179,17 +179,17 @@ mod tests {
]);
let e = Expression::parse(&v).unwrap();
assert_eq!(
e,
Expression::Let(LetExpression {
e.as_ref(),
&Expression::Let(LetExpression {
sequential: true,
bindings: vec![
Assignment {
identifier: "a".into(),
value: Expression::IntegerLiteral(1)
value: Rc::new(Expression::IntegerLiteral(1))
},
Assignment {
identifier: "b".into(),
value: Expression::IntegerLiteral(2)
value: Rc::new(Expression::IntegerLiteral(2))
}
],
body: FunctionBody {
@@ -228,16 +228,16 @@ mod tests {
]);
let e = Expression::parse(&v).unwrap();
assert_eq!(
e,
Expression::Setq(SetqExpression {
e.as_ref(),
&Expression::Setq(SetqExpression {
pairs: vec![
Assignment {
identifier: "a".into(),
value: Expression::Identifier("b".into()),
value: Rc::new(Expression::Identifier("b".into())),
},
Assignment {
identifier: "c".into(),
value: Expression::Identifier("d".into()),
value: Rc::new(Expression::Identifier("d".into())),
}
]
})
+17 -7
View File
@@ -2,8 +2,8 @@ use std::rc::Rc;
use crate::{
compile::{
Expression, ParseError,
syntax::{CollectErrors, ExpectedWhat, ExpectedWhere, ParseErrorKind},
CompileError, Expression, ParseError,
syntax::{CollectErrors, ExpectedWhat, ExpectedWhere, ParseErrorKind, SubMap, Substitute},
},
vm::value::{ConsCell, Value},
};
@@ -11,7 +11,7 @@ use crate::{
#[derive(Debug, PartialEq)]
pub struct CallExpression {
pub callee: Rc<Expression>,
pub arguments: Vec<Expression>,
pub arguments: Vec<Rc<Expression>>,
}
impl CallExpression {
@@ -39,9 +39,19 @@ impl CallExpression {
list = cdr;
}
Ok(Self { callee, arguments })
}
}
impl Substitute for CallExpression {
fn substitute(&self, map: &SubMap) -> Result<Self, CompileError> {
Ok(Self {
callee: callee.into(),
arguments,
callee: self.callee.substitute(map)?,
arguments: self
.arguments
.iter()
.map(|arg| arg.substitute(map))
.collect::<Result<_, _>>()?,
})
}
}
@@ -73,8 +83,8 @@ mod tests {
let v = Value::list_or_nil([Value::Identifier("a".into())]);
let e = Expression::parse(&v).unwrap();
assert_eq!(
e,
Expression::Call(CallExpression {
e.as_ref(),
&Expression::Call(CallExpression {
callee: Rc::new(Expression::Identifier("a".into())),
arguments: vec![]
})
+17 -17
View File
@@ -17,8 +17,8 @@ pub struct IfExpression {
#[derive(Debug, PartialEq)]
pub struct CondExpressionArm {
pub condition: Expression,
pub then: Expression,
pub condition: Rc<Expression>,
pub then: Rc<Expression>,
}
#[derive(Debug, PartialEq)]
pub struct CondExpression {
@@ -151,7 +151,7 @@ impl CondExpression {
});
}
let arm = Expression::parse_inner(arm_expr);
otherwise_arm = Some(Rc::new(arm));
otherwise_arm = Some(arm);
}
_ => {
if otherwise_arm.is_some() {
@@ -235,16 +235,16 @@ mod tests {
let v = Value::list_or_nil([Value::Keyword(Keyword::Cond), b0, b1]);
let e = Expression::parse(&v).unwrap();
assert_eq!(
e,
Expression::Cond(CondExpression {
e.as_ref(),
&Expression::Cond(CondExpression {
arms: vec![
CondExpressionArm {
condition: Expression::BooleanLiteral(true),
then: Expression::Identifier("a".into())
condition: Rc::new(Expression::BooleanLiteral(true)),
then: Rc::new(Expression::Identifier("a".into()))
},
CondExpressionArm {
condition: Expression::BooleanLiteral(false),
then: Expression::Identifier("b".into())
condition: Rc::new(Expression::BooleanLiteral(false)),
then: Rc::new(Expression::Identifier("b".into()))
}
],
otherwise_arm: None
@@ -260,11 +260,11 @@ mod tests {
let v = Value::list_or_nil([Value::Keyword(Keyword::Cond), b0, b1]);
let e = Expression::parse(&v).unwrap();
assert_eq!(
e,
Expression::Cond(CondExpression {
e.as_ref(),
&Expression::Cond(CondExpression {
arms: vec![CondExpressionArm {
condition: Expression::BooleanLiteral(true),
then: Expression::Identifier("a".into())
condition: Rc::new(Expression::BooleanLiteral(true)),
then: Rc::new(Expression::Identifier("a".into()))
},],
otherwise_arm: Some(Rc::new(Expression::Identifier("b".into())))
})
@@ -419,8 +419,8 @@ mod tests {
]);
let e = Expression::parse(&v).unwrap();
assert_eq!(
e,
Expression::If(IfExpression {
e.as_ref(),
&Expression::If(IfExpression {
condition: Rc::new(Expression::BooleanLiteral(true)),
if_true: Rc::new(Expression::IntegerLiteral(1)),
if_false: None
@@ -436,8 +436,8 @@ mod tests {
]);
let e = Expression::parse(&v).unwrap();
assert_eq!(
e,
Expression::If(IfExpression {
e.as_ref(),
&Expression::If(IfExpression {
condition: Rc::new(Expression::BooleanLiteral(false)),
if_true: Rc::new(Expression::IntegerLiteral(1)),
if_false: Some(Rc::new(Expression::IntegerLiteral(2)))
+6 -3
View File
@@ -10,7 +10,7 @@ use crate::{
#[derive(Debug, PartialEq)]
pub struct FunctionBody {
pub head: Vec<Expression>,
pub head: Vec<Rc<Expression>>,
pub tail: Rc<Expression>,
}
@@ -166,7 +166,7 @@ impl FunctionBody {
};
Ok(Self {
head: expressions,
tail: tail.into(),
tail,
})
}
}
@@ -261,7 +261,10 @@ mod tests {
assert_eq!(
e,
FunctionBody {
head: vec![Expression::IntegerLiteral(1), Expression::IntegerLiteral(2)],
head: vec![
Rc::new(Expression::IntegerLiteral(1)),
Rc::new(Expression::IntegerLiteral(2))
],
tail: Rc::new(Expression::IntegerLiteral(3))
}
);
+6 -4
View File
@@ -38,6 +38,8 @@ impl CollectErrors<ParseError> for LambdaExpression {
#[cfg(test)]
mod tests {
use std::rc::Rc;
use crate::{
compile::{
CallExpression, Expression, FunctionBody, FunctionSignature, LambdaExpression,
@@ -65,8 +67,8 @@ mod tests {
let expr = Expression::parse(&lambda).unwrap();
assert_eq!(
expr,
Expression::Lambda(LambdaExpression {
expr.as_ref(),
&Expression::Lambda(LambdaExpression {
signature: FunctionSignature {
required_arguments: vec!["a".into()],
optional_arguments: vec!["b".into()],
@@ -77,8 +79,8 @@ mod tests {
tail: Expression::Call(CallExpression {
callee: Expression::Identifier("+".into()).into(),
arguments: vec![
Expression::Identifier("a".into()),
Expression::IntegerLiteral(1)
Rc::new(Expression::Identifier("a".into())),
Rc::new(Expression::IntegerLiteral(1))
]
})
.into()
+52
View File
@@ -0,0 +1,52 @@
use std::{collections::HashMap, rc::Rc};
use crate::{
compile::{
CompileError, Expression, FunctionBody, FunctionSignature, ParseError,
syntax::CollectErrors,
},
vm::value::Value,
};
#[derive(Debug, PartialEq)]
pub struct DefmacroExpression {
pub identifier: Rc<str>,
pub signature: FunctionSignature,
pub body: FunctionBody,
}
impl DefmacroExpression {
pub(super) fn parse(_value: &Value, _input: &Value) -> Result<Self, ParseError> {
todo!()
}
pub fn expand(&self, args: &[Rc<Expression>]) -> Result<Rc<Expression>, CompileError> {
// TODO emit progn?
if !self.body.head.is_empty() {
todo!()
}
let mut substitution_map = HashMap::new();
for (i, required) in self.signature.required_arguments.iter().enumerate() {
let Some(substitution) = args.get(i) else {
todo!()
};
substitution_map.insert(required.clone(), substitution.clone());
}
for (i, optional) in self.signature.optional_arguments.iter().enumerate() {
if let Some(substitution) = args.get(i + self.signature.required_arguments.len()) {
substitution_map.insert(optional.clone(), substitution.clone());
} else {
substitution_map.insert(optional.clone(), Expression::Nil.into());
}
}
self.body.tail.substitute(&substitution_map)
}
}
impl CollectErrors<ParseError> for DefmacroExpression {
fn collect_errors(&self, _errors: &mut Vec<ParseError>) -> bool {
todo!()
}
}
+48 -16
View File
@@ -1,6 +1,9 @@
use std::rc::Rc;
use std::{collections::HashMap, rc::Rc};
use crate::vm::value::{ConsCell, Keyword, Value, ValueString};
use crate::{
compile::CompileError,
vm::value::{ConsCell, Keyword, Value, ValueString},
};
mod binding;
mod call;
@@ -8,6 +11,7 @@ mod condition;
mod error;
mod function;
mod lambda;
mod macros;
pub use binding::*;
pub use call::*;
@@ -15,6 +19,13 @@ pub use condition::*;
pub use error::*;
pub use function::*;
pub use lambda::*;
pub use macros::*;
pub type SubMap = HashMap<Rc<str>, Rc<Expression>>;
pub trait Substitute: Sized {
fn substitute(&self, map: &SubMap) -> Result<Self, CompileError>;
}
#[derive(Debug, PartialEq)]
pub enum Expression {
@@ -30,18 +41,19 @@ pub enum Expression {
Cond(CondExpression),
Setq(SetqExpression),
Let(LetExpression),
Defmacro(DefmacroExpression),
SyntaxError(ParseError),
}
impl Expression {
fn map_or<T, F: FnOnce(T) -> Self>(result: Result<T, ParseError>, map: F) -> Self {
fn map_or<T, F: FnOnce(T) -> Self>(result: Result<T, ParseError>, map: F) -> Rc<Self> {
match result {
Ok(r) => map(r),
Err(error) => Self::SyntaxError(error),
Ok(r) => Rc::new(map(r)),
Err(error) => Rc::new(Self::SyntaxError(error)),
}
}
pub fn parse(value: &Value) -> Result<Self, Vec<ParseError>> {
pub fn parse(value: &Value) -> Result<Rc<Self>, Vec<ParseError>> {
let inner = Self::parse_inner(value);
let mut errors = vec![];
if inner.collect_errors(&mut errors) {
@@ -51,14 +63,15 @@ impl Expression {
}
}
fn parse_inner(value: &Value) -> Self {
fn parse_inner(value: &Value) -> Rc<Self> {
match value {
Value::Nil => Self::Nil,
Value::Boolean(value) => Self::BooleanLiteral(*value),
Value::Integer(value) => Self::IntegerLiteral(*value),
Value::String(value) => Self::StringLiteral(value.clone()),
Value::Nil => Rc::new(Self::Nil),
Value::Boolean(value) => Rc::new(Self::BooleanLiteral(*value)),
Value::Integer(value) => Rc::new(Self::IntegerLiteral(*value)),
Value::String(value) => Rc::new(Self::StringLiteral(value.clone())),
Value::Vector(_vector) => todo!(),
Value::Identifier(value) => Self::Identifier(value.clone()),
Value::Identifier(value) => Rc::new(Self::Identifier(value.clone())),
Value::Quasi(_value) => todo!(),
Value::Cons(cons) => {
let ConsCell(car, cdr) = cons.as_ref();
match car {
@@ -80,6 +93,9 @@ impl Expression {
Value::Keyword(Keyword::Setq) => {
Self::map_or(SetqExpression::parse(cdr, value), Expression::Setq)
}
Value::Keyword(Keyword::Defmacro) => {
Self::map_or(DefmacroExpression::parse(cdr, value), Expression::Defmacro)
}
_ => Self::map_or(CallExpression::parse(cons, value), Expression::Call),
}
}
@@ -89,6 +105,21 @@ impl Expression {
}
}
}
fn substitute(self: &Rc<Self>, map: &SubMap) -> Result<Rc<Self>, CompileError> {
match self.as_ref() {
Self::Identifier(value) if let Some(sub) = map.get(value) => Ok(sub.clone()),
Self::Call(call) => call.substitute(map).map(Self::Call).map(Rc::new),
Self::If(_) => todo!(),
Self::Let(_) => todo!(),
Self::Cond(_) => todo!(),
Self::Setq(_) => todo!(),
Self::Defun(_) => todo!(),
Self::Defmacro(_) => todo!(),
Self::Lambda(_) => todo!(),
_ => Ok(self.clone()),
}
}
}
impl CollectErrors<ParseError> for Expression {
@@ -105,6 +136,7 @@ impl CollectErrors<ParseError> for Expression {
Self::Call(call) => call.collect_errors(errors),
Self::Let(let_) => let_.collect_errors(errors),
Self::Setq(setq) => setq.collect_errors(errors),
Self::Defmacro(defmacro) => defmacro.collect_errors(errors),
Self::Nil
| Self::IntegerLiteral(_)
| Self::Identifier(_)
@@ -125,19 +157,19 @@ mod tests {
fn test_parse_basic() {
let v = Value::Nil;
let e = Expression::parse(&v).unwrap();
assert_eq!(e, Expression::Nil);
assert_eq!(e.as_ref(), &Expression::Nil);
let v = Value::Integer(1234);
let e = Expression::parse(&v).unwrap();
assert_eq!(e, Expression::IntegerLiteral(1234));
assert_eq!(e.as_ref(), &Expression::IntegerLiteral(1234));
let v = Value::Boolean(false);
let e = Expression::parse(&v).unwrap();
assert_eq!(e, Expression::BooleanLiteral(false));
assert_eq!(e.as_ref(), &Expression::BooleanLiteral(false));
let v = Value::Identifier("a".into());
let e = Expression::parse(&v).unwrap();
assert_eq!(e, Expression::Identifier("a".into()));
assert_eq!(e.as_ref(), &Expression::Identifier("a".into()));
}
#[test]
+1
View File
@@ -79,6 +79,7 @@ impl TryFromValue<'_> for bool {
Value::Boolean(value) => Ok(*value),
Value::Integer(value) => Ok(*value != 0),
Value::Keyword(_)
| Value::Quasi(_)
| Value::Identifier(_)
| Value::OpaqueValue(_)
| Value::NativeFunction(_)
+2 -1
View File
@@ -3,7 +3,8 @@
debug_closure_helpers,
unboxed_closures,
iter_next_chunk,
exact_size_is_empty
exact_size_is_empty,
try_trait_v2
)]
pub mod compile;
+1 -1
View File
@@ -76,7 +76,7 @@ fn run_interactive(vm: &mut Machine) -> Result<(), Error> {
}
};
let result = vm.eval_value(&value);
let result = vm.eval_value(value.clone());
let result = match result {
EvalResult::Ok(r) => r,
EvalResult::Err(module, ip, error) => {
+10
View File
@@ -1,3 +1,5 @@
use std::rc::Rc;
use nom::{
AsChar, FindToken, IResult, Input, Parser,
branch::alt,
@@ -272,10 +274,18 @@ pub fn skip_comment_and_whitespace(mut input: &str) -> IResult<&str, ()> {
Ok((input, ()))
}
fn parse_quasi(input: &str) -> IResult<&str, Value> {
preceded(char('`'), parse_value)
.map(Rc::new)
.map(Value::Quasi)
.parse(input)
}
pub fn parse_value(input: &str) -> IResult<&str, Value> {
alt((
parse_list_or_nil,
parse_boolean,
parse_quasi,
parse_integer,
parse_string,
parse_identifier_or_keyword_or_nil,
+5
View File
@@ -1,3 +1,8 @@
pub enum Either<A, B> {
Left(A),
Right(B),
}
pub struct TryFilter<I, E1, E2, T, F>
where
I: Iterator<Item = Result<T, E1>>,
+37 -3
View File
@@ -1,4 +1,9 @@
use std::{collections::HashMap, fmt, rc::Rc};
use std::{
collections::HashMap,
fmt,
ops::{ControlFlow, FromResidual, Try},
rc::Rc,
};
use crate::{
error::EvalError,
@@ -429,6 +434,11 @@ impl Machine {
Ok(event)
}
fn macro_expand(&mut self, value: Value) -> EvalResult<Value, EvalError> {
// TODO
EvalResult::Ok(value)
}
pub fn eval_bytecode_call(
&mut self,
function: BytecodeFunction,
@@ -496,8 +506,9 @@ impl Machine {
}
}
pub fn eval_value(&mut self, value: &Value) -> EvalResult<Value, EvalError> {
let module = match Module::compile_value(value) {
pub fn eval_value(&mut self, value: Value) -> EvalResult<Value, EvalError> {
let value = self.macro_expand(value)?;
let module = match Module::compile_value(&value) {
Ok(module) => module,
Err(error) => return EvalResult::LoadErr(error.into()),
};
@@ -510,6 +521,29 @@ impl Machine {
}
}
impl<T, E> Try for EvalResult<T, E> {
type Output = T;
type Residual = EvalResult<T, E>;
fn branch(self) -> ControlFlow<Self::Residual, Self::Output> {
match self {
Self::Ok(result) => ControlFlow::Continue(result),
Self::Err(module, ip, error) => ControlFlow::Break(EvalResult::Err(module, ip, error)),
Self::LoadErr(error) => ControlFlow::Break(EvalResult::LoadErr(error)),
}
}
fn from_output(output: Self::Output) -> Self {
Self::Ok(output)
}
}
impl<T, E> FromResidual for EvalResult<T, E> {
fn from_residual(residual: <Self as Try>::Residual) -> Self {
residual
}
}
impl<T, E> EvalResult<T, E> {
pub fn unwrap(self) -> T
where
+1 -1
View File
@@ -114,7 +114,7 @@ impl Module {
FunctionSignature::EMPTY,
&FunctionBody {
head: vec![],
tail: Rc::new(expression),
tail: expression,
},
true,
)?;
+4
View File
@@ -39,6 +39,7 @@ pub enum Value {
Keyword(Keyword),
String(ValueString),
Vector(Rc<Vector>),
Quasi(Rc<Value>),
// "Runtime" values
BytecodeFunction(BytecodeFunction),
NativeFunction(NativeFunction),
@@ -143,6 +144,7 @@ impl_keyword! {
Setq => "setq",
Let => "let",
LetStar => "let*",
Defmacro => "defmacro",
}
}
@@ -182,6 +184,7 @@ impl Value {
Self::Boolean(false) => Ok("#f".into()),
Self::Identifier(value) => Ok(format!("{value}")),
Self::String(value) => Ok(format!("{value}")),
Self::Quasi(_) => todo!(),
Self::Nil => todo!(),
Self::Cons(_) => todo!(),
Self::Vector(_) => todo!(),
@@ -314,6 +317,7 @@ impl fmt::Display for Value {
Self::Identifier(value) => write!(f, "{value}"),
Self::Keyword(keyword) => write!(f, "{keyword}"),
Self::Cons(cons) => write!(f, "({cons})"),
Self::Quasi(value) => write!(f, "`{value}"),
Self::BytecodeFunction(bytecode) => write!(f, "{bytecode}"),
Self::NativeFunction(native) => write!(f, "{native}"),
Self::OpaqueValue(opaque) => write!(f, "{opaque}"),