finished let forms

Signed-off-by: Ava Hahn <ava@aidanis.online>
This commit is contained in:
Ava Hahn 2023-03-01 15:17:50 -08:00
parent 131008c3a2
commit c1d83a6285
Signed by untrusted user who does not match committer: affine
GPG key ID: 3A4645B8CF806069
5 changed files with 198 additions and 27 deletions

View file

@ -20,21 +20,18 @@ https://gitlab.com/whom/shs
https://matrix.to/#/#vomitorium:matrix.sunnypup.io
* How to use
** Syntax
*** Basic data types
TODO
*** S-Expressions
TODO
**** calling a function
TODO
*** Control flow
TODO
*** Defining variables and functions
TODO
**** Undefining variables and functions
TODO
*** Builtin functions
TODO
** TODO Syntax
*** TODO Basic data types
*** TODO S-Expressions
**** TODO calling a function
*** TODO Control flow
**** TODO if
**** TODO while
**** TODO let
**** TODO circuit
*** TODO Defining variables and functions
**** TODO Undefining variables and functions
*** TODO Builtin functions
** Configuration
By default Relish will read from ~/.relishrc for configuration, but the default shell will also accept a filename from the RELISH_CFG_FILE environment variable.
@ -58,6 +55,8 @@ Errors during configuration are non-terminal. In such a case any defaults which
- CFG_RELISH_PROMPT (default (echo "λ ")): A *function* definition which is called in order to output the prompt for each loop of the REPL.
This function will be reloaded each REPL loop and will be called by the interpreter with no arguments.
** TODO Further configuration
** Compilation
#+BEGIN_SRC sh
cargo build
@ -128,7 +127,7 @@ This contains any executable target of this project. Notably the main shell file
Note: this section will not show the status of each item unless you are viewing it with a proper orgmode viewer
*** TODO Rudimentary Control Flow
**** DONE if clause
**** TODO loop clause
**** TODO let clause
**** TODO while clause
**** TODO circuit clause
*** TODO Help function
@ -150,13 +149,18 @@ Will need a concatenate function for tables
**** TODO head (returns (head rest))
**** TODO tail (returns (rest tail))
**** TODO queue (append to front)
**** TODO snippet for dequeue
**** TODO snippet for pop
*** TODO boolean operations
**** TODO and
**** TODO and (circuit)
**** TODO or
**** TODO xor
**** TODO not
**** TODO no
**** TODO eq?
**** TODO toggle
*** TODO string operations
**** TODO contains
**** TODO len
**** TODO concat
**** TODO substr by index
**** TODO split (on delimiter)
@ -171,6 +175,9 @@ Will need a concatenate function for tables
**** TODO inc
**** TODO dec
**** TODO int (float to int)
**** TODO gt?
**** TODO lt?
**** TODO snippets for gte and lte
*** TODO file operations
**** TODO read-to-string
**** TODO write-to-file

View file

@ -69,6 +69,16 @@ pub fn static_stdlib(syms: &mut SymTable) -> Result<(), String> {
},
);
syms.insert(
"let".to_string(),
Symbol {
name: String::from("let"),
args: Args::Infinite,
conditional_branches: true,
value: ValueType::Internal(Rc::new(control::let_callback)),
},
);
Ok(())
}

View file

@ -17,7 +17,7 @@
use crate::eval::eval;
use crate::segment::{Ctr, Seg};
use crate::sym::SymTable;
use crate::sym::{SymTable, Symbol, ValueType, Args};
pub fn if_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, String> {
let cond: bool;
@ -46,7 +46,6 @@ pub fn if_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, String> {
match *then_form.car {
Ctr::Seg(ref first_arg) => Ok(*eval(first_arg, syms)?),
_ => {
//Ok(*eval(&Seg::from_mono(then_form.car.clone()), syms)?)},
let eval_tree = &Seg::from_mono(then_form.car.clone());
let eval_res = *eval(eval_tree, syms)?;
if let Ctr::Seg(ref s) = eval_res {
@ -62,7 +61,6 @@ pub fn if_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, String> {
match *else_form.car {
Ctr::Seg(ref second_arg) => Ok(*eval(second_arg, syms)?),
_ => {
//Ok(*eval(&Seg::from_mono(then_form.car.clone()), syms)?)},
let eval_tree = &Seg::from_mono(else_form.car.clone());
let eval_res = *eval(eval_tree, syms)?;
if let Ctr::Seg(ref s) = eval_res {
@ -78,18 +76,104 @@ pub fn if_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, String> {
}
}
pub fn let_callback(_ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, String> {
todo!()
pub fn let_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, String> {
let mut localsyms = syms.clone();
let locals_form: &Seg;
let eval_forms: &Seg;
if let Ctr::Seg(ref locals_form_list) = *ast.car {
locals_form = locals_form_list;
} else {
return Err("first element of let form must contain local variables".to_string())
}
if let Ctr::Seg(ref eval_forms_head) = *ast.cdr {
eval_forms = eval_forms_head;
} else {
return Err("let form should contain one or more elements to evaluate".to_string())
}
// process locals forms
if !locals_form.circuit(&mut |var_decl: &Ctr| -> bool {
if let Ctr::Seg(ref var_form) = *var_decl {
if let Ctr::Symbol(ref name) = *var_form.car {
if let Ctr::Seg(ref var_val_form) = *var_form.cdr {
let var_val_res: Result<Box<Ctr>, String>;
if let Ctr::Seg(ref val_form) = *var_val_form.car {
var_val_res = eval(val_form, &mut localsyms);
} else {
let var_tree = Seg::from_mono(Box::new(*var_val_form.car.clone()));
let intermediate = eval(&var_tree, &mut localsyms);
if intermediate.is_err() {
var_val_res = intermediate;
} else if let Ctr::Seg(ref intermediate_result) = *intermediate.unwrap() {
var_val_res = Ok(intermediate_result.car.clone())
} else {
panic!()
}
}
if let Err(e) = var_val_res {
eprintln!("failed to evaluate definition of {}: {}", name, e);
return false
}
let temp = var_val_res.clone().unwrap();
println!("dbg: {}", temp);
localsyms.insert(name.clone(), Symbol {
name: name.clone(),
args: Args::None,
conditional_branches: false,
value: ValueType::VarForm(Box::new(*var_val_res.unwrap().clone())),
});
}
} else {
eprintln!("improper declaration of {}: not a list", var_decl);
return false
}
} else {
eprintln!("improper declaration form: {}", var_decl);
return false
}
true
}) {
return Err("local variable declaration failure".to_string())
}
let mut result: Box<Ctr> = Box::new(Ctr::None);
if !eval_forms.circuit(&mut |eval_form: &Ctr| -> bool {
let res: Result<Box<Ctr>, String>;
if let Ctr::Seg(ref eval_tree) = eval_form {
res = eval(&eval_tree, &mut localsyms);
} else {
let eval_tree = Seg::from_mono(Box::new(eval_form.clone()));
let intermediate = eval(&eval_tree, &mut localsyms);
if intermediate.is_err() {
res = intermediate;
} else if let Ctr::Seg(ref intermediate_result) = *intermediate.unwrap() {
res = Ok(intermediate_result.car.clone())
} else {
panic!()
}
}
if let Err(e) = res {
eprintln!("error evaluating let form: {}", e);
return false
}
result = res.unwrap().clone();
true
}) {
return Err("evaluation failure".to_string())
}
Ok((*result).clone())
}
pub fn while_callback(_ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, String> {
todo!()
}
pub fn map_callback(_ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, String> {
todo!()
}
pub fn circuit_callback(_ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, String> {
todo!()
}

View file

@ -19,6 +19,8 @@ use crate::eval::eval;
use crate::segment::{Ctr, Seg, Type};
use std::collections::HashMap;
use std::rc::Rc;
#[derive(Clone)]
pub struct SymTable(HashMap<String, Symbol>);
#[derive(Debug, Clone)]

View file

@ -62,4 +62,72 @@ mod control_lib_tests {
assert!(false);
}
}
#[test]
fn test_let_multiphase_locals() {
let document = "(let (
(temp '1')
(temp (append () temp '2')))
temp)";
let result = "('1' '2')";
let mut syms = SymTable::new();
static_stdlib(&mut syms).unwrap();
dynamic_stdlib(&mut syms).unwrap();
if let Ok(tree) = lex(&document.to_string()) {
if let Ctr::Seg(ref i) = *eval(&tree, &mut syms).unwrap() {
assert_eq!(i.to_string(), result);
} else {
assert!(false);
}
} else {
assert!(false);
}
}
#[test]
fn test_let_multibody_evals() {
let document = "(let ((temp '1')) temp (append () temp '2'))";
let result = "('1' '2')";
let mut syms = SymTable::new();
static_stdlib(&mut syms).unwrap();
dynamic_stdlib(&mut syms).unwrap();
if let Ok(tree) = lex(&document.to_string()) {
if let Ctr::Seg(ref i) = *eval(&tree, &mut syms).unwrap() {
assert_eq!(i.to_string(), result);
} else {
assert!(false);
}
} else {
assert!(false);
}
}
#[test]
fn test_let_multiphase_local_multibody_evals() {
let document = "(let (
(temp '1')
(temp (append () temp '2')))
(echo 'first body')
(append temp '3'))";
let result = "('1' '2' '3')";
let mut syms = SymTable::new();
static_stdlib(&mut syms).unwrap();
dynamic_stdlib(&mut syms).unwrap();
if let Ok(tree) = lex(&document.to_string()) {
if let Ctr::Seg(ref i) = *eval(&tree, &mut syms).unwrap() {
assert_eq!(i.to_string(), result);
} else {
assert!(false);
}
} else {
assert!(false);
}
}
}