Compare commits
4 Commits
55e38af0ed
...
feature/io
| Author | SHA1 | Date | |
|---|---|---|---|
| db5b1dba7b | |||
| 01012ae211 | |||
| aa7e371747 | |||
| aa0026fa45 |
@@ -0,0 +1,4 @@
|
||||
;; vi:ft=lisp:sw=2:ts=2
|
||||
|
||||
(print (length *args*))
|
||||
(print *args*)
|
||||
+17
-15
@@ -7,18 +7,20 @@
|
||||
)
|
||||
)
|
||||
|
||||
(print 1 "\t" (factorial 1))
|
||||
(print 2 "\t" (factorial 2))
|
||||
(print 3 "\t" (factorial 3))
|
||||
(print 4 "\t" (factorial 4))
|
||||
(print 5 "\t" (factorial 5))
|
||||
(print 6 "\t" (factorial 6))
|
||||
(print 7 "\t" (factorial 7))
|
||||
(print 8 "\t" (factorial 8))
|
||||
(print 9 "\t" (factorial 9))
|
||||
(print 10 "\t" (factorial 10))
|
||||
(print 11 "\t" (factorial 11))
|
||||
(print 12 "\t" (factorial 12))
|
||||
(print 13 "\t" (factorial 13))
|
||||
(print 14 "\t" (factorial 14))
|
||||
(print 15 "\t" (factorial 15))
|
||||
(defun loop-factorial (x)
|
||||
(let (i 0 acc 1)
|
||||
(while (< i x)
|
||||
(setq i (+ i 1))
|
||||
(setq acc (* acc i))
|
||||
)
|
||||
acc
|
||||
)
|
||||
)
|
||||
|
||||
;; TODO for loops?
|
||||
(let (i 0)
|
||||
(while (<= i 15)
|
||||
(print i "\t" (factorial i) "\t" (loop-factorial i))
|
||||
(setq i (+ i 1))
|
||||
)
|
||||
)
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
;; vi:ft=lisp:sw=2:ts=2
|
||||
|
||||
(let (f (fopen (car *args*)))
|
||||
(fwrite (fread f))
|
||||
)
|
||||
@@ -0,0 +1,32 @@
|
||||
;; vi:ft=lisp:sw=2:ts=2
|
||||
|
||||
;; loop, broken by (return)
|
||||
(setq looped-loop (let (i 0)
|
||||
(loop
|
||||
(if (< i 10)
|
||||
(setq i (+ i 1))
|
||||
(return)
|
||||
)
|
||||
)
|
||||
i
|
||||
))
|
||||
|
||||
;; while, broken prematurely
|
||||
(setq looped-while (let (i 0)
|
||||
(while (< i 20)
|
||||
(setq i (+ i 1))
|
||||
(if (= i 10) (return))
|
||||
)
|
||||
i
|
||||
))
|
||||
|
||||
;; while, broken by condition
|
||||
(setq looped-while-full (let (i 0)
|
||||
(while (< i 10)
|
||||
(setq i (+ i 1))
|
||||
)
|
||||
i
|
||||
))
|
||||
|
||||
;; All loops execute the same count of times
|
||||
(assert (= looped-loop looped-while looped-while-full))
|
||||
@@ -0,0 +1,36 @@
|
||||
;; vi:ft=lisp:sw=2:ts=2
|
||||
|
||||
(defun cadr (x) (car (cdr x)))
|
||||
|
||||
(defun map-ok-err (f-ok f-err result)
|
||||
(if (= (car result) 'ok)
|
||||
`(ok ,(f-ok (cadr result)))
|
||||
`(err ,(f-err (cadr result)))
|
||||
)
|
||||
)
|
||||
(defun map-ok (f-ok result) (map-ok-err f-ok identity result))
|
||||
(defun map-err (f-err result) (map-ok-err identity f-err result))
|
||||
|
||||
(defun repl-print (value)
|
||||
(print "==>" value)
|
||||
)
|
||||
(defun repl-eval-print (expression)
|
||||
(map-ok-err repl-print repl-eval-error (unquote (eval expression)))
|
||||
)
|
||||
|
||||
(defun repl-eval-error (error)
|
||||
(print "Evaluation error:")
|
||||
(print error)
|
||||
)
|
||||
(defun repl-read-error (error)
|
||||
(print "Parse error:")
|
||||
(print error)
|
||||
)
|
||||
|
||||
(loop
|
||||
(let (expression (read))
|
||||
(if expression NIL (return))
|
||||
(setq expression (unquote expression))
|
||||
(map-ok-err repl-eval-print repl-read-error expression)
|
||||
)
|
||||
)
|
||||
@@ -0,0 +1,25 @@
|
||||
;; vi:ft=lisp:sw=2:ts=2
|
||||
|
||||
(defun replace-argument (x) (let (x 1) x))
|
||||
|
||||
(defun replace-let ()
|
||||
(let (x 1)
|
||||
(setq x 2) ;; mutate local x
|
||||
x
|
||||
)
|
||||
)
|
||||
|
||||
(defun reassignment-in-a-loop (iterations)
|
||||
(let (x 0 y 1)
|
||||
(while (< x iterations)
|
||||
(setq y (* y 2))
|
||||
(setq x (+ x 1))
|
||||
)
|
||||
y
|
||||
)
|
||||
)
|
||||
|
||||
(assert (= (replace-argument 2) 1))
|
||||
(assert (= (replace-argument 3) 1))
|
||||
(assert (= (replace-let) 2))
|
||||
(assert (= (reassignment-in-a-loop 4) 16))
|
||||
+192
-46
@@ -8,7 +8,8 @@ use crate::{
|
||||
module::CompilationModule,
|
||||
syntax::{
|
||||
CallExpression, CondExpression, DefmacroExpression, DefunExpression, Expression,
|
||||
FunctionBody, IfExpression, LambdaExpression, LetExpression, SetqExpression,
|
||||
FunctionBody, IfExpression, LambdaExpression, LetExpression, LoopExpression,
|
||||
PrognExpression, SetqExpression, VectorExpression, WhileExpression,
|
||||
},
|
||||
value::{BuiltinFunction, CompileConstant, CompileValue},
|
||||
},
|
||||
@@ -136,13 +137,19 @@ impl FunctionBlock {
|
||||
self.labels.insert(label, self.instructions.len());
|
||||
}
|
||||
|
||||
pub fn resolve_labels(self) -> CompiledFunction {
|
||||
pub fn resolve_labels(self, trace: bool) -> CompiledFunction {
|
||||
let mut instructions = vec![];
|
||||
// eprintln!("RESOLVE LABELS");
|
||||
|
||||
if trace {
|
||||
eprintln!("Instruction resolution:");
|
||||
}
|
||||
|
||||
for (function_offset, emitted) in self.instructions.into_iter().enumerate() {
|
||||
match emitted {
|
||||
Emitted::Instruction(instruction) => {
|
||||
// eprintln!("{function_offset}: {instruction:?}");
|
||||
if trace {
|
||||
eprintln!("{function_offset}: {instruction:?}");
|
||||
}
|
||||
instructions.push(instruction);
|
||||
}
|
||||
Emitted::Branch(label) => {
|
||||
@@ -151,9 +158,11 @@ impl FunctionBlock {
|
||||
todo!()
|
||||
}
|
||||
let diff = address.checked_signed_diff(function_offset).expect("TODO");
|
||||
// eprintln!(
|
||||
// "{function_offset}: branch to label {label} (@ {address}) -> {diff:+}"
|
||||
// );
|
||||
if trace {
|
||||
eprintln!(
|
||||
"{function_offset}: Branch: label {label} (@ {address}) -> {diff:+}"
|
||||
);
|
||||
}
|
||||
let offset = U::from_signed(diff as i64).expect("TODO");
|
||||
instructions.push(Instruction::Branch(offset));
|
||||
}
|
||||
@@ -163,7 +172,11 @@ impl FunctionBlock {
|
||||
todo!()
|
||||
}
|
||||
let diff = address.checked_signed_diff(function_offset).expect("TODO");
|
||||
// eprintln!("{function_offset}: jump to label {label} (@ {address}) -> {diff:+}");
|
||||
if trace {
|
||||
eprintln!(
|
||||
"{function_offset}: jump to label {label} (@ {address}) -> {diff:+}"
|
||||
);
|
||||
}
|
||||
let offset = U::from_signed(diff as i64).expect("TODO");
|
||||
instructions.push(Instruction::Jump(offset));
|
||||
}
|
||||
@@ -185,9 +198,9 @@ impl FunctionBlock {
|
||||
) -> Result<(), CompileError> {
|
||||
let mut local = LocalBlock::root(self, module);
|
||||
for statement in &body.head {
|
||||
local.compile_statement(statement)?;
|
||||
local.compile_statement(statement, None)?;
|
||||
}
|
||||
let value = local.compile_expression(&body.tail)?;
|
||||
let value = local.compile_expression(&body.tail, None)?;
|
||||
local.compile_return(value)?;
|
||||
Ok(())
|
||||
}
|
||||
@@ -311,8 +324,12 @@ impl<'a> LocalBlock<'a> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn compile_statement(&mut self, expression: &Rc<Expression>) -> Result<(), CompileError> {
|
||||
let value = self.compile_expression(expression)?;
|
||||
pub fn compile_statement(
|
||||
&mut self,
|
||||
expression: &Rc<Expression>,
|
||||
break_label: Option<u32>,
|
||||
) -> Result<(), CompileError> {
|
||||
let value = self.compile_expression(expression, break_label)?;
|
||||
self.compile_drop(value)?;
|
||||
Ok(())
|
||||
}
|
||||
@@ -366,10 +383,11 @@ impl<'a> LocalBlock<'a> {
|
||||
&mut self,
|
||||
math: MathInstruction,
|
||||
args: &[Rc<Expression>],
|
||||
break_label: Option<u32>,
|
||||
) -> Result<CompileValue, CompileError> {
|
||||
// TODO optimize
|
||||
for arg in args.iter().rev() {
|
||||
let arg = self.compile_expression(arg)?;
|
||||
let arg = self.compile_expression(arg, break_label)?;
|
||||
self.compile_push(arg)?;
|
||||
}
|
||||
let Some(count) = U::new(args.len() as u32) else {
|
||||
@@ -383,18 +401,25 @@ impl<'a> LocalBlock<'a> {
|
||||
&mut self,
|
||||
builtin: BuiltinFunction,
|
||||
args: &[Rc<Expression>],
|
||||
break_label: Option<u32>,
|
||||
) -> Result<CompileValue, CompileError> {
|
||||
match builtin {
|
||||
BuiltinFunction::Math(math) => self.compile_builtin_math_generic(math, args),
|
||||
BuiltinFunction::Math(math) => {
|
||||
self.compile_builtin_math_generic(math, args, break_label)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn compile_call(&mut self, call: &CallExpression) -> Result<CompileValue, CompileError> {
|
||||
fn compile_call(
|
||||
&mut self,
|
||||
call: &CallExpression,
|
||||
break_label: Option<u32>,
|
||||
) -> Result<CompileValue, CompileError> {
|
||||
match call.callee.as_ref() {
|
||||
Expression::Identifier(identifier)
|
||||
if let Some(builtin) = BuiltinFunction::from_identifier(identifier.as_ref()) =>
|
||||
{
|
||||
self.compile_call_builtin(builtin, &call.arguments)
|
||||
self.compile_call_builtin(builtin, &call.arguments, break_label)
|
||||
}
|
||||
_ => {
|
||||
// Push arguments in reverse order
|
||||
@@ -402,10 +427,10 @@ impl<'a> LocalBlock<'a> {
|
||||
todo!();
|
||||
};
|
||||
for arg in call.arguments.iter().rev() {
|
||||
let arg = self.compile_expression(arg)?;
|
||||
let arg = self.compile_expression(arg, break_label)?;
|
||||
self.compile_push(arg)?;
|
||||
}
|
||||
let callee = self.compile_expression(&call.callee)?;
|
||||
let callee = self.compile_expression(&call.callee, break_label)?;
|
||||
self.compile_push(callee)?;
|
||||
self.function.emit(Instruction::Call(count));
|
||||
Ok(CompileValue::Stack)
|
||||
@@ -413,21 +438,25 @@ impl<'a> LocalBlock<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
fn compile_if(&mut self, condition: &IfExpression) -> Result<CompileValue, CompileError> {
|
||||
fn compile_if(
|
||||
&mut self,
|
||||
condition: &IfExpression,
|
||||
break_label: Option<u32>,
|
||||
) -> 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)?;
|
||||
let condition_value = self.compile_expression(&condition.condition, break_label)?;
|
||||
self.compile_push(condition_value)?;
|
||||
self.function.emit(Emitted::Branch(label_false));
|
||||
// True branch
|
||||
let true_value = self.compile_expression(&condition.if_true)?;
|
||||
let true_value = self.compile_expression(&condition.if_true, break_label)?;
|
||||
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)?
|
||||
self.compile_expression(if_false, break_label)?
|
||||
} else {
|
||||
CompileValue::Nil
|
||||
};
|
||||
@@ -436,16 +465,20 @@ impl<'a> LocalBlock<'a> {
|
||||
Ok(CompileValue::Stack)
|
||||
}
|
||||
|
||||
fn compile_cond(&mut self, condition: &CondExpression) -> Result<CompileValue, CompileError> {
|
||||
fn compile_cond(
|
||||
&mut self,
|
||||
condition: &CondExpression,
|
||||
break_label: Option<u32>,
|
||||
) -> 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)?;
|
||||
let condition_value = self.compile_expression(&arm.condition, break_label)?;
|
||||
self.compile_push(condition_value)?;
|
||||
self.function.emit(Emitted::Branch(label_condition_end));
|
||||
// Condition true
|
||||
let then_value = self.compile_expression(&arm.then)?;
|
||||
let then_value = self.compile_expression(&arm.then, break_label)?;
|
||||
self.compile_push(then_value)?;
|
||||
self.function.emit(Emitted::Jump(label_end));
|
||||
// Condition false
|
||||
@@ -454,7 +487,7 @@ impl<'a> LocalBlock<'a> {
|
||||
|
||||
// Otherwise branch
|
||||
let otherwise_value = if let Some(othwerise_arm) = condition.otherwise_arm.as_ref() {
|
||||
self.compile_expression(othwerise_arm)?
|
||||
self.compile_expression(othwerise_arm, break_label)?
|
||||
} else {
|
||||
CompileValue::Nil
|
||||
};
|
||||
@@ -464,11 +497,61 @@ impl<'a> LocalBlock<'a> {
|
||||
Ok(CompileValue::Stack)
|
||||
}
|
||||
|
||||
fn compile_let(&mut self, binding: &LetExpression) -> Result<CompileValue, CompileError> {
|
||||
fn compile_while(
|
||||
&mut self,
|
||||
cloop: &WhileExpression,
|
||||
break_label: Option<u32>,
|
||||
) -> Result<CompileValue, CompileError> {
|
||||
let label_start = self.function.new_label();
|
||||
let label_end = self.function.new_label();
|
||||
|
||||
self.function.adjust_label(label_start);
|
||||
|
||||
// Condition
|
||||
let condition_value = self.compile_expression(&cloop.condition, break_label)?;
|
||||
self.compile_push(condition_value)?;
|
||||
self.function.emit(Emitted::Branch(label_end));
|
||||
|
||||
// Body
|
||||
for expression in &cloop.body.head {
|
||||
self.compile_statement(expression, Some(label_end))?;
|
||||
}
|
||||
self.compile_statement(&cloop.body.tail, Some(label_end))?;
|
||||
|
||||
// Jump back
|
||||
self.function.emit(Emitted::Jump(label_start));
|
||||
|
||||
self.function.adjust_label(label_end);
|
||||
Ok(CompileValue::Nil)
|
||||
}
|
||||
|
||||
fn compile_loop(&mut self, cloop: &LoopExpression) -> Result<CompileValue, CompileError> {
|
||||
let label_start = self.function.new_label();
|
||||
let label_end = self.function.new_label();
|
||||
|
||||
self.function.adjust_label(label_start);
|
||||
|
||||
for expression in &cloop.body.head {
|
||||
self.compile_statement(expression, Some(label_end))?;
|
||||
}
|
||||
self.compile_statement(&cloop.body.tail, Some(label_end))?;
|
||||
|
||||
self.function.emit(Emitted::Jump(label_start));
|
||||
|
||||
self.function.adjust_label(label_end);
|
||||
|
||||
Ok(CompileValue::Nil)
|
||||
}
|
||||
|
||||
fn compile_let(
|
||||
&mut self,
|
||||
binding: &LetExpression,
|
||||
break_label: Option<u32>,
|
||||
) -> Result<CompileValue, CompileError> {
|
||||
self.function.push_local_scope();
|
||||
let mut indices = vec![];
|
||||
for pair in &binding.bindings {
|
||||
let value = self.compile_expression(&pair.value)?;
|
||||
let value = self.compile_expression(&pair.value, break_label)?;
|
||||
let index = self.compile_set_local(&pair.identifier, value, binding.sequential)?;
|
||||
indices.push(index);
|
||||
}
|
||||
@@ -480,9 +563,9 @@ impl<'a> LocalBlock<'a> {
|
||||
}
|
||||
}
|
||||
for expr in &binding.body.head {
|
||||
self.compile_statement(expr)?;
|
||||
self.compile_statement(expr, break_label)?;
|
||||
}
|
||||
let value = self.compile_expression(&binding.body.tail)?;
|
||||
let value = self.compile_expression(&binding.body.tail, break_label)?;
|
||||
if let CompileValue::Local(_) = value {
|
||||
self.compile_push(value)?;
|
||||
self.function.pop_local_scope();
|
||||
@@ -493,10 +576,23 @@ impl<'a> LocalBlock<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
fn compile_setq(&mut self, setq: &SetqExpression) -> Result<CompileValue, CompileError> {
|
||||
fn compile_setq(
|
||||
&mut self,
|
||||
setq: &SetqExpression,
|
||||
break_label: Option<u32>,
|
||||
) -> Result<CompileValue, CompileError> {
|
||||
for pair in setq.pairs.iter() {
|
||||
let value = self.compile_expression(&pair.value)?;
|
||||
self.compile_set_global(&pair.identifier, value)?;
|
||||
let value = self.compile_expression(&pair.value, break_label)?;
|
||||
if let Some(index) = self
|
||||
.function
|
||||
.local_scope_ref()
|
||||
.and_then(|scope| scope.get(&pair.identifier))
|
||||
{
|
||||
self.compile_push(value)?;
|
||||
self.function.emit(Instruction::SetLocal(index));
|
||||
} else {
|
||||
self.compile_set_global(&pair.identifier, value)?;
|
||||
}
|
||||
}
|
||||
Ok(CompileValue::Nil)
|
||||
}
|
||||
@@ -505,9 +601,51 @@ impl<'a> LocalBlock<'a> {
|
||||
Ok(CompileValue::Quote(value.clone()))
|
||||
}
|
||||
|
||||
fn compile_progn(
|
||||
&mut self,
|
||||
value: &PrognExpression,
|
||||
break_label: Option<u32>,
|
||||
) -> Result<CompileValue, CompileError> {
|
||||
for expression in &value.body.head {
|
||||
self.compile_statement(expression, break_label)?;
|
||||
}
|
||||
self.compile_statement(&value.body.tail, break_label)?;
|
||||
Ok(CompileValue::Nil)
|
||||
}
|
||||
|
||||
fn compile_call_return(
|
||||
&mut self,
|
||||
break_label: Option<u32>,
|
||||
) -> Result<CompileValue, CompileError> {
|
||||
if let Some(break_label) = break_label {
|
||||
self.function.emit(Emitted::Jump(break_label));
|
||||
} else {
|
||||
todo!("return outside a loop")
|
||||
}
|
||||
Ok(CompileValue::Nil)
|
||||
}
|
||||
|
||||
fn compile_vector(
|
||||
&mut self,
|
||||
vector: &VectorExpression,
|
||||
break_label: Option<u32>,
|
||||
) -> Result<CompileValue, CompileError> {
|
||||
for expression in vector.elements.iter().rev() {
|
||||
let value = self.compile_expression(expression, break_label)?;
|
||||
self.compile_push(value)?;
|
||||
}
|
||||
self.compile_push(CompileValue::Global("vector".into()))?;
|
||||
let Some(count) = U::new(vector.elements.len() as u32) else {
|
||||
todo!()
|
||||
};
|
||||
self.function.emit(Instruction::Call(count));
|
||||
Ok(CompileValue::Stack)
|
||||
}
|
||||
|
||||
pub fn compile_expression(
|
||||
&mut self,
|
||||
expression: &Rc<Expression>,
|
||||
break_label: Option<u32>,
|
||||
) -> Result<CompileValue, CompileError> {
|
||||
match expression.as_ref() {
|
||||
Expression::Nil => Ok(CompileValue::Nil),
|
||||
@@ -517,13 +655,18 @@ impl<'a> LocalBlock<'a> {
|
||||
Expression::Identifier(identifier) => self.compile_identifier(identifier),
|
||||
Expression::Lambda(lambda) => self.compile_lambda(lambda),
|
||||
Expression::Defun(defun) => self.compile_defun(defun),
|
||||
Expression::Call(call) => self.compile_call(call),
|
||||
Expression::If(condition) => self.compile_if(condition),
|
||||
Expression::Cond(condition) => self.compile_cond(condition),
|
||||
Expression::Let(binding) => self.compile_let(binding),
|
||||
Expression::Setq(setq) => self.compile_setq(setq),
|
||||
Expression::Vector(vector) => self.compile_vector(vector, break_label),
|
||||
Expression::Call(call) => self.compile_call(call, break_label),
|
||||
Expression::If(condition) => self.compile_if(condition, break_label),
|
||||
Expression::Cond(condition) => self.compile_cond(condition, break_label),
|
||||
Expression::Let(binding) => self.compile_let(binding, break_label),
|
||||
Expression::Setq(setq) => self.compile_setq(setq, break_label),
|
||||
Expression::Defmacro(defmacro) => self.compile_defmacro(defmacro),
|
||||
Expression::Quote(quote) => self.compile_quote(quote),
|
||||
Expression::While(cloop) => self.compile_while(cloop, break_label),
|
||||
Expression::Loop(cloop) => self.compile_loop(cloop),
|
||||
Expression::Progn(progn) => self.compile_progn(progn, break_label),
|
||||
Expression::Return => self.compile_call_return(break_label),
|
||||
|
||||
Expression::SyntaxError(_) => unreachable!(),
|
||||
}
|
||||
@@ -599,8 +742,11 @@ mod tests {
|
||||
max_local_index: 0,
|
||||
};
|
||||
let mut local = LocalBlock::root(&mut function, &mut module);
|
||||
let value = local.compile_expression(&Rc::new(expression)).unwrap();
|
||||
(module, function.resolve_labels(), value)
|
||||
let value = local
|
||||
.compile_expression(&Rc::new(expression), None)
|
||||
.unwrap();
|
||||
let trace = module.options.trace_compile;
|
||||
(module, function.resolve_labels(trace), value)
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -647,9 +793,9 @@ mod tests {
|
||||
&f.instructions,
|
||||
&[
|
||||
Instruction::PushBool(false), // 0
|
||||
Instruction::Branch(U::truncate(4)), // 1
|
||||
Instruction::Branch(U::truncate(3)), // 1
|
||||
Instruction::PushInteger(U::truncate(1)), // 2
|
||||
Instruction::Jump(U::truncate(5)), // 3
|
||||
Instruction::Jump(U::truncate(2)), // 3
|
||||
Instruction::PushInteger(U::truncate(2)) // 4
|
||||
// 5
|
||||
]
|
||||
@@ -676,13 +822,13 @@ mod tests {
|
||||
&f.instructions,
|
||||
&[
|
||||
Instruction::PushBool(false), // 0
|
||||
Instruction::Branch(U::truncate(4)), // 1
|
||||
Instruction::Branch(U::truncate(3)), // 1
|
||||
Instruction::PushInteger(U::truncate(1)), // 2
|
||||
Instruction::Jump(U::truncate(9)), // 3
|
||||
Instruction::Jump(U::truncate(6)), // 3
|
||||
Instruction::PushBool(true), // 4
|
||||
Instruction::Branch(U::truncate(8)), // 5
|
||||
Instruction::Branch(U::truncate(3)), // 5
|
||||
Instruction::PushInteger(U::truncate(2)), // 6
|
||||
Instruction::Jump(U::truncate(9)), // 7
|
||||
Instruction::Jump(U::truncate(2)), // 7
|
||||
Instruction::PushInteger(U::truncate(3)), // 8
|
||||
// 9
|
||||
]
|
||||
|
||||
@@ -13,3 +13,8 @@ pub use syntax::{
|
||||
CallExpression, ExpectedWhat, ExpectedWhere, Expression, FunctionBody, LambdaExpression,
|
||||
ParseError, ParseErrorKind,
|
||||
};
|
||||
|
||||
#[derive(Default, Clone)]
|
||||
pub struct CompileOptions {
|
||||
pub trace_compile: bool,
|
||||
}
|
||||
|
||||
+14
-1
@@ -2,6 +2,7 @@ use std::{collections::HashMap, rc::Rc};
|
||||
|
||||
use crate::{
|
||||
compile::{
|
||||
CompileOptions,
|
||||
block::{CompiledFunction, FunctionBlock},
|
||||
error::CompileError,
|
||||
function::FunctionSignature,
|
||||
@@ -17,14 +18,24 @@ use crate::{
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct CompilationModule {
|
||||
pub(crate) name: Option<Rc<str>>,
|
||||
pub(crate) constant_pool: Pool<CompileConstant, { ConstantId::BITS }>,
|
||||
pub(crate) local_functions: HashMap<u32, CompiledFunction>,
|
||||
pub(crate) options: CompileOptions,
|
||||
macros: HashMap<Rc<str>, DefmacroExpression>,
|
||||
local_function_index: u32,
|
||||
root: Option<u32>,
|
||||
}
|
||||
|
||||
impl CompilationModule {
|
||||
pub fn new(name: Option<Rc<str>>, options: CompileOptions) -> Self {
|
||||
Self {
|
||||
name,
|
||||
options,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn define_macro(&mut self, defmacro: DefmacroExpression) {
|
||||
self.macros.insert(defmacro.name.clone(), defmacro);
|
||||
}
|
||||
@@ -49,7 +60,7 @@ impl CompilationModule {
|
||||
self.local_function_index += 1;
|
||||
let mut function = FunctionBlock::new(signature);
|
||||
function.compile_body(self, body)?;
|
||||
let function = function.resolve_labels();
|
||||
let function = function.resolve_labels(self.options.trace_compile);
|
||||
self.local_functions.insert(index, function);
|
||||
if root {
|
||||
self.root = Some(index);
|
||||
@@ -61,6 +72,7 @@ impl CompilationModule {
|
||||
// Emit all function code first
|
||||
let mut function_offsets = HashMap::new();
|
||||
let mut instructions = vec![];
|
||||
let name = self.name;
|
||||
let root = self.root.unwrap();
|
||||
for (index, function) in self.local_functions.into_iter() {
|
||||
function_offsets.insert(index, instructions.len());
|
||||
@@ -90,6 +102,7 @@ impl CompilationModule {
|
||||
.collect();
|
||||
|
||||
Ok(Module {
|
||||
name,
|
||||
constants,
|
||||
instructions,
|
||||
entry,
|
||||
|
||||
@@ -64,9 +64,9 @@ impl IfExpression {
|
||||
Some(Expression::parse_inner(if_false))
|
||||
};
|
||||
Ok(Self {
|
||||
condition: condition.into(),
|
||||
if_true: if_true.into(),
|
||||
if_false: if_false.map(Into::into),
|
||||
condition,
|
||||
if_true,
|
||||
if_false,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,11 @@ pub struct DefunExpression {
|
||||
pub body: FunctionBody,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub struct PrognExpression {
|
||||
pub body: FunctionBody,
|
||||
}
|
||||
|
||||
impl FunctionSignature {
|
||||
pub(super) fn parse(mut value: &Value, input: &Value) -> Result<Self, ParseError> {
|
||||
enum Mode {
|
||||
@@ -171,6 +176,13 @@ impl FunctionBody {
|
||||
}
|
||||
}
|
||||
|
||||
impl PrognExpression {
|
||||
pub(super) fn parse(value: &Value, input: &Value) -> Result<Self, ParseError> {
|
||||
let body = FunctionBody::parse(value, input, Keyword::Progn)?;
|
||||
Ok(Self { body })
|
||||
}
|
||||
}
|
||||
|
||||
impl DefunExpression {
|
||||
pub(super) fn parse(value: &Value, input: &Value) -> Result<Self, ParseError> {
|
||||
let Value::Cons(value) = value else {
|
||||
@@ -232,6 +244,12 @@ impl CollectErrors<ParseError> for DefunExpression {
|
||||
}
|
||||
}
|
||||
|
||||
impl CollectErrors<ParseError> for PrognExpression {
|
||||
fn collect_errors(&self, errors: &mut Vec<ParseError>) -> bool {
|
||||
self.body.collect_errors(errors)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::rc::Rc;
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
use std::rc::Rc;
|
||||
|
||||
use crate::{
|
||||
compile::{
|
||||
ExpectedWhat, ExpectedWhere, Expression, FunctionBody, ParseError, ParseErrorKind,
|
||||
syntax::CollectErrors,
|
||||
},
|
||||
vm::value::{ConsCell, Keyword, Value},
|
||||
};
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub struct WhileExpression {
|
||||
pub condition: Rc<Expression>,
|
||||
pub body: FunctionBody,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub struct LoopExpression {
|
||||
pub body: FunctionBody,
|
||||
}
|
||||
|
||||
impl WhileExpression {
|
||||
pub(super) fn parse(value: &Value, input: &Value) -> Result<Self, ParseError> {
|
||||
let Value::Cons(cons) = value else {
|
||||
return Err(ParseError {
|
||||
input: input.clone(),
|
||||
error: ParseErrorKind::Expected(
|
||||
ExpectedWhat::ProperList,
|
||||
ExpectedWhere::AfterKeyword(Keyword::While),
|
||||
),
|
||||
});
|
||||
};
|
||||
let ConsCell(car, cdr) = cons.as_ref();
|
||||
let condition = Expression::parse_inner(car);
|
||||
let body = FunctionBody::parse(cdr, input, Keyword::While)?;
|
||||
Ok(Self { condition, body })
|
||||
}
|
||||
}
|
||||
|
||||
impl LoopExpression {
|
||||
pub(super) fn parse(value: &Value, input: &Value) -> Result<Self, ParseError> {
|
||||
let body = FunctionBody::parse(value, input, Keyword::Loop)?;
|
||||
Ok(Self { body })
|
||||
}
|
||||
}
|
||||
|
||||
impl CollectErrors<ParseError> for WhileExpression {
|
||||
fn collect_errors(&self, errors: &mut Vec<ParseError>) -> bool {
|
||||
let a = self.condition.collect_errors(errors);
|
||||
let b = self.body.collect_errors(errors);
|
||||
a | b
|
||||
}
|
||||
}
|
||||
|
||||
impl CollectErrors<ParseError> for LoopExpression {
|
||||
fn collect_errors(&self, errors: &mut Vec<ParseError>) -> bool {
|
||||
self.body.collect_errors(errors)
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,9 @@ mod condition;
|
||||
mod error;
|
||||
mod function;
|
||||
mod lambda;
|
||||
mod loops;
|
||||
mod macros;
|
||||
mod vector;
|
||||
|
||||
pub use binding::*;
|
||||
pub use call::*;
|
||||
@@ -16,7 +18,9 @@ pub use condition::*;
|
||||
pub use error::*;
|
||||
pub use function::*;
|
||||
pub use lambda::*;
|
||||
pub use loops::*;
|
||||
pub use macros::*;
|
||||
pub use vector::*;
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum Expression {
|
||||
@@ -35,6 +39,11 @@ pub enum Expression {
|
||||
Defmacro(DefmacroExpression),
|
||||
SyntaxError(ParseError),
|
||||
Quote(Rc<Value>),
|
||||
While(WhileExpression),
|
||||
Loop(LoopExpression),
|
||||
Progn(PrognExpression),
|
||||
Vector(VectorExpression),
|
||||
Return,
|
||||
}
|
||||
|
||||
impl Expression {
|
||||
@@ -61,7 +70,6 @@ impl Expression {
|
||||
Value::Boolean(value) => Rc::new(Self::BooleanLiteral(*value)),
|
||||
Value::Integer(value) => Rc::new(Self::IntegerLiteral(*value)),
|
||||
Value::String(value) => Rc::new(Self::StringLiteral(value.clone())),
|
||||
Value::Vector(_vector) => todo!(),
|
||||
Value::Identifier(value) => Rc::new(Self::Identifier(value.clone())),
|
||||
Value::Quasi(_value) => todo!("{value}"),
|
||||
Value::Unquote(_value) => todo!("Unquote {_value}"),
|
||||
@@ -97,9 +105,22 @@ impl Expression {
|
||||
};
|
||||
Rc::new(Self::Quote(value.into()))
|
||||
}
|
||||
Value::Keyword(Keyword::Progn) => {
|
||||
Self::map_or(PrognExpression::parse(cdr, value), Expression::Progn)
|
||||
}
|
||||
Value::Keyword(Keyword::Loop) => {
|
||||
Self::map_or(LoopExpression::parse(cdr, value), Expression::Loop)
|
||||
}
|
||||
Value::Keyword(Keyword::While) => {
|
||||
Self::map_or(WhileExpression::parse(cdr, value), Expression::While)
|
||||
}
|
||||
Value::Keyword(Keyword::Return) => Rc::new(Self::Return),
|
||||
_ => Self::map_or(CallExpression::parse(cons, value), Expression::Call),
|
||||
}
|
||||
}
|
||||
Value::Vector(vector) => {
|
||||
Rc::new(Self::Vector(VectorExpression::parse(&vector.borrow())))
|
||||
}
|
||||
Value::Keyword(_) => todo!(),
|
||||
Value::NativeFunction(_) | Value::BytecodeFunction(_) | Value::OpaqueValue(_) => {
|
||||
todo!()
|
||||
@@ -123,7 +144,12 @@ impl CollectErrors<ParseError> for Expression {
|
||||
Self::Let(let_) => let_.collect_errors(errors),
|
||||
Self::Setq(setq) => setq.collect_errors(errors),
|
||||
Self::Defmacro(defmacro) => defmacro.collect_errors(errors),
|
||||
Self::While(cloop) => cloop.collect_errors(errors),
|
||||
Self::Loop(cloop) => cloop.collect_errors(errors),
|
||||
Self::Progn(progn) => progn.collect_errors(errors),
|
||||
Self::Vector(vector) => vector.collect_errors(errors),
|
||||
Self::Nil
|
||||
| Self::Return
|
||||
| Self::IntegerLiteral(_)
|
||||
| Self::Identifier(_)
|
||||
| Self::BooleanLiteral(_)
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
use std::rc::Rc;
|
||||
|
||||
use crate::{
|
||||
compile::{Expression, ParseError, syntax::CollectErrors},
|
||||
vm::value::Value,
|
||||
};
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub struct VectorExpression {
|
||||
pub elements: Vec<Rc<Expression>>,
|
||||
}
|
||||
|
||||
impl VectorExpression {
|
||||
pub fn parse(values: &[Value]) -> Self {
|
||||
Self {
|
||||
elements: values.iter().map(Expression::parse_inner).collect(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl CollectErrors<ParseError> for VectorExpression {
|
||||
fn collect_errors(&self, errors: &mut Vec<ParseError>) -> bool {
|
||||
let mut r = false;
|
||||
for expr in self.elements.iter() {
|
||||
r |= expr.collect_errors(errors);
|
||||
}
|
||||
r
|
||||
}
|
||||
}
|
||||
+66
-10
@@ -3,11 +3,12 @@ use std::{
|
||||
io::{self, BufReader},
|
||||
path::{Path, PathBuf},
|
||||
process::ExitCode,
|
||||
str::FromStr,
|
||||
};
|
||||
|
||||
use clap::Parser;
|
||||
use lysp::{
|
||||
compile::{CompileError, ParseError},
|
||||
compile::{CompileError, CompileOptions, ParseError},
|
||||
error::{EvalError, MachineErrorKind},
|
||||
read::{InteractiveReader, ModuleReader, read},
|
||||
util::Either,
|
||||
@@ -25,9 +26,38 @@ enum Error {
|
||||
Printed,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub enum Trace {
|
||||
Compile,
|
||||
Execute,
|
||||
Call,
|
||||
Return,
|
||||
}
|
||||
|
||||
impl FromStr for Trace {
|
||||
type Err = String;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
match s {
|
||||
"compile" => Ok(Self::Compile),
|
||||
"execute" => Ok(Self::Execute),
|
||||
"call" => Ok(Self::Call),
|
||||
"return" => Ok(Self::Return),
|
||||
_ => Err(format!("Unknown trace flag: {s:?}")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
struct Args {
|
||||
#[clap(
|
||||
short = 'T',
|
||||
long = "trace",
|
||||
help = "Enable tracing of execution/compilation steps"
|
||||
)]
|
||||
trace: Vec<Trace>,
|
||||
module: Option<PathBuf>,
|
||||
arguments: Vec<String>,
|
||||
}
|
||||
|
||||
fn print_syntax_errors(errors: &[ParseError]) {
|
||||
@@ -59,7 +89,7 @@ fn handle_eval_error(value: Option<&Value>, input: EvalError) -> Error {
|
||||
eprintln!(":: {}", error.error);
|
||||
eprintln!();
|
||||
if let Some(ip) = error.ip.as_ref() {
|
||||
ip.module.dump(Some(ip.address), 8);
|
||||
ip.module.dump(Some(ip.address), 8, 2);
|
||||
}
|
||||
}
|
||||
EvalError::Compile(CompileError::Parse(errors)) => {
|
||||
@@ -88,8 +118,13 @@ fn handle_module_error(input: Either<EvalError, Vec<ParseError>>) -> Error {
|
||||
}
|
||||
}
|
||||
|
||||
fn eval(vm: &mut Machine, env: &mut Environment, value: Value) -> Option<Value> {
|
||||
let result = vm.eval_value(env, value.clone());
|
||||
fn eval(
|
||||
options: &CompileOptions,
|
||||
vm: &mut Machine,
|
||||
env: &mut Environment,
|
||||
value: Value,
|
||||
) -> Option<Value> {
|
||||
let result = vm.eval_value(options.clone(), env, value.clone(), false);
|
||||
match result {
|
||||
Ok(r) => Some(r),
|
||||
Err(error) => {
|
||||
@@ -99,7 +134,11 @@ fn eval(vm: &mut Machine, env: &mut Environment, value: Value) -> Option<Value>
|
||||
}
|
||||
}
|
||||
|
||||
fn run_interactive(vm: &mut Machine, env: &mut Environment) -> Result<(), Error> {
|
||||
fn run_interactive(
|
||||
compile_options: &CompileOptions,
|
||||
vm: &mut Machine,
|
||||
env: &mut Environment,
|
||||
) -> Result<(), Error> {
|
||||
let mut reader = InteractiveReader::new("> ", ">> ");
|
||||
|
||||
loop {
|
||||
@@ -111,7 +150,7 @@ fn run_interactive(vm: &mut Machine, env: &mut Environment) -> Result<(), Error>
|
||||
continue;
|
||||
}
|
||||
};
|
||||
if let Some(value) = eval(vm, env, value) {
|
||||
if let Some(value) = eval(compile_options, vm, env, value) {
|
||||
println!("== {value}");
|
||||
} else {
|
||||
reader.reset();
|
||||
@@ -122,19 +161,21 @@ fn run_interactive(vm: &mut Machine, env: &mut Environment) -> Result<(), Error>
|
||||
}
|
||||
|
||||
fn run_module<P: AsRef<Path>>(
|
||||
compile_options: &CompileOptions,
|
||||
vm: &mut Machine,
|
||||
env: &mut Environment,
|
||||
path: P,
|
||||
) -> Result<(), Error> {
|
||||
let path = path.as_ref();
|
||||
let name = format!("{}", path.display());
|
||||
let reader = BufReader::new(File::open(path)?);
|
||||
let module_reader = ModuleReader::new(reader);
|
||||
let module = match module_reader.compile(env) {
|
||||
let module = match module_reader.compile(Some(name.into()), compile_options, env) {
|
||||
Ok(module) => module,
|
||||
Err(error) => return Err(handle_module_error(error)),
|
||||
};
|
||||
|
||||
match vm.eval_module(env, module) {
|
||||
match vm.eval_module(env, module, false) {
|
||||
Ok(_) => Ok(()),
|
||||
Err(error) => Err(handle_eval_error(None, error)),
|
||||
}
|
||||
@@ -143,11 +184,26 @@ fn run_module<P: AsRef<Path>>(
|
||||
fn main() -> ExitCode {
|
||||
let args = Args::parse();
|
||||
let mut vm = Machine::default();
|
||||
let compile_options = CompileOptions {
|
||||
trace_compile: args.trace.contains(&Trace::Compile),
|
||||
};
|
||||
vm.trace_instructions = args.trace.contains(&Trace::Execute);
|
||||
vm.trace_calls = args.trace.contains(&Trace::Call);
|
||||
vm.trace_returns = args.trace.contains(&Trace::Return);
|
||||
let mut env = Environment::default();
|
||||
prelude::load(&mut env);
|
||||
let mut arguments = vec![];
|
||||
if let Some(script) = args.module.as_ref() {
|
||||
arguments.push(format!("{}", script.display()));
|
||||
}
|
||||
arguments.extend(args.arguments);
|
||||
env.set_global_value(
|
||||
"*args*",
|
||||
Value::list_or_nil(arguments.into_iter().map(|arg| Value::String(arg.into()))),
|
||||
);
|
||||
let result = match args.module.as_ref() {
|
||||
Some(module) => run_module(&mut vm, &mut env, module),
|
||||
None => run_interactive(&mut vm, &mut env),
|
||||
Some(module) => run_module(&compile_options, &mut vm, &mut env, module),
|
||||
None => run_interactive(&compile_options, &mut vm, &mut env),
|
||||
};
|
||||
match result {
|
||||
Ok(()) => ExitCode::SUCCESS,
|
||||
|
||||
+13
-1
@@ -14,7 +14,7 @@ use nom::{
|
||||
sequence::{delimited, preceded},
|
||||
};
|
||||
|
||||
use crate::vm::value::{Keyword, Value};
|
||||
use crate::vm::value::{Keyword, Value, Vector};
|
||||
|
||||
struct IdentifierHead;
|
||||
struct IdentifierTail;
|
||||
@@ -179,6 +179,17 @@ fn parse_list_or_nil(input: &str) -> IResult<&str, Value> {
|
||||
.parse(input)
|
||||
}
|
||||
|
||||
fn parse_vector(input: &str) -> IResult<&str, Value> {
|
||||
delimited(
|
||||
char('['),
|
||||
many0(preceded(skip_comment_and_whitespace, parse_value)),
|
||||
preceded(skip_comment_and_whitespace, char(']')),
|
||||
)
|
||||
.map(Vector::from)
|
||||
.map(Value::from)
|
||||
.parse(input)
|
||||
}
|
||||
|
||||
fn parse_boolean(input: &str) -> IResult<&str, Value> {
|
||||
map(
|
||||
alt((
|
||||
@@ -298,6 +309,7 @@ fn parse_quote(input: &str) -> IResult<&str, Value> {
|
||||
pub fn parse_value(input: &str) -> IResult<&str, Value> {
|
||||
alt((
|
||||
parse_list_or_nil,
|
||||
parse_vector,
|
||||
parse_boolean,
|
||||
parse_quote,
|
||||
parse_quasi,
|
||||
|
||||
+9
-4
@@ -5,7 +5,9 @@ use std::{
|
||||
};
|
||||
|
||||
use crate::{
|
||||
compile::{CompilationModule, Expression, FunctionBody, FunctionSignature, ParseError},
|
||||
compile::{
|
||||
CompilationModule, CompileOptions, Expression, FunctionBody, FunctionSignature, ParseError,
|
||||
},
|
||||
error::EvalError,
|
||||
parse::{self, parse_value},
|
||||
util::Either,
|
||||
@@ -106,6 +108,7 @@ impl<R: BufRead> ModuleReader<R> {
|
||||
|
||||
pub fn read_expression(
|
||||
&mut self,
|
||||
options: &CompileOptions,
|
||||
env: &mut Environment,
|
||||
) -> Result<Option<Rc<Expression>>, Either<EvalError, Vec<ParseError>>> {
|
||||
loop {
|
||||
@@ -117,7 +120,7 @@ impl<R: BufRead> ModuleReader<R> {
|
||||
let expression = Expression::parse(&value).map_err(Either::Right)?;
|
||||
if let Expression::Defmacro(_) = expression.as_ref() {
|
||||
self.macro_machine
|
||||
.eval_value(env, value)
|
||||
.eval_value(options.clone(), env, value, false)
|
||||
.map_err(Either::Left)?;
|
||||
continue;
|
||||
}
|
||||
@@ -127,9 +130,11 @@ impl<R: BufRead> ModuleReader<R> {
|
||||
|
||||
pub fn compile(
|
||||
mut self,
|
||||
module_name: Option<Rc<str>>,
|
||||
options: &CompileOptions,
|
||||
env: &mut Environment,
|
||||
) -> Result<ModuleRef, Either<EvalError, Vec<ParseError>>> {
|
||||
let mut module = CompilationModule::default();
|
||||
let mut module = CompilationModule::new(module_name, options.clone());
|
||||
let mut body = FunctionBody {
|
||||
head: vec![],
|
||||
tail: Rc::new(Expression::Nil),
|
||||
@@ -138,7 +143,7 @@ impl<R: BufRead> ModuleReader<R> {
|
||||
let mut syntax_errors = vec![];
|
||||
|
||||
loop {
|
||||
let expression = match self.read_expression(env) {
|
||||
let expression = match self.read_expression(options, env) {
|
||||
Ok(Some(expression)) => expression,
|
||||
Ok(None) => break,
|
||||
Err(Either::Left(error)) => return Err(Either::Left(error)),
|
||||
|
||||
@@ -91,7 +91,7 @@ pub enum Instruction {
|
||||
}
|
||||
|
||||
pub type ConstantId = U<12>;
|
||||
pub type FunctionOffset = U<12>;
|
||||
pub type FunctionOffset = U<10>;
|
||||
pub type LocalId = U<8>;
|
||||
pub type ArgumentId = U<6>;
|
||||
pub type ArgumentCount = U<6>;
|
||||
@@ -222,7 +222,7 @@ impl TryFrom<u32> for Instruction {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::vm::instruction::U;
|
||||
use crate::vm::instruction::{FunctionOffset, U};
|
||||
|
||||
#[test]
|
||||
fn test_u_convert() {
|
||||
@@ -238,4 +238,10 @@ mod tests {
|
||||
let t = T::from_signed(-0x1000001);
|
||||
assert!(t.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_branch_target_extend() {
|
||||
let target = FunctionOffset::truncate(1022);
|
||||
assert_eq!(target.sign_extend_i64(), -2);
|
||||
}
|
||||
}
|
||||
|
||||
+105
-19
@@ -1,6 +1,7 @@
|
||||
use std::{collections::HashMap, fmt};
|
||||
|
||||
use crate::{
|
||||
compile::CompileOptions,
|
||||
error::{EvalError, MachineError, MachineErrorKind},
|
||||
vm::{
|
||||
env::Environment,
|
||||
@@ -32,6 +33,8 @@ pub struct Machine {
|
||||
value_stack: Stack<Value>,
|
||||
pub call_stack: Stack<CallFrame>,
|
||||
pub trace_instructions: bool,
|
||||
pub trace_calls: bool,
|
||||
pub trace_returns: bool,
|
||||
// Top-level locals
|
||||
locals: HashMap<u32, Value>,
|
||||
}
|
||||
@@ -52,6 +55,8 @@ impl Default for Machine {
|
||||
locals: HashMap::new(),
|
||||
|
||||
trace_instructions: false,
|
||||
trace_calls: false,
|
||||
trace_returns: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -122,10 +127,20 @@ impl Machine {
|
||||
}),
|
||||
locals: HashMap::new(),
|
||||
};
|
||||
let entry_ip = InstructionPointer { module, address };
|
||||
if self.trace_calls {
|
||||
eprintln!("TRACE: Call bytecode function");
|
||||
if let Some(source_ip) = self.ip.as_ref() {
|
||||
eprintln!("TRACE: From {source_ip}");
|
||||
} else {
|
||||
eprintln!("TRACE: From <undefined>");
|
||||
}
|
||||
eprintln!("TRACE: To {entry_ip}");
|
||||
}
|
||||
if self.call_stack.push(frame).is_err() {
|
||||
return Err(self.error_at_ip(MachineErrorKind::CallStackOverflow));
|
||||
}
|
||||
self.ip = Some(InstructionPointer { module, address });
|
||||
self.ip = Some(entry_ip);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -186,10 +201,26 @@ impl Machine {
|
||||
|
||||
fn execute_return(&mut self) -> Result<ExecutionEvent, MachineError> {
|
||||
let ip = self.ip.clone().unwrap();
|
||||
if self.trace_returns {
|
||||
eprintln!("TRACE: Return");
|
||||
eprintln!("TRACE: From {ip}");
|
||||
ip.module.dump(Some(ip.address), 4, 0);
|
||||
}
|
||||
|
||||
if let Some(frame) = self.call_stack.pop() {
|
||||
if self.trace_returns {
|
||||
if let Some(target_ip) = frame.return_address.as_ref() {
|
||||
eprintln!("TRACE: To {target_ip}");
|
||||
} else {
|
||||
eprintln!("TRACE: To <undefined>");
|
||||
}
|
||||
}
|
||||
self.ip = frame.return_address;
|
||||
Ok(frame.event)
|
||||
} else {
|
||||
if self.trace_returns {
|
||||
eprintln!("TRACE: To <undefined>");
|
||||
}
|
||||
self.ip = None;
|
||||
Ok(ExecutionEvent::ModuleExit(ip.module))
|
||||
}
|
||||
@@ -369,6 +400,36 @@ impl Machine {
|
||||
eprintln!();
|
||||
}
|
||||
|
||||
fn unwind(&mut self, until: ExecutionEvent) {
|
||||
if self.trace_returns {
|
||||
eprintln!("TRACE: Begin unwind");
|
||||
if let Some(ip) = self.ip.as_ref() {
|
||||
eprintln!("TRACE: <- {ip}");
|
||||
} else {
|
||||
eprintln!("TRACE: <- <undefined>");
|
||||
}
|
||||
}
|
||||
let mut ip = self.ip.clone();
|
||||
while let Some(frame) = self.call_stack.pop() {
|
||||
if self.trace_returns {
|
||||
eprintln!("TRACE: Unwind frame:");
|
||||
if let Some(ip) = frame.return_address.as_ref() {
|
||||
eprintln!("TRACE: -> {ip}");
|
||||
} else {
|
||||
eprintln!("TRACE: -> <undefined>");
|
||||
}
|
||||
}
|
||||
ip = frame.return_address;
|
||||
if frame.event == until {
|
||||
break;
|
||||
}
|
||||
}
|
||||
self.ip = ip;
|
||||
if self.trace_returns {
|
||||
eprintln!("TRACE: Finished unwind");
|
||||
}
|
||||
}
|
||||
|
||||
pub fn execute_next(
|
||||
&mut self,
|
||||
environment: &mut Environment,
|
||||
@@ -468,23 +529,38 @@ impl Machine {
|
||||
Ok(value)
|
||||
}
|
||||
|
||||
pub fn load_module(&mut self, module: ModuleRef) -> Result<ModuleRef, MachineError> {
|
||||
pub fn load_module(
|
||||
&mut self,
|
||||
module: ModuleRef,
|
||||
advance_on_return: bool,
|
||||
) -> Result<ModuleRef, MachineError> {
|
||||
let entry = module.entry();
|
||||
let entry_ip = InstructionPointer {
|
||||
module: module.clone(),
|
||||
address: entry,
|
||||
};
|
||||
if let Some(ip) = self.ip.clone()
|
||||
&& self
|
||||
.call_stack
|
||||
.push(CallFrame {
|
||||
arguments: vec![],
|
||||
return_address: Some(ip),
|
||||
event: ExecutionEvent::ModuleExit(module.clone()),
|
||||
locals: HashMap::new(),
|
||||
})
|
||||
.is_err()
|
||||
{
|
||||
|
||||
let entry_frame = CallFrame {
|
||||
arguments: vec![],
|
||||
event: ExecutionEvent::ModuleExit(module.clone()),
|
||||
locals: HashMap::new(),
|
||||
return_address: self.ip.clone().map(|ip| InstructionPointer {
|
||||
module: ip.module,
|
||||
address: ip.address + advance_on_return as usize,
|
||||
}),
|
||||
};
|
||||
|
||||
if self.trace_calls {
|
||||
eprintln!("TRACE: Enter module");
|
||||
if let Some(source_ip) = self.ip.as_ref() {
|
||||
eprintln!("TRACE: From {source_ip}");
|
||||
} else {
|
||||
eprintln!("TRACE: From <undefined>");
|
||||
}
|
||||
eprintln!("TRACE: To {entry_ip}");
|
||||
}
|
||||
|
||||
if self.call_stack.push(entry_frame).is_err() {
|
||||
return Err(self.error_at_ip(MachineErrorKind::CallStackOverflow));
|
||||
}
|
||||
self.ip = Some(entry_ip);
|
||||
@@ -495,8 +571,9 @@ impl Machine {
|
||||
&mut self,
|
||||
environment: &mut Environment,
|
||||
module: ModuleRef,
|
||||
advance_on_return: bool,
|
||||
) -> Result<Value, EvalError> {
|
||||
let module = match self.load_module(module) {
|
||||
let module = match self.load_module(module, advance_on_return) {
|
||||
Ok(module) => module,
|
||||
Err(error) => return Err(EvalError::Machine(error)),
|
||||
};
|
||||
@@ -504,7 +581,10 @@ impl Machine {
|
||||
loop {
|
||||
let event = match self.execute_next(environment) {
|
||||
Ok(event) => event,
|
||||
Err(error) => return Err(EvalError::Machine(error)),
|
||||
Err(error) => {
|
||||
self.unwind(expect);
|
||||
return Err(EvalError::Machine(error));
|
||||
}
|
||||
};
|
||||
if event == expect {
|
||||
break;
|
||||
@@ -516,19 +596,25 @@ impl Machine {
|
||||
|
||||
pub fn eval_value(
|
||||
&mut self,
|
||||
compile_options: CompileOptions,
|
||||
environment: &mut Environment,
|
||||
value: Value,
|
||||
advance_on_return: bool,
|
||||
) -> Result<Value, EvalError> {
|
||||
let value = value.macro_expand(self, environment, false)?;
|
||||
let module = Module::compile_value(&value)?;
|
||||
let module = Module::compile_value(compile_options, &value)?;
|
||||
let module = ModuleRef::from(module);
|
||||
self.eval_module(environment, module)
|
||||
self.eval_module(environment, module, advance_on_return)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for InstructionPointer {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{:p}:{}", self.module, self.address)
|
||||
if let Some(name) = self.module.name.as_ref() {
|
||||
write!(f, "<{} {:p}>:{}", name, self.module, self.address)
|
||||
} else {
|
||||
write!(f, "<unnamed {:p}>:{}", self.module, self.address)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -566,7 +652,7 @@ mod tests {
|
||||
build(i as u32, &mut builder);
|
||||
builder.add(Instruction::Return);
|
||||
let module = builder.build();
|
||||
values.push(machine.eval_module(&mut env, module.into()).unwrap());
|
||||
values.push(machine.eval_module(&mut env, module.into(), false).unwrap());
|
||||
}
|
||||
(machine, values)
|
||||
}
|
||||
|
||||
+5
-1
@@ -75,7 +75,11 @@ impl MacroExpand for Value {
|
||||
let value = expand_quasiquote(value);
|
||||
value.macro_expand(vm, env, false)
|
||||
}
|
||||
Self::Vector(_) => todo!(),
|
||||
Self::Vector(vector) => Ok(Value::Vector(
|
||||
vector
|
||||
.try_map(|value| value.macro_expand(vm, env, false))?
|
||||
.into(),
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+19
-10
@@ -7,7 +7,10 @@ use std::{
|
||||
};
|
||||
|
||||
use crate::{
|
||||
compile::{CompilationModule, CompileError, Expression, FunctionBody, FunctionSignature},
|
||||
compile::{
|
||||
CompilationModule, CompileError, CompileOptions, Expression, FunctionBody,
|
||||
FunctionSignature,
|
||||
},
|
||||
vm::{
|
||||
instruction::{ConstantId, Instruction},
|
||||
pool::Pool,
|
||||
@@ -38,6 +41,7 @@ impl Hash for ModuleRef {
|
||||
impl Eq for ModuleRef {}
|
||||
|
||||
pub struct Module {
|
||||
pub name: Option<Rc<str>>,
|
||||
pub constants: HashMap<ConstantId, ModuleConstant>,
|
||||
pub instructions: Vec<u32>,
|
||||
pub entry: usize,
|
||||
@@ -94,6 +98,7 @@ impl Deref for ModuleRef {
|
||||
impl Module {
|
||||
pub fn dummy() -> Self {
|
||||
Self {
|
||||
name: None,
|
||||
constants: HashMap::new(),
|
||||
instructions: vec![0],
|
||||
entry: 0,
|
||||
@@ -122,9 +127,9 @@ impl Module {
|
||||
self.entry
|
||||
}
|
||||
|
||||
pub fn compile_value(value: &Value) -> Result<Self, CompileError> {
|
||||
pub fn compile_value(options: CompileOptions, value: &Value) -> Result<Self, CompileError> {
|
||||
let expression = Expression::parse(value).map_err(CompileError::Parse)?;
|
||||
let mut module = CompilationModule::default();
|
||||
let mut module = CompilationModule::new(None, options);
|
||||
module.compile_function(
|
||||
FunctionSignature::EMPTY,
|
||||
&FunctionBody {
|
||||
@@ -136,10 +141,10 @@ impl Module {
|
||||
module.compile_module()
|
||||
}
|
||||
|
||||
pub fn dump(&self, highlight: Option<usize>, context: usize) {
|
||||
pub fn dump(&self, highlight: Option<usize>, context_backward: usize, context_forward: usize) {
|
||||
let window = highlight
|
||||
.map(|end| (end + 1).min(self.instructions.len()))
|
||||
.map(|end| end.saturating_sub(context)..end)
|
||||
.map(|end| end.saturating_sub(context_backward)..end.saturating_add(context_forward))
|
||||
.unwrap_or(0..self.instructions.len());
|
||||
|
||||
let start = window.start;
|
||||
@@ -175,6 +180,7 @@ impl ModuleBuilder {
|
||||
|
||||
pub fn build(self) -> Module {
|
||||
Module {
|
||||
name: None,
|
||||
constants: self.constants.into_map(),
|
||||
instructions: self.instructions,
|
||||
entry: self.entry.unwrap(),
|
||||
@@ -215,10 +221,13 @@ impl fmt::Display for ModuleConstant {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::vm::{
|
||||
instruction::{Instruction, MathInstruction, U},
|
||||
module::Module,
|
||||
value::Value,
|
||||
use crate::{
|
||||
compile::CompileOptions,
|
||||
vm::{
|
||||
instruction::{Instruction, MathInstruction, U},
|
||||
module::Module,
|
||||
value::Value,
|
||||
},
|
||||
};
|
||||
|
||||
#[test]
|
||||
@@ -228,7 +237,7 @@ mod tests {
|
||||
Value::Integer(1),
|
||||
Value::Integer(2),
|
||||
]);
|
||||
let m = Module::compile_value(&v).unwrap();
|
||||
let m = Module::compile_value(CompileOptions::default(), &v).unwrap();
|
||||
assert!(m.constants.is_empty());
|
||||
let is = [
|
||||
Instruction::PushInteger(U::truncate(2)),
|
||||
|
||||
@@ -0,0 +1,119 @@
|
||||
use std::{
|
||||
cell::RefCell,
|
||||
fs::File,
|
||||
io::{Read, Write, stdin, stdout},
|
||||
};
|
||||
|
||||
use crate::vm::{
|
||||
env::Environment,
|
||||
value::{Value, Vector},
|
||||
};
|
||||
|
||||
enum FileStream {
|
||||
Closed,
|
||||
File(File),
|
||||
}
|
||||
|
||||
enum Stream {
|
||||
Stdin,
|
||||
Stdout,
|
||||
File(RefCell<FileStream>),
|
||||
}
|
||||
|
||||
impl Stream {
|
||||
fn read_bytes(&self, data: &mut [u8]) -> Option<usize> {
|
||||
let result = match self {
|
||||
Self::Stdin => stdin().read(data),
|
||||
Self::Stdout => return None,
|
||||
Self::File(file) => match &mut *file.borrow_mut() {
|
||||
FileStream::File(file) => file.read(data),
|
||||
FileStream::Closed => return None,
|
||||
},
|
||||
};
|
||||
result.ok()
|
||||
}
|
||||
|
||||
fn write_bytes(&self, data: &[u8]) -> Option<usize> {
|
||||
match self {
|
||||
Self::Stdin => None,
|
||||
Self::Stdout => stdout().write(data).ok(),
|
||||
Self::File(file) => match &mut *file.borrow_mut() {
|
||||
FileStream::File(file) => file.write(data).ok(),
|
||||
FileStream::Closed => None,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn load(env: &mut Environment) {
|
||||
env.set_global_value("*stdin*", Value::opaque(Stream::Stdin));
|
||||
env.set_global_value("*stdout*", Value::opaque(Stream::Stdout));
|
||||
|
||||
env.defun_native("fopen", |_, _, args| {
|
||||
let [path] = args else {
|
||||
todo!();
|
||||
};
|
||||
let Value::String(path) = path else { todo!() };
|
||||
match File::open(&**path) {
|
||||
Ok(file) => Ok(Value::opaque(Stream::File(RefCell::new(FileStream::File(
|
||||
file,
|
||||
))))),
|
||||
Err(_) => Ok(Value::Nil),
|
||||
}
|
||||
});
|
||||
env.defun_native("fclose", |vm, _, args| {
|
||||
let [stream] = args else { todo!() };
|
||||
let stream = stream
|
||||
.as_opaque::<Stream>()
|
||||
.map_err(|e| vm.error_at_ip(e))?;
|
||||
if let Stream::File(file) = stream {
|
||||
*file.borrow_mut() = FileStream::Closed;
|
||||
}
|
||||
Ok(Value::Nil)
|
||||
});
|
||||
env.defun_native("fread", |vm, _, args| {
|
||||
let stream = match args {
|
||||
[] => &Stream::Stdin,
|
||||
[stream] => stream
|
||||
.as_opaque::<Stream>()
|
||||
.map_err(|e| vm.error_at_ip(e))?,
|
||||
_ => todo!(),
|
||||
};
|
||||
let mut buffer = [0; 256];
|
||||
let count = stream.read_bytes(&mut buffer);
|
||||
match count {
|
||||
Some(len) => {
|
||||
let vector = Vector::from_iter(&buffer[..len]);
|
||||
Ok(Value::Vector(vector.into()))
|
||||
}
|
||||
None => Ok(Value::Nil),
|
||||
}
|
||||
});
|
||||
env.defun_native("fwrite", |vm, _, args| {
|
||||
let (stream, data) = match args {
|
||||
[data] => (&Stream::Stdout, data),
|
||||
[stream, data] => (
|
||||
stream
|
||||
.as_opaque::<Stream>()
|
||||
.map_err(|e| vm.error_at_ip(e))?,
|
||||
data,
|
||||
),
|
||||
_ => todo!(),
|
||||
};
|
||||
|
||||
match data {
|
||||
Value::Vector(vector) => {
|
||||
let bytes = vector.to_bytes().unwrap();
|
||||
match stream.write_bytes(&bytes) {
|
||||
Some(count) => Ok(Value::Integer(count as i64)),
|
||||
None => Ok(Value::Nil),
|
||||
}
|
||||
}
|
||||
Value::String(value) => match stream.write_bytes(value.as_bytes()) {
|
||||
Some(count) => Ok(Value::Integer(count as i64)),
|
||||
None => Ok(Value::Nil),
|
||||
},
|
||||
_ => todo!(),
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -200,6 +200,7 @@ pub(crate) fn builtin_cmp(
|
||||
(Value::Integer(a), Value::Integer(b)) => Ord::cmp(a, b),
|
||||
(Value::Boolean(a), Value::Boolean(b)) => Ord::cmp(a, b),
|
||||
(Value::String(a), Value::String(b)) => Ord::cmp(a, b),
|
||||
(Value::Identifier(a), Value::Identifier(b)) => Ord::cmp(a, b),
|
||||
_ => Ordering::Less,
|
||||
}
|
||||
}
|
||||
@@ -266,3 +267,25 @@ pub(crate) fn builtin_cmp_le(
|
||||
) -> Result<Value, MachineError> {
|
||||
builtin_cmp(vm, args, CompareOperation::Le)
|
||||
}
|
||||
|
||||
pub(super) fn load(env: &mut Environment) {
|
||||
// math
|
||||
env.defun_native("+", builtin_add);
|
||||
env.defun_native("-", builtin_sub);
|
||||
env.defun_native("*", builtin_mul);
|
||||
env.defun_native("%", builtin_mod);
|
||||
env.defun_native("/", builtin_div);
|
||||
|
||||
env.defun_native("&&", builtin_and);
|
||||
env.defun_native("||", builtin_or);
|
||||
env.defun_native("&", builtin_bitwise_and);
|
||||
env.defun_native("|", builtin_bitwise_or);
|
||||
env.defun_native("^", builtin_bitwise_xor);
|
||||
|
||||
env.defun_native(">", builtin_cmp_gt);
|
||||
env.defun_native("<", builtin_cmp_lt);
|
||||
env.defun_native("=", builtin_cmp_eq);
|
||||
env.defun_native("/=", builtin_cmp_ne);
|
||||
env.defun_native(">=", builtin_cmp_ge);
|
||||
env.defun_native("<=", builtin_cmp_le);
|
||||
}
|
||||
|
||||
+79
-23
@@ -2,36 +2,22 @@ use std::{rc::Rc, slice};
|
||||
|
||||
use crate::{
|
||||
error::MachineErrorKind,
|
||||
read::{self, InteractiveReader},
|
||||
util::IteratorExt,
|
||||
vm::{
|
||||
env::Environment,
|
||||
value::{AnyFunction, ConsCell, Keyword, TryFromValue, Value, ValueString},
|
||||
value::{AnyFunction, ConsCell, Keyword, TryFromValue, Value, ValueString, Vector},
|
||||
},
|
||||
};
|
||||
|
||||
mod io;
|
||||
mod math;
|
||||
|
||||
pub(crate) use math::*;
|
||||
|
||||
pub fn load(env: &mut Environment) {
|
||||
// math
|
||||
env.defun_native("+", builtin_add);
|
||||
env.defun_native("-", builtin_sub);
|
||||
env.defun_native("*", builtin_mul);
|
||||
env.defun_native("%", builtin_mod);
|
||||
env.defun_native("/", builtin_div);
|
||||
|
||||
env.defun_native("&&", builtin_and);
|
||||
env.defun_native("||", builtin_or);
|
||||
env.defun_native("&", builtin_bitwise_and);
|
||||
env.defun_native("|", builtin_bitwise_or);
|
||||
env.defun_native("^", builtin_bitwise_xor);
|
||||
|
||||
env.defun_native(">", builtin_cmp_gt);
|
||||
env.defun_native("<", builtin_cmp_lt);
|
||||
env.defun_native("=", builtin_cmp_eq);
|
||||
env.defun_native("/=", builtin_cmp_ne);
|
||||
env.defun_native(">=", builtin_cmp_ge);
|
||||
env.defun_native("<=", builtin_cmp_le);
|
||||
math::load(env);
|
||||
io::load(env);
|
||||
|
||||
// conversion
|
||||
env.defun_native("string->int", |vm, _, args| {
|
||||
@@ -50,8 +36,30 @@ pub fn load(env: &mut Environment) {
|
||||
let result = Value::String(format!("{arg}").into());
|
||||
Ok(result)
|
||||
});
|
||||
env.defun_native("vector", |_, _, args| {
|
||||
let vector = Vector::from_iter(args.iter().cloned());
|
||||
Ok(Value::Vector(vector.into()))
|
||||
});
|
||||
|
||||
// lists
|
||||
env.defun_native("car", |vm, _env, args| {
|
||||
let [x] = args else {
|
||||
return Err(vm.error_at_ip(MachineErrorKind::InvalidArgument));
|
||||
};
|
||||
let Value::Cons(cons) = x else {
|
||||
return Err(vm.error_at_ip(MachineErrorKind::InvalidArgument));
|
||||
};
|
||||
Ok(cons.0.clone())
|
||||
});
|
||||
env.defun_native("cdr", |vm, _env, args| {
|
||||
let [x] = args else {
|
||||
return Err(vm.error_at_ip(MachineErrorKind::InvalidArgument));
|
||||
};
|
||||
let Value::Cons(cons) = x else {
|
||||
return Err(vm.error_at_ip(MachineErrorKind::InvalidArgument));
|
||||
};
|
||||
Ok(cons.1.clone())
|
||||
});
|
||||
env.defun_native("cons", |vm, _env, args| {
|
||||
let [car, cdr] = args else {
|
||||
return Err(vm.error_at_ip(MachineErrorKind::InvalidArgument));
|
||||
@@ -85,6 +93,23 @@ pub fn load(env: &mut Environment) {
|
||||
let out = Value::list_or_nil(args.iter().cloned());
|
||||
Ok(out)
|
||||
});
|
||||
env.defun_native("length", |vm, _, args| {
|
||||
let [xs] = args else {
|
||||
return Err(vm.error_at_ip(MachineErrorKind::InvalidArgument));
|
||||
};
|
||||
|
||||
let mut xs = xs;
|
||||
let mut count = 0;
|
||||
while !xs.is_nil() {
|
||||
let Value::Cons(cons) = xs else {
|
||||
break;
|
||||
};
|
||||
let ConsCell(_, cdr) = cons.as_ref();
|
||||
count += 1;
|
||||
xs = cdr;
|
||||
}
|
||||
Ok(Value::Integer(count))
|
||||
});
|
||||
|
||||
// functional
|
||||
env.defun_native("identity", |vm, _, args| {
|
||||
@@ -102,9 +127,15 @@ pub fn load(env: &mut Environment) {
|
||||
[_, _] => todo!(),
|
||||
_ => todo!(),
|
||||
};
|
||||
let value = match vm.eval_value(env, value.clone()) {
|
||||
Ok(result) => result,
|
||||
_ => todo!(),
|
||||
let value = match vm.eval_value(Default::default(), env, value.clone(), true) {
|
||||
Ok(result) => Value::Quote(Rc::new(Value::list_or_nil([
|
||||
Value::Identifier("ok".into()),
|
||||
result,
|
||||
]))),
|
||||
Err(error) => Value::Quote(Rc::new(Value::list_or_nil([
|
||||
Value::Identifier("err".into()),
|
||||
Value::String(format!("{error}").into()),
|
||||
]))),
|
||||
};
|
||||
Ok(value)
|
||||
});
|
||||
@@ -121,6 +152,31 @@ pub fn load(env: &mut Environment) {
|
||||
});
|
||||
|
||||
// io
|
||||
env.defun_native("read", |vm, env, _args| {
|
||||
let mut reader = InteractiveReader::new("> ", ">> ");
|
||||
let value = read::read(&mut reader, vm, env);
|
||||
let value = match value {
|
||||
Ok(Some(value)) => Value::Quote(Rc::new(Value::list_or_nil([
|
||||
Value::Identifier("ok".into()),
|
||||
value,
|
||||
]))),
|
||||
Ok(None) => Value::Nil,
|
||||
Err(error) => Value::Quote(Rc::new(Value::list_or_nil([
|
||||
Value::Identifier("err".into()),
|
||||
Value::String(format!("{error}").into()),
|
||||
]))),
|
||||
};
|
||||
Ok(value)
|
||||
});
|
||||
env.defun_native("unquote", |vm, _env, args| {
|
||||
let [x] = args else {
|
||||
return Err(vm.error_at_ip(MachineErrorKind::InvalidArgument));
|
||||
};
|
||||
let Value::Quote(value) = x else {
|
||||
return Err(vm.error_at_ip(MachineErrorKind::InvalidArgument));
|
||||
};
|
||||
Ok(value.as_ref().clone())
|
||||
});
|
||||
env.defun_native("print", |_, _, args| {
|
||||
for (i, arg) in args.iter().enumerate() {
|
||||
if i != 0 {
|
||||
|
||||
@@ -39,6 +39,12 @@ macro_rules! impl_primitive_value {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&$t> for Value {
|
||||
fn from(value: &$t) -> Self {
|
||||
Self::Integer(*value as i64)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFromValue<'_> for $t {
|
||||
fn try_from_value(value: &Value) -> Result<Self, MachineErrorKind> {
|
||||
match value {
|
||||
|
||||
@@ -47,6 +47,9 @@ impl_keyword! {
|
||||
LetStar => "let*",
|
||||
Defmacro => "defmacro",
|
||||
Quote => "quote",
|
||||
Progn => "progn",
|
||||
Loop => "loop",
|
||||
Return => "return",
|
||||
// Cons => "cons",
|
||||
}
|
||||
}
|
||||
|
||||
+13
-1
@@ -1,4 +1,4 @@
|
||||
use std::{fmt, hash::Hash, rc::Rc};
|
||||
use std::{any::Any, fmt, hash::Hash, rc::Rc};
|
||||
|
||||
use crate::{
|
||||
compile::{ExpectedWhat, ExpectedWhere, ParseError, ParseErrorKind},
|
||||
@@ -78,6 +78,12 @@ impl Value {
|
||||
matches!(self, Self::Nil)
|
||||
}
|
||||
|
||||
pub fn opaque<T: 'static>(value: T) -> Self {
|
||||
let value: Rc<dyn Any> = Rc::new(value);
|
||||
let opaque = OpaqueValue::from(value);
|
||||
Self::OpaqueValue(opaque)
|
||||
}
|
||||
|
||||
pub fn as_opaque<T: 'static>(&self) -> Result<&T, MachineErrorKind> {
|
||||
match self {
|
||||
Self::OpaqueValue(opaque) => opaque.cast(),
|
||||
@@ -135,6 +141,12 @@ impl Value {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Vector> for Value {
|
||||
fn from(value: Vector) -> Self {
|
||||
Self::Vector(Rc::new(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Value {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
|
||||
+29
-4
@@ -5,7 +5,10 @@ use std::{
|
||||
ops::Deref,
|
||||
};
|
||||
|
||||
use crate::vm::value::Value;
|
||||
use crate::{
|
||||
error::MachineErrorKind,
|
||||
vm::value::{TryFromValue, Value},
|
||||
};
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub struct Vector(RefCell<Vec<Value>>);
|
||||
@@ -16,7 +19,21 @@ impl Hash for Vector {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Vec<Value>> for Vector {
|
||||
fn from(value: Vec<Value>) -> Self {
|
||||
Self(RefCell::new(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl Vector {
|
||||
pub fn try_map<E, F: FnMut(&Value) -> Result<Value, E>>(&self, map: F) -> Result<Vector, E> {
|
||||
self.0.borrow().iter().map(map).collect()
|
||||
}
|
||||
|
||||
pub fn to_bytes(&self) -> Result<Vec<u8>, MachineErrorKind> {
|
||||
self.0.borrow().iter().map(u8::try_from_value).collect()
|
||||
}
|
||||
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.0.borrow().is_empty()
|
||||
}
|
||||
@@ -26,9 +43,17 @@ impl Vector {
|
||||
}
|
||||
}
|
||||
|
||||
impl FromIterator<Value> for Vector {
|
||||
fn from_iter<T: IntoIterator<Item = Value>>(iter: T) -> Self {
|
||||
Self(RefCell::new(Vec::from_iter(iter)))
|
||||
// impl FromIterator<Value> for Vector {
|
||||
// fn from_iter<T: IntoIterator<Item = Value>>(iter: T) -> Self {
|
||||
// Self(RefCell::new(Vec::from_iter(iter)))
|
||||
// }
|
||||
// }
|
||||
|
||||
impl<T: Into<Value>> FromIterator<T> for Vector {
|
||||
fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
|
||||
Self(RefCell::new(Vec::from_iter(
|
||||
iter.into_iter().map(Into::into),
|
||||
)))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ fn eval_str_in(code: &str, env: &mut Environment) -> Result<Value, EvalError> {
|
||||
Err(error) => panic!("{error}"),
|
||||
};
|
||||
|
||||
last_value = Some(machine.eval_value(env, value));
|
||||
last_value = Some(machine.eval_value(Default::default(), env, value, false));
|
||||
}
|
||||
|
||||
last_value.expect("no expressions evaluated")
|
||||
|
||||
Reference in New Issue
Block a user