Tracing options, while loop
This commit is contained in:
+17
-15
@@ -7,18 +7,20 @@
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
(print 1 "\t" (factorial 1))
|
(defun loop-factorial (x)
|
||||||
(print 2 "\t" (factorial 2))
|
(let (i 0 acc 1)
|
||||||
(print 3 "\t" (factorial 3))
|
(while (< i x)
|
||||||
(print 4 "\t" (factorial 4))
|
(setq i (+ i 1))
|
||||||
(print 5 "\t" (factorial 5))
|
(setq acc (* acc i))
|
||||||
(print 6 "\t" (factorial 6))
|
)
|
||||||
(print 7 "\t" (factorial 7))
|
acc
|
||||||
(print 8 "\t" (factorial 8))
|
)
|
||||||
(print 9 "\t" (factorial 9))
|
)
|
||||||
(print 10 "\t" (factorial 10))
|
|
||||||
(print 11 "\t" (factorial 11))
|
;; TODO for loops?
|
||||||
(print 12 "\t" (factorial 12))
|
(let (i 0)
|
||||||
(print 13 "\t" (factorial 13))
|
(while (<= i 15)
|
||||||
(print 14 "\t" (factorial 14))
|
(print i "\t" (factorial i) "\t" (loop-factorial i))
|
||||||
(print 15 "\t" (factorial 15))
|
(setq i (+ i 1))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|||||||
@@ -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))
|
||||||
+63
-15
@@ -9,6 +9,7 @@ use crate::{
|
|||||||
syntax::{
|
syntax::{
|
||||||
CallExpression, CondExpression, DefmacroExpression, DefunExpression, Expression,
|
CallExpression, CondExpression, DefmacroExpression, DefunExpression, Expression,
|
||||||
FunctionBody, IfExpression, LambdaExpression, LetExpression, SetqExpression,
|
FunctionBody, IfExpression, LambdaExpression, LetExpression, SetqExpression,
|
||||||
|
WhileExpression,
|
||||||
},
|
},
|
||||||
value::{BuiltinFunction, CompileConstant, CompileValue},
|
value::{BuiltinFunction, CompileConstant, CompileValue},
|
||||||
},
|
},
|
||||||
@@ -136,13 +137,19 @@ impl FunctionBlock {
|
|||||||
self.labels.insert(label, self.instructions.len());
|
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![];
|
let mut instructions = vec![];
|
||||||
// eprintln!("RESOLVE LABELS");
|
|
||||||
|
if trace {
|
||||||
|
eprintln!("Instruction resolution:");
|
||||||
|
}
|
||||||
|
|
||||||
for (function_offset, emitted) in self.instructions.into_iter().enumerate() {
|
for (function_offset, emitted) in self.instructions.into_iter().enumerate() {
|
||||||
match emitted {
|
match emitted {
|
||||||
Emitted::Instruction(instruction) => {
|
Emitted::Instruction(instruction) => {
|
||||||
// eprintln!("{function_offset}: {instruction:?}");
|
if trace {
|
||||||
|
eprintln!("{function_offset}: {instruction:?}");
|
||||||
|
}
|
||||||
instructions.push(instruction);
|
instructions.push(instruction);
|
||||||
}
|
}
|
||||||
Emitted::Branch(label) => {
|
Emitted::Branch(label) => {
|
||||||
@@ -151,9 +158,11 @@ impl FunctionBlock {
|
|||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
let diff = address.checked_signed_diff(function_offset).expect("TODO");
|
let diff = address.checked_signed_diff(function_offset).expect("TODO");
|
||||||
// eprintln!(
|
if trace {
|
||||||
// "{function_offset}: branch to label {label} (@ {address}) -> {diff:+}"
|
eprintln!(
|
||||||
// );
|
"{function_offset}: Branch: label {label} (@ {address}) -> {diff:+}"
|
||||||
|
);
|
||||||
|
}
|
||||||
let offset = U::from_signed(diff as i64).expect("TODO");
|
let offset = U::from_signed(diff as i64).expect("TODO");
|
||||||
instructions.push(Instruction::Branch(offset));
|
instructions.push(Instruction::Branch(offset));
|
||||||
}
|
}
|
||||||
@@ -163,7 +172,11 @@ impl FunctionBlock {
|
|||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
let diff = address.checked_signed_diff(function_offset).expect("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");
|
let offset = U::from_signed(diff as i64).expect("TODO");
|
||||||
instructions.push(Instruction::Jump(offset));
|
instructions.push(Instruction::Jump(offset));
|
||||||
}
|
}
|
||||||
@@ -464,6 +477,30 @@ impl<'a> LocalBlock<'a> {
|
|||||||
Ok(CompileValue::Stack)
|
Ok(CompileValue::Stack)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn compile_while(&mut self, cloop: &WhileExpression) -> 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)?;
|
||||||
|
self.compile_push(condition_value)?;
|
||||||
|
self.function.emit(Emitted::Branch(label_end));
|
||||||
|
|
||||||
|
// Body
|
||||||
|
for expression in &cloop.body.head {
|
||||||
|
self.compile_statement(expression)?;
|
||||||
|
}
|
||||||
|
self.compile_statement(&cloop.body.tail)?;
|
||||||
|
|
||||||
|
// Jump back
|
||||||
|
self.function.emit(Emitted::Jump(label_start));
|
||||||
|
|
||||||
|
self.function.adjust_label(label_end);
|
||||||
|
Ok(CompileValue::Nil)
|
||||||
|
}
|
||||||
|
|
||||||
fn compile_let(&mut self, binding: &LetExpression) -> Result<CompileValue, CompileError> {
|
fn compile_let(&mut self, binding: &LetExpression) -> Result<CompileValue, CompileError> {
|
||||||
self.function.push_local_scope();
|
self.function.push_local_scope();
|
||||||
let mut indices = vec![];
|
let mut indices = vec![];
|
||||||
@@ -496,7 +533,16 @@ impl<'a> LocalBlock<'a> {
|
|||||||
fn compile_setq(&mut self, setq: &SetqExpression) -> Result<CompileValue, CompileError> {
|
fn compile_setq(&mut self, setq: &SetqExpression) -> Result<CompileValue, CompileError> {
|
||||||
for pair in setq.pairs.iter() {
|
for pair in setq.pairs.iter() {
|
||||||
let value = self.compile_expression(&pair.value)?;
|
let value = self.compile_expression(&pair.value)?;
|
||||||
self.compile_set_global(&pair.identifier, value)?;
|
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)
|
Ok(CompileValue::Nil)
|
||||||
}
|
}
|
||||||
@@ -524,6 +570,7 @@ impl<'a> LocalBlock<'a> {
|
|||||||
Expression::Setq(setq) => self.compile_setq(setq),
|
Expression::Setq(setq) => self.compile_setq(setq),
|
||||||
Expression::Defmacro(defmacro) => self.compile_defmacro(defmacro),
|
Expression::Defmacro(defmacro) => self.compile_defmacro(defmacro),
|
||||||
Expression::Quote(quote) => self.compile_quote(quote),
|
Expression::Quote(quote) => self.compile_quote(quote),
|
||||||
|
Expression::While(cloop) => self.compile_while(cloop),
|
||||||
|
|
||||||
Expression::SyntaxError(_) => unreachable!(),
|
Expression::SyntaxError(_) => unreachable!(),
|
||||||
}
|
}
|
||||||
@@ -600,7 +647,8 @@ mod tests {
|
|||||||
};
|
};
|
||||||
let mut local = LocalBlock::root(&mut function, &mut module);
|
let mut local = LocalBlock::root(&mut function, &mut module);
|
||||||
let value = local.compile_expression(&Rc::new(expression)).unwrap();
|
let value = local.compile_expression(&Rc::new(expression)).unwrap();
|
||||||
(module, function.resolve_labels(), value)
|
let trace = module.options.trace_compile;
|
||||||
|
(module, function.resolve_labels(trace), value)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -647,9 +695,9 @@ mod tests {
|
|||||||
&f.instructions,
|
&f.instructions,
|
||||||
&[
|
&[
|
||||||
Instruction::PushBool(false), // 0
|
Instruction::PushBool(false), // 0
|
||||||
Instruction::Branch(U::truncate(4)), // 1
|
Instruction::Branch(U::truncate(3)), // 1
|
||||||
Instruction::PushInteger(U::truncate(1)), // 2
|
Instruction::PushInteger(U::truncate(1)), // 2
|
||||||
Instruction::Jump(U::truncate(5)), // 3
|
Instruction::Jump(U::truncate(2)), // 3
|
||||||
Instruction::PushInteger(U::truncate(2)) // 4
|
Instruction::PushInteger(U::truncate(2)) // 4
|
||||||
// 5
|
// 5
|
||||||
]
|
]
|
||||||
@@ -676,13 +724,13 @@ mod tests {
|
|||||||
&f.instructions,
|
&f.instructions,
|
||||||
&[
|
&[
|
||||||
Instruction::PushBool(false), // 0
|
Instruction::PushBool(false), // 0
|
||||||
Instruction::Branch(U::truncate(4)), // 1
|
Instruction::Branch(U::truncate(3)), // 1
|
||||||
Instruction::PushInteger(U::truncate(1)), // 2
|
Instruction::PushInteger(U::truncate(1)), // 2
|
||||||
Instruction::Jump(U::truncate(9)), // 3
|
Instruction::Jump(U::truncate(6)), // 3
|
||||||
Instruction::PushBool(true), // 4
|
Instruction::PushBool(true), // 4
|
||||||
Instruction::Branch(U::truncate(8)), // 5
|
Instruction::Branch(U::truncate(3)), // 5
|
||||||
Instruction::PushInteger(U::truncate(2)), // 6
|
Instruction::PushInteger(U::truncate(2)), // 6
|
||||||
Instruction::Jump(U::truncate(9)), // 7
|
Instruction::Jump(U::truncate(2)), // 7
|
||||||
Instruction::PushInteger(U::truncate(3)), // 8
|
Instruction::PushInteger(U::truncate(3)), // 8
|
||||||
// 9
|
// 9
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -13,3 +13,8 @@ pub use syntax::{
|
|||||||
CallExpression, ExpectedWhat, ExpectedWhere, Expression, FunctionBody, LambdaExpression,
|
CallExpression, ExpectedWhat, ExpectedWhere, Expression, FunctionBody, LambdaExpression,
|
||||||
ParseError, ParseErrorKind,
|
ParseError, ParseErrorKind,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[derive(Default, Clone)]
|
||||||
|
pub struct CompileOptions {
|
||||||
|
pub trace_compile: bool,
|
||||||
|
}
|
||||||
|
|||||||
+10
-1
@@ -2,6 +2,7 @@ use std::{collections::HashMap, rc::Rc};
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
compile::{
|
compile::{
|
||||||
|
CompileOptions,
|
||||||
block::{CompiledFunction, FunctionBlock},
|
block::{CompiledFunction, FunctionBlock},
|
||||||
error::CompileError,
|
error::CompileError,
|
||||||
function::FunctionSignature,
|
function::FunctionSignature,
|
||||||
@@ -19,12 +20,20 @@ use crate::{
|
|||||||
pub struct CompilationModule {
|
pub struct CompilationModule {
|
||||||
pub(crate) constant_pool: Pool<CompileConstant, { ConstantId::BITS }>,
|
pub(crate) constant_pool: Pool<CompileConstant, { ConstantId::BITS }>,
|
||||||
pub(crate) local_functions: HashMap<u32, CompiledFunction>,
|
pub(crate) local_functions: HashMap<u32, CompiledFunction>,
|
||||||
|
pub(crate) options: CompileOptions,
|
||||||
macros: HashMap<Rc<str>, DefmacroExpression>,
|
macros: HashMap<Rc<str>, DefmacroExpression>,
|
||||||
local_function_index: u32,
|
local_function_index: u32,
|
||||||
root: Option<u32>,
|
root: Option<u32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CompilationModule {
|
impl CompilationModule {
|
||||||
|
pub fn new(options: CompileOptions) -> Self {
|
||||||
|
Self {
|
||||||
|
options,
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn define_macro(&mut self, defmacro: DefmacroExpression) {
|
pub fn define_macro(&mut self, defmacro: DefmacroExpression) {
|
||||||
self.macros.insert(defmacro.name.clone(), defmacro);
|
self.macros.insert(defmacro.name.clone(), defmacro);
|
||||||
}
|
}
|
||||||
@@ -49,7 +58,7 @@ impl CompilationModule {
|
|||||||
self.local_function_index += 1;
|
self.local_function_index += 1;
|
||||||
let mut function = FunctionBlock::new(signature);
|
let mut function = FunctionBlock::new(signature);
|
||||||
function.compile_body(self, body)?;
|
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);
|
self.local_functions.insert(index, function);
|
||||||
if root {
|
if root {
|
||||||
self.root = Some(index);
|
self.root = Some(index);
|
||||||
|
|||||||
@@ -64,9 +64,9 @@ impl IfExpression {
|
|||||||
Some(Expression::parse_inner(if_false))
|
Some(Expression::parse_inner(if_false))
|
||||||
};
|
};
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
condition: condition.into(),
|
condition,
|
||||||
if_true: if_true.into(),
|
if_true,
|
||||||
if_false: if_false.map(Into::into),
|
if_false,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,41 @@
|
|||||||
|
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,
|
||||||
|
}
|
||||||
|
|
||||||
|
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 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
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,6 +8,7 @@ mod condition;
|
|||||||
mod error;
|
mod error;
|
||||||
mod function;
|
mod function;
|
||||||
mod lambda;
|
mod lambda;
|
||||||
|
mod loops;
|
||||||
mod macros;
|
mod macros;
|
||||||
|
|
||||||
pub use binding::*;
|
pub use binding::*;
|
||||||
@@ -16,6 +17,7 @@ pub use condition::*;
|
|||||||
pub use error::*;
|
pub use error::*;
|
||||||
pub use function::*;
|
pub use function::*;
|
||||||
pub use lambda::*;
|
pub use lambda::*;
|
||||||
|
pub use loops::*;
|
||||||
pub use macros::*;
|
pub use macros::*;
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
@@ -35,6 +37,7 @@ pub enum Expression {
|
|||||||
Defmacro(DefmacroExpression),
|
Defmacro(DefmacroExpression),
|
||||||
SyntaxError(ParseError),
|
SyntaxError(ParseError),
|
||||||
Quote(Rc<Value>),
|
Quote(Rc<Value>),
|
||||||
|
While(WhileExpression),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Expression {
|
impl Expression {
|
||||||
@@ -97,6 +100,9 @@ impl Expression {
|
|||||||
};
|
};
|
||||||
Rc::new(Self::Quote(value.into()))
|
Rc::new(Self::Quote(value.into()))
|
||||||
}
|
}
|
||||||
|
Value::Keyword(Keyword::While) => {
|
||||||
|
Self::map_or(WhileExpression::parse(cdr, value), Expression::While)
|
||||||
|
}
|
||||||
_ => Self::map_or(CallExpression::parse(cons, value), Expression::Call),
|
_ => Self::map_or(CallExpression::parse(cons, value), Expression::Call),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -123,6 +129,7 @@ impl CollectErrors<ParseError> for Expression {
|
|||||||
Self::Let(let_) => let_.collect_errors(errors),
|
Self::Let(let_) => let_.collect_errors(errors),
|
||||||
Self::Setq(setq) => setq.collect_errors(errors),
|
Self::Setq(setq) => setq.collect_errors(errors),
|
||||||
Self::Defmacro(defmacro) => defmacro.collect_errors(errors),
|
Self::Defmacro(defmacro) => defmacro.collect_errors(errors),
|
||||||
|
Self::While(cloop) => cloop.collect_errors(errors),
|
||||||
Self::Nil
|
Self::Nil
|
||||||
| Self::IntegerLiteral(_)
|
| Self::IntegerLiteral(_)
|
||||||
| Self::Identifier(_)
|
| Self::Identifier(_)
|
||||||
|
|||||||
+47
-8
@@ -3,11 +3,12 @@ use std::{
|
|||||||
io::{self, BufReader},
|
io::{self, BufReader},
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
process::ExitCode,
|
process::ExitCode,
|
||||||
|
str::FromStr,
|
||||||
};
|
};
|
||||||
|
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use lysp::{
|
use lysp::{
|
||||||
compile::{CompileError, ParseError},
|
compile::{CompileError, CompileOptions, ParseError},
|
||||||
error::{EvalError, MachineErrorKind},
|
error::{EvalError, MachineErrorKind},
|
||||||
read::{InteractiveReader, ModuleReader, read},
|
read::{InteractiveReader, ModuleReader, read},
|
||||||
util::Either,
|
util::Either,
|
||||||
@@ -25,8 +26,32 @@ enum Error {
|
|||||||
Printed,
|
Printed,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
|
pub enum Trace {
|
||||||
|
Compile,
|
||||||
|
Execute,
|
||||||
|
}
|
||||||
|
|
||||||
|
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),
|
||||||
|
_ => Err(format!("Unknown trace flag: {s:?}")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Parser)]
|
#[derive(Debug, Parser)]
|
||||||
struct Args {
|
struct Args {
|
||||||
|
#[clap(
|
||||||
|
short = 'T',
|
||||||
|
long = "trace",
|
||||||
|
help = "Enable tracing of execution/compilation steps"
|
||||||
|
)]
|
||||||
|
trace: Vec<Trace>,
|
||||||
module: Option<PathBuf>,
|
module: Option<PathBuf>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -88,8 +113,13 @@ fn handle_module_error(input: Either<EvalError, Vec<ParseError>>) -> Error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eval(vm: &mut Machine, env: &mut Environment, value: Value) -> Option<Value> {
|
fn eval(
|
||||||
let result = vm.eval_value(env, value.clone());
|
options: &CompileOptions,
|
||||||
|
vm: &mut Machine,
|
||||||
|
env: &mut Environment,
|
||||||
|
value: Value,
|
||||||
|
) -> Option<Value> {
|
||||||
|
let result = vm.eval_value(options.clone(), env, value.clone());
|
||||||
match result {
|
match result {
|
||||||
Ok(r) => Some(r),
|
Ok(r) => Some(r),
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
@@ -99,7 +129,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("> ", ">> ");
|
let mut reader = InteractiveReader::new("> ", ">> ");
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
@@ -111,7 +145,7 @@ fn run_interactive(vm: &mut Machine, env: &mut Environment) -> Result<(), Error>
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if let Some(value) = eval(vm, env, value) {
|
if let Some(value) = eval(compile_options, vm, env, value) {
|
||||||
println!("== {value}");
|
println!("== {value}");
|
||||||
} else {
|
} else {
|
||||||
reader.reset();
|
reader.reset();
|
||||||
@@ -122,6 +156,7 @@ fn run_interactive(vm: &mut Machine, env: &mut Environment) -> Result<(), Error>
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn run_module<P: AsRef<Path>>(
|
fn run_module<P: AsRef<Path>>(
|
||||||
|
compile_options: &CompileOptions,
|
||||||
vm: &mut Machine,
|
vm: &mut Machine,
|
||||||
env: &mut Environment,
|
env: &mut Environment,
|
||||||
path: P,
|
path: P,
|
||||||
@@ -129,7 +164,7 @@ fn run_module<P: AsRef<Path>>(
|
|||||||
let path = path.as_ref();
|
let path = path.as_ref();
|
||||||
let reader = BufReader::new(File::open(path)?);
|
let reader = BufReader::new(File::open(path)?);
|
||||||
let module_reader = ModuleReader::new(reader);
|
let module_reader = ModuleReader::new(reader);
|
||||||
let module = match module_reader.compile(env) {
|
let module = match module_reader.compile(compile_options, env) {
|
||||||
Ok(module) => module,
|
Ok(module) => module,
|
||||||
Err(error) => return Err(handle_module_error(error)),
|
Err(error) => return Err(handle_module_error(error)),
|
||||||
};
|
};
|
||||||
@@ -143,11 +178,15 @@ fn run_module<P: AsRef<Path>>(
|
|||||||
fn main() -> ExitCode {
|
fn main() -> ExitCode {
|
||||||
let args = Args::parse();
|
let args = Args::parse();
|
||||||
let mut vm = Machine::default();
|
let mut vm = Machine::default();
|
||||||
|
let compile_options = CompileOptions {
|
||||||
|
trace_compile: args.trace.contains(&Trace::Compile),
|
||||||
|
};
|
||||||
|
vm.trace_instructions = args.trace.contains(&Trace::Execute);
|
||||||
let mut env = Environment::default();
|
let mut env = Environment::default();
|
||||||
prelude::load(&mut env);
|
prelude::load(&mut env);
|
||||||
let result = match args.module.as_ref() {
|
let result = match args.module.as_ref() {
|
||||||
Some(module) => run_module(&mut vm, &mut env, module),
|
Some(module) => run_module(&compile_options, &mut vm, &mut env, module),
|
||||||
None => run_interactive(&mut vm, &mut env),
|
None => run_interactive(&compile_options, &mut vm, &mut env),
|
||||||
};
|
};
|
||||||
match result {
|
match result {
|
||||||
Ok(()) => ExitCode::SUCCESS,
|
Ok(()) => ExitCode::SUCCESS,
|
||||||
|
|||||||
+8
-4
@@ -5,7 +5,9 @@ use std::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
compile::{CompilationModule, Expression, FunctionBody, FunctionSignature, ParseError},
|
compile::{
|
||||||
|
CompilationModule, CompileOptions, Expression, FunctionBody, FunctionSignature, ParseError,
|
||||||
|
},
|
||||||
error::EvalError,
|
error::EvalError,
|
||||||
parse::{self, parse_value},
|
parse::{self, parse_value},
|
||||||
util::Either,
|
util::Either,
|
||||||
@@ -106,6 +108,7 @@ impl<R: BufRead> ModuleReader<R> {
|
|||||||
|
|
||||||
pub fn read_expression(
|
pub fn read_expression(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
options: &CompileOptions,
|
||||||
env: &mut Environment,
|
env: &mut Environment,
|
||||||
) -> Result<Option<Rc<Expression>>, Either<EvalError, Vec<ParseError>>> {
|
) -> Result<Option<Rc<Expression>>, Either<EvalError, Vec<ParseError>>> {
|
||||||
loop {
|
loop {
|
||||||
@@ -117,7 +120,7 @@ impl<R: BufRead> ModuleReader<R> {
|
|||||||
let expression = Expression::parse(&value).map_err(Either::Right)?;
|
let expression = Expression::parse(&value).map_err(Either::Right)?;
|
||||||
if let Expression::Defmacro(_) = expression.as_ref() {
|
if let Expression::Defmacro(_) = expression.as_ref() {
|
||||||
self.macro_machine
|
self.macro_machine
|
||||||
.eval_value(env, value)
|
.eval_value(options.clone(), env, value)
|
||||||
.map_err(Either::Left)?;
|
.map_err(Either::Left)?;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -127,9 +130,10 @@ impl<R: BufRead> ModuleReader<R> {
|
|||||||
|
|
||||||
pub fn compile(
|
pub fn compile(
|
||||||
mut self,
|
mut self,
|
||||||
|
options: &CompileOptions,
|
||||||
env: &mut Environment,
|
env: &mut Environment,
|
||||||
) -> Result<ModuleRef, Either<EvalError, Vec<ParseError>>> {
|
) -> Result<ModuleRef, Either<EvalError, Vec<ParseError>>> {
|
||||||
let mut module = CompilationModule::default();
|
let mut module = CompilationModule::new(options.clone());
|
||||||
let mut body = FunctionBody {
|
let mut body = FunctionBody {
|
||||||
head: vec![],
|
head: vec![],
|
||||||
tail: Rc::new(Expression::Nil),
|
tail: Rc::new(Expression::Nil),
|
||||||
@@ -138,7 +142,7 @@ impl<R: BufRead> ModuleReader<R> {
|
|||||||
let mut syntax_errors = vec![];
|
let mut syntax_errors = vec![];
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let expression = match self.read_expression(env) {
|
let expression = match self.read_expression(options, env) {
|
||||||
Ok(Some(expression)) => expression,
|
Ok(Some(expression)) => expression,
|
||||||
Ok(None) => break,
|
Ok(None) => break,
|
||||||
Err(Either::Left(error)) => return Err(Either::Left(error)),
|
Err(Either::Left(error)) => return Err(Either::Left(error)),
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ pub enum Instruction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub type ConstantId = U<12>;
|
pub type ConstantId = U<12>;
|
||||||
pub type FunctionOffset = U<12>;
|
pub type FunctionOffset = U<10>;
|
||||||
pub type LocalId = U<8>;
|
pub type LocalId = U<8>;
|
||||||
pub type ArgumentId = U<6>;
|
pub type ArgumentId = U<6>;
|
||||||
pub type ArgumentCount = U<6>;
|
pub type ArgumentCount = U<6>;
|
||||||
@@ -222,7 +222,7 @@ impl TryFrom<u32> for Instruction {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::vm::instruction::U;
|
use crate::vm::instruction::{FunctionOffset, U};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_u_convert() {
|
fn test_u_convert() {
|
||||||
@@ -238,4 +238,10 @@ mod tests {
|
|||||||
let t = T::from_signed(-0x1000001);
|
let t = T::from_signed(-0x1000001);
|
||||||
assert!(t.is_none());
|
assert!(t.is_none());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_branch_target_extend() {
|
||||||
|
let target = FunctionOffset::truncate(1022);
|
||||||
|
assert_eq!(target.sign_extend_i64(), -2);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-1
@@ -1,6 +1,7 @@
|
|||||||
use std::{collections::HashMap, fmt};
|
use std::{collections::HashMap, fmt};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
compile::CompileOptions,
|
||||||
error::{EvalError, MachineError, MachineErrorKind},
|
error::{EvalError, MachineError, MachineErrorKind},
|
||||||
vm::{
|
vm::{
|
||||||
env::Environment,
|
env::Environment,
|
||||||
@@ -516,11 +517,12 @@ impl Machine {
|
|||||||
|
|
||||||
pub fn eval_value(
|
pub fn eval_value(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
compile_options: CompileOptions,
|
||||||
environment: &mut Environment,
|
environment: &mut Environment,
|
||||||
value: Value,
|
value: Value,
|
||||||
) -> Result<Value, EvalError> {
|
) -> Result<Value, EvalError> {
|
||||||
let value = value.macro_expand(self, environment, false)?;
|
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);
|
let module = ModuleRef::from(module);
|
||||||
self.eval_module(environment, module)
|
self.eval_module(environment, module)
|
||||||
}
|
}
|
||||||
|
|||||||
+14
-8
@@ -7,7 +7,10 @@ use std::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
compile::{CompilationModule, CompileError, Expression, FunctionBody, FunctionSignature},
|
compile::{
|
||||||
|
CompilationModule, CompileError, CompileOptions, Expression, FunctionBody,
|
||||||
|
FunctionSignature,
|
||||||
|
},
|
||||||
vm::{
|
vm::{
|
||||||
instruction::{ConstantId, Instruction},
|
instruction::{ConstantId, Instruction},
|
||||||
pool::Pool,
|
pool::Pool,
|
||||||
@@ -122,9 +125,9 @@ impl Module {
|
|||||||
self.entry
|
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 expression = Expression::parse(value).map_err(CompileError::Parse)?;
|
||||||
let mut module = CompilationModule::default();
|
let mut module = CompilationModule::new(options);
|
||||||
module.compile_function(
|
module.compile_function(
|
||||||
FunctionSignature::EMPTY,
|
FunctionSignature::EMPTY,
|
||||||
&FunctionBody {
|
&FunctionBody {
|
||||||
@@ -215,10 +218,13 @@ impl fmt::Display for ModuleConstant {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::vm::{
|
use crate::{
|
||||||
instruction::{Instruction, MathInstruction, U},
|
compile::CompileOptions,
|
||||||
module::Module,
|
vm::{
|
||||||
value::Value,
|
instruction::{Instruction, MathInstruction, U},
|
||||||
|
module::Module,
|
||||||
|
value::Value,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -228,7 +234,7 @@ mod tests {
|
|||||||
Value::Integer(1),
|
Value::Integer(1),
|
||||||
Value::Integer(2),
|
Value::Integer(2),
|
||||||
]);
|
]);
|
||||||
let m = Module::compile_value(&v).unwrap();
|
let m = Module::compile_value(CompileOptions::default(), &v).unwrap();
|
||||||
assert!(m.constants.is_empty());
|
assert!(m.constants.is_empty());
|
||||||
let is = [
|
let is = [
|
||||||
Instruction::PushInteger(U::truncate(2)),
|
Instruction::PushInteger(U::truncate(2)),
|
||||||
|
|||||||
@@ -102,7 +102,7 @@ pub fn load(env: &mut Environment) {
|
|||||||
[_, _] => todo!(),
|
[_, _] => todo!(),
|
||||||
_ => todo!(),
|
_ => todo!(),
|
||||||
};
|
};
|
||||||
let value = match vm.eval_value(env, value.clone()) {
|
let value = match vm.eval_value(Default::default(), env, value.clone()) {
|
||||||
Ok(result) => result,
|
Ok(result) => result,
|
||||||
_ => todo!(),
|
_ => todo!(),
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ fn eval_str_in(code: &str, env: &mut Environment) -> Result<Value, EvalError> {
|
|||||||
Err(error) => panic!("{error}"),
|
Err(error) => panic!("{error}"),
|
||||||
};
|
};
|
||||||
|
|
||||||
last_value = Some(machine.eval_value(env, value));
|
last_value = Some(machine.eval_value(Default::default(), env, value));
|
||||||
}
|
}
|
||||||
|
|
||||||
last_value.expect("no expressions evaluated")
|
last_value.expect("no expressions evaluated")
|
||||||
|
|||||||
Reference in New Issue
Block a user