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
|
https://matrix.to/#/#vomitorium:matrix.sunnypup.io
|
||||||
|
|
||||||
* How to use
|
* How to use
|
||||||
** Syntax
|
** TODO Syntax
|
||||||
*** Basic data types
|
*** TODO Basic data types
|
||||||
TODO
|
*** TODO S-Expressions
|
||||||
*** S-Expressions
|
**** TODO calling a function
|
||||||
TODO
|
*** TODO Control flow
|
||||||
**** calling a function
|
**** TODO if
|
||||||
TODO
|
**** TODO while
|
||||||
*** Control flow
|
**** TODO let
|
||||||
TODO
|
**** TODO circuit
|
||||||
*** Defining variables and functions
|
*** TODO Defining variables and functions
|
||||||
TODO
|
**** TODO Undefining variables and functions
|
||||||
**** Undefining variables and functions
|
*** TODO Builtin functions
|
||||||
TODO
|
|
||||||
*** Builtin functions
|
|
||||||
TODO
|
|
||||||
|
|
||||||
** Configuration
|
** 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.
|
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.
|
- 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.
|
This function will be reloaded each REPL loop and will be called by the interpreter with no arguments.
|
||||||
|
|
||||||
|
** TODO Further configuration
|
||||||
|
|
||||||
** Compilation
|
** Compilation
|
||||||
#+BEGIN_SRC sh
|
#+BEGIN_SRC sh
|
||||||
cargo build
|
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
|
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
|
*** TODO Rudimentary Control Flow
|
||||||
**** DONE if clause
|
**** DONE if clause
|
||||||
**** TODO loop clause
|
**** TODO let clause
|
||||||
**** TODO while clause
|
**** TODO while clause
|
||||||
**** TODO circuit clause
|
**** TODO circuit clause
|
||||||
*** TODO Help function
|
*** TODO Help function
|
||||||
|
|
@ -150,13 +149,18 @@ Will need a concatenate function for tables
|
||||||
**** TODO head (returns (head rest))
|
**** TODO head (returns (head rest))
|
||||||
**** TODO tail (returns (rest tail))
|
**** TODO tail (returns (rest tail))
|
||||||
**** TODO queue (append to front)
|
**** TODO queue (append to front)
|
||||||
|
**** TODO snippet for dequeue
|
||||||
|
**** TODO snippet for pop
|
||||||
*** TODO boolean operations
|
*** TODO boolean operations
|
||||||
**** TODO and
|
**** TODO and (circuit)
|
||||||
**** TODO or
|
**** TODO or
|
||||||
**** TODO xor
|
**** TODO xor
|
||||||
**** TODO not
|
**** TODO no
|
||||||
|
**** TODO eq?
|
||||||
**** TODO toggle
|
**** TODO toggle
|
||||||
*** TODO string operations
|
*** TODO string operations
|
||||||
|
**** TODO contains
|
||||||
|
**** TODO len
|
||||||
**** TODO concat
|
**** TODO concat
|
||||||
**** TODO substr by index
|
**** TODO substr by index
|
||||||
**** TODO split (on delimiter)
|
**** TODO split (on delimiter)
|
||||||
|
|
@ -171,6 +175,9 @@ Will need a concatenate function for tables
|
||||||
**** TODO inc
|
**** TODO inc
|
||||||
**** TODO dec
|
**** TODO dec
|
||||||
**** TODO int (float to int)
|
**** TODO int (float to int)
|
||||||
|
**** TODO gt?
|
||||||
|
**** TODO lt?
|
||||||
|
**** TODO snippets for gte and lte
|
||||||
*** TODO file operations
|
*** TODO file operations
|
||||||
**** TODO read-to-string
|
**** TODO read-to-string
|
||||||
**** TODO write-to-file
|
**** 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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@
|
||||||
|
|
||||||
use crate::eval::eval;
|
use crate::eval::eval;
|
||||||
use crate::segment::{Ctr, Seg};
|
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> {
|
pub fn if_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, String> {
|
||||||
let cond: bool;
|
let cond: bool;
|
||||||
|
|
@ -46,7 +46,6 @@ pub fn if_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, String> {
|
||||||
match *then_form.car {
|
match *then_form.car {
|
||||||
Ctr::Seg(ref first_arg) => Ok(*eval(first_arg, syms)?),
|
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_tree = &Seg::from_mono(then_form.car.clone());
|
||||||
let eval_res = *eval(eval_tree, syms)?;
|
let eval_res = *eval(eval_tree, syms)?;
|
||||||
if let Ctr::Seg(ref s) = eval_res {
|
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 {
|
match *else_form.car {
|
||||||
Ctr::Seg(ref second_arg) => Ok(*eval(second_arg, syms)?),
|
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_tree = &Seg::from_mono(else_form.car.clone());
|
||||||
let eval_res = *eval(eval_tree, syms)?;
|
let eval_res = *eval(eval_tree, syms)?;
|
||||||
if let Ctr::Seg(ref s) = eval_res {
|
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> {
|
pub fn let_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, String> {
|
||||||
todo!()
|
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> {
|
pub fn while_callback(_ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, String> {
|
||||||
todo!()
|
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> {
|
pub fn circuit_callback(_ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, String> {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,8 @@ use crate::eval::eval;
|
||||||
use crate::segment::{Ctr, Seg, Type};
|
use crate::segment::{Ctr, Seg, Type};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct SymTable(HashMap<String, Symbol>);
|
pub struct SymTable(HashMap<String, Symbol>);
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
|
|
||||||
|
|
@ -62,4 +62,72 @@ mod control_lib_tests {
|
||||||
assert!(false);
|
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