WIP: I/O
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
;; vi:ft=lisp:sw=2:ts=2
|
||||
|
||||
(let (f (fopen (car *args*)))
|
||||
(fwrite (fread f))
|
||||
)
|
||||
+19
-1
@@ -9,7 +9,7 @@ use crate::{
|
||||
syntax::{
|
||||
CallExpression, CondExpression, DefmacroExpression, DefunExpression, Expression,
|
||||
FunctionBody, IfExpression, LambdaExpression, LetExpression, LoopExpression,
|
||||
PrognExpression, SetqExpression, WhileExpression,
|
||||
PrognExpression, SetqExpression, VectorExpression, WhileExpression,
|
||||
},
|
||||
value::{BuiltinFunction, CompileConstant, CompileValue},
|
||||
},
|
||||
@@ -625,6 +625,23 @@ impl<'a> LocalBlock<'a> {
|
||||
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>,
|
||||
@@ -638,6 +655,7 @@ 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::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),
|
||||
|
||||
@@ -10,6 +10,7 @@ mod function;
|
||||
mod lambda;
|
||||
mod loops;
|
||||
mod macros;
|
||||
mod vector;
|
||||
|
||||
pub use binding::*;
|
||||
pub use call::*;
|
||||
@@ -19,6 +20,7 @@ pub use function::*;
|
||||
pub use lambda::*;
|
||||
pub use loops::*;
|
||||
pub use macros::*;
|
||||
pub use vector::*;
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum Expression {
|
||||
@@ -40,6 +42,7 @@ pub enum Expression {
|
||||
While(WhileExpression),
|
||||
Loop(LoopExpression),
|
||||
Progn(PrognExpression),
|
||||
Vector(VectorExpression),
|
||||
Return,
|
||||
}
|
||||
|
||||
@@ -67,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}"),
|
||||
@@ -116,6 +118,9 @@ impl Expression {
|
||||
_ => 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!()
|
||||
@@ -142,6 +147,7 @@ impl CollectErrors<ParseError> for Expression {
|
||||
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(_)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
+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,
|
||||
|
||||
+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(),
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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!(),
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -267,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);
|
||||
}
|
||||
|
||||
+9
-20
@@ -6,33 +6,18 @@ use crate::{
|
||||
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| {
|
||||
@@ -51,6 +36,10 @@ 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| {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
+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),
|
||||
)))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user