diff --git a/src/cell.rs b/src/cell.rs
deleted file mode 100644
index cb7d4b0..0000000
--- a/src/cell.rs
+++ /dev/null
@@ -1,245 +0,0 @@
-/* relish: versatile lisp shell
- * Copyright (C) 2021 Aidan Hahn
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-use std::fmt;
-use std::boxed::Box;
-
-
-// Container
-#[derive(Clone)]
-pub enum Ctr {
- Symbol(String),
- String(String),
- Integer(i128),
- Float(f64),
- Bool(bool),
- Cell(Box),
- None
-}
-
-// Type of Container
-#[derive(PartialEq)]
-#[derive(Clone)]
-pub enum Type {
- Symbol,
- String,
- Integer,
- Float,
- Bool,
- Cell,
- None
-}
-
-/* Cell
- * Holds two Containers.
- * Basic building block for more complex data structures.
- */
-#[derive(Clone)]
-pub struct Cell {
- /* "Cell Address Register"
- * Historical way of referring to the first value in a cell.
- */
- pub car: Ctr,
-
- /* "Cell Decrement Register"
- * Historical way of referring to the second value in a cell.
- */
- pub cdr: Ctr
-}
-
-impl Ctr {
- pub fn to_type(&self) -> Type {
- match self {
- Ctr::Symbol(_s) => Type::Symbol,
- Ctr::String(_s) => Type::String,
- Ctr::Integer(_s) => Type::Integer,
- Ctr::Float(_s) => Type::Float,
- Ctr::Bool(_s) => Type::Bool,
- Ctr::Cell(_s) => Type::Cell,
- Ctr::None => Type::None
- }
- }
-}
-
-impl Type {
- pub fn to_str(&self) -> String {
- let ret: &str;
- match self {
- Type::Symbol => ret = "symbol",
- Type::String => ret = "string",
- Type::Integer => ret = "integer",
- Type::Float => ret = "float",
- Type::Bool => ret = "bool",
- Type::Cell => ret = "cell",
- Type::None => ret = "none"
- }
-
- ret.to_owned()
- }
-}
-
-// creates a cell containing two boxes
-pub fn cons (l_ctr: Ctr, r_ctr: Ctr) -> Cell {
- Cell {
- car: l_ctr,
- cdr: r_ctr
- }
-}
-
-/* Prints any cell as a string
- * recurs on CELL type Containers
- */
-pub fn cell_as_string(c: &Cell, with_parens: bool) -> String {
- let mut string = String::new();
- let mut prn_space = true;
- match &c.car {
- Ctr::Symbol(s) => string.push_str(&s),
- Ctr::String(s) => {
- string.push('\'');
- string.push_str(&s);
- string.push('\'');
- },
- Ctr::Integer(i) => string = string + &i.to_string(),
- Ctr::Float(f) => string = string + &f.to_string(),
- Ctr::Bool(b) => string = string + &b.to_string(),
- Ctr::Cell(c) => string.push_str(cell_as_string(&c, true).as_str()),
- Ctr::None => prn_space = false
- }
-
- if prn_space {
- string.push(' ');
- }
-
- match &c.cdr {
- Ctr::Symbol(s) => string.push_str(&s),
- Ctr::String(s) => {
- string.push('\'');
- string.push_str(&s);
- string.push('\'');
- },
- Ctr::Integer(i) => string = string + &i.to_string(),
- Ctr::Float(f) => string = string + &f.to_string(),
- Ctr::Bool(b) => string = string + &b.to_string(),
- Ctr::Cell(c) => string.push_str(cell_as_string(&c, false).as_str()),
- Ctr::None => {
- if prn_space {
- string.pop();
- }
- }
- }
-
- // TODO: maybe a better way to do this
- if with_parens {
- let mut extra = String::from("(");
- extra.push_str(&string);
- extra.push(')');
- string = extra
- }
- return string
-}
-
-impl fmt::Display for Cell {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "{}", cell_as_string(self, true).as_str())
- }
-}
-
-/* NOTE: "Standard form" is used here to refer to a list of cells
- * that resembles a typical linked list. This means that Car may hold whatever,
- * but Cdr must either be Cell or None.
- */
-impl Cell {
- /* applies a function across a Cell list in standard form
- * function must take a Ctr and return a bool
- * short circuits on the first false returned.
- * also returns false on a non standard form list
- */
- pub fn circuit bool>(&self, func: &mut F) -> bool{
- if func(&self.car) {
- match &self.cdr {
- Ctr::None => true,
- Ctr::Cell(c) => c.circuit(func),
- _ => false
- }
- } else {
- false
- }
- }
-
- /* recurs over a chain of cells
- * adds obj to chain
- * not public, only meant for internal use... yet
- * steals ownership of obj
- */
- pub fn append(&mut self, obj: Ctr) {
- match &mut self.car {
- Ctr::None => {
- self.car = obj;
- },
- _ => {
- match &mut self.cdr {
- Ctr::None => {
- self.cdr = Ctr::Cell(Box::new(Cell{
- car: obj,
- cdr: Ctr::None
- }));
- },
- Ctr::Cell(cell) => {
- cell.append(obj);
- },
- _ => ()
- }
- }
- }
- }
-
- /* recurs over a chain of cell
- * returns length of chain
- */
- pub fn len(&self) -> i128 {
- match &self.cdr {
- Ctr::Cell(c) => c.len() + 1,
- _ => 1
- }
- }
-
- /* iterates through a list.
- * returns a CLONE of the cell at the cooresponding index
- */
- pub fn index(&self, idx: usize) -> Ctr {
- if idx > 0 {
- match &self.cdr {
- Ctr::None => Ctr::None,
- Ctr::Cell(c) => c.index(idx-1),
- _ => {
- if idx == 1 {
- self.cdr.clone()
- } else {
- Ctr::None
- }
- }
- }
- } else {
- match self.car {
- Ctr::None => Ctr::None,
- _ => {
- self.cdr.clone()
- }
- }
- }
- }
-}
diff --git a/src/eval.rs b/src/eval.rs
index 17a05b3..8769087 100644
--- a/src/eval.rs
+++ b/src/eval.rs
@@ -15,8 +15,9 @@
* along with this program. If not, see .
*/
-use std::boxed::Box;
-use crate::cell::{Cell};
+use std::rc::Rc;
+use std::cell::RefCell;
+use crate::segment::{Ast};
use crate::func::FTable;
use crate::vars::VTable;
@@ -25,10 +26,10 @@ use crate::vars::VTable;
* representing the simplest possible form of the input
*/
pub fn eval(
- _ast: &Box,
- _vars: &Box,
- _funcs: &Box,
+ _ast: Ast,
+ _vars: Rc>,
+ _funcs: Rc>,
_sym_loose: bool
-) -> Result, String> {
+) -> Result {
Err("Unimplemented".to_string())
}
diff --git a/src/func.rs b/src/func.rs
index 4d54c70..e118856 100644
--- a/src/func.rs
+++ b/src/func.rs
@@ -15,23 +15,24 @@
* along with this program. If not, see .
*/
-use std::boxed::Box;
+use std::rc::Rc;
+use std::cell::RefCell;
use std::convert::TryInto;
use std::collections::HashMap;
-use crate::cell::{Ctr, Cell, Type};
+use crate::segment::{Ctr, Type, circuit, list_len, list_idx, Ast};
use crate::vars::{VTable};
use crate::eval::eval;
-pub type FTable = HashMap>;
+pub type FTable = HashMap>>;
// Standardized function signature for stdlib functions
-pub type InternalOperation = fn(&Box, &mut Box, &mut Box) -> Box;
+pub type InternalOperation = fn(Ast, Rc>, Rc>) -> Ast;
pub struct ExternalOperation {
// Un-evaluated abstract syntax tree
// TODO: Intermediate evaluation to simplify branches with no argument in them
// Simplified branches must not have side effects.
// TODO: Apply Memoization?
- ast: Box,
+ ast: Ast,
// list of argument string tokens
arg_syms: Vec
}
@@ -67,113 +68,110 @@ pub struct Function {
pub eval_lazy: bool
}
-impl Function {
- /* call
- * routine is called by eval when a function call is detected
- */
- pub fn call(
- &self,
- args: &Box,
- vars: &mut Box,
- funcs: &mut Box
- ) -> Result, String> {
- let n_args: &Box;
- let outer_owner: Box;
- if !self.eval_lazy {
- match eval(args, vars, funcs, self.loose_syms) {
- Ok(box_cell) => outer_owner = box_cell,
- Err(s) => return Err(
- format!(
- "error evaluating args to {}: {}",
- self.name,
- s
- )
+/* call
+ * routine is called by eval when a function call is detected
+ */
+pub fn func_call(
+ function: Rc>,
+ args: Ast,
+ vars: Rc>,
+ funcs: Rc>
+) -> Result {
+ let called_func = function.borrow_mut();
+ let mut n_args: Ast = args.clone();
+ if !called_func.eval_lazy {
+ match eval(args, vars.clone(), funcs.clone(), called_func.loose_syms) {
+ Ok(rc_seg) => n_args = rc_seg.clone(),
+ Err(s) => return Err(
+ format!(
+ "error evaluating args to {}: {}",
+ called_func.name,
+ s
)
- }
- n_args = &outer_owner;
- } else {
- n_args = args;
+ )
}
+ }
- match &self.args {
- Args::Lazy(num) => {
- if *num < 0 {
+ match &called_func.args {
+ Args::Lazy(num) => {
+ if *num < 0 {
+ }
+
+ if !(*num == (list_len(n_args.clone()) as i128 - 1)) {
+ return Err(format!("expected {} args in call to {}", num, called_func.name))
+ }
+ },
+
+ Args::Strict(arg_types) => {
+ let mut idx: usize = 0;
+ let passes = circuit(n_args.clone(), &mut |c: &Ctr| {
+ if idx >= arg_types.len() {
+ return false;
}
- if !(*num == (n_args.len() - 1)) {
- return Err(format!("expected {} args in call to {}", num, self.name))
+ if let Ctr::None = c {
+ return false;
}
- },
- Args::Strict(arg_types) => {
- let mut idx: usize = 0;
- let passes = n_args.circuit(&mut |c: &Ctr| {
- if idx >= arg_types.len() {
- return false;
- }
+ let ret = arg_types[idx] == c.to_type();
+ if ret {
+ idx += 1;
+ }
+ return ret;
+ });
- if let Ctr::None = c {
- return false;
- }
+ if passes && idx < (arg_types.len() - 1) {
+ return Err(format!(
+ "{} too little arguments in call to {}",
+ arg_types.len() - (idx + 1),
+ called_func.name
+ ));
+ }
- let ret = arg_types[idx] == c.to_type();
- if ret {
- idx += 1;
- }
- return ret;
- });
-
- if passes && idx < (arg_types.len() - 1) {
+ if !passes {
+ if idx < (arg_types.len() - 1) {
return Err(format!(
- "{} too little arguments in call to {}",
- arg_types.len() - (idx + 1),
- self.name
+ "argument {} in call to {} is of wrong type (expected {})",
+ idx + 1,
+ called_func.name,
+ arg_types[idx].to_str()
));
}
- if !passes {
- if idx < (arg_types.len() - 1) {
- return Err(format!(
- "argument {} in call to {} is of wrong type (expected {})",
- idx + 1,
- self.name,
- arg_types[idx].to_str()
- ));
- }
-
- if idx == (arg_types.len() - 1) {
- return Err(format!(
- "too many arguments in call to {}",
- self.name
- ));
- }
+ if idx == (arg_types.len() - 1) {
+ return Err(format!(
+ "too many arguments in call to {}",
+ called_func.name
+ ));
}
}
}
+ }
- match &self.function {
- Operation::Internal(f) => Ok((f)(&n_args, vars, funcs)),
- Operation::External(f) => {
- // copy var table and add args
- let mut temp = vars.clone();
- for n in 0..f.arg_syms.len() {
- temp.insert(
- f.arg_syms[n].clone(),
- Box::new(n_args.index(n))
- );
- }
- eval(&f.ast, &temp, funcs, self.loose_syms)
+ match &called_func.function {
+ Operation::Internal(f) => Ok((f)(n_args, vars, funcs)),
+ Operation::External(f) => {
+ let mut temp = vars.borrow().clone();
+ for n in 0..f.arg_syms.len() {
+ temp.insert(
+ f.arg_syms[n].clone(),
+ Rc::new(list_idx(n_args.clone(), n as u128))
+ );
}
+
+ eval(f.ast.clone(), Rc::new(RefCell::new(temp)), funcs, called_func.loose_syms)
}
}
}
-pub fn declare(
- ft: &mut Box,
- f: Box
+pub fn func_declare(
+ ft: Rc>,
+ f: Rc>
) -> Option {
- if let Operation::External(fun) = &f.function {
- if let Args::Lazy(i) = f.args {
+ let func = f.borrow();
+ let name = func.name.clone();
+ if let Operation::External(fun) = &func.function {
+ if let Args::Lazy(i) = func.args {
if fun.arg_syms.len() != i.try_into().unwrap() {
return Some(
"external function must have lazy args equal to declared arg_syms length"
@@ -188,6 +186,7 @@ pub fn declare(
}
}
- ft.insert(f.name.clone(), f);
+ drop(func);
+ ft.borrow_mut().insert(name, f);
None
}
diff --git a/src/lex.rs b/src/lex.rs
index 8232e45..60ebdad 100644
--- a/src/lex.rs
+++ b/src/lex.rs
@@ -15,8 +15,7 @@
* along with this program. If not, see .
*/
-use std::boxed::Box;
-use crate::cell::{Ctr, Cell};
+use crate::segment::{Ctr, Ast, list_append, new_ast};
const UNMATCHED_STR_DELIM: &str = "Unmatched string delimiter in input";
const UNMATCHED_LIST_DELIM: &str = "Unmatched list delimiter in input";
@@ -24,7 +23,7 @@ const UNMATCHED_LIST_DELIM: &str = "Unmatched list delimiter in input";
/* takes a line of user input
* returns an unsimplified tree of tokens.
*/
-pub fn lex(document: String) -> Result, String> {
+pub fn lex(document: String) -> Result {
if !document.is_ascii() {
return Err("document may only contain ascii characters".to_string());
}
@@ -40,10 +39,10 @@ pub fn lex(document: String) -> Result, String> {
}
/* The logic used in lex
- * Returns Ok(Box| ) if lexing passes
+ * Returns Ok(Rc) if lexing passes
* Returns Err(String) if an error occurs
*/
-fn process(document: String) -> Result, String> {
+fn process(document: String) -> Result {
let doc_len = document.len();
if doc_len == 0 {
@@ -110,16 +109,13 @@ fn process(document: String) -> Result, String> {
// match a delimiter
if !needs_alloc {
match c {
- // add a new Cell reference to the stack
+ // add a new Seg reference to the stack
'(' => {
if token != "" {
return Err("list started in middle of another token".to_string());
}
- ref_stack.push(Box::new(Cell{
- car: Ctr::None,
- cdr: Ctr::None
- }));
+ ref_stack.push(new_ast(Ctr::None, Ctr::None));
delim_stack.push(')');
},
@@ -151,7 +147,7 @@ fn process(document: String) -> Result, String> {
return Err("Empty token".to_string());
}
- let mut current_cell_ref = ref_stack.pop().unwrap();
+ let mut current_seg_ref = ref_stack.pop().unwrap();
let mut obj;
if token.len() > 0 {
if is_str {
@@ -172,22 +168,22 @@ fn process(document: String) -> Result, String> {
}
token = String::new();
- current_cell_ref.append(obj);
+ list_append(current_seg_ref.clone(), obj);
}
if alloc_list {
// return if we have finished the document
if ref_stack.len() == 0 {
- return Ok(Box::new(*current_cell_ref));
+ return Ok(current_seg_ref);
}
// shortening this will lead to naught but pain
- obj = Ctr::Cell(Box::new(*current_cell_ref));
- current_cell_ref = ref_stack.pop().unwrap();
- current_cell_ref.append(obj);
+ obj = Ctr::Seg(current_seg_ref.clone());
+ current_seg_ref = ref_stack.pop().unwrap();
+ list_append(current_seg_ref.clone(), obj);
}
- ref_stack.push(current_cell_ref);
+ ref_stack.push(current_seg_ref);
}
}
diff --git a/src/lib.rs b/src/lib.rs
index e0a4022..9c4bc73 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -15,18 +15,18 @@
* along with this program. If not, see .
*/
-mod cell;
+mod segment;
mod lex;
mod func;
mod eval;
mod vars;
pub mod ast {
- pub use crate::cell::{Cell, Ctr, cons, cell_as_string};
+ pub use crate::segment::{Seg, Ctr, ast_to_string, Type, Ast, new_ast};
pub use crate::lex::lex;
pub use crate::func::{Function, Operation, FTable, Args,
InternalOperation, ExternalOperation,
- declare};
- pub use crate::vars::VTable;
+ func_declare, func_call};
+ pub use crate::vars::{VTable, define};
pub use crate::eval::eval;
}
diff --git a/src/segment.rs b/src/segment.rs
new file mode 100644
index 0000000..bf6f4cd
--- /dev/null
+++ b/src/segment.rs
@@ -0,0 +1,245 @@
+/* relish: versatile lisp shell
+ * Copyright (C) 2021 Aidan Hahn
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+use std::rc::Rc;
+use std::cell::RefCell;
+
+// Recursive data type for a tree of Segments
+pub type Ast = Rc>;
+
+// Container
+#[derive(Clone)]
+pub enum Ctr {
+ Symbol(String),
+ String(String),
+ Integer(i128),
+ Float(f64),
+ Bool(bool),
+ Seg(Ast),
+ None
+}
+
+// Type of Container
+#[derive(PartialEq)]
+#[derive(Clone)]
+pub enum Type {
+ Symbol,
+ String,
+ Integer,
+ Float,
+ Bool,
+ Seg,
+ None
+}
+
+/* Segment
+ * Holds two Containers.
+ * Basic building block for more complex data structures.
+ * I was going to call it Cell and then I learned about
+ * how important RefCells were in Rust
+ */
+#[derive(Clone)]
+pub struct Seg {
+ /* "Contents of Address Register"
+ * Historical way of referring to the first value in a cell.
+ */
+ pub car: Ctr,
+
+ /* "Contents of Decrement Register"
+ * Historical way of referring to the second value in a cell.
+ */
+ pub cdr: Ctr
+}
+
+impl Ctr {
+ pub fn to_type(&self) -> Type {
+ match self {
+ Ctr::Symbol(_s) => Type::Symbol,
+ Ctr::String(_s) => Type::String,
+ Ctr::Integer(_s) => Type::Integer,
+ Ctr::Float(_s) => Type::Float,
+ Ctr::Bool(_s) => Type::Bool,
+ Ctr::Seg(_s) => Type::Seg,
+ Ctr::None => Type::None
+ }
+ }
+}
+
+impl Type {
+ pub fn to_str(&self) -> String {
+ let ret: &str;
+ match self {
+ Type::Symbol => ret = "symbol",
+ Type::String => ret = "string",
+ Type::Integer => ret = "integer",
+ Type::Float => ret = "float",
+ Type::Bool => ret = "bool",
+ Type::Seg => ret = "segment",
+ Type::None => ret = "none"
+ }
+
+ ret.to_owned()
+ }
+}
+
+/* Prints a Syntax Tree as a string
+ */
+pub fn ast_as_string(c: Ast, with_parens: bool) -> String {
+ let mut string = String::new();
+ let mut prn_space = true;
+ let seg = c.borrow();
+ match &seg.car {
+ Ctr::Symbol(s) => string.push_str(&s),
+ Ctr::String(s) => {
+ string.push('\'');
+ string.push_str(&s);
+ string.push('\'');
+ },
+ Ctr::Integer(i) => string = string + &i.to_string(),
+ Ctr::Float(f) => string = string + &f.to_string(),
+ Ctr::Bool(b) => string = string + &b.to_string(),
+ Ctr::Seg(c) => string.push_str(ast_as_string(c.clone(), true).as_str()),
+ Ctr::None => prn_space = false
+ }
+
+ if prn_space {
+ string.push(' ');
+ }
+
+ match &seg.cdr {
+ Ctr::Symbol(s) => string.push_str(&s),
+ Ctr::String(s) => {
+ string.push('\'');
+ string.push_str(&s);
+ string.push('\'');
+ },
+ Ctr::Integer(i) => string = string + &i.to_string(),
+ Ctr::Float(f) => string = string + &f.to_string(),
+ Ctr::Bool(b) => string = string + &b.to_string(),
+ Ctr::Seg(c) => string.push_str(ast_as_string(c.clone(), false).as_str()),
+ Ctr::None => {
+ if prn_space {
+ string.pop();
+ }
+ }
+ }
+
+ // TODO: maybe a better way to do this
+ if with_parens {
+ let mut extra = String::from("(");
+ extra.push_str(&string);
+ extra.push(')');
+ string = extra
+ }
+ return string
+}
+
+pub fn ast_to_string(c: Ast) -> String {
+ ast_as_string(c.clone(), true)
+}
+
+/* NOTE: "Standard form" is used here to refer to a list of segments
+ * that resembles a typical linked list. This means that Car may hold whatever,
+ * but Cdr must either be Seg or None.
+ */
+
+/* Initializes a new ast node with segment car and cdr passed in
+ */
+pub fn new_ast(car: Ctr, cdr: Ctr) -> Ast {
+ Rc::new(RefCell::new(Seg{
+ car: car,
+ cdr: cdr
+ }))
+}
+
+/* applies a function across a list in standard form
+ * function must take a Ctr and return a bool
+ * short circuits on the first false returned.
+ * also returns false on a non standard form list
+ */
+pub fn circuit bool>(tree: Ast, func: &mut F) -> bool{
+ let inner = tree.borrow();
+ if func(&inner.car) {
+ match &inner.cdr {
+ Ctr::None => true,
+ Ctr::Seg(c) => circuit(c.clone(), func),
+ _ => false
+ }
+ } else {
+ false
+ }
+}
+
+/* recurs over ast assumed to be list in standard form
+ * returns length
+ */
+pub fn list_len(tree: Ast) -> u128 {
+ match &tree.borrow().cdr {
+ Ctr::Seg(c) => list_len(c.clone()) + 1,
+ _ => 1
+ }
+}
+
+/* recurs over tree assumed to be list in standard form
+ * returns clone of ctr at index provided
+ */
+pub fn list_idx(tree: Ast, idx: u128) -> Ctr {
+ let inner = tree.borrow();
+ if idx > 0 {
+ match &inner.cdr {
+ Ctr::None => Ctr::None,
+ Ctr::Seg(c) => list_idx(c.clone(), idx - 1),
+ _ => {
+ if idx == 1 {
+ inner.cdr.clone()
+ } else {
+ Ctr::None
+ }
+ }
+ }
+ } else {
+ match inner.car {
+ Ctr::None => Ctr::None,
+ _ => {
+ inner.cdr.clone()
+ }
+ }
+ }
+}
+
+/* recurs over tree assumed to be list in standard form
+ * appends object to end of list
+ */
+pub fn list_append(tree: Ast, obj: Ctr) {
+ let mut inner = tree.borrow_mut();
+ match &inner.car {
+ Ctr::None => {
+ inner.car = obj;
+ },
+ _ => {
+ match &inner.cdr {
+ Ctr::None => {
+ inner.cdr = Ctr::Seg(new_ast(obj, Ctr::None));
+ },
+ Ctr::Seg(tr) => {
+ list_append(tr.clone(), obj);
+ },
+ _ => ()
+ }
+ }
+ }
+}
diff --git a/src/vars.rs b/src/vars.rs
index 3799123..82ba6d3 100644
--- a/src/vars.rs
+++ b/src/vars.rs
@@ -15,22 +15,23 @@
* along with this program. If not, see .
*/
-use std::boxed::Box;
+use std::cell::RefCell;
+use std::rc::Rc;
use std::collections::HashMap;
-use crate::cell::{Ctr};
+use crate::segment::{Ctr};
-/* Mapping between a string token and a tree of Cells
+/* Mapping between a string token and a tree of Segments
* The string token can be found in any Ctr::Symbol value
* it is expected that the trees stored are already evaluated
*/
-pub type VTable = HashMap>;
+pub type VTable = HashMap>;
pub fn define(
- vt: &mut Box,
+ vt: Rc>,
identifier: String,
- var_tree: Box
+ var_tree: Rc
) {
- if let Some(boxed_cell) = vt.insert(identifier, var_tree) {
- drop(boxed_cell);
+ if let Some(rc_segment) = vt.borrow_mut().insert(identifier, var_tree) {
+ drop(rc_segment);
}
}
diff --git a/tests/test_func.rs b/tests/test_func.rs
new file mode 100644
index 0000000..05cd14c
--- /dev/null
+++ b/tests/test_func.rs
@@ -0,0 +1,58 @@
+mod func_tests {
+ use std::rc::Rc;
+ use std::cell::RefCell;
+ use relish::ast::{Ast, Type, Ctr, new_ast};
+ use relish::ast::VTable;
+ use relish::ast::{Function, Operation, FTable, Args, func_declare, func_call};
+
+ #[test]
+ fn decl_and_call_internal_func() {
+ let test_internal_func: Function = Function{
+ name: String::from("test_func_in"),
+ loose_syms: false,
+ eval_lazy: true,
+ args: Args::Strict(vec![Type::Bool]),
+ function: Operation::Internal(
+ |a: Ast, _b: Rc>, _c: Rc>| -> Ast {
+ let inner = a.borrow();
+ let mut is_bool = false;
+ if let Ctr::Bool(_) = &inner.car {
+ is_bool = true;
+ }
+
+ new_ast(Ctr::Bool(is_bool), Ctr::None)
+ }
+ )
+ };
+ let ft = Rc::new(RefCell::new(FTable::new()));
+ let vt = Rc::new(RefCell::new(VTable::new()));
+ let args = new_ast(Ctr::Bool(true), Ctr::None);
+ if let Some(s) = func_declare(ft.clone(),
+ Rc::new(RefCell::new(test_internal_func))) {
+ print!("{}", s);
+ assert!(false);
+ }
+
+ let func: Rc>;
+ if let Some(f) = ft.borrow().get(&"test_func_in".to_string()) {
+ func = f.clone();
+ } else {
+ print!("failed to retrieve function!");
+ assert!(false);
+ return;
+ }
+
+ if let Ok(ast) = func_call(func, args, vt, ft) {
+ match &ast.borrow().car {
+ Ctr::Bool(b) => assert!(b),
+ _ => {
+ print!("invalid return from func!");
+ assert!(false);
+ }
+ }
+ } else {
+ print!("call to function failed!");
+ assert!(false);
+ }
+ }
+}
diff --git a/tests/test_lex.rs b/tests/test_lex.rs
index f7e9f1d..0e9fb5f 100644
--- a/tests/test_lex.rs
+++ b/tests/test_lex.rs
@@ -1,12 +1,12 @@
mod lex_tests {
- use relish::ast::{lex};
+ use relish::ast::{lex, ast_to_string};
#[test]
fn test_lex_basic_pair() {
let document: &str = "(hello 'world')";
match lex(document.to_string()) {
- Ok(box_cell) => {
- assert_eq!(format!("{}", *box_cell), document);
+ Ok(tree) => {
+ assert_eq!(ast_to_string(tree), document);
},
Err(s) => {
print!("{}\n", s);
@@ -19,8 +19,8 @@ mod lex_tests {
fn test_lex_basic_list() {
let document: &str = "(hello 'world' 1 2 3)";
match lex(document.to_string()) {
- Ok(box_cell) => {
- assert_eq!(format!("{}", *box_cell), document);
+ Ok(tree) => {
+ assert_eq!(ast_to_string(tree), document);
},
Err(s) => {
print!("{}\n", s);
@@ -33,8 +33,8 @@ mod lex_tests {
fn test_lex_complex_list() {
let document: &str = "(hello 'world' (1 2 (1 2 3)) 1 2 3)";
match lex(document.to_string()) {
- Ok(box_cell) => {
- assert_eq!(format!("{}", *box_cell), document);
+ Ok(tree) => {
+ assert_eq!(ast_to_string(tree), document);
},
Err(s) => {
print!("{}\n", s);
@@ -48,8 +48,8 @@ mod lex_tests {
let document: &str = "(as;dd)";
let output: &str = "Problem lexing document: \"Unparsable token:as;dd\"";
match lex(document.to_string()) {
- Ok(box_cell) => {
- print!("Bad token yielded: {}\n", *box_cell);
+ Ok(tree) => {
+ print!("Bad token yielded: {}\n", ast_to_string(tree));
assert!(false);
},
Err(s) => {
@@ -63,8 +63,8 @@ mod lex_tests {
let document: &str = "(one two";
let output: &str = "Problem lexing document: \"Unmatched list delimiter in input\"";
match lex(document.to_string()) {
- Ok(box_cell) => {
- print!("Bad token yielded: {}\n", *box_cell);
+ Ok(tree) => {
+ print!("Bad token yielded: {}\n", ast_to_string(tree));
assert!(false);
},
Err(s) => {
@@ -78,8 +78,8 @@ mod lex_tests {
let document: &str = "(one two (three)";
let output: &str = "Problem lexing document: \"Unmatched list delimiter in input\"";
match lex(document.to_string()) {
- Ok(box_cell) => {
- print!("Bad token yielded: {}\n", *box_cell);
+ Ok(tree) => {
+ print!("Bad token yielded: {}\n", ast_to_string(tree));
assert!(false);
},
Err(s) => {
@@ -93,8 +93,8 @@ mod lex_tests {
let document: &str = "#!/bin/relish\n(one two)";
let output: &str = "(one two)";
match lex(document.to_string()) {
- Ok(box_cell) => {
- assert_eq!(format!("{}", *box_cell), output.to_string());
+ Ok(tree) => {
+ assert_eq!(ast_to_string(tree), output.to_string());
},
Err(s) => {
print!("{}\n", s);
@@ -108,8 +108,8 @@ mod lex_tests {
let document: &str = "#!/bin/relish\n((one two)# another doc comment\n(three four))";
let output: &str = "((one two) (three four))";
match lex(document.to_string()) {
- Ok(box_cell) => {
- assert_eq!(format!("{}", *box_cell), output.to_string());
+ Ok(tree) => {
+ assert_eq!(ast_to_string(tree), output.to_string());
},
Err(s) => {
print!("{}\n", s);
@@ -123,8 +123,8 @@ mod lex_tests {
let document: &str = "#!/bin/relish\n((one two)\n# another doc comment\nthree)";
let output: &str = "((one two) three)";
match lex(document.to_string()) {
- Ok(box_cell) => {
- assert_eq!(format!("{}", *box_cell), output.to_string());
+ Ok(tree) => {
+ assert_eq!(ast_to_string(tree), output.to_string());
},
Err(s) => {
print!("{}\n", s);
@@ -138,8 +138,8 @@ mod lex_tests {
let document: &str = "(one t(wo)";
let output: &str = "Problem lexing document: \"list started in middle of another token\"";
match lex(document.to_string()) {
- Ok(box_cell) => {
- print!("Bad token yielded: {}\n", *box_cell);
+ Ok(tree) => {
+ print!("Bad token yielded: {}\n", ast_to_string(tree));
assert!(false);
},
Err(s) => {
| | | | | | | | |