From 9cf11332fa1e68d6c2b13480465f073fc2c64b1a Mon Sep 17 00:00:00 2001 From: certainty Date: Mon, 11 Jul 2022 11:34:36 +0200 Subject: [PATCH 01/13] WIP --- src/vm/value.rs | 2 ++ src/vm/value/port.rs | 7 +++++++ 2 files changed, 9 insertions(+) create mode 100644 src/vm/value/port.rs diff --git a/src/vm/value.rs b/src/vm/value.rs index 2c617fb..2941ba6 100644 --- a/src/vm/value.rs +++ b/src/vm/value.rs @@ -25,6 +25,7 @@ pub mod equality; pub mod error; pub mod list; pub mod number; +pub mod port; pub mod procedure; pub mod string; pub mod symbol; @@ -52,6 +53,7 @@ pub enum Value { ImproperList(list::List, Reference), Procedure(procedure::Procedure), Closure(closure::Closure), + Port(port::Port), Unspecified, } diff --git a/src/vm/value/port.rs b/src/vm/value/port.rs new file mode 100644 index 0000000..7ba6724 --- /dev/null +++ b/src/vm/value/port.rs @@ -0,0 +1,7 @@ +use std::io::{BufWriter, Write}; + +#[derive(Debug)] +pub enum Port { + InputPort(), + OutputPort(BufWriter), +} From f934bc9138c5ebb4c8268e76a7d361263b86cf01 Mon Sep 17 00:00:00 2001 From: certainty Date: Mon, 11 Jul 2022 12:30:39 +0200 Subject: [PATCH 02/13] Ignore .envrc --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index de87e25..fa86d38 100644 --- a/.gitignore +++ b/.gitignore @@ -19,3 +19,4 @@ r7rs.pdf .#* .idea *.iml +.envrc From 5078ca9b51bf14e9587b1549c54d6c024a8f1e97 Mon Sep 17 00:00:00 2001 From: certainty Date: Mon, 11 Jul 2022 12:54:46 +0200 Subject: [PATCH 03/13] WIP --- src/vm/value/port.rs | 42 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 39 insertions(+), 3 deletions(-) diff --git a/src/vm/value/port.rs b/src/vm/value/port.rs index 7ba6724..08488ce 100644 --- a/src/vm/value/port.rs +++ b/src/vm/value/port.rs @@ -1,7 +1,43 @@ use std::io::{BufWriter, Write}; +pub type Result = std::result::Result; + #[derive(Debug)] -pub enum Port { - InputPort(), - OutputPort(BufWriter), +pub enum Content { + Eof, + Data(T), +} + +pub trait SchemePort { + fn is_binary_port() -> bool; + fn is_textual_port() -> bool; + fn is_input_port() -> bool; +} + +pub trait BinaryOutputPort { + fn write_u8(&mut self, byte: u8) -> Result; + fn flush(&mut self) -> Result<()>; + fn close(&self) -> Result<()>; +} + +pub trait BinaryInputPort { + fn read_u8(&mut self) -> Result>; + fn peek(&self) -> Result>; + fn is_ready(&self) -> bool; + fn close(&self) -> Result<()>; +} + +pub trait TextualOutputPort { + fn write_char(&mut self, c: char) -> Result; + fn write(&mut self, buf: &str) -> Result; + fn flush(&mut self) -> Result<()>; + fn close(&self) -> Result<()>; +} + +pub trait TextualInputPort { + fn read_line(&mut self) -> Result>; + fn read_char(&mut self) -> Result>; + fn peek_char(&mut self) -> Result>; + fn is_ready(&self) -> bool; + fn close(&self) -> Result<()>; } From 477272c300b0444f7f21f7f6d29eb8a6f4879234 Mon Sep 17 00:00:00 2001 From: certainty Date: Mon, 11 Jul 2022 13:28:05 +0200 Subject: [PATCH 04/13] WIP --- src/vm/value.rs | 1 + src/vm/value/port.rs | 17 ++++++++++++----- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/vm/value.rs b/src/vm/value.rs index 2941ba6..2f099c6 100644 --- a/src/vm/value.rs +++ b/src/vm/value.rs @@ -54,6 +54,7 @@ pub enum Value { Procedure(procedure::Procedure), Closure(closure::Closure), Port(port::Port), + EofObject, Unspecified, } diff --git a/src/vm/value/port.rs b/src/vm/value/port.rs index 08488ce..ea7ffd2 100644 --- a/src/vm/value/port.rs +++ b/src/vm/value/port.rs @@ -1,4 +1,4 @@ -use std::io::{BufWriter, Write}; +use std::io::{BufWriter, Cursor, Read, Write}; pub type Result = std::result::Result; @@ -12,12 +12,11 @@ pub trait SchemePort { fn is_binary_port() -> bool; fn is_textual_port() -> bool; fn is_input_port() -> bool; + fn is_output_port() -> bool; } -pub trait BinaryOutputPort { - fn write_u8(&mut self, byte: u8) -> Result; - fn flush(&mut self) -> Result<()>; - fn close(&self) -> Result<()>; +pub trait BinaryPort { + fn u8_write>(&mut self) -> &mut O; } pub trait BinaryInputPort { @@ -41,3 +40,11 @@ pub trait TextualInputPort { fn is_ready(&self) -> bool; fn close(&self) -> Result<()>; } + +pub enum Port { + FilePort(std::fs::File), + StringInputPort(String), + StringOutputPort(Cursor), +} + +std::io::stdout() From 47745dfdc110b90be7a9651532e2889e3bfe4e28 Mon Sep 17 00:00:00 2001 From: certainty Date: Mon, 11 Jul 2022 19:25:59 +0200 Subject: [PATCH 05/13] Add port value --- src/vm/scheme/writer.rs | 6 ++ src/vm/value/port.rs | 129 ++++++++++++++++++++++++++++++---------- 2 files changed, 104 insertions(+), 31 deletions(-) diff --git a/src/vm/scheme/writer.rs b/src/vm/scheme/writer.rs index 3522787..0cd2353 100644 --- a/src/vm/scheme/writer.rs +++ b/src/vm/scheme/writer.rs @@ -77,6 +77,12 @@ impl Writer { format!("({} . {})", head_body.join(" "), tail_body) } Value::Unspecified => "#".to_string(), + Value::Port(p) if p.is_input_port() && p.is_output_port() => { + "#".to_string() + } + Value::Port(p) if p.is_input_port() => "#".to_string(), + Value::Port(_p) => "#".to_string(), + Value::EofObject => "#".to_string(), } } diff --git a/src/vm/value/port.rs b/src/vm/value/port.rs index ea7ffd2..a7e4d1b 100644 --- a/src/vm/value/port.rs +++ b/src/vm/value/port.rs @@ -1,6 +1,10 @@ -use std::io::{BufWriter, Cursor, Read, Write}; +use super::{equality::SchemeEqual, error}; +use std::{ + io::{Read, Write}, + rc::Rc, +}; -pub type Result = std::result::Result; +pub type Result = std::result::Result; #[derive(Debug)] pub enum Content { @@ -8,43 +12,106 @@ pub enum Content { Data(T), } -pub trait SchemePort { - fn is_binary_port() -> bool; - fn is_textual_port() -> bool; - fn is_input_port() -> bool; - fn is_output_port() -> bool; +#[derive(Clone, Debug, PartialEq)] +pub enum PortType { + Binary, + Textual, } -pub trait BinaryPort { - fn u8_write>(&mut self) -> &mut O; -} +pub trait ReadWrite: Read + Write {} -pub trait BinaryInputPort { - fn read_u8(&mut self) -> Result>; - fn peek(&self) -> Result>; - fn is_ready(&self) -> bool; - fn close(&self) -> Result<()>; +#[derive(Clone)] +pub enum Port { + InputPort(Rc, PortType), + OutputPort(Rc, PortType), + InputOutputPort(Rc, PortType), } -pub trait TextualOutputPort { - fn write_char(&mut self, c: char) -> Result; - fn write(&mut self, buf: &str) -> Result; - fn flush(&mut self) -> Result<()>; - fn close(&self) -> Result<()>; +impl PartialEq for Port { + fn eq(&self, other: &Self) -> bool { + match (self, other) { + (Self::InputPort(l0, l1), Self::InputPort(r0, r1)) => Rc::ptr_eq(l0, r0) && l1 == r1, + (Self::OutputPort(l0, l1), Self::OutputPort(r0, r1)) => Rc::ptr_eq(l0, r0) && l1 == r1, + (Self::InputOutputPort(l0, l1), Self::InputOutputPort(r0, r1)) => { + Rc::ptr_eq(l0, r0) && l1 == r1 + } + _ => false, + } + } } -pub trait TextualInputPort { - fn read_line(&mut self) -> Result>; - fn read_char(&mut self) -> Result>; - fn peek_char(&mut self) -> Result>; - fn is_ready(&self) -> bool; - fn close(&self) -> Result<()>; +impl std::fmt::Debug for Port { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let struct_name = match self { + Self::InputPort(_, _) => "InputPort", + Self::OutputPort(_, _) => "OutputPort", + _ => "InputOutputPort", + }; + + f.debug_struct(struct_name) + .field("type", &self.port_type()) + .finish() + } } -pub enum Port { - FilePort(std::fs::File), - StringInputPort(String), - StringOutputPort(Cursor), +impl SchemeEqual for Port { + fn is_eq(&self, other: &Port) -> bool { + self == other + } + + fn is_eqv(&self, other: &Port) -> bool { + self == other + } + + fn is_equal(&self, other: &Port) -> bool { + self == other + } } -std::io::stdout() +impl Port { + pub fn stdout() -> Self { + Self::OutputPort(Rc::new(std::io::stdout()), PortType::Textual) + } + + pub fn stderr() -> Self { + Self::OutputPort(Rc::new(std::io::stderr()), PortType::Textual) + } + + pub fn stdin() -> Self { + Self::InputPort(Rc::new(std::io::stdin()), PortType::Textual) + } + + pub fn is_output_port(&self) -> bool { + match self { + Self::InputPort(_, _) => false, + _ => true, + } + } + + pub fn is_input_port(&self) -> bool { + match self { + Self::InputPort(_, _) => true, + Self::InputOutputPort(_, _) => true, + _ => false, + } + } + + pub fn is_textual(&self) -> bool { + match self.port_type() { + PortType::Binary => false, + _ => true, + } + } + + pub fn is_binary(&self) -> bool { + !self.is_textual() + } + + fn port_type(&self) -> &PortType { + match &self { + Self::InputPort(_, tpe) => tpe, + Self::OutputPort(_, tpe) => tpe, + Self::InputOutputPort(_, tpe) => tpe, + } + } +} From 0c16dc9cb090cf6d1fb6343a0e02225fd870b990 Mon Sep 17 00:00:00 2001 From: certainty Date: Mon, 11 Jul 2022 20:47:50 +0200 Subject: [PATCH 06/13] start to implement port procedures --- src/vm/scheme/core.rs | 2 ++ src/vm/scheme/core/ports.rs | 62 +++++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+) create mode 100644 src/vm/scheme/core/ports.rs diff --git a/src/vm/scheme/core.rs b/src/vm/scheme/core.rs index 85e65b7..cd5b2be 100644 --- a/src/vm/scheme/core.rs +++ b/src/vm/scheme/core.rs @@ -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}; @@ -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) -> FunctionResult> { diff --git a/src/vm/scheme/core/ports.rs b/src/vm/scheme/core/ports.rs new file mode 100644 index 0000000..feb7ce1 --- /dev/null +++ b/src/vm/scheme/core/ports.rs @@ -0,0 +1,62 @@ +use crate::vm::scheme::ffi::*; +use crate::vm::value::access::Access; +use crate::vm::value::port::Port; +use crate::vm::value::procedure::foreign; +use crate::vm::value::procedure::Arity; +use crate::vm::value::{error, Value}; +use crate::vm::Instance; +use crate::vm::VM; + +pub fn register(vm: &mut VM) { + super::register_core!(vm, "port?", port_p, Arity::Exactly(1)); + super::register_core!( + vm, + "current-input-port", + current_input_port, + Arity::Exactly(0) + ); + super::register_core!( + vm, + "current-output-port", + current_output_port, + Arity::Exactly(0) + ); + super::register_core!( + vm, + "current-error-port", + current_error_port, + Arity::Exactly(0) + ); +} + +fn port_p(_vm: &mut Instance, args: Vec) -> FunctionResult> { + match unary_procedure(&args)? { + Value::Port(_) => Ok(Value::Bool(true).into()), + _ => Ok(Value::Bool(false).into()), + } +} + +// TODO: return srfi-parameter value +fn current_input_port(_vm: &mut Instance, args: Vec) -> FunctionResult> { + if args.len() != 0 { + return Err(error::arity_mismatch(Arity::Exactly(0), args.len())); + } + + Ok(Value::Port(Port::stdin()).into()) +} + +fn current_output_port(_vm: &mut Instance, args: Vec) -> FunctionResult> { + if args.len() != 0 { + return Err(error::arity_mismatch(Arity::Exactly(0), args.len())); + } + + Ok(Value::Port(Port::stdout()).into()) +} + +fn current_error_port(_vm: &mut Instance, args: Vec) -> FunctionResult> { + if args.len() != 0 { + return Err(error::arity_mismatch(Arity::Exactly(0), args.len())); + } + + Ok(Value::Port(Port::stderr()).into()) +} From 3e082b14b8d4f9e53bd5a65e9ad9868ccda2dc72 Mon Sep 17 00:00:00 2001 From: certainty Date: Thu, 21 Jul 2022 12:14:55 +0200 Subject: [PATCH 07/13] WIP --- src/vm.rs | 22 ++++++- src/vm/error/reporting.rs | 3 + src/vm/instance.rs | 14 +++- src/vm/scheme/core/ports.rs | 9 ++- src/vm/scheme/ffi.rs | 28 ++++++++ src/vm/scheme/writer.rs | 6 +- src/vm/value/error.rs | 2 + src/vm/value/port.rs | 124 ++++++++++++++---------------------- src/vm/value/vector.rs | 4 ++ 9 files changed, 122 insertions(+), 90 deletions(-) diff --git a/src/vm.rs b/src/vm.rs index 83e1c62..5d04f34 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -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; @@ -34,21 +35,31 @@ pub mod value; pub type Result = std::result::Result; -#[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(), } @@ -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( @@ -106,6 +123,7 @@ impl VM { &form_value, arguments, &mut self.top_level, + &mut self.io_resources, &mut self.values, )?, location, diff --git a/src/vm/error/reporting.rs b/src/vm/error/reporting.rs index a2f94d7..e6e8504 100644 --- a/src/vm/error/reporting.rs +++ b/src/vm/error/reporting.rs @@ -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) } diff --git a/src/vm/instance.rs b/src/vm/instance.rs index 173a356..4a50b73 100644 --- a/src/vm/instance.rs +++ b/src/vm/instance.rs @@ -44,6 +44,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; @@ -79,6 +80,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, + + io_resources: &'a mut IORegistry, // a simple stack to manage intermediate values and locals stack: ValueStack, // manage all live functions @@ -98,9 +101,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 @@ -109,6 +113,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); @@ -121,6 +126,7 @@ impl<'a> Instance<'a> { call_stack, top_level, active_frame: std::ptr::null_mut(), + io_resources, open_up_values, settings, } @@ -130,9 +136,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 { - 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() } @@ -141,9 +148,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 { - 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))?; diff --git a/src/vm/scheme/core/ports.rs b/src/vm/scheme/core/ports.rs index feb7ce1..35ec102 100644 --- a/src/vm/scheme/core/ports.rs +++ b/src/vm/scheme/core/ports.rs @@ -21,12 +21,15 @@ pub fn register(vm: &mut VM) { current_output_port, Arity::Exactly(0) ); + super::register_core!( vm, "current-error-port", current_error_port, Arity::Exactly(0) ); + + //super::register_core!(vm, "write-char", write_char, Arity::AtLeast(1)) } fn port_p(_vm: &mut Instance, args: Vec) -> FunctionResult> { @@ -42,7 +45,7 @@ fn current_input_port(_vm: &mut Instance, args: Vec) -> FunctionResult) -> FunctionResult> { @@ -50,7 +53,7 @@ fn current_output_port(_vm: &mut Instance, args: Vec) -> FunctionResult) -> FunctionResult> { @@ -58,5 +61,5 @@ fn current_error_port(_vm: &mut Instance, args: Vec) -> FunctionResult) -> FunctionResult<&Value> { _ => Err(error::arity_mismatch(Arity::Exactly(1), args.len())), } } + +pub fn positional_and_rest_procedure1( + args: &Vec, +) -> FunctionResult<(&Value, &[Reference])> { + match &args[..] { + [first, Value::Vector(rest)] => Ok((first, &rest.slice())), + _ => Err(error::arity_mismatch(Arity::AtLeast(1), args.len())), + } +} + +pub fn positional_and_rest_procedure2( + args: &Vec, +) -> FunctionResult<(&Value, &Value, &[Reference])> { + match &args[..] { + [first, second, Value::Vector(rest)] => Ok((first, second, &rest.slice())), + _ => Err(error::arity_mismatch(Arity::AtLeast(2), args.len())), + } +} + +pub fn positional_and_rest_procedure3( + args: &Vec, +) -> FunctionResult<(&Value, &Value, &Value, &[Reference])> { + match &args[..] { + [first, second, third, Value::Vector(rest)] => Ok((first, second, third, &rest.slice())), + _ => Err(error::arity_mismatch(Arity::AtLeast(3), args.len())), + } +} diff --git a/src/vm/scheme/writer.rs b/src/vm/scheme/writer.rs index 0cd2353..35cde53 100644 --- a/src/vm/scheme/writer.rs +++ b/src/vm/scheme/writer.rs @@ -77,11 +77,7 @@ impl Writer { format!("({} . {})", head_body.join(" "), tail_body) } Value::Unspecified => "#".to_string(), - Value::Port(p) if p.is_input_port() && p.is_output_port() => { - "#".to_string() - } - Value::Port(p) if p.is_input_port() => "#".to_string(), - Value::Port(_p) => "#".to_string(), + Value::Port(p) => format!("#", p), Value::EofObject => "#".to_string(), } } diff --git a/src/vm/value/error.rs b/src/vm/value/error.rs index d1c2fce..1a74980 100644 --- a/src/vm/value/error.rs +++ b/src/vm/value/error.rs @@ -20,6 +20,8 @@ pub enum RuntimeError { SyntaxError(String), #[error("LoadError")] LoadError(std::path::PathBuf, Box), + #[error(transparent)] + IOError(#[from] std::io::Error), } pub fn load_error(file: std::path::PathBuf, e: crate::vm::Error) -> RuntimeError { diff --git a/src/vm/value/port.rs b/src/vm/value/port.rs index a7e4d1b..8b041b3 100644 --- a/src/vm/value/port.rs +++ b/src/vm/value/port.rs @@ -1,17 +1,15 @@ +use rustc_hash::FxHashMap; + use super::{equality::SchemeEqual, error}; use std::{ - io::{Read, Write}, + cell::RefCell, + io::Read, + io::{Stdin, Stdout, Write}, rc::Rc, }; pub type Result = std::result::Result; -#[derive(Debug)] -pub enum Content { - Eof, - Data(T), -} - #[derive(Clone, Debug, PartialEq)] pub enum PortType { Binary, @@ -20,37 +18,57 @@ pub enum PortType { pub trait ReadWrite: Read + Write {} -#[derive(Clone)] -pub enum Port { - InputPort(Rc, PortType), - OutputPort(Rc, PortType), - InputOutputPort(Rc, PortType), +#[derive(Debug)] +pub struct OutputPort { + underlying: Rc>, +} + +#[derive(Debug)] +pub struct InputPort { + underlying: Rc>, +} + +// holds references to input and output facilitys +#[repr(transparent)] +pub struct IORegistry(FxHashMap); + +impl IORegistry { + pub fn new() -> Self { + Self(FxHashMap::default()) + } +} + +pub enum IOEntry { + Stdout(Rc>), + Stdin(Rc>), } -impl PartialEq for Port { - fn eq(&self, other: &Self) -> bool { - match (self, other) { - (Self::InputPort(l0, l1), Self::InputPort(r0, r1)) => Rc::ptr_eq(l0, r0) && l1 == r1, - (Self::OutputPort(l0, l1), Self::OutputPort(r0, r1)) => Rc::ptr_eq(l0, r0) && l1 == r1, - (Self::InputOutputPort(l0, l1), Self::InputOutputPort(r0, r1)) => { - Rc::ptr_eq(l0, r0) && l1 == r1 - } - _ => false, - } +#[derive(PartialEq, Eq, Debug, Clone, Hash)] +pub enum IOKey { + Stdin, + Stdout, + Uri(String), +} + +#[derive(Clone, PartialEq)] +#[repr(transparent)] +pub struct Port(IOKey); + +impl Port { + pub fn write_char(&mut self, c: &char) -> Result { + todo!() } } impl std::fmt::Debug for Port { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let struct_name = match self { - Self::InputPort(_, _) => "InputPort", - Self::OutputPort(_, _) => "OutputPort", - _ => "InputOutputPort", + let struct_name = match &self.0 { + IOKey::Stdin => "StdinPort".to_string(), + IOKey::Stdout => "StdoutPort".to_string(), + IOKey::Uri(uri) => format!("{}", uri), }; - f.debug_struct(struct_name) - .field("type", &self.port_type()) - .finish() + f.debug_struct(&struct_name).finish() } } @@ -67,51 +85,3 @@ impl SchemeEqual for Port { self == other } } - -impl Port { - pub fn stdout() -> Self { - Self::OutputPort(Rc::new(std::io::stdout()), PortType::Textual) - } - - pub fn stderr() -> Self { - Self::OutputPort(Rc::new(std::io::stderr()), PortType::Textual) - } - - pub fn stdin() -> Self { - Self::InputPort(Rc::new(std::io::stdin()), PortType::Textual) - } - - pub fn is_output_port(&self) -> bool { - match self { - Self::InputPort(_, _) => false, - _ => true, - } - } - - pub fn is_input_port(&self) -> bool { - match self { - Self::InputPort(_, _) => true, - Self::InputOutputPort(_, _) => true, - _ => false, - } - } - - pub fn is_textual(&self) -> bool { - match self.port_type() { - PortType::Binary => false, - _ => true, - } - } - - pub fn is_binary(&self) -> bool { - !self.is_textual() - } - - fn port_type(&self) -> &PortType { - match &self { - Self::InputPort(_, tpe) => tpe, - Self::OutputPort(_, tpe) => tpe, - Self::InputOutputPort(_, tpe) => tpe, - } - } -} diff --git a/src/vm/value/vector.rs b/src/vm/value/vector.rs index f70c79b..d241667 100644 --- a/src/vm/value/vector.rs +++ b/src/vm/value/vector.rs @@ -27,6 +27,10 @@ impl Vector { Vector::from(new_vec) } + pub fn slice(&self) -> &[Reference] { + &self.0 + } + #[inline] pub fn len(&self) -> usize { self.0.len() From a6ebf301390f7a272be1ba266af32d4ce822c347 Mon Sep 17 00:00:00 2001 From: certainty Date: Thu, 21 Jul 2022 12:17:51 +0200 Subject: [PATCH 08/13] WIP --- src/vm/scheme/core/ports.rs | 4 ++-- src/vm/value/port.rs | 12 ++++++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/vm/scheme/core/ports.rs b/src/vm/scheme/core/ports.rs index 35ec102..bcfeef5 100644 --- a/src/vm/scheme/core/ports.rs +++ b/src/vm/scheme/core/ports.rs @@ -45,7 +45,7 @@ fn current_input_port(_vm: &mut Instance, args: Vec) -> FunctionResult) -> FunctionResult> { @@ -53,7 +53,7 @@ fn current_output_port(_vm: &mut Instance, args: Vec) -> FunctionResult) -> FunctionResult> { diff --git a/src/vm/value/port.rs b/src/vm/value/port.rs index 8b041b3..5c098b8 100644 --- a/src/vm/value/port.rs +++ b/src/vm/value/port.rs @@ -58,13 +58,21 @@ impl Port { pub fn write_char(&mut self, c: &char) -> Result { todo!() } + + pub fn stdin() -> Self { + Self(IOKey::Stdin) + } + + pub fn stdout() -> Self { + Self(IOKey::Stdout) + } } impl std::fmt::Debug for Port { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let struct_name = match &self.0 { - IOKey::Stdin => "StdinPort".to_string(), - IOKey::Stdout => "StdoutPort".to_string(), + IOKey::Stdin => "stdin".to_string(), + IOKey::Stdout => "stdout".to_string(), IOKey::Uri(uri) => format!("{}", uri), }; From 35c7124b17e81e7c80f6670c7793aeb0e3f096d6 Mon Sep 17 00:00:00 2001 From: certainty Date: Thu, 21 Jul 2022 12:59:04 +0200 Subject: [PATCH 09/13] WIP --- src/vm/instance.rs | 3 ++- src/vm/scheme/core/ports.rs | 20 +++++++++++++++++++- src/vm/scheme/ffi.rs | 10 +++++++--- src/vm/value/list.rs | 7 +++++++ src/vm/value/port.rs | 34 ++++++++++++++++++++++++++++++++-- 5 files changed, 67 insertions(+), 7 deletions(-) diff --git a/src/vm/instance.rs b/src/vm/instance.rs index 4a50b73..8d83b97 100644 --- a/src/vm/instance.rs +++ b/src/vm/instance.rs @@ -81,7 +81,7 @@ pub struct Instance<'a> { // top level environment which can be shared between individual instance runs top_level: &'a mut TopLevel, - io_resources: &'a mut IORegistry, + pub(crate) io_resources: &'a mut IORegistry, // a simple stack to manage intermediate values and locals stack: ValueStack, // manage all live functions @@ -705,6 +705,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() diff --git a/src/vm/scheme/core/ports.rs b/src/vm/scheme/core/ports.rs index bcfeef5..89c91b4 100644 --- a/src/vm/scheme/core/ports.rs +++ b/src/vm/scheme/core/ports.rs @@ -6,6 +6,7 @@ use crate::vm::value::procedure::Arity; use crate::vm::value::{error, Value}; use crate::vm::Instance; use crate::vm::VM; +use std::io::Write; pub fn register(vm: &mut VM) { super::register_core!(vm, "port?", port_p, Arity::Exactly(1)); @@ -29,7 +30,7 @@ pub fn register(vm: &mut VM) { Arity::Exactly(0) ); - //super::register_core!(vm, "write-char", write_char, Arity::AtLeast(1)) + super::register_core!(vm, "write-char", write_char, Arity::AtLeast(1)) } fn port_p(_vm: &mut Instance, args: Vec) -> FunctionResult> { @@ -63,3 +64,20 @@ fn current_error_port(_vm: &mut Instance, args: Vec) -> FunctionResult) -> FunctionResult> { + match positional_and_rest_procedure1(&args)? { + (Value::Char(c), r) if r.is_empty() => { + vm.io_resources + .stdout() + .borrow_mut() + .write(c.encode_utf8(&mut [0; 4]).as_bytes())?; + Ok(Value::Unspecified.into()) + } + (c, r) => todo!(), + other => { + println!("other: {:?}", other); + Err(error::arity_mismatch(Arity::AtLeast(1), args.len())) + } + } +} diff --git a/src/vm/scheme/ffi.rs b/src/vm/scheme/ffi.rs index e6a649f..917cc57 100644 --- a/src/vm/scheme/ffi.rs +++ b/src/vm/scheme/ffi.rs @@ -49,10 +49,14 @@ pub fn unary_procedure(args: &Vec) -> FunctionResult<&Value> { pub fn positional_and_rest_procedure1( args: &Vec, -) -> FunctionResult<(&Value, &[Reference])> { +) -> FunctionResult<(&Value, Vec>)> { match &args[..] { - [first, Value::Vector(rest)] => Ok((first, &rest.slice())), - _ => Err(error::arity_mismatch(Arity::AtLeast(1), args.len())), + [first, Value::ProperList(rest)] => Ok((first, rest.to_vector())), + + other => { + println!("other: {:?}", other); + Err(error::arity_mismatch(Arity::AtLeast(1), args.len())) + } } } diff --git a/src/vm/value/list.rs b/src/vm/value/list.rs index 5c5665a..1510601 100644 --- a/src/vm/value/list.rs +++ b/src/vm/value/list.rs @@ -33,6 +33,13 @@ impl List { } } + pub fn to_vector(&self) -> Vec> { + match self { + Self::Nil => Vec::new(), + Self::Cons(inner) => inner.iter().cloned().collect(), + } + } + // create a fresh list by concateneting the two supplied lists pub fn append(lhs: &List, rhs: &List) -> List { match (lhs, rhs) { diff --git a/src/vm/value/port.rs b/src/vm/value/port.rs index 5c098b8..e4fa2eb 100644 --- a/src/vm/value/port.rs +++ b/src/vm/value/port.rs @@ -4,7 +4,7 @@ use super::{equality::SchemeEqual, error}; use std::{ cell::RefCell, io::Read, - io::{Stdin, Stdout, Write}, + io::{Stderr, Stdin, Stdout, Write}, rc::Rc, }; @@ -34,19 +34,48 @@ pub struct IORegistry(FxHashMap); impl IORegistry { pub fn new() -> Self { - Self(FxHashMap::default()) + let mut map = FxHashMap::default(); + + map.insert(IOKey::Stdin, IOEntry::stdin()); + map.insert(IOKey::Stdout, IOEntry::stdout()); + map.insert(IOKey::Stderr, IOEntry::stderr()); + + Self(map) + } + + pub fn stdout(&mut self) -> &mut Rc> { + match self.0.get_mut(&IOKey::Stdout).unwrap() { + IOEntry::Stdout(inner) => inner, + _ => unreachable!(), + } } } pub enum IOEntry { Stdout(Rc>), Stdin(Rc>), + Stderr(Rc>), +} + +impl IOEntry { + pub fn stdin() -> Self { + Self::Stdin(Rc::new(RefCell::new(std::io::stdin()))) + } + + pub fn stdout() -> Self { + Self::Stdout(Rc::new(RefCell::new(std::io::stdout()))) + } + + pub fn stderr() -> Self { + Self::Stderr(Rc::new(RefCell::new(std::io::stderr()))) + } } #[derive(PartialEq, Eq, Debug, Clone, Hash)] pub enum IOKey { Stdin, Stdout, + Stderr, Uri(String), } @@ -73,6 +102,7 @@ impl std::fmt::Debug for Port { let struct_name = match &self.0 { IOKey::Stdin => "stdin".to_string(), IOKey::Stdout => "stdout".to_string(), + IOKey::Stderr => "stderr".to_string(), IOKey::Uri(uri) => format!("{}", uri), }; From 98c94530266807f3871e2ad6cb5ed722ac4d6fb6 Mon Sep 17 00:00:00 2001 From: certainty Date: Sat, 5 Nov 2022 12:27:31 +0100 Subject: [PATCH 10/13] Make tests compile --- src/vm/instance.rs | 13 +++++++++++-- src/vm/scheme/core/ports.rs | 36 +++++++++++++++++++++++++++++++----- src/vm/scheme/ffi.rs | 12 +++++++++++- 3 files changed, 53 insertions(+), 8 deletions(-) diff --git a/src/vm/instance.rs b/src/vm/instance.rs index 8d83b97..0f79d07 100644 --- a/src/vm/instance.rs +++ b/src/vm/instance.rs @@ -1096,6 +1096,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}; @@ -1106,8 +1107,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)))?; @@ -1129,9 +1132,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)))?; diff --git a/src/vm/scheme/core/ports.rs b/src/vm/scheme/core/ports.rs index 89c91b4..ab71181 100644 --- a/src/vm/scheme/core/ports.rs +++ b/src/vm/scheme/core/ports.rs @@ -30,7 +30,9 @@ pub fn register(vm: &mut VM) { Arity::Exactly(0) ); - super::register_core!(vm, "write-char", write_char, Arity::AtLeast(1)) + super::register_core!(vm, "write-char", write_char, Arity::AtLeast(1)); + super::register_core!(vm, "write-string", write_string, Arity::AtLeast(1)); + super::register_core!(vm, "flush-output-port", flush_port, Arity::AtLeast(0)); } fn port_p(_vm: &mut Instance, args: Vec) -> FunctionResult> { @@ -68,10 +70,8 @@ fn current_error_port(_vm: &mut Instance, args: Vec) -> FunctionResult) -> FunctionResult> { match positional_and_rest_procedure1(&args)? { (Value::Char(c), r) if r.is_empty() => { - vm.io_resources - .stdout() - .borrow_mut() - .write(c.encode_utf8(&mut [0; 4]).as_bytes())?; + let mut stdout = vm.io_resources.stdout().borrow_mut(); + stdout.write_all(c.encode_utf8(&mut [0; 4]).as_bytes())?; Ok(Value::Unspecified.into()) } (c, r) => todo!(), @@ -81,3 +81,29 @@ fn write_char(vm: &mut Instance, args: Vec) -> FunctionResult) -> FunctionResult> { + match positional_and_rest_procedure1(&args)? { + (Value::String(s), r) if r.is_empty() => { + let mut stdout = vm.io_resources.stdout().borrow_mut(); + stdout.write_all((&s.as_ref()).as_bytes())?; + Ok(Value::Unspecified.into()) + } + (c, r) => todo!(), + other => { + println!("other: {:?}", other); + Err(error::arity_mismatch(Arity::AtLeast(1), args.len())) + } + } +} + +fn flush_port(vm: &mut Instance, args: Vec) -> FunctionResult> { + match optional_unary_procedure(&args)? { + None => { + vm.io_resources.stdout().borrow_mut().flush()?; + Ok(Value::Unspecified.into()) + } + Some(v) => todo!(), + _ => todo!(), + } +} diff --git a/src/vm/scheme/ffi.rs b/src/vm/scheme/ffi.rs index 917cc57..76fc5fd 100644 --- a/src/vm/scheme/ffi.rs +++ b/src/vm/scheme/ffi.rs @@ -1,4 +1,4 @@ -use crate::vm::value::access::Reference; +use crate::vm::value::access::{Access, Reference}; use crate::vm::value::Value; use crate::vm::value::{error, procedure::Arity}; use thiserror::Error; @@ -47,6 +47,16 @@ pub fn unary_procedure(args: &Vec) -> FunctionResult<&Value> { } } +pub fn optional_unary_procedure(args: &Vec) -> FunctionResult>> { + match &args[..] { + [Value::ProperList(rest)] => Ok(rest.to_vector().get(0).cloned()), + other => { + println!("other: {:?}", other); + Err(error::arity_mismatch(Arity::AtLeast(0), args.len())) + } + } +} + pub fn positional_and_rest_procedure1( args: &Vec, ) -> FunctionResult<(&Value, Vec>)> { From 47550ced811421f25a68d02fc4bdac12ca4d2689 Mon Sep 17 00:00:00 2001 From: certainty Date: Sat, 5 Nov 2022 13:26:30 +0100 Subject: [PATCH 11/13] All tests green --- examples/io.scm | 1 + src/vm/instance.rs | 4 ++- src/vm/scheme/core/numbers.rs | 52 ++++++++++++++++++++++------------- src/vm/scheme/ffi.rs | 17 ++---------- 4 files changed, 40 insertions(+), 34 deletions(-) create mode 100644 examples/io.scm diff --git a/examples/io.scm b/examples/io.scm new file mode 100644 index 0000000..1592fea --- /dev/null +++ b/examples/io.scm @@ -0,0 +1 @@ + (begin (write-char #) (write-char #) (write-char # \ No newline at end of file diff --git a/src/vm/instance.rs b/src/vm/instance.rs index 0f79d07..f04d978 100644 --- a/src/vm/instance.rs +++ b/src/vm/instance.rs @@ -16,6 +16,7 @@ /// ``` /// 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(); @@ -23,7 +24,8 @@ /// // 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); /// ``` /// diff --git a/src/vm/scheme/core/numbers.rs b/src/vm/scheme/core/numbers.rs index 9280683..f5c6885 100644 --- a/src/vm/scheme/core/numbers.rs +++ b/src/vm/scheme/core/numbers.rs @@ -71,10 +71,14 @@ macro_rules! define_fold { pub fn $func(_vm: &mut Instance, args: Vec) -> FunctionResult> { 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")), + } + } } } @@ -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) -> FunctionResult> { - 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")), } } }; @@ -113,13 +122,18 @@ macro_rules! define_ordering { fn $func(vm: &mut Instance, args: Vec) -> FunctionResult> { 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()) } diff --git a/src/vm/scheme/ffi.rs b/src/vm/scheme/ffi.rs index 76fc5fd..a8aefa2 100644 --- a/src/vm/scheme/ffi.rs +++ b/src/vm/scheme/ffi.rs @@ -70,20 +70,9 @@ pub fn positional_and_rest_procedure1( } } -pub fn positional_and_rest_procedure2( - args: &Vec, -) -> FunctionResult<(&Value, &Value, &[Reference])> { - match &args[..] { - [first, second, Value::Vector(rest)] => Ok((first, second, &rest.slice())), - _ => Err(error::arity_mismatch(Arity::AtLeast(2), args.len())), - } -} - -pub fn positional_and_rest_procedure3( - args: &Vec, -) -> FunctionResult<(&Value, &Value, &Value, &[Reference])> { +pub fn rest_procedure(args: &Vec) -> FunctionResult>> { match &args[..] { - [first, second, third, Value::Vector(rest)] => Ok((first, second, third, &rest.slice())), - _ => Err(error::arity_mismatch(Arity::AtLeast(3), args.len())), + [Value::ProperList(rest_args)] => Ok(rest_args.to_vector()), + _ => Err(error::arity_mismatch(Arity::Many, args.len())), } } From 6e61092b3513616cae27776985424dc137198e52 Mon Sep 17 00:00:00 2001 From: certainty Date: Sat, 5 Nov 2022 13:35:15 +0100 Subject: [PATCH 12/13] Example program works --- Makefile | 2 +- examples/io.scm | 2 +- src/cmd/run.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index a431af0..fd4b3b1 100644 --- a/Makefile +++ b/Makefile @@ -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) diff --git a/examples/io.scm b/examples/io.scm index 1592fea..06ca8ca 100644 --- a/examples/io.scm +++ b/examples/io.scm @@ -1 +1 @@ - (begin (write-char #) (write-char #) (write-char # \ No newline at end of file + (write-string "Hello world") diff --git a/src/cmd/run.rs b/src/cmd/run.rs index 5f50004..5b07043 100644 --- a/src/cmd/run.rs +++ b/src/cmd/run.rs @@ -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<()> { From ed9ec7d6a918cda9041e58f7ddf4c97a3c6b8202 Mon Sep 17 00:00:00 2001 From: certainty Date: Sat, 5 Nov 2022 17:03:17 +0100 Subject: [PATCH 13/13] WIP --- src/compiler/frontend/reader/datum/number.rs | 2 +- src/repl.rs | 13 ++++--- src/vm/scheme/core/ports.rs | 12 +++---- src/vm/scheme/ffi.rs | 2 +- src/vm/value/port.rs | 38 ++++++++++---------- 5 files changed, 33 insertions(+), 34 deletions(-) diff --git a/src/compiler/frontend/reader/datum/number.rs b/src/compiler/frontend/reader/datum/number.rs index dfdd049..de08b3a 100644 --- a/src/compiler/frontend/reader/datum/number.rs +++ b/src/compiler/frontend/reader/datum/number.rs @@ -197,7 +197,7 @@ fn parse_decimal_short(input: Input) -> ParseResult { fn apply_exponent(num: f64, exp: Option) -> f64 { match exp { Some(e) => (num as f64) * (f64::powi(10.0, e) as f64), - _ => (num as f64), + _ => num as f64, } } diff --git a/src/repl.rs b/src/repl.rs index 96f92ed..a2adddb 100644 --- a/src/repl.rs +++ b/src/repl.rs @@ -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), } diff --git a/src/vm/scheme/core/ports.rs b/src/vm/scheme/core/ports.rs index ab71181..f92bd42 100644 --- a/src/vm/scheme/core/ports.rs +++ b/src/vm/scheme/core/ports.rs @@ -74,7 +74,7 @@ fn write_char(vm: &mut Instance, args: Vec) -> FunctionResult todo!(), + (Value::Char(c), r) => todo!(), other => { println!("other: {:?}", other); Err(error::arity_mismatch(Arity::AtLeast(1), args.len())) @@ -89,11 +89,8 @@ fn write_string(vm: &mut Instance, args: Vec) -> FunctionResult todo!(), - other => { - println!("other: {:?}", other); - Err(error::arity_mismatch(Arity::AtLeast(1), args.len())) - } + (Value::String(_s), _r) => todo!(), + (other, _) => Err(error::argument_error(other.clone(), "Expected String")), } } @@ -103,7 +100,6 @@ fn flush_port(vm: &mut Instance, args: Vec) -> FunctionResult todo!(), - _ => todo!(), + Some(_v) => todo!(), } } diff --git a/src/vm/scheme/ffi.rs b/src/vm/scheme/ffi.rs index a8aefa2..a128989 100644 --- a/src/vm/scheme/ffi.rs +++ b/src/vm/scheme/ffi.rs @@ -1,4 +1,4 @@ -use crate::vm::value::access::{Access, Reference}; +use crate::vm::value::access::Reference; use crate::vm::value::Value; use crate::vm::value::{error, procedure::Arity}; use thiserror::Error; diff --git a/src/vm/value/port.rs b/src/vm/value/port.rs index e4fa2eb..cd4b311 100644 --- a/src/vm/value/port.rs +++ b/src/vm/value/port.rs @@ -3,8 +3,7 @@ use rustc_hash::FxHashMap; use super::{equality::SchemeEqual, error}; use std::{ cell::RefCell, - io::Read, - io::{Stderr, Stdin, Stdout, Write}, + io::{Stderr, Stdin, Stdout}, rc::Rc, }; @@ -16,19 +15,6 @@ pub enum PortType { Textual, } -pub trait ReadWrite: Read + Write {} - -#[derive(Debug)] -pub struct OutputPort { - underlying: Rc>, -} - -#[derive(Debug)] -pub struct InputPort { - underlying: Rc>, -} - -// holds references to input and output facilitys #[repr(transparent)] pub struct IORegistry(FxHashMap); @@ -49,6 +35,20 @@ impl IORegistry { _ => unreachable!(), } } + + pub fn stderr(&mut self) -> &mut Rc> { + match self.0.get_mut(&IOKey::Stderr).unwrap() { + IOEntry::Stderr(inner) => inner, + _ => unreachable!(), + } + } + + pub fn stdin(&mut self) -> &mut Rc> { + match self.0.get_mut(&IOKey::Stdin).unwrap() { + IOEntry::Stdin(inner) => inner, + _ => unreachable!(), + } + } } pub enum IOEntry { @@ -84,10 +84,6 @@ pub enum IOKey { pub struct Port(IOKey); impl Port { - pub fn write_char(&mut self, c: &char) -> Result { - todo!() - } - pub fn stdin() -> Self { Self(IOKey::Stdin) } @@ -95,6 +91,10 @@ impl Port { pub fn stdout() -> Self { Self(IOKey::Stdout) } + + pub fn stderr() -> Self { + Self(IOKey::Stderr) + } } impl std::fmt::Debug for Port {