Skip to content

Commit

Permalink
fix missing add-watch, remove-watch; bump 0.3.1
Browse files Browse the repository at this point in the history
  • Loading branch information
tiye committed May 1, 2021
1 parent 6eed2cf commit 0a0883c
Show file tree
Hide file tree
Showing 8 changed files with 100 additions and 23 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "calcit_runner"
version = "0.3.0"
version = "0.3.1"
authors = ["jiyinyiyong <jiyinyiyong@gmail.com>"]
edition = "2018"
license = "MIT"
Expand Down
3 changes: 3 additions & 0 deletions calcit/snapshots/test.cirru
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,10 @@
fn ()
log-title "|Testing refs"
assert= 0 @*ref-demo
add-watch *ref-demo :change $ fn (prev current)
println "|change happened:" prev current
reset! *ref-demo 2
remove-watch *ref-demo :change
assert= 2 @*ref-demo
assert= :ref (type-of *ref-demo)

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@calcit/procs",
"version": "0.3.0",
"version": "0.3.1",
"main": "./lib/calcit.procs.js",
"devDependencies": {
"@types/node": "^15.0.1",
Expand Down
4 changes: 2 additions & 2 deletions src/builtins.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,6 @@ pub fn is_proc_name(s: &str) -> bool {
| "stringify-json"
// refs
| "deref"
| "reset!"
| "add-watch"
| "remove-watch"
// records
Expand Down Expand Up @@ -265,7 +264,6 @@ pub fn handle_proc(name: &str, args: &CalcitItems) -> Result<Calcit, String> {
"stringify-json" => json::stringify_json(args),
// refs
"deref" => refs::deref(args),
"reset!" => refs::reset_bang(args),
"add-watch" => refs::add_watch(args),
"remove-watch" => refs::remove_watch(args),
// records
Expand Down Expand Up @@ -297,6 +295,7 @@ pub fn is_syntax_name(s: &str) -> bool {
| "try"
| "sort" // TODO need better solution
| "defatom"
| "reset!"
)
}

Expand Down Expand Up @@ -324,6 +323,7 @@ pub fn handle_syntax(
"sort" => lists::sort(nodes, scope, file_ns, program),
// "define reference" although it uses a confusing name "atom"
"defatom" => refs::defatom(nodes, scope, file_ns, program),
"reset!" => refs::reset_bang(nodes, scope, file_ns, program),
a => Err(format!("TODO syntax: {}", a)),
}
}
Expand Down
98 changes: 82 additions & 16 deletions src/builtins/refs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,41 @@ use crate::primes::{Calcit, CalcitItems, CalcitScope};
use crate::program::ProgramCodeData;
use crate::runner;

type ValueAndListeners = (Calcit, HashMap<String, Calcit>);

lazy_static! {
static ref REFS_DICT: Mutex<HashMap<String, Calcit>> = Mutex::new(HashMap::new());
static ref REFS_DICT: Mutex<HashMap<String, ValueAndListeners>> = Mutex::new(HashMap::new());
}

// need functions with shorter lifetime to escape dead lock
fn read_ref(path: &str) -> Option<Calcit> {
let dict = &REFS_DICT.lock().unwrap();
match dict.get(path) {
Some(v) => Some(v.to_owned()),
Some((v, _)) => Some(v.to_owned()),
None => None,
}
}

fn write_to_ref(path: String, v: Calcit) {
let dict = &mut REFS_DICT.lock().unwrap();
let _ = dict.insert(path, v);
let _ = dict.insert(path, (v, HashMap::new()));
}

fn modify_ref(path: String, v: Calcit, program_code: &ProgramCodeData) -> Result<(), String> {
let dict = &mut REFS_DICT.lock().unwrap();
let (prev, listeners) = &dict.get(&path).unwrap().clone();
let _ = dict.insert(path, (v.to_owned(), listeners.to_owned()));

for f in listeners.values() {
match f {
Calcit::Fn(_, def_ns, _, def_scope, args, body) => {
let values = im::vector![prev.to_owned(), v.to_owned()];
runner::run_fn(&values, &def_scope, args, body, def_ns, program_code)?;
}
a => return Err(format!("expected fn to trigger after `reset!`, got {}", a)),
}
}
Ok(())
}

/// syntax to prevent expr re-evaluating
Expand Down Expand Up @@ -60,25 +79,72 @@ pub fn deref(xs: &CalcitItems) -> Result<Calcit, String> {
}
}

pub fn reset_bang(xs: &CalcitItems) -> Result<Calcit, String> {
match (xs.get(0), xs.get(1)) {
(Some(Calcit::Ref(path)), Some(v)) => {
if read_ref(path).is_none() {
/// need to be syntax since triggering internal functions requires program data
pub fn reset_bang(
expr: &CalcitItems,
scope: &CalcitScope,
file_ns: &str,
program_code: &ProgramCodeData,
) -> Result<Calcit, String> {
if expr.len() < 2 {
return Err(format!("reset! excepted 2 arguments, got: {:?}", expr));
}
println!("reset! {:?}", expr[0]);
let target = runner::evaluate_expr(&expr[0], scope, file_ns, program_code)?;
let new_value = runner::evaluate_expr(&expr[1], scope, file_ns, program_code)?;
match (target, new_value) {
(Calcit::Ref(path), v) => {
if read_ref(&path).is_none() {
return Err(format!("missing pre-exisiting data for path &{}", path));
}
write_to_ref(path.to_owned(), v.to_owned());
modify_ref(path, v, program_code)?;
Ok(Calcit::Nil)
}
(Some(a), Some(b)) => Err(format!("reset! expected a ref and a value, got: {} {}", a, b)),
(a, b) => Err(format!("reset! expected 2 arguments, got: {:?} {:?}", a, b)),
(a, b) => Err(format!("reset! expected a ref and a value, got: {} {}", a, b)),
}
}

// TODO
pub fn add_watch(_xs: &CalcitItems) -> Result<Calcit, String> {
Ok(Calcit::Nil)
pub fn add_watch(xs: &CalcitItems) -> Result<Calcit, String> {
match (xs.get(0), xs.get(1), xs.get(2)) {
(Some(Calcit::Ref(path)), Some(Calcit::Keyword(k)), Some(Calcit::Fn(..))) => {
let dict = &mut REFS_DICT.lock().unwrap();
let (prev, listeners) = &dict.get(path).unwrap().clone();
if listeners.contains_key(k) {
Err(format!("add-watch failed, listener with key `{}` existed", k))
} else {
let mut new_listeners = listeners.clone();
new_listeners.insert(k.to_owned(), xs.get(2).unwrap().to_owned());
let _ = dict.insert(path.to_owned(), (prev.to_owned(), new_listeners));
Ok(Calcit::Nil)
}
}
(Some(Calcit::Ref(_)), Some(Calcit::Keyword(_)), Some(a)) => {
Err(format!("add-watch expected fn instead of proc, got {}", a))
}
(Some(Calcit::Ref(_)), Some(a), Some(_)) => Err(format!("add-watch expected a keyword, but got: {}", a)),
(Some(a), _, _) => Err(format!("add-watch expected ref, got: {}", a)),
(a, b, c) => Err(format!(
"add-watch expected ref, keyword, function, got {:?} {:?} {:?}",
a, b, c
)),
}
}
// TODO
pub fn remove_watch(_xs: &CalcitItems) -> Result<Calcit, String> {
Ok(Calcit::Nil)

pub fn remove_watch(xs: &CalcitItems) -> Result<Calcit, String> {
match (xs.get(0), xs.get(1)) {
(Some(Calcit::Ref(path)), Some(Calcit::Keyword(k))) => {
let dict = &mut REFS_DICT.lock().unwrap();
let (prev, listeners) = &dict.get(path).unwrap().clone();
if listeners.contains_key(k) {
let mut new_listeners = listeners.clone();
new_listeners.remove(k);
let _ = dict.insert(path.to_owned(), (prev.to_owned(), new_listeners));
Ok(Calcit::Nil)
} else {
Err(format!("remove-watch failed, listener with key `{}` missing", k))
}
}
(Some(a), Some(b)) => Err(format!("remove-watch expected ref and keyword, got: {} {}", a, b)),
(a, b) => Err(format!("remove-watch expected 2 arguments, got {:?} {:?}", a, b)),
}
}
9 changes: 8 additions & 1 deletion src/runner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,14 @@ pub fn evaluate_expr(
Calcit::Number(_) => Ok(expr.clone()),
Calcit::Symbol(s, ..) if s == "&" => Ok(expr.clone()),
Calcit::Symbol(s, ns, resolved) => match resolved {
Some(ResolvedDef(r_ns, r_def)) => evaluate_symbol(&r_def, scope, &r_ns, program_code),
Some(ResolvedDef(r_ns, r_def)) => {
let v = evaluate_symbol(&r_def, scope, &r_ns, program_code)?;
match v {
// extra check to make sure thunks extracted
Calcit::Thunk(code) => evaluate_expr(&code, scope, file_ns, program_code),
_ => Ok(v),
}
}
_ => evaluate_symbol(&s, scope, &ns, program_code),
},
Calcit::Keyword(_) => Ok(expr.clone()),
Expand Down
3 changes: 2 additions & 1 deletion src/runner/preprocess.rs
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,8 @@ fn process_list_call(
preprocess_call_let(&name, &name_ns, args, scope_defs, file_ns, program_code)?,
None,
)),
"if" | "assert" | "do" | "try" | "macroexpand" | "macroexpand-all" | "macroexpand-1" | "foldl" | "sort" => Ok((
"if" | "assert" | "do" | "try" | "macroexpand" | "macroexpand-all" | "macroexpand-1" | "foldl" | "sort"
| "reset!" => Ok((
preprocess_each_items(&name, &name_ns, args, scope_defs, file_ns, program_code)?,
None,
)),
Expand Down

0 comments on commit 0a0883c

Please sign in to comment.