Implement missing parser functions

This commit is contained in:
2026-05-01 14:05:10 +03:00
parent 36e6cc8364
commit 58cc01c114
20 changed files with 1879 additions and 335 deletions
+249 -18
View File
@@ -1,18 +1,28 @@
use std::rc::Rc;
use std::{collections::HashMap, rc::Rc};
use crate::{
compile::{
error::CompileError,
function::FunctionSignature,
instruction::Emitted,
module::CompilationModule,
syntax::{CallExpression, Expression, FunctionBody, LambdaExpression},
syntax::{
CallExpression, CondExpression, Expression, FunctionBody, IfExpression,
LambdaExpression,
},
value::{BuiltinFunction, CompileConstant, CompileValue},
},
vm::instruction::{Instruction, U},
vm::instruction::{Comparison, Instruction, U},
};
pub struct FunctionBlock {
pub struct CompiledFunction {
pub(crate) instructions: Vec<Instruction>,
}
pub struct FunctionBlock {
pub(crate) instructions: Vec<Emitted>,
labels: HashMap<u32, usize>,
last_label: u32,
signature: FunctionSignature,
}
@@ -27,13 +37,55 @@ impl FunctionBlock {
pub fn new(signature: FunctionSignature) -> Self {
Self {
instructions: vec![],
labels: HashMap::new(),
last_label: 0,
signature,
}
}
pub fn emit(&mut self, instruction: Instruction) {
eprintln!("emit {instruction:?}");
self.instructions.push(instruction);
pub fn new_label(&mut self) -> u32 {
let id = self.last_label;
self.last_label += 1;
self.labels.insert(id, usize::MAX);
id
}
pub fn adjust_label(&mut self, label: u32) {
self.labels.insert(label, self.instructions.len());
}
pub fn resolve_labels(self) -> CompiledFunction {
let mut instructions = vec![];
for emitted in self.instructions {
match emitted {
Emitted::Instruction(instruction) => {
instructions.push(instruction);
}
Emitted::Branch(label) => {
let address = self.labels.get(&label).copied().unwrap_or(usize::MAX);
if address == usize::MAX {
todo!()
}
let offset = U::new(address as u32).unwrap();
instructions.push(Instruction::Branch(offset));
}
Emitted::Jump(label) => {
let address = self.labels.get(&label).copied().unwrap_or(usize::MAX);
if address == usize::MAX {
todo!()
}
let offset = U::new(address as u32).unwrap();
instructions.push(Instruction::Jump(offset));
}
}
}
CompiledFunction { instructions }
}
pub fn emit<E: Into<Emitted>>(&mut self, instruction: E) {
let emitted = instruction.into();
// eprintln!("emit {emitted:?}");
self.instructions.push(emitted);
}
pub fn compile_body(
@@ -62,8 +114,18 @@ impl<'a> LocalBlock<'a> {
fn compile_push(&mut self, value: CompileValue) -> Result<(), CompileError> {
match value {
CompileValue::Nil => todo!(),
CompileValue::Boolean(_) => todo!(),
CompileValue::Nil => {
self.function.emit(Instruction::PushNil);
}
CompileValue::Global(identifier) => {
let value = self
.module
.constant(CompileConstant::Identifier(identifier))?;
self.function.emit(Instruction::PushConstant(value));
}
CompileValue::Boolean(value) => {
self.function.emit(Instruction::PushBool(value));
}
CompileValue::Integer(value) => {
// TODO signed/unsigned
if let Some(value) = U::new(value as u32) {
@@ -91,6 +153,13 @@ impl<'a> LocalBlock<'a> {
Ok(())
}
fn compile_drop(&mut self, value: CompileValue) -> Result<(), CompileError> {
if matches!(value, CompileValue::Stack) {
self.function.emit(Instruction::Drop);
}
Ok(())
}
pub fn compile_return(&mut self, value: CompileValue) -> Result<(), CompileError> {
self.compile_push(value)?;
self.function.emit(Instruction::Return);
@@ -98,7 +167,9 @@ impl<'a> LocalBlock<'a> {
}
pub fn compile_statement(&mut self, expression: &Expression) -> Result<(), CompileError> {
todo!()
let value = self.compile_expression(expression)?;
self.compile_drop(value)?;
Ok(())
}
fn compile_identifier(&mut self, identifier: &Rc<str>) -> Result<CompileValue, CompileError> {
@@ -109,7 +180,7 @@ impl<'a> LocalBlock<'a> {
return Ok(CompileValue::Argument(argument));
}
// TODO local bindings
todo!()
Ok(CompileValue::Global(identifier.clone()))
}
fn compile_lambda(&mut self, lambda: &LambdaExpression) -> Result<CompileValue, CompileError> {
@@ -136,6 +207,24 @@ impl<'a> LocalBlock<'a> {
todo!()
}
fn compile_builtin_cmp(
&mut self,
not: bool,
cmp: Comparison,
args: &[Expression],
) -> Result<CompileValue, CompileError> {
// TODO optimize literals
for arg in args.iter().rev() {
let arg = self.compile_expression(arg)?;
self.compile_push(arg)?;
}
let Some(count) = U::new(args.len() as u32) else {
todo!()
};
self.function.emit(Instruction::Compare(not, cmp, count));
Ok(CompileValue::Stack)
}
fn compile_call_builtin(
&mut self,
builtin: BuiltinFunction,
@@ -144,6 +233,7 @@ impl<'a> LocalBlock<'a> {
match builtin {
BuiltinFunction::Add => self.compile_builtin_add(args),
BuiltinFunction::Sub => self.compile_builtin_sub(args),
BuiltinFunction::Cmp(not, cmp) => self.compile_builtin_cmp(not, cmp, args),
}
}
@@ -172,6 +262,57 @@ impl<'a> LocalBlock<'a> {
}
}
fn compile_if(&mut self, condition: &IfExpression) -> Result<CompileValue, CompileError> {
let label_false = self.function.new_label();
let label_end = self.function.new_label();
// Emit condition
let condition_value = self.compile_expression(&condition.condition)?;
self.compile_push(condition_value)?;
self.function.emit(Emitted::Branch(label_false));
// True branch
let true_value = self.compile_expression(&condition.if_true)?;
self.compile_push(true_value)?;
self.function.emit(Emitted::Jump(label_end));
// False branch
self.function.adjust_label(label_false);
let false_value = if let Some(if_false) = condition.if_false.as_ref() {
self.compile_expression(if_false)?
} else {
CompileValue::Nil
};
self.compile_push(false_value)?;
self.function.adjust_label(label_end);
Ok(CompileValue::Stack)
}
fn compile_cond(&mut self, condition: &CondExpression) -> Result<CompileValue, CompileError> {
let label_end = self.function.new_label();
for arm in condition.arms.iter() {
let label_condition_end = self.function.new_label();
let condition_value = self.compile_expression(&arm.condition)?;
self.compile_push(condition_value)?;
self.function.emit(Emitted::Branch(label_condition_end));
// Condition true
let then_value = self.compile_expression(&arm.then)?;
self.compile_push(then_value)?;
self.function.emit(Emitted::Jump(label_end));
// Condition false
self.function.adjust_label(label_condition_end);
}
// Otherwise branch
let otherwise_value = if let Some(othwerise_arm) = condition.otherwise_arm.as_ref() {
self.compile_expression(othwerise_arm)?
} else {
CompileValue::Nil
};
self.compile_push(otherwise_value)?;
self.function.adjust_label(label_end);
Ok(CompileValue::Stack)
}
pub fn compile_expression(
&mut self,
expression: &Expression,
@@ -183,26 +324,35 @@ impl<'a> LocalBlock<'a> {
Expression::Identifier(identifier) => self.compile_identifier(identifier),
Expression::Lambda(lambda) => self.compile_lambda(lambda),
Expression::Call(call) => self.compile_call(call),
Expression::If(condition) => self.compile_if(condition),
Expression::Cond(condition) => self.compile_cond(condition),
Expression::SyntaxError(_) => unreachable!(),
}
}
}
#[cfg(test)]
mod tests {
use std::rc::Rc;
use std::{collections::HashMap, rc::Rc};
use crate::{
compile::{
block::{FunctionBlock, LocalBlock},
block::{CompiledFunction, FunctionBlock, LocalBlock},
function::FunctionSignature,
module::CompilationModule,
syntax::{CallExpression, Expression, FunctionBody, LambdaExpression},
value::CompileValue,
syntax::{
CallExpression, CondExpression, CondExpressionArm, Expression, FunctionBody,
IfExpression, LambdaExpression,
},
value::{CompileConstant, CompileValue},
},
vm::instruction::{Instruction, U},
vm::instruction::{Comparison, Instruction, U},
};
fn test_compile(expression: &Expression) -> (CompilationModule, FunctionBlock, CompileValue) {
fn test_compile(
expression: &Expression,
) -> (CompilationModule, CompiledFunction, CompileValue) {
let mut module = CompilationModule::default();
let mut function = FunctionBlock {
signature: FunctionSignature {
@@ -210,11 +360,13 @@ mod tests {
optional_arguments: vec!["arg1".into()],
rest_argument: Some("arg2".into()),
},
labels: HashMap::new(),
last_label: 0,
instructions: vec![],
};
let mut local = LocalBlock::root(&mut function, &mut module);
let value = local.compile_expression(expression).unwrap();
(module, function, value)
(module, function.resolve_labels(), value)
}
#[test]
@@ -224,6 +376,85 @@ mod tests {
assert_eq!(v, CompileValue::Integer(1));
}
#[test]
fn test_comparison_compile() {
let (m, f, v) = test_compile(&Expression::Call(CallExpression {
callee: Rc::new(Expression::Identifier(">".into())),
arguments: vec![
Expression::Identifier("a".into()),
Expression::IntegerLiteral(1),
],
}));
let cs = m.constant_pool.into_map();
assert_eq!(
cs,
[(U::truncate(1), CompileConstant::Identifier("a".into()))].into()
);
assert_eq!(
&f.instructions,
&[
Instruction::PushInteger(U::truncate(1)),
Instruction::PushConstant(U::truncate(1)),
Instruction::Compare(false, Comparison::Gt, U::truncate(2)),
]
);
assert_eq!(v, CompileValue::Stack);
}
#[test]
fn test_if_compile() {
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))),
}));
assert_eq!(
&f.instructions,
&[
Instruction::PushBool(false), // 0
Instruction::Branch(U::truncate(4)), // 1
Instruction::PushInteger(U::truncate(1)), // 2
Instruction::Jump(U::truncate(5)), // 3
Instruction::PushInteger(U::truncate(2)) // 4
// 5
]
);
assert_eq!(v, CompileValue::Stack);
}
#[test]
fn test_cond_compile() {
let (_, f, v) = test_compile(&Expression::Cond(CondExpression {
arms: vec![
CondExpressionArm {
condition: Expression::BooleanLiteral(false),
then: Expression::IntegerLiteral(1),
},
CondExpressionArm {
condition: Expression::BooleanLiteral(true),
then: Expression::IntegerLiteral(2),
},
],
otherwise_arm: Some(Rc::new(Expression::IntegerLiteral(3))),
}));
assert_eq!(
&f.instructions,
&[
Instruction::PushBool(false), // 0
Instruction::Branch(U::truncate(4)), // 1
Instruction::PushInteger(U::truncate(1)), // 2
Instruction::Jump(U::truncate(9)), // 3
Instruction::PushBool(true), // 4
Instruction::Branch(U::truncate(8)), // 5
Instruction::PushInteger(U::truncate(2)), // 6
Instruction::Jump(U::truncate(9)), // 7
Instruction::PushInteger(U::truncate(3)), // 8
// 9
]
);
assert_eq!(v, CompileValue::Stack);
}
#[test]
fn test_compile_lambda_returning_lambda() {
// ( ((lambda () (lambda (a b) (+ a b)))) 1 2 )
+8 -2
View File
@@ -2,6 +2,12 @@ use crate::compile::syntax::ParseError;
#[derive(Debug, thiserror::Error)]
pub enum CompileError {
#[error("parse error: {0}")]
Parse(#[from] ParseError),
#[error("parse error: {0:?}")]
Parse(Vec<ParseError>),
}
impl From<Vec<ParseError>> for CompileError {
fn from(value: Vec<ParseError>) -> Self {
Self::Parse(value)
}
}
+1 -1
View File
@@ -34,7 +34,7 @@ impl FunctionSignature {
{
Some(self.required_arguments.len() + self.optional_arguments.len())
} else {
todo!()
None
}
}
}
+14
View File
@@ -0,0 +1,14 @@
use crate::vm::instruction::Instruction;
#[derive(Debug, Clone, Copy)]
pub enum Emitted {
Branch(u32),
Jump(u32),
Instruction(Instruction),
}
impl From<Instruction> for Emitted {
fn from(value: Instruction) -> Self {
Self::Instruction(value)
}
}
+2 -1
View File
@@ -1,6 +1,7 @@
mod block;
mod error;
mod function;
mod instruction;
mod module;
mod syntax;
mod value;
@@ -8,4 +9,4 @@ mod value;
pub use error::CompileError;
pub use function::FunctionSignature;
pub use module::CompilationModule;
pub use syntax::{CallExpression, Expression, FunctionBody, LambdaExpression};
pub use syntax::{CallExpression, Expression, FunctionBody, LambdaExpression, ParseError};
+11 -4
View File
@@ -2,8 +2,11 @@ use std::collections::HashMap;
use crate::{
compile::{
block::FunctionBlock, error::CompileError, function::FunctionSignature,
syntax::FunctionBody, value::CompileConstant,
block::{CompiledFunction, FunctionBlock},
error::CompileError,
function::FunctionSignature,
syntax::FunctionBody,
value::CompileConstant,
},
vm::{
instruction::ConstantId,
@@ -14,8 +17,8 @@ use crate::{
#[derive(Default)]
pub struct CompilationModule {
constant_pool: Pool<CompileConstant, { ConstantId::BITS }>,
pub(crate) local_functions: HashMap<u32, FunctionBlock>,
pub(crate) constant_pool: Pool<CompileConstant, { ConstantId::BITS }>,
pub(crate) local_functions: HashMap<u32, CompiledFunction>,
local_function_index: u32,
root: Option<u32>,
}
@@ -41,6 +44,7 @@ impl CompilationModule {
self.local_function_index += 1;
let mut function = FunctionBlock::new(signature);
function.compile_body(self, body)?;
let function = function.resolve_labels();
self.local_functions.insert(index, function);
if root {
self.root = Some(index);
@@ -66,6 +70,9 @@ impl CompilationModule {
key,
match value {
CompileConstant::Integer(value) => ModuleConstant::Integer(value),
CompileConstant::Identifier(identifier) => {
ModuleConstant::Identifier(identifier)
}
CompileConstant::LocalFunction(index) => {
let address = *function_offsets.get(&index).unwrap();
ModuleConstant::LocalFunction(address)
-264
View File
@@ -1,264 +0,0 @@
use std::rc::Rc;
use crate::{
compile::function::FunctionSignature,
vm::value::{ConsCell, Keyword, Value},
};
#[derive(Debug, thiserror::Error)]
pub enum ParseError {
#[error("Non-expression value")]
NonExpressionValue,
#[error("Expected argument list: {0}")]
ExpectedArgumentList(Value),
}
#[derive(Debug, PartialEq)]
pub struct FunctionBody {
pub head: Vec<Expression>,
pub tail: Rc<Expression>,
}
#[derive(Debug, PartialEq)]
pub struct LambdaExpression {
pub signature: FunctionSignature,
pub body: FunctionBody,
}
#[derive(Debug, PartialEq)]
pub struct CallExpression {
pub callee: Rc<Expression>,
pub arguments: Vec<Expression>,
}
#[derive(Debug, PartialEq)]
pub enum Expression {
Nil,
BooleanLiteral(bool),
IntegerLiteral(i64),
Identifier(Rc<str>),
Lambda(LambdaExpression),
Call(CallExpression),
}
impl FunctionSignature {
fn parse(mut value: &Value) -> Result<Self, ParseError> {
enum Mode {
Required,
Optional,
Rest,
}
let mut required_arguments = vec![];
let mut optional_arguments = vec![];
let mut rest_argument = None;
let mut mode = Mode::Required;
while !value.is_nil() {
let Value::Cons(cons) = value else {
todo!();
};
let ConsCell(car, cdr) = cons.as_ref();
match (&mode, car) {
(Mode::Required, Value::Identifier(arg)) => {
required_arguments.push(arg.clone());
}
(Mode::Optional, Value::Identifier(arg)) => {
optional_arguments.push(arg.clone());
}
(Mode::Rest, Value::Identifier(arg)) => {
if rest_argument.is_some() {
todo!();
}
rest_argument = Some(arg.clone());
}
(Mode::Required, Value::Keyword(Keyword::Optional)) => {
mode = Mode::Optional;
}
(Mode::Required, Value::Keyword(Keyword::Rest)) => {
mode = Mode::Rest;
}
(Mode::Optional, Value::Keyword(Keyword::Rest)) => {
if optional_arguments.is_empty() {
todo!();
}
mode = Mode::Rest;
}
_ => todo!(),
}
value = cdr;
}
match mode {
Mode::Required => (),
Mode::Optional => {
if optional_arguments.is_empty() {
todo!()
}
}
Mode::Rest => {
if rest_argument.is_none() {
todo!()
}
}
}
Ok(Self {
required_arguments,
optional_arguments,
rest_argument,
})
}
}
impl FunctionBody {
fn parse(mut value: &Value) -> Result<Self, ParseError> {
let mut expressions = vec![];
while !value.is_nil() {
let Value::Cons(cons) = value else { todo!() };
let ConsCell(car, cdr) = cons.as_ref();
let expression = Expression::parse(car)?;
expressions.push(expression);
value = cdr;
}
let Some(tail) = expressions.pop() else {
todo!()
};
Ok(Self {
head: expressions,
tail: tail.into(),
})
}
}
impl LambdaExpression {
fn parse(value: &ConsCell) -> Result<Self, ParseError> {
let ConsCell(car, cdr) = value;
let signature = FunctionSignature::parse(car)?;
let body = FunctionBody::parse(cdr)?;
Ok(Self { signature, body })
}
}
impl Expression {
fn parse_cons(value: &ConsCell) -> Result<Self, ParseError> {
let ConsCell(car, cdr) = value;
match car {
Value::Keyword(Keyword::Lambda) => {
let Value::Cons(cdr) = cdr else {
todo!();
};
LambdaExpression::parse(cdr).map(Self::Lambda)
}
_ => {
let callee = Expression::parse(car)?;
let mut arguments = vec![];
let mut list = cdr;
while !list.is_nil() {
let Value::Cons(cons) = list else {
todo!();
};
let ConsCell(car, cdr) = cons.as_ref();
let expression = Expression::parse(car)?;
arguments.push(expression);
list = cdr;
}
Ok(Self::Call(CallExpression {
callee: callee.into(),
arguments,
}))
}
}
}
pub fn parse(value: &Value) -> Result<Self, ParseError> {
match value {
Value::Nil => Ok(Self::Nil),
Value::Boolean(value) => Ok(Self::BooleanLiteral(*value)),
Value::Integer(value) => Ok(Self::IntegerLiteral(*value)),
Value::Identifier(value) => Ok(Self::Identifier(value.clone())),
Value::Cons(cons) => Self::parse_cons(cons),
_ => Err(ParseError::NonExpressionValue),
}
}
}
#[cfg(test)]
mod tests {
use crate::{
compile::{
function::FunctionSignature,
syntax::{CallExpression, Expression, FunctionBody, LambdaExpression},
},
vm::value::{Keyword, Value},
};
#[test]
fn test_parse_basic() {
let v = Value::Nil;
let e = Expression::parse(&v).unwrap();
assert_eq!(e, Expression::Nil);
let v = Value::Integer(1234);
let e = Expression::parse(&v).unwrap();
assert_eq!(e, Expression::IntegerLiteral(1234));
let v = Value::Boolean(false);
let e = Expression::parse(&v).unwrap();
assert_eq!(e, Expression::BooleanLiteral(false));
let v = Value::Identifier("a".into());
let e = Expression::parse(&v).unwrap();
assert_eq!(e, Expression::Identifier("a".into()));
}
#[test]
fn test_parse_lambda() {
let args = Value::list_or_nil([
Value::Identifier("a".into()),
Value::Keyword(Keyword::Optional),
Value::Identifier("b".into()),
Value::Keyword(Keyword::Rest),
Value::Identifier("c".into()),
]);
let body = Value::list_or_nil([
Value::Identifier("+".into()),
Value::Identifier("a".into()),
Value::Integer(1),
]);
let lambda = Value::Keyword(Keyword::Lambda).cons(args.cons(body.cons(Value::Nil)));
let expr = Expression::parse(&lambda).unwrap();
assert_eq!(
expr,
Expression::Lambda(LambdaExpression {
signature: FunctionSignature {
required_arguments: vec!["a".into()],
optional_arguments: vec!["b".into()],
rest_argument: Some("c".into())
},
body: FunctionBody {
head: vec![],
tail: Expression::Call(CallExpression {
callee: Expression::Identifier("+".into()).into(),
arguments: vec![
Expression::Identifier("a".into()),
Expression::IntegerLiteral(1)
]
})
.into()
}
})
);
let lambda = Value::list_or_nil([Value::Keyword(())]);
}
}
+97
View File
@@ -0,0 +1,97 @@
use std::rc::Rc;
use crate::{
compile::{
Expression, ParseError,
syntax::{CollectErrors, ExpectedWhat, ExpectedWhere, ParseErrorKind},
},
vm::value::{ConsCell, Value},
};
#[derive(Debug, PartialEq)]
pub struct CallExpression {
pub callee: Rc<Expression>,
pub arguments: Vec<Expression>,
}
impl CallExpression {
pub(super) fn parse(cons: &ConsCell, input: &Value) -> Result<Self, ParseError> {
let ConsCell(car, cdr) = cons;
let callee = Expression::parse_inner(car);
let mut arguments = vec![];
let mut list = cdr;
while !list.is_nil() {
let Value::Cons(cons) = list else {
return Err(ParseError {
input: input.clone(),
error: ParseErrorKind::Expected(
ExpectedWhat::ProperList,
ExpectedWhere::InCallExpression,
),
});
};
let ConsCell(car, cdr) = cons.as_ref();
let expression = Expression::parse_inner(car);
arguments.push(expression);
list = cdr;
}
Ok(Self {
callee: callee.into(),
arguments,
})
}
}
impl CollectErrors<ParseError> for CallExpression {
fn collect_errors(&self, errors: &mut Vec<ParseError>) -> bool {
let mut r = self.callee.collect_errors(errors);
for expr in self.arguments.iter() {
r |= expr.collect_errors(errors);
}
r
}
}
#[cfg(test)]
mod tests {
use std::rc::Rc;
use crate::{
compile::{
CallExpression, Expression, ParseError,
syntax::{ExpectedWhat, ExpectedWhere, ParseErrorKind},
},
vm::value::Value,
};
#[test]
fn test_parse_call() {
let v = Value::list_or_nil([Value::Identifier("a".into())]);
let e = Expression::parse(&v).unwrap();
assert_eq!(
e,
Expression::Call(CallExpression {
callee: Rc::new(Expression::Identifier("a".into())),
arguments: vec![]
})
);
// Syntax errors
let v = Value::Identifier("a".into()).cons(Value::Integer(1));
let e = Expression::parse(&v).unwrap_err();
assert_eq!(
e,
vec![ParseError {
input: v,
error: ParseErrorKind::Expected(
ExpectedWhat::ProperList,
ExpectedWhere::InCallExpression
),
}]
);
}
}
+490
View File
@@ -0,0 +1,490 @@
use std::rc::Rc;
use crate::{
compile::{
Expression, ParseError,
syntax::{CollectErrors, ExpectedWhat, ExpectedWhere, ParseErrorKind},
},
vm::value::{ConsCell, Keyword, Value},
};
#[derive(Debug, PartialEq)]
pub struct IfExpression {
pub condition: Rc<Expression>,
pub if_true: Rc<Expression>,
pub if_false: Option<Rc<Expression>>,
}
#[derive(Debug, PartialEq)]
pub struct CondExpressionArm {
pub condition: Expression,
pub then: Expression,
}
#[derive(Debug, PartialEq)]
pub struct CondExpression {
pub arms: Vec<CondExpressionArm>,
pub otherwise_arm: Option<Rc<Expression>>,
}
impl IfExpression {
pub(super) fn parse(value: &Value, input: &Value) -> Result<Self, ParseError> {
let Value::Cons(value) = value else {
return Err(ParseError {
input: input.clone(),
error: ParseErrorKind::Expected(
ExpectedWhat::Condition,
ExpectedWhere::AfterKeyword(Keyword::If),
),
});
};
let ConsCell(condition, cdr) = value.as_ref();
let condition = Expression::parse_inner(condition);
let Value::Cons(cdr) = cdr else {
return Err(ParseError {
input: input.clone(),
error: ParseErrorKind::Expected(
ExpectedWhat::Expression,
ExpectedWhere::AfterCondition,
),
});
};
let ConsCell(if_true, cdr) = cdr.as_ref();
let if_true = Expression::parse_inner(if_true);
let if_false = if cdr.is_nil() {
None
} else {
let Value::Cons(cdr) = cdr else { todo!() };
let ConsCell(if_false, cdr) = cdr.as_ref();
if !cdr.is_nil() {
return Err(ParseError {
input: input.clone(),
error: ParseErrorKind::extraneous(cdr),
});
}
Some(Expression::parse_inner(if_false))
};
Ok(Self {
condition: condition.into(),
if_true: if_true.into(),
if_false: if_false.map(Into::into),
})
}
}
impl CondExpressionArm {
fn parse(cons: &ConsCell, input: &Value) -> Result<Self, ParseError> {
let ConsCell(condition, cdr) = cons;
let condition = Expression::parse_inner(condition);
let Value::Cons(cons) = cdr else {
return Err(ParseError {
input: input.clone(),
error: ParseErrorKind::Expected(
ExpectedWhat::Expression,
ExpectedWhere::InConditionArm,
),
});
};
let ConsCell(then, cdr) = cons.as_ref();
if !cdr.is_nil() {
return Err(ParseError {
input: input.clone(),
error: ParseErrorKind::extraneous(cdr),
});
}
let then = Expression::parse_inner(then);
Ok(Self { condition, then })
}
}
impl CondExpression {
pub(super) fn parse(mut value: &Value, input: &Value) -> Result<Self, ParseError> {
let mut arms = vec![];
let mut otherwise_arm = None;
while !value.is_nil() {
let Value::Cons(cons) = value else {
return Err(ParseError {
input: input.clone(),
error: ParseErrorKind::Expected(
ExpectedWhat::ConditionList,
ExpectedWhere::AfterKeyword(Keyword::Cond),
),
});
};
let ConsCell(arm, cdr) = cons.as_ref();
// Arm must be a list
let Value::Cons(arm_cons) = arm else {
return Err(ParseError {
input: arm.clone(),
error: ParseErrorKind::Expected(
ExpectedWhat::Condition,
ExpectedWhere::InConditionList,
),
});
};
let ConsCell(arm_condition, arm_condition_cdr) = arm_cons.as_ref();
match arm_condition {
Value::Keyword(Keyword::Otherwise) => {
if otherwise_arm.is_some() {
return Err(ParseError {
input: input.clone(),
error: ParseErrorKind::extraneous(arm),
});
}
let Value::Cons(otherwise_cons) = arm_condition_cdr else {
return Err(ParseError {
input: arm.clone(),
error: ParseErrorKind::Expected(
ExpectedWhat::ProperList,
ExpectedWhere::InConditionList,
),
});
};
let ConsCell(arm_expr, arm_cdr) = otherwise_cons.as_ref();
if !arm_cdr.is_nil() {
return Err(ParseError {
input: arm.clone(),
error: ParseErrorKind::extraneous(arm_cdr),
});
}
let arm = Expression::parse_inner(arm_expr);
otherwise_arm = Some(Rc::new(arm));
}
_ => {
if otherwise_arm.is_some() {
return Err(ParseError {
input: input.clone(),
error: ParseErrorKind::extraneous(arm),
});
}
let arm = CondExpressionArm::parse(arm_cons, arm)?;
arms.push(arm);
}
}
value = cdr;
}
if arms.is_empty() {
return Err(ParseError {
input: input.clone(),
error: ParseErrorKind::Expected(
ExpectedWhat::ConditionList,
ExpectedWhere::AfterKeyword(Keyword::Cond),
),
});
}
Ok(Self {
arms,
otherwise_arm,
})
}
}
impl CollectErrors<ParseError> for IfExpression {
fn collect_errors(&self, errors: &mut Vec<ParseError>) -> bool {
let a = self.condition.collect_errors(errors);
let b = self.if_true.collect_errors(errors);
let c = self
.if_false
.as_ref()
.map(|x| x.collect_errors(errors))
.unwrap_or_default();
a | b | c
}
}
impl CollectErrors<ParseError> for CondExpression {
fn collect_errors(&self, errors: &mut Vec<ParseError>) -> bool {
let mut r = false;
for arm in self.arms.iter() {
r |= arm.condition.collect_errors(errors);
r |= arm.then.collect_errors(errors);
}
if let Some(otherwise_arm) = self.otherwise_arm.as_ref() {
r |= otherwise_arm.collect_errors(errors);
}
r
}
}
#[cfg(test)]
mod tests {
use std::rc::Rc;
use crate::{
compile::{
Expression, ParseError,
syntax::{
CondExpression, CondExpressionArm, ExpectedWhat, ExpectedWhere, IfExpression,
ParseErrorKind,
},
},
vm::value::{ConsCell, Keyword, Value},
};
#[test]
fn test_parse_cond() {
// without &otherwise branch
let b0 = Value::list_or_nil([Value::Boolean(true), Value::Identifier("a".into())]);
let b1 = Value::list_or_nil([Value::Boolean(false), Value::Identifier("b".into())]);
let v = Value::list_or_nil([Value::Keyword(Keyword::Cond), b0, b1]);
let e = Expression::parse(&v).unwrap();
assert_eq!(
e,
Expression::Cond(CondExpression {
arms: vec![
CondExpressionArm {
condition: Expression::BooleanLiteral(true),
then: Expression::Identifier("a".into())
},
CondExpressionArm {
condition: Expression::BooleanLiteral(false),
then: Expression::Identifier("b".into())
}
],
otherwise_arm: None
})
);
// with &otherwise branch
let b0 = Value::list_or_nil([Value::Boolean(true), Value::Identifier("a".into())]);
let b1 = Value::list_or_nil([
Value::Keyword(Keyword::Otherwise),
Value::Identifier("b".into()),
]);
let v = Value::list_or_nil([Value::Keyword(Keyword::Cond), b0, b1]);
let e = Expression::parse(&v).unwrap();
assert_eq!(
e,
Expression::Cond(CondExpression {
arms: vec![CondExpressionArm {
condition: Expression::BooleanLiteral(true),
then: Expression::Identifier("a".into())
},],
otherwise_arm: Some(Rc::new(Expression::Identifier("b".into())))
})
);
// syntax error
let v = Value::list_or_nil([Value::Keyword(Keyword::Cond)]);
let e = Expression::parse(&v).unwrap_err();
assert_eq!(
e,
vec![ParseError {
input: v,
error: ParseErrorKind::Expected(
ExpectedWhat::ConditionList,
ExpectedWhere::AfterKeyword(Keyword::Cond)
)
}]
);
let v = Value::Keyword(Keyword::Cond).cons(Value::Identifier("a".into()));
let e = Expression::parse(&v).unwrap_err();
assert_eq!(
e,
vec![ParseError {
input: v,
error: ParseErrorKind::Expected(
ExpectedWhat::ConditionList,
ExpectedWhere::AfterKeyword(Keyword::Cond)
)
}]
);
let b0 = Value::list_or_nil([Value::Boolean(false)]);
let v = Value::list_or_nil([Value::Keyword(Keyword::Cond), b0.clone()]);
let e = Expression::parse(&v).unwrap_err();
assert_eq!(
e,
vec![ParseError {
input: b0,
error: ParseErrorKind::Expected(
ExpectedWhat::Expression,
ExpectedWhere::InConditionArm
)
}]
);
let b0 = Value::Boolean(false);
let v = Value::list_or_nil([Value::Keyword(Keyword::Cond), b0.clone()]);
let e = Expression::parse(&v).unwrap_err();
assert_eq!(
e,
vec![ParseError {
input: b0,
error: ParseErrorKind::Expected(
ExpectedWhat::Condition,
ExpectedWhere::InConditionList
)
}]
);
let b0 = Value::Keyword(Keyword::Otherwise);
let v = Value::list_or_nil([Value::Keyword(Keyword::Cond), b0.clone()]);
let e = Expression::parse(&v).unwrap_err();
assert_eq!(
e,
vec![ParseError {
input: b0,
error: ParseErrorKind::Expected(
ExpectedWhat::Condition,
ExpectedWhere::InConditionList
)
}]
);
let b0 = Value::Keyword(Keyword::Otherwise).cons(Value::Integer(1));
let v = Value::list_or_nil([Value::Keyword(Keyword::Cond), b0.clone()]);
let e = Expression::parse(&v).unwrap_err();
assert_eq!(
e,
vec![ParseError {
input: b0,
error: ParseErrorKind::Expected(
ExpectedWhat::ProperList,
ExpectedWhere::InConditionList
)
}]
);
let b0 = Value::Boolean(false).cons(Value::Boolean(false));
let v = Value::list_or_nil([Value::Keyword(Keyword::Cond), b0.clone()]);
let e = Expression::parse(&v).unwrap_err();
assert_eq!(
e,
vec![ParseError {
input: b0,
error: ParseErrorKind::Expected(
ExpectedWhat::Expression,
ExpectedWhere::InConditionArm
)
}]
);
let b0 = Value::list_or_nil([Value::Boolean(false), Value::Integer(1), Value::Integer(2)]);
let v = Value::list_or_nil([Value::Keyword(Keyword::Cond), b0.clone()]);
let e = Expression::parse(&v).unwrap_err();
assert_eq!(
e,
vec![ParseError {
input: b0,
error: ParseErrorKind::extraneous(&Value::list_or_nil([Value::Integer(2)]))
}]
);
let b0 = Value::list_or_nil([
Value::Keyword(Keyword::Otherwise),
Value::Integer(1),
Value::Integer(2),
]);
let v = Value::list_or_nil([Value::Keyword(Keyword::Cond), b0.clone()]);
let e = Expression::parse(&v).unwrap_err();
assert_eq!(
e,
vec![ParseError {
input: b0,
error: ParseErrorKind::extraneous(&Value::list_or_nil([Value::Integer(2)]))
}]
);
let b0 = Value::list_or_nil([Value::Keyword(Keyword::Otherwise), Value::Integer(1)]);
let v = Value::list_or_nil([Value::Keyword(Keyword::Cond), b0.clone(), b0.clone()]);
let e = Expression::parse(&v).unwrap_err();
assert_eq!(
e,
vec![ParseError {
input: v,
error: ParseErrorKind::extraneous(&b0)
}]
);
let b0 = Value::list_or_nil([Value::Keyword(Keyword::Otherwise), Value::Integer(1)]);
let b1 = Value::list_or_nil([Value::Boolean(false), Value::Integer(1)]);
let v = Value::list_or_nil([Value::Keyword(Keyword::Cond), b0, b1.clone()]);
let e = Expression::parse(&v).unwrap_err();
assert_eq!(
e,
vec![ParseError {
input: v,
error: ParseErrorKind::extraneous(&b1)
}]
);
}
#[test]
fn test_parse_if() {
// without false branch
let v = Value::list_or_nil([
Value::Keyword(Keyword::If),
Value::Boolean(true),
Value::Integer(1),
]);
let e = Expression::parse(&v).unwrap();
assert_eq!(
e,
Expression::If(IfExpression {
condition: Rc::new(Expression::BooleanLiteral(true)),
if_true: Rc::new(Expression::IntegerLiteral(1)),
if_false: None
})
);
// with false branch
let v = Value::list_or_nil([
Value::Keyword(Keyword::If),
Value::Boolean(false),
Value::Integer(1),
Value::Integer(2),
]);
let e = Expression::parse(&v).unwrap();
assert_eq!(
e,
Expression::If(IfExpression {
condition: Rc::new(Expression::BooleanLiteral(false)),
if_true: Rc::new(Expression::IntegerLiteral(1)),
if_false: Some(Rc::new(Expression::IntegerLiteral(2)))
})
);
// invalid syntax
let v = Value::list_or_nil([Value::Keyword(Keyword::If)]);
let e = Expression::parse(&v).unwrap_err();
assert_eq!(
e,
vec![ParseError {
input: v,
error: ParseErrorKind::Expected(
ExpectedWhat::Condition,
ExpectedWhere::AfterKeyword(Keyword::If)
)
}]
);
let v = Value::list_or_nil([Value::Keyword(Keyword::If), Value::Boolean(true)]);
let e = Expression::parse(&v).unwrap_err();
assert_eq!(
e,
vec![ParseError {
input: v,
error: ParseErrorKind::Expected(
ExpectedWhat::Expression,
ExpectedWhere::AfterCondition
)
}]
);
let v = Value::list_or_nil([
Value::Keyword(Keyword::If),
Value::Boolean(true),
Value::Integer(1),
Value::Integer(2),
Value::Integer(3),
]);
let e = Expression::parse(&v).unwrap_err();
assert_eq!(
e,
vec![ParseError {
input: v,
error: ParseErrorKind::ExtraneousExpressionList(Rc::new(ConsCell::end(
Value::Integer(3)
)))
}]
);
}
}
+87
View File
@@ -0,0 +1,87 @@
#![coverage(off)]
use std::{error::Error as StdError, fmt, rc::Rc};
use crate::vm::value::{ConsCell, Keyword, Value};
#[derive(Debug, Clone, PartialEq)]
pub struct ParseError {
pub input: Value,
pub error: ParseErrorKind,
}
#[derive(Debug, Clone, PartialEq, thiserror::Error)]
pub enum ParseErrorKind {
#[error("Not an expression")]
NotAnExpression,
#[error("Expected {0} {1}")]
Expected(ExpectedWhat, ExpectedWhere),
#[error("Extraneous expression: {0}")]
ExtraneousExpression(Value),
#[error("Extraneous expression(s): {0}")]
ExtraneousExpressionList(Rc<ConsCell>),
}
#[derive(Debug, Clone, PartialEq, thiserror::Error)]
pub enum ExpectedWhat {
#[error("an expression")]
Expression,
#[error("an argument list")]
ArgumentList,
#[error("a condition")]
Condition,
#[error("a condition list")]
ConditionList,
#[error("at least one argument")]
AtLeastOneArgument,
#[error("exactly one argument")]
ExactlyOneArgument,
#[error("an argument, &optional or &rest keywords")]
ArgumentSpec,
#[error("a proper list")]
ProperList,
}
#[derive(Debug, Clone, PartialEq, thiserror::Error)]
pub enum ExpectedWhere {
#[error("after a condition")]
AfterCondition,
#[error("after the \"{0}\" keyword")]
AfterKeyword(Keyword),
#[error("after the argument list in a {0}")]
AfterArgumentList(Keyword),
#[error("in the argument list")]
InArgumentList,
#[error("in the call expression")]
InCallExpression,
#[error("in the condition list")]
InConditionList,
#[error("in the condition arm")]
InConditionArm,
}
pub(super) trait CollectErrors<E> {
fn collect_errors(&self, errors: &mut Vec<E>) -> bool;
}
impl fmt::Display for ParseError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(&self.error, f)
}
}
impl StdError for ParseError {
fn description(&self) -> &str {
"Parse error"
}
}
impl ParseErrorKind {
pub fn extraneous(value: &Value) -> Self {
match value {
Value::Nil => unreachable!(),
Value::Cons(cons) => Self::ExtraneousExpressionList(cons.clone()),
_ => Self::ExtraneousExpression(value.clone()),
}
}
}
+373
View File
@@ -0,0 +1,373 @@
use std::rc::Rc;
use crate::{
compile::{
Expression, FunctionSignature, ParseError,
syntax::{CollectErrors, ExpectedWhat, ExpectedWhere, ParseErrorKind},
},
vm::value::{ConsCell, Keyword, Value},
};
#[derive(Debug, PartialEq)]
pub struct FunctionBody {
pub head: Vec<Expression>,
pub tail: Rc<Expression>,
}
impl FunctionSignature {
pub(super) fn parse(mut value: &Value, input: &Value) -> Result<Self, ParseError> {
enum Mode {
Required,
Optional,
Rest,
}
let mut required_arguments = vec![];
let mut optional_arguments = vec![];
let mut rest_argument = None;
let mut mode = Mode::Required;
while !value.is_nil() {
let Value::Cons(cons) = value else {
return Err(ParseError {
input: input.clone(),
error: ParseErrorKind::Expected(
ExpectedWhat::ArgumentSpec,
ExpectedWhere::InArgumentList,
),
});
};
let ConsCell(car, cdr) = cons.as_ref();
match (&mode, car) {
(Mode::Required, Value::Identifier(arg)) => {
required_arguments.push(arg.clone());
}
(Mode::Optional, Value::Identifier(arg)) => {
optional_arguments.push(arg.clone());
}
(Mode::Rest, Value::Identifier(arg)) => {
if rest_argument.is_some() {
return Err(ParseError {
input: input.clone(),
error: ParseErrorKind::Expected(
ExpectedWhat::ExactlyOneArgument,
ExpectedWhere::AfterKeyword(Keyword::Rest),
),
});
}
rest_argument = Some(arg.clone());
}
(Mode::Required, Value::Keyword(Keyword::Optional)) => {
mode = Mode::Optional;
}
(Mode::Required, Value::Keyword(Keyword::Rest)) => {
mode = Mode::Rest;
}
(Mode::Optional, Value::Keyword(Keyword::Rest)) => {
if optional_arguments.is_empty() {
return Err(ParseError {
input: input.clone(),
error: ParseErrorKind::Expected(
ExpectedWhat::AtLeastOneArgument,
ExpectedWhere::AfterKeyword(Keyword::Optional),
),
});
}
mode = Mode::Rest;
}
_ => {
return Err(ParseError {
input: input.clone(),
error: ParseErrorKind::Expected(
ExpectedWhat::ArgumentSpec,
ExpectedWhere::InArgumentList,
),
});
}
}
value = cdr;
}
match mode {
Mode::Required => (),
Mode::Optional => {
if optional_arguments.is_empty() {
return Err(ParseError {
input: input.clone(),
error: ParseErrorKind::Expected(
ExpectedWhat::AtLeastOneArgument,
ExpectedWhere::AfterKeyword(Keyword::Optional),
),
});
}
}
Mode::Rest => {
if rest_argument.is_none() {
return Err(ParseError {
input: input.clone(),
error: ParseErrorKind::Expected(
ExpectedWhat::ExactlyOneArgument,
ExpectedWhere::AfterKeyword(Keyword::Rest),
),
});
}
}
}
Ok(Self {
required_arguments,
optional_arguments,
rest_argument,
})
}
}
impl FunctionBody {
pub(super) fn parse(
mut value: &Value,
input: &Value,
inside: Keyword,
) -> Result<Self, ParseError> {
let mut expressions = vec![];
while !value.is_nil() {
let Value::Cons(cons) = value else {
return Err(ParseError {
input: input.clone(),
error: ParseErrorKind::Expected(
ExpectedWhat::ProperList,
ExpectedWhere::AfterArgumentList(inside),
),
});
};
let ConsCell(car, cdr) = cons.as_ref();
let expression = Expression::parse_inner(car);
expressions.push(expression);
value = cdr;
}
let Some(tail) = expressions.pop() else {
return Err(ParseError {
input: input.clone(),
error: ParseErrorKind::Expected(
ExpectedWhat::Expression,
ExpectedWhere::AfterArgumentList(inside),
),
});
};
Ok(Self {
head: expressions,
tail: tail.into(),
})
}
}
impl CollectErrors<ParseError> for FunctionBody {
fn collect_errors(&self, errors: &mut Vec<ParseError>) -> bool {
let mut r = false;
for expr in self.head.iter() {
r |= expr.collect_errors(errors);
}
r |= self.tail.collect_errors(errors);
r
}
}
#[cfg(test)]
mod tests {
use std::rc::Rc;
use crate::{
compile::{
Expression, FunctionBody, FunctionSignature, ParseError,
syntax::{ExpectedWhat, ExpectedWhere, ParseErrorKind},
},
vm::value::{Keyword, Value},
};
#[test]
fn test_parse_function_body() {
let v = Value::list_or_nil([Value::Integer(1)]);
let e = FunctionBody::parse(&v, &v, Keyword::Lambda).unwrap();
assert_eq!(
e,
FunctionBody {
head: vec![],
tail: Rc::new(Expression::IntegerLiteral(1))
}
);
let v = Value::list_or_nil([Value::Integer(1), Value::Integer(2), Value::Integer(3)]);
let e = FunctionBody::parse(&v, &v, Keyword::Lambda).unwrap();
assert_eq!(
e,
FunctionBody {
head: vec![Expression::IntegerLiteral(1), Expression::IntegerLiteral(2)],
tail: Rc::new(Expression::IntegerLiteral(3))
}
);
// syntax error
let v = Value::list_or_nil([]);
let e = FunctionBody::parse(&v, &v, Keyword::Lambda).unwrap_err();
assert_eq!(
e,
ParseError {
input: v,
error: ParseErrorKind::Expected(
ExpectedWhat::Expression,
ExpectedWhere::AfterArgumentList(Keyword::Lambda)
),
}
);
let v = Value::Identifier("a".into()).cons(Value::Identifier("b".into()));
let e = FunctionBody::parse(&v, &v, Keyword::Lambda).unwrap_err();
assert_eq!(
e,
ParseError {
input: v,
error: ParseErrorKind::Expected(
ExpectedWhat::ProperList,
ExpectedWhere::AfterArgumentList(Keyword::Lambda)
),
}
);
}
#[test]
fn test_parse_function_signature() {
let args = Value::list_or_nil([]);
let v = FunctionSignature::parse(&args, &args).unwrap();
assert_eq!(
v,
FunctionSignature {
required_arguments: vec![],
optional_arguments: vec![],
rest_argument: None
}
);
let args =
Value::list_or_nil([Value::Identifier("a".into()), Value::Identifier("b".into())]);
let v = FunctionSignature::parse(&args, &args).unwrap();
assert_eq!(
v,
FunctionSignature {
required_arguments: vec!["a".into(), "b".into()],
optional_arguments: vec![],
rest_argument: None
}
);
let args = Value::list_or_nil([
Value::Identifier("a".into()),
Value::Keyword(Keyword::Optional),
Value::Identifier("b".into()),
]);
let v = FunctionSignature::parse(&args, &args).unwrap();
assert_eq!(
v,
FunctionSignature {
required_arguments: vec!["a".into()],
optional_arguments: vec!["b".into()],
rest_argument: None
}
);
let args = Value::list_or_nil([
Value::Identifier("a".into()),
Value::Keyword(Keyword::Rest),
Value::Identifier("b".into()),
]);
let v = FunctionSignature::parse(&args, &args).unwrap();
assert_eq!(
v,
FunctionSignature {
required_arguments: vec!["a".into()],
optional_arguments: vec![],
rest_argument: Some("b".into())
}
);
let args =
Value::list_or_nil([Value::Keyword(Keyword::Rest), Value::Identifier("c".into())]);
let v = FunctionSignature::parse(&args, &args).unwrap();
assert_eq!(
v,
FunctionSignature {
required_arguments: vec![],
optional_arguments: vec![],
rest_argument: Some("c".into())
}
);
let args = Value::list_or_nil([
Value::Keyword(Keyword::Optional),
Value::Identifier("b".into()),
Value::Keyword(Keyword::Rest),
Value::Identifier("c".into()),
]);
let v = FunctionSignature::parse(&args, &args).unwrap();
assert_eq!(
v,
FunctionSignature {
required_arguments: vec![],
optional_arguments: vec!["b".into()],
rest_argument: Some("c".into())
}
);
let args = Value::list_or_nil([
Value::Identifier("a".into()),
Value::Keyword(Keyword::Rest),
Value::Identifier("c".into()),
]);
let v = FunctionSignature::parse(&args, &args).unwrap();
assert_eq!(
v,
FunctionSignature {
required_arguments: vec!["a".into()],
optional_arguments: vec![],
rest_argument: Some("c".into())
}
);
// syntax errors
let args = Value::list_or_nil([Value::Keyword(Keyword::Optional)]);
let e = FunctionSignature::parse(&args, &args).unwrap_err();
assert_eq!(
e,
ParseError {
input: args,
error: ParseErrorKind::Expected(
ExpectedWhat::AtLeastOneArgument,
ExpectedWhere::AfterKeyword(Keyword::Optional)
)
}
);
let args = Value::list_or_nil([
Value::Keyword(Keyword::Rest),
Value::Identifier("a".into()),
Value::Identifier("b".into()),
]);
let e = FunctionSignature::parse(&args, &args).unwrap_err();
assert_eq!(
e,
ParseError {
input: args,
error: ParseErrorKind::Expected(
ExpectedWhat::ExactlyOneArgument,
ExpectedWhere::AfterKeyword(Keyword::Rest)
)
}
);
let args = Value::list_or_nil([Value::Boolean(false)]);
let e = FunctionSignature::parse(&args, &args).unwrap_err();
assert_eq!(
e,
ParseError {
input: args,
error: ParseErrorKind::Expected(
ExpectedWhat::ArgumentSpec,
ExpectedWhere::InArgumentList
)
}
);
}
}
+115
View File
@@ -0,0 +1,115 @@
use crate::{
compile::{
FunctionBody, FunctionSignature, ParseError,
syntax::{CollectErrors, ExpectedWhat, ExpectedWhere, ParseErrorKind},
},
vm::value::{ConsCell, Keyword, Value},
};
#[derive(Debug, PartialEq)]
pub struct LambdaExpression {
pub signature: FunctionSignature,
pub body: FunctionBody,
}
impl LambdaExpression {
pub(super) fn parse(value: &Value, input: &Value) -> Result<Self, ParseError> {
let Value::Cons(value) = value else {
return Err(ParseError {
input: input.clone(),
error: ParseErrorKind::Expected(
ExpectedWhat::ArgumentList,
ExpectedWhere::AfterKeyword(Keyword::Lambda),
),
});
};
let ConsCell(car, cdr) = value.as_ref();
let signature = FunctionSignature::parse(car, input)?;
let body = FunctionBody::parse(cdr, input, Keyword::Lambda)?;
Ok(Self { signature, body })
}
}
impl CollectErrors<ParseError> for LambdaExpression {
fn collect_errors(&self, errors: &mut Vec<ParseError>) -> bool {
self.body.collect_errors(errors)
}
}
#[cfg(test)]
mod tests {
use crate::{
compile::{
CallExpression, Expression, FunctionBody, FunctionSignature, LambdaExpression,
ParseError,
syntax::{ExpectedWhat, ExpectedWhere, ParseErrorKind},
},
vm::value::{Keyword, Value},
};
#[test]
fn test_parse_lambda() {
let args = Value::list_or_nil([
Value::Identifier("a".into()),
Value::Keyword(Keyword::Optional),
Value::Identifier("b".into()),
Value::Keyword(Keyword::Rest),
Value::Identifier("c".into()),
]);
let body = Value::list_or_nil([
Value::Identifier("+".into()),
Value::Identifier("a".into()),
Value::Integer(1),
]);
let lambda = Value::Keyword(Keyword::Lambda).cons(args.cons(body.cons(Value::Nil)));
let expr = Expression::parse(&lambda).unwrap();
assert_eq!(
expr,
Expression::Lambda(LambdaExpression {
signature: FunctionSignature {
required_arguments: vec!["a".into()],
optional_arguments: vec!["b".into()],
rest_argument: Some("c".into())
},
body: FunctionBody {
head: vec![],
tail: Expression::Call(CallExpression {
callee: Expression::Identifier("+".into()).into(),
arguments: vec![
Expression::Identifier("a".into()),
Expression::IntegerLiteral(1)
]
})
.into()
}
})
);
// syntax errors
let lambda = Value::list_or_nil([Value::Keyword(Keyword::Lambda)]);
let e = Expression::parse(&lambda).unwrap_err();
assert_eq!(
e,
vec![ParseError {
input: lambda,
error: ParseErrorKind::Expected(
ExpectedWhat::ArgumentList,
ExpectedWhere::AfterKeyword(Keyword::Lambda)
)
}]
);
let lambda = Value::list_or_nil([Value::Keyword(Keyword::Lambda), Value::Nil]);
let e = Expression::parse(&lambda).unwrap_err();
assert_eq!(
e,
vec![ParseError {
input: lambda,
error: ParseErrorKind::Expected(
ExpectedWhat::Expression,
ExpectedWhere::AfterArgumentList(Keyword::Lambda)
)
}]
);
}
}
+150
View File
@@ -0,0 +1,150 @@
use std::{error::Error as StdError, fmt, rc::Rc};
use crate::vm::value::{ConsCell, Keyword, Value};
mod call;
mod condition;
mod error;
mod function;
mod lambda;
pub use call::*;
pub use condition::*;
pub use error::*;
pub use function::*;
pub use lambda::*;
#[derive(Debug, PartialEq)]
pub enum Expression {
Nil,
BooleanLiteral(bool),
IntegerLiteral(i64),
Identifier(Rc<str>),
Lambda(LambdaExpression),
Call(CallExpression),
If(IfExpression),
Cond(CondExpression),
SyntaxError(ParseError),
}
impl Expression {
fn map_or<T, F: FnOnce(T) -> Self>(result: Result<T, ParseError>, map: F) -> Self {
match result {
Ok(r) => map(r),
Err(error) => Self::SyntaxError(error),
}
}
pub fn parse(value: &Value) -> Result<Self, Vec<ParseError>> {
let inner = Self::parse_inner(value);
let mut errors = vec![];
if inner.collect_errors(&mut errors) {
Err(errors)
} else {
Ok(inner)
}
}
fn parse_inner(value: &Value) -> Self {
match value {
Value::Nil => Self::Nil,
Value::Boolean(value) => Self::BooleanLiteral(*value),
Value::Integer(value) => Self::IntegerLiteral(*value),
Value::Identifier(value) => Self::Identifier(value.clone()),
Value::Cons(cons) => {
let ConsCell(car, cdr) = cons.as_ref();
match car {
Value::Keyword(Keyword::Lambda) => {
Self::map_or(LambdaExpression::parse(cdr, value), Expression::Lambda)
}
Value::Keyword(Keyword::If) => {
Self::map_or(IfExpression::parse(cdr, value), Expression::If)
}
Value::Keyword(Keyword::Cond) => {
Self::map_or(CondExpression::parse(cdr, value), Expression::Cond)
}
_ => Self::map_or(CallExpression::parse(cons, value), Expression::Call),
}
}
Value::Keyword(_) => todo!(),
Value::NativeFunction(_) | Value::BytecodeFunction(_) => todo!(),
}
}
}
impl CollectErrors<ParseError> for Expression {
fn collect_errors(&self, errors: &mut Vec<ParseError>) -> bool {
match self {
Self::SyntaxError(error) => {
errors.push(error.clone());
true
}
Self::If(condition) => condition.collect_errors(errors),
Self::Cond(condition) => condition.collect_errors(errors),
Self::Lambda(condition) => condition.collect_errors(errors),
Self::Call(call) => call.collect_errors(errors),
Self::Nil | Self::IntegerLiteral(_) | Self::Identifier(_) | Self::BooleanLiteral(_) => {
false
}
}
}
}
#[cfg(test)]
mod tests {
use crate::{
compile::syntax::{ExpectedWhat, ExpectedWhere, Expression, ParseError, ParseErrorKind},
vm::value::{Keyword, Value},
};
#[test]
fn test_parse_basic() {
let v = Value::Nil;
let e = Expression::parse(&v).unwrap();
assert_eq!(e, Expression::Nil);
let v = Value::Integer(1234);
let e = Expression::parse(&v).unwrap();
assert_eq!(e, Expression::IntegerLiteral(1234));
let v = Value::Boolean(false);
let e = Expression::parse(&v).unwrap();
assert_eq!(e, Expression::BooleanLiteral(false));
let v = Value::Identifier("a".into());
let e = Expression::parse(&v).unwrap();
assert_eq!(e, Expression::Identifier("a".into()));
}
#[test]
fn test_nested_syntax_error() {
let inner_if = Value::list_or_nil([Value::Keyword(Keyword::If)]);
let inner_lambda = Value::list_or_nil([Value::Keyword(Keyword::Lambda)]);
let outer_if = Value::list_or_nil([
Value::Keyword(Keyword::If),
inner_if.clone(),
inner_lambda.clone(),
Value::Integer(3),
]);
let e = Expression::parse(&outer_if).unwrap_err();
assert_eq!(
e,
vec![
ParseError {
input: inner_if,
error: ParseErrorKind::Expected(
ExpectedWhat::Condition,
ExpectedWhere::AfterKeyword(Keyword::If)
)
},
ParseError {
input: inner_lambda,
error: ParseErrorKind::Expected(
ExpectedWhat::ArgumentList,
ExpectedWhere::AfterKeyword(Keyword::Lambda)
)
}
]
);
}
}
+13
View File
@@ -1,9 +1,14 @@
use std::rc::Rc;
use crate::vm::instruction::Comparison;
#[derive(Debug, PartialEq)]
pub enum CompileValue {
Integer(i64),
Boolean(bool),
LocalFunction(u32),
Argument(usize),
Global(Rc<str>),
Stack,
Nil,
}
@@ -12,12 +17,14 @@ pub enum CompileValue {
pub enum CompileConstant {
Integer(i64),
LocalFunction(u32),
Identifier(Rc<str>),
}
#[derive(Debug, PartialEq, Clone, Copy)]
pub enum BuiltinFunction {
Add,
Sub,
Cmp(bool, Comparison),
}
impl BuiltinFunction {
@@ -25,6 +32,12 @@ impl BuiltinFunction {
match identifier {
"+" => Some(Self::Add),
"-" => Some(Self::Sub),
">" => Some(Self::Cmp(false, Comparison::Gt)),
">=" => Some(Self::Cmp(true, Comparison::Lt)),
"=" => Some(Self::Cmp(false, Comparison::Eq)),
"/=" => Some(Self::Cmp(true, Comparison::Eq)),
"<=" => Some(Self::Cmp(true, Comparison::Gt)),
"<" => Some(Self::Cmp(false, Comparison::Lt)),
_ => None,
}
}
+39 -3
View File
@@ -1,6 +1,11 @@
use std::io::stdin;
use lysp::{parse::parse_value, vm::machine::Machine};
use lysp::{
compile::{CompileError, ParseError},
error::EvalError,
parse::parse_value,
vm::machine::{EvalResult, Machine},
};
fn main() {
let mut vm = Machine::default();
@@ -30,13 +35,44 @@ fn main() {
let result = vm.eval_value(&value);
let result = match result {
Ok(r) => r,
Err(error) => {
EvalResult::Ok(r) => r,
EvalResult::Err(module, error) => {
eprintln!("Error in expression:");
eprintln!();
eprintln!(" {value}:");
eprintln!();
eprintln!(":: {error}");
eprintln!();
module.dump();
i = "";
break;
}
EvalResult::LoadErr(error) => {
match error {
EvalError::Compile(CompileError::Parse(errors)) => {
if errors.len() > 1 {
eprintln!("Syntax errors:");
} else {
eprintln!("Syntax error:");
}
eprintln!();
for error in errors {
let ParseError { input, error } = error;
eprintln!(" * In (sub)expression:");
eprintln!();
eprintln!(" {input}");
eprintln!();
eprintln!(" :: {error}");
}
}
_ => {
eprintln!("Error in expression:");
eprintln!();
eprintln!(" {value}:");
eprintln!();
eprintln!(":: {error}")
}
}
i = "";
break;
}
+1 -4
View File
@@ -159,10 +159,7 @@ fn parse_identifier(input: &str) -> IResult<&str, &str> {
fn parse_identifier_or_keyword_or_nil(input: &str) -> IResult<&str, Value> {
map(parse_identifier, |ident| match ident {
"NIL" | "nil" => Value::Nil,
"lambda" => Value::Keyword(Keyword::Lambda),
"defun" => Value::Keyword(Keyword::Defun),
"&optional" => Value::Keyword(Keyword::Optional),
"&rest" => Value::Keyword(Keyword::Rest),
_ if let Some(keyword) = Keyword::from_str(ident) => Value::Keyword(keyword),
_ => Value::Identifier(ident.into()),
})
.parse(input)
+35
View File
@@ -14,6 +14,27 @@ pub enum InstructionEncodeError {}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct U<const N: usize>(u32);
#[derive(Debug, Clone, Copy, PartialEq)]
#[repr(u32)]
pub enum Comparison {
Eq = 0,
Lt = 1,
Gt = 2,
}
impl TryFrom<u32> for Comparison {
type Error = InstructionError;
fn try_from(value: u32) -> Result<Self, Self::Error> {
match value {
0 => Ok(Self::Eq),
1 => Ok(Self::Lt),
2 => Ok(Self::Gt),
_ => Err(InstructionError::Invalid),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Instruction {
PushNil,
@@ -21,12 +42,16 @@ pub enum Instruction {
PushBool(bool),
PushConstant(ConstantId),
PushArgument(U<6>),
Drop,
SetGlobal,
GetGlobal,
Call(U<6>),
Return,
Add(U<6>),
Sub(U<6>),
Branch(U<12>),
Jump(U<12>),
Compare(bool, Comparison, U<6>),
}
pub type ConstantId = U<24>;
@@ -81,6 +106,7 @@ impl<const N: usize> Into<u32> for U<N> {
impl From<Instruction> for u32 {
fn from(instruction: Instruction) -> u32 {
match instruction {
Instruction::Drop => 0b0000_0000_0000_0000,
Instruction::PushNil => 0b0000_0000_0000_0001,
Instruction::PushBool(value) => 0b0000_0000_0000_0010 | (value as u32),
Instruction::Return => 0b0000_0000_0000_0100,
@@ -92,6 +118,11 @@ impl From<Instruction> for u32 {
Instruction::PushInteger(value) => 0b0001_0000_0000_0000 | value.0,
Instruction::PushConstant(index) => 0b0010_0000_0000_0000 | index.0,
Instruction::PushArgument(index) => 0b0000_0000_1000_0000 | index.0,
Instruction::Branch(offset) => 0b0000_1000_0000_0000 | offset.0,
Instruction::Jump(offset) => 0b0000_1100_0000_0000 | offset.0,
Instruction::Compare(not, cmp, count) => {
0b0000_0010_0000_0000 | ((not as u32) << 8) | ((cmp as u32) << 6) | count.0
}
}
}
}
@@ -103,6 +134,7 @@ impl TryFrom<u32> for Instruction {
fn try_from(value: u32) -> Result<Self, Self::Error> {
#[bitmatch]
match value {
"0000_0000_0000_0000" => Ok(Instruction::Drop),
"0000_0000_0000_0001" => Ok(Instruction::PushNil),
"0000_0000_0000_001x" => Ok(Instruction::PushBool(x != 0)),
"0000_0000_0000_0100" => Ok(Instruction::Return),
@@ -112,6 +144,9 @@ impl TryFrom<u32> for Instruction {
"0000_0000_10xx_xxxx" => Ok(Instruction::PushArgument(U(x))),
"0000_0001_00xx_xxxx" => Ok(Instruction::Add(U(x))),
"0000_0001_01xx_xxxx" => Ok(Instruction::Sub(U(x))),
"0000_001x_yyzz_zzzz" => Ok(Instruction::Compare(x != 0, y.try_into()?, U(z))),
"0000_10xx_xxxx_xxxx" => Ok(Instruction::Branch(U(x))),
"0000_11xx_xxxx_xxxx" => Ok(Instruction::Jump(U(x))),
"0001_xxxx_xxxx_xxxx" => Ok(Instruction::PushInteger(U(x))),
"0010_xxxx_xxxx_xxxx" => Ok(Instruction::PushConstant(U(x))),
_ => todo!(),
+131 -15
View File
@@ -1,9 +1,9 @@
use std::{collections::HashMap, fmt, rc::Rc};
use std::{cmp::Ordering, collections::HashMap, fmt, rc::Rc};
use crate::{
error::EvalError,
vm::{
instruction::{ConstantId, Instruction, InstructionError},
instruction::{Comparison, ConstantId, Instruction, InstructionError},
module::{Module, ModuleConstant, ModuleRef},
stack::Stack,
value::{BytecodeFunction, NativeFunction, Value},
@@ -14,6 +14,8 @@ use crate::{
pub enum MachineError {
#[error("Instruction error: {0}")]
Instruction(#[from] InstructionError),
#[error("Instruction out of bounds: {0}")]
InstructionOutOfBounds(InstructionPointer),
#[error("Instruction pointer is undefined")]
UndefinedInstructionPointer,
#[error("Data stack underflowed")]
@@ -26,6 +28,13 @@ pub enum MachineError {
CallStackOverflow,
}
#[derive(Debug)]
pub enum EvalResult<T, E> {
Ok(T),
Err(ModuleRef, E),
LoadErr(E),
}
#[derive(Debug, Clone, PartialEq)]
pub struct InstructionPointer {
pub module: ModuleRef,
@@ -152,6 +161,65 @@ impl Machine {
todo!()
}
fn execute_compare(
&mut self,
not: bool,
cmp: Comparison,
count: usize,
) -> Result<(), MachineError> {
fn ordering(a: &Value, b: &Value) -> Ordering {
match (a, b) {
(Value::Integer(a), Value::Integer(b)) => Ord::cmp(a, b),
_ => todo!(),
}
}
// TODO checks
let values = (0..count)
.map(|_| self.pop())
.collect::<Result<Vec<_>, _>>()?;
let mut accumulator = true;
for i in 0..values.len() - 1 {
let a = &values[i];
let b = &values[i + 1];
let ord = ordering(a, b);
let check = match (not, cmp) {
(true, Comparison::Gt) => ord.is_le(),
(false, Comparison::Gt) => ord.is_gt(),
(true, Comparison::Eq) => ord.is_ne(),
(false, Comparison::Eq) => ord.is_eq(),
(true, Comparison::Lt) => ord.is_ge(),
(false, Comparison::Lt) => ord.is_lt(),
};
accumulator &= check;
}
self.push(Value::Boolean(accumulator))?;
Ok(())
}
fn execute_branch(&mut self, offset: usize) -> Result<bool, MachineError> {
let value = self.pop()?;
let do_branch = match value {
Value::Boolean(true) => false,
Value::Boolean(false) => true,
Value::Nil => todo!(),
_ => todo!(),
};
if do_branch {
self.execute_jump(offset)?;
}
Ok(!do_branch)
}
fn execute_jump(&mut self, offset: usize) -> Result<(), MachineError> {
let ip = self.ip.clone().unwrap();
self.ip = Some(InstructionPointer {
module: ip.module,
address: offset,
});
Ok(())
}
fn execute_push_constant(&mut self, index: ConstantId) -> Result<(), MachineError> {
let ip = self.ip.as_ref().unwrap();
let constant = ip.module.constant(index).expect("TODO");
@@ -204,7 +272,10 @@ impl Machine {
pub fn execute_next(&mut self) -> Result<ExecutionEvent, MachineError> {
let ip = self.ip.clone().unwrap();
let instruction = ip.module.instruction(ip.address).expect("TODO");
let instruction = ip
.module
.instruction(ip.address)
.ok_or_else(|| MachineError::InstructionOutOfBounds(ip.clone()))?;
let instruction = Instruction::try_from(instruction)?;
eprintln!("{ip}: {instruction:?}");
let mut advance = true;
@@ -225,6 +296,9 @@ impl Machine {
Instruction::PushArgument(index) => {
self.execute_push_argument(index.into())?;
}
Instruction::Drop => {
self.pop()?;
}
Instruction::GetGlobal => {
self.execute_get_global()?;
}
@@ -245,6 +319,16 @@ impl Machine {
Instruction::Sub(count) => {
self.execute_sub(count.into())?;
}
Instruction::Branch(offset) => {
advance = self.execute_branch(offset.into())?;
}
Instruction::Jump(offset) => {
advance = false;
self.execute_jump(offset.into())?;
}
Instruction::Compare(not, cmp, count) => {
self.execute_compare(not, cmp, count.into())?;
}
}
if advance {
self.ip = Some(InstructionPointer {
@@ -255,8 +339,7 @@ impl Machine {
Ok(event)
}
pub fn load_module(&mut self, module: Module) -> Result<ModuleRef, MachineError> {
let module = ModuleRef::from(module);
pub fn load_module(&mut self, module: ModuleRef) -> Result<ModuleRef, MachineError> {
let entry = module.entry();
let entry_ip = InstructionPointer {
module: module.clone(),
@@ -278,22 +361,55 @@ impl Machine {
Ok(module)
}
pub fn eval_module(&mut self, module: Module) -> Result<Value, MachineError> {
let module = self.load_module(module)?;
let expect = ExecutionEvent::ModuleEntry(module);
pub fn eval_module(&mut self, module: ModuleRef) -> EvalResult<Value, MachineError> {
let module = match self.load_module(module) {
Ok(module) => module,
Err(error) => return EvalResult::LoadErr(error),
};
let expect = ExecutionEvent::ModuleEntry(module.clone());
loop {
let event = self.execute_next()?;
let event = match self.execute_next() {
Ok(event) => event,
Err(error) => return EvalResult::Err(module, error),
};
if event == expect {
break;
}
}
let value = self.pop()?;
Ok(value)
match self.pop() {
Ok(value) => EvalResult::Ok(value),
Err(error) => EvalResult::Err(module, error),
}
}
pub fn eval_value(&mut self, value: &Value) -> Result<Value, EvalError> {
let module = Module::compile_value(value)?;
self.eval_module(module).map_err(EvalError::from)
pub fn eval_value(&mut self, value: &Value) -> EvalResult<Value, EvalError> {
let module = match Module::compile_value(value) {
Ok(module) => module,
Err(error) => return EvalResult::LoadErr(error.into()),
};
let module = ModuleRef::from(module);
match self.eval_module(module) {
EvalResult::Ok(value) => EvalResult::Ok(value),
EvalResult::Err(module, error) => EvalResult::Err(module, error.into()),
EvalResult::LoadErr(error) => EvalResult::LoadErr(error.into()),
}
}
}
impl<T, E> EvalResult<T, E> {
pub fn unwrap(self) -> T
where
E: fmt::Display,
{
match self {
Self::Ok(value) => value,
Self::Err(module, error) => {
panic!("Unwrap called on module {module:p} error: {error}");
}
Self::LoadErr(error) => {
panic!("Unwrap called on error: {error}");
}
}
}
}
@@ -335,7 +451,7 @@ mod tests {
build(i as u32, &mut builder);
builder.add(Instruction::Return);
let module = builder.build();
values.push(machine.eval_module(module).unwrap());
values.push(machine.eval_module(module.into()).unwrap());
}
(machine, values)
}
+12 -1
View File
@@ -107,7 +107,7 @@ impl Module {
}
pub fn compile_value(value: &Value) -> Result<Self, CompileError> {
let expression = Expression::parse(value)?;
let expression = Expression::parse(value).map_err(CompileError::Parse)?;
let mut module = CompilationModule::default();
module.compile_function(
FunctionSignature::EMPTY,
@@ -119,6 +119,17 @@ impl Module {
)?;
module.compile_module()
}
pub fn dump(&self) {
for (i, instruction) in self.instructions.iter().enumerate() {
print!(" {i:4}: {instruction:#x}");
if let Ok(instruction) = Instruction::try_from(*instruction) {
println!(" {instruction:?}");
} else {
println!();
}
}
}
}
impl ModuleBuilder {
+51 -22
View File
@@ -34,12 +34,51 @@ pub enum Value {
NativeFunction(NativeFunction),
}
#[derive(Debug, Clone, PartialEq)]
pub enum Keyword {
Lambda,
Defun,
Optional,
Rest,
macro_rules! impl_keyword {
(
$vis:vis enum $name:ident {
$($variant:ident => $s:literal),* $(,)?
}
) => {
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
$vis enum $name {
$($variant),*
}
impl $name {
pub fn from_str(s: &str) -> Option<Self> {
match s {
$(
$s => Some(Self::$variant),
)*
_ => None,
}
}
}
impl fmt::Display for $name {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(match self {
$(
Self::$variant => $s
),*
})
}
}
};
}
impl_keyword! {
pub enum Keyword {
Lambda => "lambda",
Defun => "defun",
If => "if",
Cond => "cond",
While => "while",
Otherwise => "&otherwise",
Optional => "&optional",
Rest => "&rest"
}
}
#[derive(Debug, Clone, PartialEq)]
@@ -67,6 +106,10 @@ impl Value {
}
impl ConsCell {
pub fn end(value: Value) -> Self {
Self(value, Value::Nil)
}
fn fmt_inner(&self, f: &mut fmt::Formatter<'_>, first: bool) -> fmt::Result {
let Self(car, cdr) = self;
if !first {
@@ -107,9 +150,7 @@ impl PartialEq for NativeFunction {
impl fmt::Display for ConsCell {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "(")?;
self.fmt_inner(f, true)?;
write!(f, ")")
self.fmt_inner(f, true)
}
}
@@ -125,18 +166,6 @@ impl fmt::Display for BytecodeFunction {
}
}
impl fmt::Display for Keyword {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let word = match self {
Self::Lambda => "lambda",
Self::Defun => "defun",
Self::Optional => "&optional",
Self::Rest => "&rest",
};
write!(f, "{word}")
}
}
impl fmt::Display for Value {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
@@ -146,7 +175,7 @@ impl fmt::Display for Value {
Self::Integer(value) => write!(f, "{value}"),
Self::Identifier(value) => write!(f, "{value}"),
Self::Keyword(keyword) => write!(f, "{keyword}"),
Self::Cons(cons) => write!(f, "{cons}"),
Self::Cons(cons) => write!(f, "({cons})"),
Self::BytecodeFunction(bytecode) => write!(f, "{bytecode}"),
Self::NativeFunction(native) => write!(f, "{native}"),
}