Implement missing parser functions
This commit is contained in:
+249
-18
@@ -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 )
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ impl FunctionSignature {
|
||||
{
|
||||
Some(self.required_arguments.len() + self.optional_arguments.len())
|
||||
} else {
|
||||
todo!()
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -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)
|
||||
|
||||
@@ -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(())]);
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
),
|
||||
}]
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
)))
|
||||
}]
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -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()),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
)
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
)
|
||||
}]
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
)
|
||||
}
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -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
@@ -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
@@ -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)
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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}"),
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user