finished let forms
Signed-off-by: Ava Hahn <ava@aidanis.online>
This commit is contained in:
parent
131008c3a2
commit
c1d83a6285
5 changed files with 198 additions and 27 deletions
43
Readme.org
43
Readme.org
|
|
@ -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
|
||||
|
|
|
|||
10
src/stl.rs
10
src/stl.rs
|
|
@ -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(())
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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!()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)]
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue