feat: add foregin exprssions and vec3 functions
This commit is contained in:
parent
8ce07f4ea4
commit
6f8499acaf
7
Cargo.lock
generated
7
Cargo.lock
generated
@ -2,6 +2,12 @@
|
|||||||
# It is not intended for manual editing.
|
# It is not intended for manual editing.
|
||||||
version = 3
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "as-any"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5b8a30a44e99a1c83ccb2a6298c563c888952a1c9134953db26876528f84c93a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "autocfg"
|
name = "autocfg"
|
||||||
version = "1.4.0"
|
version = "1.4.0"
|
||||||
@ -125,6 +131,7 @@ checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1"
|
|||||||
name = "lispers"
|
name = "lispers"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"as-any",
|
||||||
"futures",
|
"futures",
|
||||||
"nix",
|
"nix",
|
||||||
]
|
]
|
||||||
|
|||||||
@ -7,5 +7,6 @@ version = "0.1.0"
|
|||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
as-any = "0.3.1"
|
||||||
futures = "0.3.30"
|
futures = "0.3.30"
|
||||||
nix = "0.29.0"
|
nix = "0.29.0"
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
use super::{expression::Expression, prelude::mk_prelude};
|
use super::{expression::Expression, prelude::mk_prelude, vec::mk_vec3};
|
||||||
use std::{cell::RefCell, collections::HashMap, rc::Rc};
|
use std::{cell::RefCell, collections::HashMap, rc::Rc};
|
||||||
|
|
||||||
#[derive(PartialEq, Clone, Debug)]
|
#[derive(PartialEq, Clone, Debug)]
|
||||||
@ -124,12 +124,13 @@ impl<'a> Environment<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Environment<'_> {
|
impl Default for Environment<'_> {
|
||||||
/// Get the default prelude layer
|
/// Get the default prelude+vec3 layer
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
let mut prelude = EnvironmentLayer::new();
|
let mut d = EnvironmentLayer::new();
|
||||||
mk_prelude(&mut prelude);
|
mk_prelude(&mut d);
|
||||||
|
mk_vec3(&mut d);
|
||||||
Environment {
|
Environment {
|
||||||
layer: prelude,
|
layer: d,
|
||||||
outer: None,
|
outer: None,
|
||||||
shared: Rc::new(RefCell::new(EnvironmentLayer::new())),
|
shared: Rc::new(RefCell::new(EnvironmentLayer::new())),
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,9 +1,64 @@
|
|||||||
|
use std::fmt::Debug;
|
||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
|
|
||||||
|
use as_any::AsAny;
|
||||||
|
|
||||||
use super::environment::Environment;
|
use super::environment::Environment;
|
||||||
use super::eval::CellIterator;
|
use super::eval::CellIterator;
|
||||||
use super::eval::EvalError;
|
use super::eval::EvalError;
|
||||||
|
|
||||||
|
/// A trait for foreign data types that can be used in lisp expressions.
|
||||||
|
/// Note: This trait requires explicit implementation of:
|
||||||
|
/// - partial_cmp
|
||||||
|
/// - clone_data
|
||||||
|
/// - eq
|
||||||
|
/// To avoid a derive cycle.
|
||||||
|
pub trait ForeignData: Debug + Display + AsAny {
|
||||||
|
fn partial_cmp(&self, other: &dyn ForeignData) -> Option<std::cmp::Ordering>;
|
||||||
|
fn clone_data(&self) -> Box<dyn ForeignData>;
|
||||||
|
fn eq(&self, other: &dyn ForeignData) -> bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
/// A Wrapper struct for foreign data types injected in expressions.
|
||||||
|
pub struct ForeignDataWrapper {
|
||||||
|
/// The actual foreign data.
|
||||||
|
pub data: Box<dyn ForeignData>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ForeignDataWrapper {
|
||||||
|
/// Create a new ForeignDataWrapper from a ForeignData trait object.
|
||||||
|
pub fn new(data: Box<dyn ForeignData>) -> Self {
|
||||||
|
ForeignDataWrapper { data }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Clone for ForeignDataWrapper {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
ForeignDataWrapper {
|
||||||
|
data: self.data.clone_data(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq for ForeignDataWrapper {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self.data.eq(other.data.as_ref())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialOrd for ForeignDataWrapper {
|
||||||
|
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
||||||
|
self.data.partial_cmp(other.data.as_ref())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for ForeignDataWrapper {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "{}", self.data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, PartialOrd)]
|
#[derive(Clone, Debug, PartialEq, PartialOrd)]
|
||||||
/// A sum type of all possible lisp expressions.
|
/// A sum type of all possible lisp expressions.
|
||||||
pub enum Expression {
|
pub enum Expression {
|
||||||
@ -16,6 +71,8 @@ pub enum Expression {
|
|||||||
argument_symbols: Vec<String>,
|
argument_symbols: Vec<String>,
|
||||||
body: Box<Expression>,
|
body: Box<Expression>,
|
||||||
},
|
},
|
||||||
|
/// A foreign data expression.
|
||||||
|
ForeignExpression(ForeignDataWrapper),
|
||||||
/// A Quoted expression.
|
/// A Quoted expression.
|
||||||
Quote(Box<Expression>),
|
Quote(Box<Expression>),
|
||||||
/// A symbol.
|
/// A symbol.
|
||||||
@ -155,6 +212,7 @@ impl TryFrom<Expression> for (Expression, Expression) {
|
|||||||
impl Display for Expression {
|
impl Display for Expression {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
|
Expression::ForeignExpression(e) => write!(f, "{}", e),
|
||||||
Expression::Cell(a, b) => {
|
Expression::Cell(a, b) => {
|
||||||
match self.clone().try_into() as Result<Vec<Expression>, EvalError> {
|
match self.clone().try_into() as Result<Vec<Expression>, EvalError> {
|
||||||
Ok(lst) => write!(
|
Ok(lst) => write!(
|
||||||
|
|||||||
@ -2,9 +2,8 @@ pub mod environment;
|
|||||||
pub mod eval;
|
pub mod eval;
|
||||||
pub mod expression;
|
pub mod expression;
|
||||||
pub mod prelude;
|
pub mod prelude;
|
||||||
|
pub mod vec;
|
||||||
|
|
||||||
pub use environment::Environment;
|
pub use environment::Environment;
|
||||||
pub use environment::EnvironmentLayer;
|
|
||||||
pub use eval::eval;
|
pub use eval::eval;
|
||||||
pub use eval::EvalError;
|
|
||||||
pub use expression::Expression;
|
pub use expression::Expression;
|
||||||
|
|||||||
96
src/lisp/vec.rs
Normal file
96
src/lisp/vec.rs
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
use std::fmt::Display;
|
||||||
|
|
||||||
|
use as_any::AsAny;
|
||||||
|
|
||||||
|
use super::{
|
||||||
|
environment::{Environment, EnvironmentLayer},
|
||||||
|
eval::{eval, EvalError},
|
||||||
|
expression::ForeignData,
|
||||||
|
expression::{Expression, ForeignDataWrapper},
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
/// A simple 3d vector.
|
||||||
|
struct Vec3 {
|
||||||
|
x: f64,
|
||||||
|
y: f64,
|
||||||
|
z: f64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for Vec3 {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "(vec3 {} {} {})", self.x, self.y, self.z)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ForeignData for Vec3 {
|
||||||
|
fn clone_data(&self) -> Box<dyn ForeignData> {
|
||||||
|
Box::new(*self)
|
||||||
|
}
|
||||||
|
fn eq(&self, other: &dyn ForeignData) -> bool {
|
||||||
|
if let Some(other) = other.as_any().downcast_ref::<Vec3>() {
|
||||||
|
self.x == other.x && self.y == other.y && self.z == other.z
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn partial_cmp(&self, other: &dyn ForeignData) -> Option<std::cmp::Ordering> {
|
||||||
|
if let Some(other) = other.as_any().downcast_ref::<Vec3>() {
|
||||||
|
Some(
|
||||||
|
self.x
|
||||||
|
.partial_cmp(&other.x)?
|
||||||
|
.then(self.y.partial_cmp(&other.y)?)
|
||||||
|
.then(self.z.partial_cmp(&other.z)?),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<Expression> for Vec3 {
|
||||||
|
type Error = EvalError;
|
||||||
|
fn try_from(value: Expression) -> Result<Self, Self::Error> {
|
||||||
|
match value {
|
||||||
|
Expression::ForeignExpression(fe) => {
|
||||||
|
if let Some(vec) = fe.data.as_ref().as_any().downcast_ref::<Vec3>() {
|
||||||
|
Ok(*vec)
|
||||||
|
} else {
|
||||||
|
Err(EvalError::TypeError("Expected vec3".to_string()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => Err(EvalError::TypeError("Expected vec3".to_string())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a vec3 expression from a list of 3 floats
|
||||||
|
pub fn vec_vec(_env: &Environment, expr: Expression) -> Result<Expression, EvalError> {
|
||||||
|
let [x, y, z]: [f64; 3] = expr.try_into()?;
|
||||||
|
|
||||||
|
Ok(Expression::ForeignExpression(ForeignDataWrapper::new(
|
||||||
|
Box::new(Vec3 { x, y, z }),
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Add two vec3 expressions
|
||||||
|
pub fn vec_add(env: &Environment, expr: Expression) -> Result<Expression, EvalError> {
|
||||||
|
let [a, b]: [Expression; 2] = expr.try_into()?;
|
||||||
|
|
||||||
|
let a = Vec3::try_from(eval(env, a)?)?;
|
||||||
|
let b = Vec3::try_from(eval(env, b)?)?;
|
||||||
|
|
||||||
|
Ok(Expression::ForeignExpression(ForeignDataWrapper::new(
|
||||||
|
Box::new(Vec3 {
|
||||||
|
x: a.x + b.x,
|
||||||
|
y: a.y + b.y,
|
||||||
|
z: a.z + b.z,
|
||||||
|
}),
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Add vec3 functions to a layer
|
||||||
|
pub fn mk_vec3(layer: &mut EnvironmentLayer) {
|
||||||
|
layer.set("vec3".to_string(), Expression::Function(vec_vec));
|
||||||
|
layer.set("vec3-add".to_string(), Expression::Function(vec_add));
|
||||||
|
}
|
||||||
@ -15,6 +15,7 @@ fn main() {
|
|||||||
"pow",
|
"pow",
|
||||||
"(pow 2 10)",
|
"(pow 2 10)",
|
||||||
"(let '((fib . (lambda (n) (if (< n 2) n (+ (fib (- n 1)) (fib (- n 2))))))) (fib 10))",
|
"(let '((fib . (lambda (n) (if (< n 2) n (+ (fib (- n 1)) (fib (- n 2))))))) (fib 10))",
|
||||||
|
"(vec3-add (vec3 1.0 2.0 3.0) (vec3 4.0 5.0 6.0))",
|
||||||
];
|
];
|
||||||
|
|
||||||
let environment = Environment::default();
|
let environment = Environment::default();
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user