diff --git a/lispers-core/src/lisp/environment.rs b/lispers-core/src/lisp/environment.rs index 2bda578..834f17e 100644 --- a/lispers-core/src/lisp/environment.rs +++ b/lispers-core/src/lisp/environment.rs @@ -1,5 +1,5 @@ use super::{expression::Expression, prelude::mk_prelude}; -use std::{cell::RefCell, collections::HashMap, rc::Rc}; +use std::{cell::RefCell, collections::HashMap, env, path::Path, rc::Rc}; #[derive(PartialEq, Clone, Debug)] /// A Environment is a stack of `EnvironmentLayer`s. Each `EnvironmentLayer` is a mapping from diff --git a/lispers-core/src/lisp/eval.rs b/lispers-core/src/lisp/eval.rs index 1d89f8e..2871735 100644 --- a/lispers-core/src/lisp/eval.rs +++ b/lispers-core/src/lisp/eval.rs @@ -19,6 +19,12 @@ pub enum EvalError { ParserError(ParserError), } +impl From for EvalError { + fn from(value: ParserError) -> Self { + EvalError::ParserError(value) + } +} + impl Display for EvalError { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { match self { diff --git a/lispers-core/src/lisp/expression.rs b/lispers-core/src/lisp/expression.rs index 08dd417..2538a58 100644 --- a/lispers-core/src/lisp/expression.rs +++ b/lispers-core/src/lisp/expression.rs @@ -361,7 +361,7 @@ impl Display for Expression { Expression::Symbol(s) => write!(f, "{}", s), Expression::Integer(i) => write!(f, "{}", i), Expression::Float(fl) => write!(f, "{}", fl), - Expression::String(s) => write!(f, "{}", s), + Expression::String(s) => write!(f, "\"{}\"", s), Expression::True => write!(f, "true"), Expression::Nil => write!(f, "nil"), } diff --git a/lispers-core/src/lisp/prelude.rs b/lispers-core/src/lisp/prelude.rs index 5206338..e31628f 100644 --- a/lispers-core/src/lisp/prelude.rs +++ b/lispers-core/src/lisp/prelude.rs @@ -1,3 +1,6 @@ +use crate::parser::ExpressionStream; +use crate::parser::ParserError; + use super::environment::Environment; use super::environment::EnvironmentLayer; use super::eval::eval; @@ -5,6 +8,7 @@ use super::eval::CellIterator; use super::eval::EvalError; use super::expression::Expression; use std::collections::HashMap; +use std::path::PathBuf; pub fn prelude_add(env: &Environment, expr: Expression) -> Result { let [a, b] = expr.try_into()?; @@ -325,6 +329,54 @@ pub fn prelude_to_string(env: &Environment, expr: Expression) -> Result Result { + let [expr] = expr.try_into()?; + let lisp_string: String = eval(env, expr)?.try_into()?; + + let mut last_result = Expression::Nil; + + for expr in ExpressionStream::from_char_stream(lisp_string.chars()) + .collect::, ParserError>>()? + { + last_result = eval(env, expr)?; + } + + Ok(last_result) +} + +pub fn prelude_include(env: &Environment, expr: Expression) -> Result { + let [expr] = expr.try_into()?; + let lisp_file: String = eval(env, expr)?.try_into()?; + + // Try to resolve as relative to FILE + let resolved_lisp_file: PathBuf = PathBuf::from( + env.get("FILE") + .map(|x| x.try_into()) + .unwrap_or(Ok(String::new()))?, + ) + .parent() + .ok_or(EvalError::RuntimeError( + "Could not get parent of current file.".to_string(), + ))? + .join(&lisp_file); + + let lisp_string = std::fs::read_to_string(&resolved_lisp_file) + .map_err(|e| EvalError::RuntimeError(e.to_string()))?; + + // Use enviroment for resolved file or fallback to the lisp_file argument + let mut env = env.mk_inner(); + env.set( + "FILE".to_string(), + resolved_lisp_file + .to_str() + .unwrap_or(&lisp_file) + .to_string() + .into(), + ); + + prelude_load(&env, [lisp_string.into()].into()) +} + pub fn mk_prelude(layer: &mut EnvironmentLayer) { layer.set("+".to_string(), Expression::Function(prelude_add)); layer.set("-".to_string(), Expression::Function(prelude_sub)); @@ -355,4 +407,6 @@ pub fn mk_prelude(layer: &mut EnvironmentLayer) { "to-string".to_string(), Expression::Function(prelude_to_string), ); + layer.set("load".to_string(), Expression::Function(prelude_load)); + layer.set("include".to_string(), Expression::Function(prelude_include)); } diff --git a/src/bin/lisp_demo.rs b/src/bin/lisp_demo.rs index 77be388..6711a56 100644 --- a/src/bin/lisp_demo.rs +++ b/src/bin/lisp_demo.rs @@ -15,6 +15,8 @@ fn main() { "(defun do-n-times (f n) (if (= n 0) '() (cons (f) (do-n-times f (- n 1)))))", "(do-n-times (lambda () (print 'hello)) 5)", "(progn (print 'hello) (print 'world))", + "(load \"(defun loaded-foo (x) (+ x 1))\")", + "(loaded-foo 1)", ]; let environment = Environment::default();