This commit is contained in:
2026-05-09 00:30:35 +03:00
parent 01012ae211
commit db5b1dba7b
12 changed files with 276 additions and 29 deletions
+5
View File
@@ -0,0 +1,5 @@
;; vi:ft=lisp:sw=2:ts=2
(let (f (fopen (car *args*)))
(fwrite (fread f))
)
+19 -1
View File
@@ -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),
+7 -1
View File
@@ -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(_)
+29
View File
@@ -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
View File
@@ -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
View File
@@ -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(),
)),
}
}
}
+119
View File
@@ -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!(),
}
});
}
+22
View File
@@ -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
View File
@@ -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| {
+6
View File
@@ -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
View File
@@ -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
View File
@@ -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),
)))
}
}