From e79a93fed54849eb5c71bd957a06e90aaf8b32ad Mon Sep 17 00:00:00 2001 From: jiyinyiyong Date: Mon, 26 Apr 2021 23:22:29 +0800 Subject: [PATCH] fix dead lock in defatom; alpha release --- Cargo.lock | 2 +- Cargo.toml | 2 +- lib/calcit.procs.ts | 2 +- package.json | 2 +- src/builtins/refs.rs | 46 +++++++++++++++++++++++------------------- src/codegen/emit_js.rs | 7 ++++++- src/primes.rs | 2 +- 7 files changed, 36 insertions(+), 27 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 234f0e22..7e38f418 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -81,7 +81,7 @@ dependencies = [ [[package]] name = "calcit_runner" -version = "0.3.0-a4" +version = "0.3.0-a5" dependencies = [ "cirru_edn", "cirru_parser", diff --git a/Cargo.toml b/Cargo.toml index bb98e3b5..2b4a6cf4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "calcit_runner" -version = "0.3.0-a4" +version = "0.3.0-a5" authors = ["jiyinyiyong "] edition = "2018" license = "MIT" diff --git a/lib/calcit.procs.ts b/lib/calcit.procs.ts index 5a1c4651..26c9eb98 100644 --- a/lib/calcit.procs.ts +++ b/lib/calcit.procs.ts @@ -1215,7 +1215,7 @@ export let pr_str = (...args: CrDataValue[]): string => { return args.map((x) => toString(x, true)).join(" "); }; -/** helper function for println */ +/** helper function for println, js only */ export let printable = (...args: CrDataValue[]): string => { return args.map((x) => toString(x, false)).join(" "); }; diff --git a/package.json b/package.json index c841a81d..9574c4b8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@calcit/procs", - "version": "0.3.0-a4", + "version": "0.3.0-a5", "main": "./lib/calcit.procs.js", "devDependencies": { "@types/node": "^14.14.41", diff --git a/src/builtins/refs.rs b/src/builtins/refs.rs index fe4993ad..23539c86 100644 --- a/src/builtins/refs.rs +++ b/src/builtins/refs.rs @@ -11,6 +11,20 @@ lazy_static! { static ref REFS_DICT: Mutex> = Mutex::new(HashMap::new()); } +// need functions with shorter lifetime to escape dead lock +fn read_ref(path: &str) -> Option { + let dict = &REFS_DICT.lock().unwrap(); + match dict.get(path) { + 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); +} + /// syntax to prevent expr re-evaluating pub fn defatom( expr: &CalcitItems, @@ -24,15 +38,11 @@ pub fn defatom( path.push('/'); path.push_str(s); - let dict = &mut REFS_DICT.lock().unwrap(); - - if dict.contains_key(&path) { - Ok(Calcit::Ref(path)) - } else { + if read_ref(&path).is_none() { let v = runner::evaluate_expr(code, scope, file_ns, program_code)?; - dict.insert(path.clone(), v); - Ok(Calcit::Ref(path)) + write_to_ref(path.to_owned(), v) } + Ok(Calcit::Ref(path)) } (Some(a), Some(b)) => Err(format!("defref expected a symbol and an expression: {} , {}", a, b)), _ => Err(String::from("defref expected 2 nodes")), @@ -41,13 +51,10 @@ pub fn defatom( pub fn deref(xs: &CalcitItems) -> Result { match xs.get(0) { - Some(Calcit::Ref(path)) => { - let dict = &REFS_DICT.lock().unwrap(); - match dict.get(path) { - Some(v) => Ok(v.clone()), - None => Err(format!("found nothing after refer &{}", path)), - } - } + Some(Calcit::Ref(path)) => match read_ref(path) { + Some(v) => Ok(v), + None => Err(format!("found nothing after refer &{}", path)), + }, Some(a) => Err(format!("deref expected a ref, got: {}", a)), _ => Err(String::from("deref expected 1 argument, got nothing")), } @@ -56,14 +63,11 @@ pub fn deref(xs: &CalcitItems) -> Result { pub fn reset_bang(xs: &CalcitItems) -> Result { match (xs.get(0), xs.get(1)) { (Some(Calcit::Ref(path)), Some(v)) => { - let dict = &mut REFS_DICT.lock().unwrap(); - - if dict.contains_key(path) { - dict.insert(path.clone(), v.clone()); - Ok(Calcit::Nil) - } else { - Err(format!("missing pre-exisiting data for path &{}", path)) + 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()); + 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)), diff --git a/src/codegen/emit_js.rs b/src/codegen/emit_js.rs index 9fb7ef5a..b45c33f6 100644 --- a/src/codegen/emit_js.rs +++ b/src/codegen/emit_js.rs @@ -249,6 +249,11 @@ fn gen_call_code( file_imports: &RefCell, ) -> Result { let var_prefix = if ns == "calcit.core" { "" } else { "$calcit." }; + let proc_prefix = if ns == primes::CORE_NS { + "$calcit_procs." + } else { + "$calcit." + }; if ys.is_empty() { println!("[Warn] Unexpected empty list inside {}", xs); return Ok(String::from("()")); @@ -337,7 +342,7 @@ fn gen_call_code( // not core syntax, but treat as macro for better debugging experience let args = ys.skip(1); let args_code = gen_args_code(&args, ns, local_defs, file_imports)?; - Ok(format!("console.log({}printable({}))", var_prefix, args_code)) + Ok(format!("console.log({}printable({}))", proc_prefix, args_code)) } "exists?" => { // not core syntax, but treat as macro for availability diff --git a/src/primes.rs b/src/primes.rs index 77dc8366..b9145f3a 100644 --- a/src/primes.rs +++ b/src/primes.rs @@ -408,7 +408,7 @@ impl PartialEq for Calcit { pub const CORE_NS: &str = "calcit.core"; pub const GENERATED_NS: &str = "calcit.gen"; -pub const CALCI_VERSION: &str = "0.3.0-a4"; +pub const CALCI_VERSION: &str = "0.3.0-a5"; impl Calcit { pub fn turn_string(&self) -> String {