Add defmacro stubs
This commit is contained in:
@@ -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
@@ -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);
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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())),
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
@@ -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,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)))
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
);
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
@@ -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]
|
||||
|
||||
@@ -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
@@ -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
@@ -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) => {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
@@ -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
@@ -114,7 +114,7 @@ impl Module {
|
||||
FunctionSignature::EMPTY,
|
||||
&FunctionBody {
|
||||
head: vec![],
|
||||
tail: Rc::new(expression),
|
||||
tail: expression,
|
||||
},
|
||||
true,
|
||||
)?;
|
||||
|
||||
@@ -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}"),
|
||||
|
||||
Reference in New Issue
Block a user