Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,4 @@ r7rs.pdf
.#*
.idea
*.iml
.envrc
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ install: build
$(CARGO) install

run:
$(CARGO) run --bin bracesi
$(CARGO) run --bin bracesi -- run $(RUN_FILE)

debug_run:
$(CARGO) run --features debug_vm --features debug_code --bin bracesi -- run $(RUN_FILE)
Expand Down
1 change: 1 addition & 0 deletions examples/io.scm
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
(write-string "Hello world")
2 changes: 1 addition & 1 deletion src/cmd/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ impl Command {
clap::Command::new("run")
.alias("r")
.about("run the specified file")
.arg(arg!([INPUT]))
.arg(arg!(input: [INPUT]))
}

pub fn run(&self) -> anyhow::Result<()> {
Expand Down
2 changes: 1 addition & 1 deletion src/compiler/frontend/reader/datum/number.rs
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ fn parse_decimal_short(input: Input) -> ParseResult<f64> {
fn apply_exponent(num: f64, exp: Option<i32>) -> f64 {
match exp {
Some(e) => (num as f64) * (f64::powi(10.0, e) as f64),
_ => (num as f64),
_ => num as f64,
}
}

Expand Down
13 changes: 8 additions & 5 deletions src/repl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -177,11 +177,14 @@ impl Repl {
self.command_counter += 1;

match compiler.compile(&mut source) {
Ok(unit) => match self.vm.interpret(unit) {
Ok(Value::Unspecified) => (),
Ok(v) => println!("{}", self.vm.write(&v)),
Err(e) => self.vm.print_error(&e, &compiler),
},
Ok(unit) => {
match self.vm.interpret(unit) {
Ok(Value::Unspecified) => (),
Ok(v) => println!("{}", self.vm.write(&v)),
Err(e) => self.vm.print_error(&e, &compiler),
};
}

Err(e) => compiler.print_error(&e),
}

Expand Down
22 changes: 20 additions & 2 deletions src/vm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use scheme::writer::Writer;
pub use settings::{Setting, Settings};
use value::Value;

use self::value::port::IORegistry;
use self::value::procedure::foreign;
use self::value::procedure::native;
use crate::compiler::frontend::reader::datum::Datum;
Expand All @@ -34,21 +35,31 @@ pub mod value;

pub type Result<T> = std::result::Result<T, Error>;

#[derive(Debug)]
pub struct VM {
stack_size: usize,
pub values: value::Factory,
pub top_level: TopLevel,
pub io_resources: IORegistry,
writer: Writer,
pub settings: Settings,
}

impl std::fmt::Debug for VM {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("VM")
.field("settings", &self.settings)
.field("stack_size", &self.stack_size)
.finish()
}
}

impl VM {
pub fn new(stack_size: usize) -> VM {
VM {
stack_size,
values: value::Factory::default(),
top_level: TopLevel::new(),
io_resources: IORegistry::new(),
writer: Writer::new(),
settings: Settings::default(),
}
Expand Down Expand Up @@ -88,7 +99,13 @@ impl VM {
debug_mode: self.settings.is_enabled(&Setting::Debug),
};

Instance::interpret(unit.closure, &mut self.top_level, &mut self.values, options)
Instance::interpret(
unit.closure,
&mut self.top_level,
&mut self.values,
&mut self.io_resources,
options,
)
}

pub fn interpret_expander(
Expand All @@ -106,6 +123,7 @@ impl VM {
&form_value,
arguments,
&mut self.top_level,
&mut self.io_resources,
&mut self.values,
)?,
location,
Expand Down
3 changes: 3 additions & 0 deletions src/vm/error/reporting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@ impl<'a> ErrorReporter<'a> {
RuntimeError::OutOfBoundError(idx, accepted) => {
format!("OutOfBoudError: can't access element at index `{}`. The allowed ranged is ({}..{})", idx, accepted.start, accepted.end)
}
RuntimeError::IOError(e) => {
format!("IOError: {}", e)
}
RuntimeError::SyntaxError(msg) => {
format!("Error during macro expansion: {}", msg)
}
Expand Down
32 changes: 26 additions & 6 deletions src/vm/instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,16 @@
/// ```
/// use braces::vm::instance::{Instance, Options};
/// use braces::vm::{value, global::TopLevel, VM};
/// use braces::vm::value::port::IORegistry;
/// use braces::compiler::{source::StringSource, Compiler};
/// let mut source = StringSource::new("(define (id x) x) (id #t)");
/// let mut compiler = Compiler::new();
/// let unit = compiler.compile(&mut source).unwrap();
/// // Now interpret the unit
/// let mut top_level = TopLevel::new();
/// let mut values = value::Factory::default();
/// let result = Instance::interpret(unit.closure, &mut top_level, &mut values, Options::default()).unwrap();
/// let mut io_resources = IORegistry::new();
/// let result = Instance::interpret(unit.closure, &mut top_level, &mut values, &mut io_resources, Options::default()).unwrap();
/// println!("{:#?}", result);
/// ```
///
Expand All @@ -44,6 +46,7 @@ use super::stack_trace::StackTrace;
use super::value;
use super::value::closure::Closure;
use super::value::error;
use super::value::port::IORegistry;
use super::value::procedure::{self, Arity};
use super::value::symbol::Symbol;
use super::value::Value;
Expand Down Expand Up @@ -79,6 +82,8 @@ pub struct Instance<'a> {
pub(crate) values: &'a mut value::Factory,
// top level environment which can be shared between individual instance runs
top_level: &'a mut TopLevel,

pub(crate) io_resources: &'a mut IORegistry,
// a simple stack to manage intermediate values and locals
stack: ValueStack,
// manage all live functions
Expand All @@ -98,9 +103,10 @@ impl<'a> Instance<'a> {
initial_closure: value::closure::Closure,
top_level: &'a mut TopLevel,
values: &'a mut value::Factory,
io_resources: &'a mut IORegistry,
options: Options,
) -> Self {
let mut vm = Self::vanilla(top_level, values, options);
let mut vm = Self::vanilla(top_level, values, io_resources, options);
vm.push(Value::Closure(initial_closure.clone())).unwrap();
vm.push_frame(initial_closure, 0).unwrap();
vm
Expand All @@ -109,6 +115,7 @@ impl<'a> Instance<'a> {
pub fn vanilla(
top_level: &'a mut TopLevel,
values: &'a mut value::Factory,
io_resources: &'a mut IORegistry,
settings: Options,
) -> Self {
let stack = ValueStack::new(settings.stack_size * 255);
Expand All @@ -121,6 +128,7 @@ impl<'a> Instance<'a> {
call_stack,
top_level,
active_frame: std::ptr::null_mut(),
io_resources,
open_up_values,
settings,
}
Expand All @@ -130,9 +138,10 @@ impl<'a> Instance<'a> {
initial_closure: value::closure::Closure,
top_level: &'a mut TopLevel,
values: &'a mut value::Factory,
io_resources: &'a mut IORegistry,
options: Options,
) -> Result<Value> {
let mut instance = Self::new(initial_closure, top_level, values, options);
let mut instance = Self::new(initial_closure, top_level, values, io_resources, options);
instance.run()
}

Expand All @@ -141,9 +150,10 @@ impl<'a> Instance<'a> {
syntax: &Value,
arguments: &[Value],
top_level: &'a mut TopLevel,
io_resources: &'a mut IORegistry,
values: &'a mut value::Factory,
) -> Result<Value> {
let mut vm = Self::vanilla(top_level, values, Options::default());
let mut vm = Self::vanilla(top_level, values, io_resources, Options::default());
let is_native = expander.is_native();

vm.push(Value::Procedure(expander))?;
Expand Down Expand Up @@ -697,6 +707,7 @@ impl<'a> Instance<'a> {
arg_count: usize,
) -> Result<()> {
self.check_arity(&proc.arity, arg_count)?;
let arg_count = self.bind_arguments(&proc.arity, arg_count)?;
let arguments = self
.pop_n(arg_count)
.iter()
Expand Down Expand Up @@ -1087,6 +1098,7 @@ impl<'a> Instance<'a> {

#[cfg(test)]
mod tests {
use super::value::port::IORegistry;
use crate::vm::global::TopLevel;
use crate::vm::instance::{Instance, Options};
use crate::vm::value::access::{Access, Reference};
Expand All @@ -1097,8 +1109,10 @@ mod tests {
fn test_bind_arguments_exactly_n() -> super::Result<()> {
let mut top_level = TopLevel::new();
let mut values = Factory::default();
let mut io_resources = IORegistry::new();
let settings = Options::default();
let mut instance = Instance::vanilla(&mut top_level, &mut values, settings);
let mut instance =
Instance::vanilla(&mut top_level, &mut values, &mut io_resources, settings);

instance.push(Access::ByVal(Value::Bool(true)))?;
instance.push(Access::ByVal(Value::Bool(false)))?;
Expand All @@ -1120,9 +1134,15 @@ mod tests {
fn test_bind_arguments_rest_args() -> super::Result<()> {
let mut top_level = TopLevel::new();
let mut values = Factory::default();
let mut io_resources = IORegistry::new();
let expected_rest_args = values.proper_list(vec![Value::Bool(false), Value::Bool(false)]);

let mut instance = Instance::vanilla(&mut top_level, &mut values, Options::default());
let mut instance = Instance::vanilla(
&mut top_level,
&mut values,
&mut io_resources,
Options::default(),
);

instance.push(Access::ByVal(Value::Bool(true)))?;
instance.push(Access::ByVal(Value::Bool(false)))?;
Expand Down
2 changes: 2 additions & 0 deletions src/vm/scheme/core.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
pub mod numbers;
pub mod ports;
use super::ffi::*;
use crate::vm::instance::Instance;
use crate::vm::value::access::{Access, Reference};
Expand Down Expand Up @@ -47,6 +48,7 @@ pub fn register(vm: &mut VM) {
register_core!(vm, "gensym", gensym, Arity::Exactly(0));

numbers::register(vm);
ports::register(vm);
}

pub fn load_file(vm: &mut Instance, args: Vec<Value>) -> FunctionResult<Access<Value>> {
Expand Down
52 changes: 33 additions & 19 deletions src/vm/scheme/core/numbers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,10 +71,14 @@ macro_rules! define_fold {
pub fn $func(_vm: &mut Instance, args: Vec<Value>) -> FunctionResult<Access<Value>> {
let mut result = number::Number::fixnum($identity);

for n in args {
match n {
Value::Number(n) => result = result.$op(n)?,
v => return Err(error::argument_error(v.clone(), "is not a number")),
match rest_procedure(&args)? {
numbers => {
for n in numbers {
match n.to_owned() {
Value::Number(n) => result = result.$op(n)?,
v => return Err(error::argument_error(v, "is not a number")),
}
}
}
}

Expand All @@ -89,17 +93,22 @@ define_fold!(mul, 1, mul);
macro_rules! define_reduction {
($func:ident, $op:ident) => {
pub fn $func(_vm: &mut Instance, args: Vec<Value>) -> FunctionResult<Access<Value>> {
if let Value::Number(mut result) = args[0].clone() {
for n in args[1..].iter().cloned() {
match n {
Value::Number(n) => result = result.$op(n)?,
v => return Err(error::argument_error(v.clone(), "is not a number")),
match positional_and_rest_procedure1(&args)? {
(num @ Value::Number(_), rest) if rest.is_empty() => Ok(num.clone().into()),

(Value::Number(init), rest) => {
let mut result = init.clone();

for n in rest {
match n.to_owned() {
Value::Number(n) => result = result.$op(n)?,
v => return Err(error::argument_error(v.clone(), "is not a number")),
}
}
}

Ok(Value::Number(result).into())
} else {
return Err(error::argument_error(args[0].clone(), "is not a number"));
Ok(Value::Number(result).into())
}
(other, _) => Err(error::argument_error(other.clone(), "Expected number")),
}
}
};
Expand All @@ -113,13 +122,18 @@ macro_rules! define_ordering {
fn $func(vm: &mut Instance, args: Vec<Value>) -> FunctionResult<Access<Value>> {
let mut result = true;

for n in 0..args.len() {
if n == 0 {
result = true;
} else {
result = as_number(vm, &args[n - 1])? $op as_number(vm, &args[n])?;
match rest_procedure(&args)? {
rest => {
for n in 0..rest.len() {
if n == 0 {
result = true;
} else {
result = as_number(vm, &rest[n - 1].get_inner_ref())? $op as_number(vm, &rest[n].get_inner_ref())?;
}
}
}
}
};


Ok(Value::Bool(result).into())
}
Expand Down
Loading