From 6a381c5b571f2ea6f8950f7deeda9db21f6c0ddd Mon Sep 17 00:00:00 2001 From: Lawrence Bethlenfalvy Date: Mon, 8 May 2023 20:27:52 +0100 Subject: [PATCH] Fixing some showstoppers - inertness now tracked separately from gas - atomic_impl now correctly rolls over when the argument is inert - syntax fixes - tree shaking --- Cargo.lock | 184 +----------------------- Cargo.toml | 8 +- src/external/bool/equals.rs | 2 +- src/external/bool/ifthenelse.rs | 2 +- src/external/conv/parse_float.rs | 2 +- src/external/conv/parse_uint.rs | 2 +- src/external/conv/to_string.rs | 2 +- src/external/cpsio/print.rs | 2 +- src/external/cpsio/readline.rs | 5 +- src/external/num/operators/add.rs | 2 +- src/external/num/operators/divide.rs | 2 +- src/external/num/operators/multiply.rs | 2 +- src/external/num/operators/remainder.rs | 2 +- src/external/num/operators/subtract.rs | 2 +- src/external/str/char_at.rs | 2 +- src/external/str/concatenate.rs | 2 +- src/foreign.rs | 22 ++- src/foreign_macros/atomic_impl.rs | 8 +- src/foreign_macros/atomic_inert.rs | 6 +- src/foreign_macros/externfn_impl.rs | 9 +- src/interpreter/apply.rs | 46 +++--- src/interpreter/context.rs | 1 + src/interpreter/error.rs | 2 +- src/interpreter/run.rs | 21 +-- src/representations/interpreted.rs | 21 +-- src/rule/matcher_second/build.rs | 4 - src/run_dir.rs | 13 +- src/utils/interner.rs | 181 ----------------------- 28 files changed, 112 insertions(+), 445 deletions(-) delete mode 100644 src/utils/interner.rs diff --git a/Cargo.lock b/Cargo.lock index b3ce5d8..1bed437 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -79,12 +79,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" -[[package]] -name = "base64" -version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a4ddaa51a5bc52a6948f74c06d20aaaddb71924eab79b8c97a8c556e942d6a" - [[package]] name = "bitflags" version = "1.3.2" @@ -103,12 +97,6 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" -[[package]] -name = "cfg_aliases" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" - [[package]] name = "chumsky" version = "0.9.2" @@ -152,7 +140,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.13", + "syn", ] [[package]] @@ -167,16 +155,6 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" -[[package]] -name = "dashmap" -version = "4.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e77a43b28d0668df09411cb0bc9a8c2adc40f9a048afe863e05fd43251e8e39c" -dependencies = [ - "cfg-if", - "num_cpus", -] - [[package]] name = "dyn-clone" version = "1.0.11" @@ -221,15 +199,6 @@ dependencies = [ "wasi", ] -[[package]] -name = "hashbrown" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" -dependencies = [ - "ahash 0.7.6", -] - [[package]] name = "hashbrown" version = "0.12.3" @@ -254,37 +223,19 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" -[[package]] -name = "hermit-abi" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" -dependencies = [ - "libc", -] - [[package]] name = "hermit-abi" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" -[[package]] -name = "instant" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" -dependencies = [ - "cfg-if", -] - [[package]] name = "io-lifetimes" version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c66c74d2ae7e79a5a8f7ac924adbe38ee42a859c6539ad869eb51f0b52dc220" dependencies = [ - "hermit-abi 0.3.1", + "hermit-abi", "libc", "windows-sys", ] @@ -295,7 +246,7 @@ version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "adcf93614601c8129ddf72e2d5633df827ba6551541c6d8c59520a371475be1f" dependencies = [ - "hermit-abi 0.3.1", + "hermit-abi", "io-lifetimes", "rustix", "windows-sys", @@ -310,16 +261,6 @@ dependencies = [ "either", ] -[[package]] -name = "lasso" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aeb7b21a526375c5ca55f1a6dfd4e1fad9fa4edd750f530252a718a44b2608f0" -dependencies = [ - "dashmap", - "hashbrown 0.11.2", -] - [[package]] name = "libc" version = "0.2.142" @@ -332,28 +273,6 @@ version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ece97ea872ece730aed82664c424eb4c8291e1ff2480247ccf7409044bc6479f" -[[package]] -name = "lock_api" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" -dependencies = [ - "autocfg", - "scopeguard", -] - -[[package]] -name = "mappable-rc" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "204651f31b0a6a7b2128d2b92c372cd94607b210c3a6b6e542c57a8cfd4db996" - -[[package]] -name = "memchr" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" - [[package]] name = "num-traits" version = "0.2.15" @@ -363,16 +282,6 @@ dependencies = [ "autocfg", ] -[[package]] -name = "num_cpus" -version = "1.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" -dependencies = [ - "hermit-abi 0.2.6", - "libc", -] - [[package]] name = "once_cell" version = "1.17.1" @@ -381,19 +290,15 @@ checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" [[package]] name = "orchid" -version = "0.2.0" +version = "0.2.1" dependencies = [ - "base64", "chumsky", "clap", "dyn-clone", "hashbrown 0.13.2", "itertools", - "lasso", - "mappable-rc", "ordered-float", "smallvec", - "static_init", "thiserror", ] @@ -406,31 +311,6 @@ dependencies = [ "num-traits", ] -[[package]] -name = "parking_lot" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" -dependencies = [ - "instant", - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc" -dependencies = [ - "cfg-if", - "instant", - "libc", - "redox_syscall", - "smallvec", - "winapi", -] - [[package]] name = "proc-macro2" version = "1.0.56" @@ -458,15 +338,6 @@ dependencies = [ "proc-macro2", ] -[[package]] -name = "redox_syscall" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" -dependencies = [ - "bitflags", -] - [[package]] name = "rustix" version = "0.37.19" @@ -481,12 +352,6 @@ dependencies = [ "windows-sys", ] -[[package]] -name = "scopeguard" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" - [[package]] name = "smallvec" version = "1.10.0" @@ -506,51 +371,12 @@ dependencies = [ "winapi", ] -[[package]] -name = "static_init" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a2a1c578e98c1c16fc3b8ec1328f7659a500737d7a0c6d625e73e830ff9c1f6" -dependencies = [ - "bitflags", - "cfg_aliases", - "libc", - "parking_lot", - "parking_lot_core", - "static_init_macro", - "winapi", -] - -[[package]] -name = "static_init_macro" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70a2595fc3aa78f2d0e45dd425b22282dd863273761cc77780914b2cf3003acf" -dependencies = [ - "cfg_aliases", - "memchr", - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "strsim" version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - [[package]] name = "syn" version = "2.0.13" @@ -579,7 +405,7 @@ checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.13", + "syn", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 431fbdf..4bba97b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "orchid" -version = "0.2.0" +version = "0.2.1" edition = "2021" authors = [ "Lawrence Bethlenfalvy " @@ -12,12 +12,8 @@ authors = [ thiserror = "1.0" chumsky = "0.9.2" hashbrown = "0.13.2" -mappable-rc = "0.1" ordered-float = "3.0" itertools = "0.10" smallvec = { version = "1.10.0", features = ['const_generics'] } dyn-clone = "1.0.11" -lasso = { version = "0.6.0", features = ['multi-threaded'] } -base64 = "0.21.0" -static_init = "1.0.3" -clap = { version = "4.2.7", features = ["derive"] } +clap = { version = "4.2.4", features = ["derive"] } diff --git a/src/external/bool/equals.rs b/src/external/bool/equals.rs index 3ae203d..de74f72 100644 --- a/src/external/bool/equals.rs +++ b/src/external/bool/equals.rs @@ -13,7 +13,7 @@ use super::boolean::Boolean; #[derive(Clone)] pub struct Equals2; -externfn_impl!(Equals2, |_: &Self, x: ExprInst| {Ok(Equals1{x})}); +externfn_impl!(Equals2, |_: &Self, x: ExprInst| Ok(Equals1{x})); /// Partially applied Equals function /// diff --git a/src/external/bool/ifthenelse.rs b/src/external/bool/ifthenelse.rs index 9f1205e..44aeeb6 100644 --- a/src/external/bool/ifthenelse.rs +++ b/src/external/bool/ifthenelse.rs @@ -13,7 +13,7 @@ use super::Boolean; #[derive(Clone)] pub struct IfThenElse1; -externfn_impl!(IfThenElse1, |_: &Self, x: ExprInst| {Ok(IfThenElse0{x})}); +externfn_impl!(IfThenElse1, |_: &Self, x: ExprInst| Ok(IfThenElse0{x})); /// Partially applied IfThenElse function /// diff --git a/src/external/conv/parse_float.rs b/src/external/conv/parse_float.rs index cf3f500..6f1252b 100644 --- a/src/external/conv/parse_float.rs +++ b/src/external/conv/parse_float.rs @@ -15,7 +15,7 @@ use crate::{atomic_impl, atomic_redirect, externfn_impl}; #[derive(Clone)] pub struct ParseFloat1; -externfn_impl!(ParseFloat1, |_: &Self, x: ExprInst| {Ok(ParseFloat0{x})}); +externfn_impl!(ParseFloat1, |_: &Self, x: ExprInst| Ok(ParseFloat0{x})); /// Applied to_string function /// diff --git a/src/external/conv/parse_uint.rs b/src/external/conv/parse_uint.rs index 7bc6b62..130b719 100644 --- a/src/external/conv/parse_uint.rs +++ b/src/external/conv/parse_uint.rs @@ -14,7 +14,7 @@ use crate::parse::int_parser; #[derive(Clone)] pub struct ParseUint1; -externfn_impl!(ParseUint1, |_: &Self, x: ExprInst| {Ok(ParseUint0{x})}); +externfn_impl!(ParseUint1, |_: &Self, x: ExprInst| Ok(ParseUint0{x})); /// Applied ParseUint function /// diff --git a/src/external/conv/to_string.rs b/src/external/conv/to_string.rs index 34cb46a..cd5b56f 100644 --- a/src/external/conv/to_string.rs +++ b/src/external/conv/to_string.rs @@ -11,7 +11,7 @@ use crate::{atomic_impl, atomic_redirect, externfn_impl}; #[derive(Clone)] pub struct ToString1; -externfn_impl!(ToString1, |_: &Self, x: ExprInst| {Ok(ToString0{x})}); +externfn_impl!(ToString1, |_: &Self, x: ExprInst| Ok(ToString0{x})); /// Applied ToString function /// diff --git a/src/external/cpsio/print.rs b/src/external/cpsio/print.rs index 9f2ad63..79557a5 100644 --- a/src/external/cpsio/print.rs +++ b/src/external/cpsio/print.rs @@ -12,7 +12,7 @@ use crate::representations::interpreted::{Clause, ExprInst}; #[derive(Clone)] pub struct Print2; -externfn_impl!(Print2, |_: &Self, x: ExprInst| {Ok(Print1{x})}); +externfn_impl!(Print2, |_: &Self, x: ExprInst| Ok(Print1{x})); /// Partially applied Print function /// diff --git a/src/external/cpsio/readline.rs b/src/external/cpsio/readline.rs index 9954e88..c8e8672 100644 --- a/src/external/cpsio/readline.rs +++ b/src/external/cpsio/readline.rs @@ -12,7 +12,7 @@ use crate::representations::interpreted::{Clause, ExprInst}; #[derive(Clone)] pub struct Readln2; -externfn_impl!(Readln2, |_: &Self, x: ExprInst| {Ok(Readln1{x})}); +externfn_impl!(Readln2, |_: &Self, x: ExprInst| Ok(Readln1{x})); /// Partially applied Readln function /// @@ -23,7 +23,8 @@ pub struct Readln1{ x: ExprInst } atomic_redirect!(Readln1, x); atomic_impl!(Readln1, |Self{ x }: &Self| { let mut buf = String::new(); - stdin().read_line(&mut buf).map_err(|e| RuntimeError::ext(e.to_string(), "reading from stdin"))?; + stdin().read_line(&mut buf) + .map_err(|e| RuntimeError::ext(e.to_string(), "reading from stdin"))?; buf.pop(); Ok(Clause::Apply { f: x.clone(), diff --git a/src/external/num/operators/add.rs b/src/external/num/operators/add.rs index 5aec23d..d1b3b02 100644 --- a/src/external/num/operators/add.rs +++ b/src/external/num/operators/add.rs @@ -12,7 +12,7 @@ use crate::representations::interpreted::ExprInst; #[derive(Clone)] pub struct Add2; -externfn_impl!(Add2, |_: &Self, x: ExprInst| {Ok(Add1{x})}); +externfn_impl!(Add2, |_: &Self, x: ExprInst| Ok(Add1{x})); /// Partially applied Add function /// diff --git a/src/external/num/operators/divide.rs b/src/external/num/operators/divide.rs index aeda6a6..5b9c310 100644 --- a/src/external/num/operators/divide.rs +++ b/src/external/num/operators/divide.rs @@ -12,7 +12,7 @@ use crate::representations::interpreted::ExprInst; #[derive(Clone)] pub struct Divide2; -externfn_impl!(Divide2, |_: &Self, x: ExprInst| {Ok(Divide1{x})}); +externfn_impl!(Divide2, |_: &Self, x: ExprInst| Ok(Divide1{x})); /// Partially applied Divide function /// diff --git a/src/external/num/operators/multiply.rs b/src/external/num/operators/multiply.rs index 1f38379..df990f3 100644 --- a/src/external/num/operators/multiply.rs +++ b/src/external/num/operators/multiply.rs @@ -12,7 +12,7 @@ use crate::representations::interpreted::ExprInst; #[derive(Clone)] pub struct Multiply2; -externfn_impl!(Multiply2, |_: &Self, x: ExprInst| {Ok(Multiply1{x})}); +externfn_impl!(Multiply2, |_: &Self, x: ExprInst| Ok(Multiply1{x})); /// Partially applied Multiply function /// diff --git a/src/external/num/operators/remainder.rs b/src/external/num/operators/remainder.rs index c2b3b23..037eb5a 100644 --- a/src/external/num/operators/remainder.rs +++ b/src/external/num/operators/remainder.rs @@ -12,7 +12,7 @@ use crate::representations::interpreted::ExprInst; #[derive(Clone)] pub struct Remainder2; -externfn_impl!(Remainder2, |_: &Self, x: ExprInst| {Ok(Remainder1{x})}); +externfn_impl!(Remainder2, |_: &Self, x: ExprInst| Ok(Remainder1{x})); /// Partially applied Remainder function /// diff --git a/src/external/num/operators/subtract.rs b/src/external/num/operators/subtract.rs index 35d88bd..f3aab97 100644 --- a/src/external/num/operators/subtract.rs +++ b/src/external/num/operators/subtract.rs @@ -12,7 +12,7 @@ use crate::representations::interpreted::ExprInst; #[derive(Clone)] pub struct Subtract2; -externfn_impl!(Subtract2, |_: &Self, x: ExprInst| {Ok(Subtract1{x})}); +externfn_impl!(Subtract2, |_: &Self, x: ExprInst| Ok(Subtract1{x})); /// Partially applied Subtract function /// diff --git a/src/external/str/char_at.rs b/src/external/str/char_at.rs index 4a120fb..e64edd4 100644 --- a/src/external/str/char_at.rs +++ b/src/external/str/char_at.rs @@ -12,7 +12,7 @@ use crate::representations::interpreted::{Clause, ExprInst}; #[derive(Clone)] pub struct CharAt2; -externfn_impl!(CharAt2, |_: &Self, x: ExprInst| {Ok(CharAt1{x})}); +externfn_impl!(CharAt2, |_: &Self, x: ExprInst| Ok(CharAt1{x})); /// Partially applied CharAt function /// diff --git a/src/external/str/concatenate.rs b/src/external/str/concatenate.rs index 9741a4f..0df75e8 100644 --- a/src/external/str/concatenate.rs +++ b/src/external/str/concatenate.rs @@ -11,7 +11,7 @@ use crate::representations::interpreted::{Clause, ExprInst}; #[derive(Clone)] pub struct Concatenate2; -externfn_impl!(Concatenate2, |_: &Self, c: ExprInst| {Ok(Concatenate1{c})}); +externfn_impl!(Concatenate2, |_: &Self, c: ExprInst| Ok(Concatenate1{c})); /// Partially applied Concatenate function /// diff --git a/src/foreign.rs b/src/foreign.rs index 6d3ee49..7b84770 100644 --- a/src/foreign.rs +++ b/src/foreign.rs @@ -1,4 +1,5 @@ use std::any::Any; +use std::error::Error; use std::fmt::{Display, Debug}; use std::hash::Hash; use std::rc::Rc; @@ -11,10 +12,16 @@ use crate::representations::Primitive; pub use crate::representations::interpreted::Clause; use crate::representations::interpreted::ExprInst; +pub struct AtomicReturn { + pub clause: Clause, + pub gas: Option, + pub inert: bool +} + // Aliases for concise macros pub type RcError = Rc; -pub type AtomicResult = Result<(Clause, Option), RuntimeError>; -pub type XfnResult = Result<(Clause, Option), RcError>; +pub type AtomicResult = Result; +pub type XfnResult = Result; pub type RcExpr = ExprInst; pub trait ExternError: Display { @@ -24,6 +31,14 @@ pub trait ExternError: Display { } } +impl Debug for dyn ExternError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{self}") + } +} + +impl Error for dyn ExternError {} + /// Represents an externally defined function from the perspective of /// the executor. Since Orchid lacks basic numerical operations, /// these are also external functions. @@ -85,6 +100,9 @@ impl Atom { self.data().as_any().downcast_ref() .expect("Type mismatch on Atom::cast") } + pub fn run(&self, ctx: Context) -> AtomicResult { + self.0.run(ctx) + } } impl Clone for Atom { diff --git a/src/foreign_macros/atomic_impl.rs b/src/foreign_macros/atomic_impl.rs index 155c6e4..9669dcd 100644 --- a/src/foreign_macros/atomic_impl.rs +++ b/src/foreign_macros/atomic_impl.rs @@ -56,14 +56,14 @@ macro_rules! atomic_impl { AsRef<$crate::foreign::RcExpr> >::as_ref(self).clone(); // run the expression - let ret = $crate::interpreter::run(expr, ctx)?; - let $crate::interpreter::Return{ gas, state } = ret; + let ret = $crate::interpreter::run(expr, ctx.clone())?; + let $crate::interpreter::Return{ gas, state, inert } = ret; // rebuild the atomic let next_self = >::from((self, state)); // branch off or wrap up - let next_clause = if gas.map(|g| g > 0).unwrap_or(true) { + let clause = if inert { match ($next_phase)(&next_self) { Ok(r) => r, Err(e) => return Err( @@ -72,7 +72,7 @@ macro_rules! atomic_impl { } } else { next_self.to_atom_cls() }; // package and return - Ok((next_clause, gas)) + Ok($crate::foreign::AtomicReturn{ clause, gas, inert: false }) } } }; diff --git a/src/foreign_macros/atomic_inert.rs b/src/foreign_macros/atomic_inert.rs index 4a6b3e5..559a319 100644 --- a/src/foreign_macros/atomic_inert.rs +++ b/src/foreign_macros/atomic_inert.rs @@ -18,7 +18,11 @@ macro_rules! atomic_inert { fn run(&self, ctx: $crate::interpreter::Context) -> $crate::foreign::AtomicResult { - Ok((self.clone().to_atom_cls(), ctx.gas)) + Ok($crate::foreign::AtomicReturn{ + clause: self.clone().to_atom_cls(), + gas: ctx.gas, + inert: true + }) } } }; diff --git a/src/foreign_macros/externfn_impl.rs b/src/foreign_macros/externfn_impl.rs index ee3159c..1e00231 100644 --- a/src/foreign_macros/externfn_impl.rs +++ b/src/foreign_macros/externfn_impl.rs @@ -23,17 +23,16 @@ macro_rules! externfn_impl { fn name(&self) -> &str {stringify!($typ)} fn apply(&self, arg: $crate::foreign::RcExpr, - ctx: $crate::interpreter::Context + _ctx: $crate::interpreter::Context ) -> $crate::foreign::XfnResult { match ($next_atomic)(self, arg) { // ? casts the result but we want to strictly forward it - Ok(r) => Ok(( + Ok(r) => Ok( $crate::representations::interpreted::Clause::P( $crate::representations::Primitive::Atom( $crate::foreign::Atom::new(r) ) - ), - ctx.gas.map(|g| g - 1) - )), + ) + ), Err(e) => Err(e) } } diff --git a/src/interpreter/apply.rs b/src/interpreter/apply.rs index 4147893..f1d43a9 100644 --- a/src/interpreter/apply.rs +++ b/src/interpreter/apply.rs @@ -1,4 +1,4 @@ -use crate::foreign::Atom; +use crate::foreign::AtomicReturn; use crate::representations::Primitive; use crate::representations::PathSet; use crate::representations::interpreted::{ExprInst, Clause}; @@ -19,18 +19,18 @@ fn map_at( source.try_update(|value| { // Pass right through lambdas if let Clause::Lambda { args, body } = value { - return Ok(Clause::Lambda { + return Ok((Clause::Lambda { args: args.clone(), body: map_at(path, body.clone(), mapper)? - }) + }, ())) } // If the path ends here, process the next (non-lambda) node let (head, tail) = if let Some(sf) = path.split_first() {sf} else { - return Ok(mapper(value)?) + return Ok((mapper(value)?, ())) }; // If it's an Apply, execute the next step in the path if let Clause::Apply { f, x } = value { - return Ok(match head { + return Ok((match head { Side::Left => Clause::Apply { f: map_at(tail, f.clone(), mapper)?, x: x.clone(), @@ -39,10 +39,10 @@ fn map_at( f: f.clone(), x: map_at(tail, x.clone(), mapper)?, } - }) + }, ())) } panic!("Invalid path") - }) + }).map(|p| p.0) } fn substitute(paths: &PathSet, value: Clause, body: ExprInst) -> ExprInst { @@ -64,15 +64,14 @@ fn substitute(paths: &PathSet, value: Clause, body: ExprInst) -> ExprInst { /// Apply a function-like expression to a parameter. /// If any work is being done, gas will be deducted. pub fn apply( - f: ExprInst, x: ExprInst, mut ctx: Context + f: ExprInst, x: ExprInst, ctx: Context ) -> Result { - let state = f.clone().try_update(|clause| match clause { + let (state, (gas, inert)) = f.clone().try_update(|clause| match clause { // apply an ExternFn or an internal function Clause::P(Primitive::ExternFn(f)) => { - let (clause, gas) = f.apply(x, ctx.clone()) + let clause = f.apply(x, ctx.clone()) .map_err(|e| RuntimeError::Extern(e))?; - ctx.gas = gas.map(|g| g - 1); // cost of extern call - Ok(clause) + Ok((clause, (ctx.gas.map(|g| g - 1), false))) } Clause::Lambda{args, body} => Ok(if let Some(args) = args { let x_cls = x.expr().clause.clone(); @@ -80,25 +79,22 @@ pub fn apply( let new_xpr = new_xpr_inst.expr(); // cost of substitution // XXX: should this be the number of occurrences instead? - ctx.gas = ctx.gas.map(|x| x - 1); - new_xpr.clause.clone() - } else {body.expr().clause.clone()}), + (new_xpr.clause.clone(), (ctx.gas.map(|x| x - 1), false)) + } else {(body.expr().clause.clone(), (ctx.gas, false))}), Clause::Constant(name) => { let symval = ctx.symbols.get(name).expect("missing symbol for function").clone(); - ctx.gas = ctx.gas.map(|x| x - 1); // cost of lookup - Ok(Clause::Apply { f: symval, x, }) + Ok((Clause::Apply { f: symval, x, }, (ctx.gas, false))) } - Clause::P(Primitive::Atom(Atom(atom))) => { // take a step in expanding atom - let (clause, gas) = atom.run(ctx.clone())?; - ctx.gas = gas.map(|x| x - 1); // cost of dispatch - Ok(Clause::Apply { f: clause.wrap(), x }) + Clause::P(Primitive::Atom(atom)) => { // take a step in expanding atom + let AtomicReturn { clause, gas, inert } = atom.run(ctx.clone())?; + Ok((Clause::Apply { f: clause.wrap(), x }, (gas, inert))) }, Clause::Apply{ f: fun, x: arg } => { // take a step in resolving pre-function - let res = apply(fun.clone(), arg.clone(), ctx.clone())?; - ctx.gas = res.gas; // if work has been done, it has been paid - Ok(Clause::Apply{ f: res.state, x }) + let ret = apply(fun.clone(), arg.clone(), ctx.clone())?; + let Return { state, inert, gas } = ret; + Ok((Clause::Apply{ f: state, x }, (gas, inert))) }, _ => Err(RuntimeError::NonFunctionApplication(f.clone())) })?; - Ok(Return { state, gas: ctx.gas }) + Ok(Return { state, gas, inert }) } \ No newline at end of file diff --git a/src/interpreter/context.rs b/src/interpreter/context.rs index b4155ee..55fe66f 100644 --- a/src/interpreter/context.rs +++ b/src/interpreter/context.rs @@ -24,4 +24,5 @@ impl Context<'_> { pub struct Return { pub state: ExprInst, pub gas: Option, + pub inert: bool, } diff --git a/src/interpreter/error.rs b/src/interpreter/error.rs index c7a67f6..7055974 100644 --- a/src/interpreter/error.rs +++ b/src/interpreter/error.rs @@ -5,7 +5,7 @@ use crate::representations::interpreted::ExprInst; use crate::foreign::ExternError; /// Problems in the process of execution -#[derive(Clone)] +#[derive(Clone, Debug)] pub enum RuntimeError { Extern(Rc), NonFunctionApplication(ExprInst), diff --git a/src/interpreter/run.rs b/src/interpreter/run.rs index 6650299..0308a5f 100644 --- a/src/interpreter/run.rs +++ b/src/interpreter/run.rs @@ -1,4 +1,4 @@ -use crate::foreign::Atom; +use crate::foreign::AtomicReturn; use crate::representations::Primitive; use crate::representations::interpreted::{Clause, ExprInst}; @@ -9,19 +9,20 @@ use super::context::{Context, Return}; pub fn run(expr: ExprInst, mut ctx: Context) -> Result { - let state = expr.try_normalize(|cls| -> Result { + let (state, (gas, inert)) = expr.try_normalize(|cls| -> Result<(Clause, _), RuntimeError> { let mut i = cls.clone(); while ctx.gas.map(|g| g > 0).unwrap_or(true) { match &i { Clause::Apply { f, x } => { let res = apply(f.clone(), x.clone(), ctx.clone())?; - if ctx.is_stuck(res.gas) {return Ok(i)} + if res.inert {return Ok((i, (res.gas, true)))} ctx.gas = res.gas; i = res.state.expr().clause.clone(); } - Clause::P(Primitive::Atom(Atom(data))) => { - let (clause, gas) = data.run(ctx.clone())?; - if ctx.is_stuck(gas) {return Ok(i)} + Clause::P(Primitive::Atom(data)) => { + let ret = data.run(ctx.clone())?; + let AtomicReturn { clause, gas, inert } = ret; + if inert {return Ok((i, (gas, true)))} ctx.gas = gas; i = clause.clone(); } @@ -30,10 +31,12 @@ pub fn run(expr: ExprInst, mut ctx: Context) ctx.gas = ctx.gas.map(|g| g - 1); // cost of lookup i = symval.expr().clause.clone(); } - _ => return Ok(i) + // non-reducible + _ => return Ok((i, (ctx.gas, true))) } } - Ok(i) + // out of gas + Ok((i, (ctx.gas, false))) })?; - Ok(Return { state, gas: ctx.gas }) + Ok(Return { state, gas, inert }) } \ No newline at end of file diff --git a/src/representations/interpreted.rs b/src/representations/interpreted.rs index 03d9213..d9c2399 100644 --- a/src/representations/interpreted.rs +++ b/src/representations/interpreted.rs @@ -56,26 +56,27 @@ impl ExprInst { /// Call a normalization function on the expression. The expr is /// updated with the new clause which affects all copies of it /// across the tree. - pub fn try_normalize(&self, - mapper: impl FnOnce(&Clause) -> Result - ) -> Result { - let new_clause = mapper(&self.expr().clause)?; + pub fn try_normalize(&self, + mapper: impl FnOnce(&Clause) -> Result<(Clause, T), E> + ) -> Result<(Self, T), E> { + let (new_clause, extra) = mapper(&self.expr().clause)?; self.expr_mut().clause = new_clause; - Ok(self.clone()) + Ok((self.clone(), extra)) } /// Run a mutation function on the expression, producing a new, /// distinct expression. The new expression shares location info with /// the original but is normalized independently. - pub fn try_update(&self, - mapper: impl FnOnce(&Clause) -> Result - ) -> Result { + pub fn try_update(&self, + mapper: impl FnOnce(&Clause) -> Result<(Clause, T), E> + ) -> Result<(Self, T), E> { let expr = self.expr(); + let (clause, extra) = mapper(&expr.clause)?; let new_expr = Expr{ - clause: mapper(&expr.clause)?, + clause, location: expr.location.clone(), }; - Ok(Self(Rc::new(RefCell::new(new_expr)))) + Ok((Self(Rc::new(RefCell::new(new_expr))), extra)) } /// Call a predicate on the expression, returning whatever the diff --git a/src/rule/matcher_second/build.rs b/src/rule/matcher_second/build.rs index 0ae1030..44e19fb 100644 --- a/src/rule/matcher_second/build.rs +++ b/src/rule/matcher_second/build.rs @@ -34,7 +34,6 @@ fn scal_cnt<'a>(iter: impl Iterator) -> usize { /// Recursively convert this pattern into a matcher that can be /// efficiently applied to slices. pub fn mk_matcher(pattern: &[Expr]) -> AnyMatcher { - println!("matcher from {:?}", pattern); let left_split = scal_cnt(pattern.iter()); if pattern.len() <= left_split { return AnyMatcher::Scalar(mk_scalv(pattern)) @@ -51,13 +50,11 @@ pub fn mk_matcher(pattern: &[Expr]) -> AnyMatcher { /// Pattern MUST NOT contain vectorial placeholders fn mk_scalv(pattern: &[Expr]) -> Vec { - println!("Scalv from {:?}", pattern); pattern.iter().map(mk_scalar).collect() } /// Pattern MUST start and end with a vectorial placeholder fn mk_vec(pattern: &[Expr]) -> VecMatcher { - println!("Vec from {:?}", pattern); debug_assert!(!pattern.is_empty(), "pattern cannot be empty"); debug_assert!(pattern.first().map(vec_attrs).is_some(), "pattern must start with a vectorial"); debug_assert!(pattern.last().map(vec_attrs).is_some(), "pattern must end with a vectorial"); @@ -103,7 +100,6 @@ fn mk_vec(pattern: &[Expr]) -> VecMatcher { /// Pattern MUST NOT be a vectorial placeholder fn mk_scalar(pattern: &Expr) -> ScalMatcher { - println!("Scalar from {:?}", pattern); match &pattern.value { Clause::P(p) => ScalMatcher::P(p.clone()), Clause::Name(n) => ScalMatcher::Name(*n), diff --git a/src/run_dir.rs b/src/run_dir.rs index 06aedbb..1f290ae 100644 --- a/src/run_dir.rs +++ b/src/run_dir.rs @@ -112,7 +112,7 @@ pub fn run_dir(dir: &Path) { match repo.step(&tree) { None => break tree, Some(phase) => { - // println!("Step {idx}/{macro_timeout}: {}", phase.bundle(&i)); + println!("Step {idx}/{macro_timeout}: {}", phase.bundle(&i)); tree = phase; }, } @@ -135,9 +135,16 @@ pub fn run_dir(dir: &Path) { .join(", ") ) }); - let Return{ gas, state } = interpreter::run(entrypoint.clone(), ctx) + let Return{ gas, state, inert } = interpreter::run(entrypoint.clone(), ctx) .unwrap_or_else(|e| panic!("Runtime error: {}", e)); - println!("Settled at {}", state.bundle(&i)); + if inert { + println!("Expression not reducible"); + println!("Settled at {}", state.expr().clause.bundle(&i)); + println!("Remaining gas: {}", + gas.map(|g| g.to_string()) + .unwrap_or(String::from("∞")) + ); + } if gas == Some(0) {println!("Ran out of gas!")} else {println!("Expression not reducible.")} } \ No newline at end of file diff --git a/src/utils/interner.rs b/src/utils/interner.rs deleted file mode 100644 index 815e6f1..0000000 --- a/src/utils/interner.rs +++ /dev/null @@ -1,181 +0,0 @@ -use std::sync::{Mutex, Arc}; -use std::num::NonZeroU32; -use std::hash::Hash; - -use lasso::{Rodeo, Spur, Key}; -use base64::{engine::general_purpose::STANDARD_NO_PAD as BASE64, Engine}; - -/// A token representing an interned string or sequence in an interner -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, PartialOrd, Ord)] -pub struct Token(pub Spur); - -/// An interner that can intern strings, and sequences of things it -/// interned as long as they have the same rank -pub trait Interner: Sync { - fn str2tok(&self, str: &str) -> Token; - fn tok2str(&self, token: Token) -> String; - fn slc2tok(&self, slice: &[Token]) -> Token<{RANK + 1}>; - fn tok2slc(&self, token: Token) -> Vec>; - fn tok2strv(&self, token: Token>>) -> Vec { - self.tok2slc(token).into_iter().map(|t| self.tok2str(t)).collect() - } - fn tokv2strv(&self, slice: &[Token]) -> Vec { - slice.iter().map(|t| self.tok2str(*t)).collect() - } - /// Get the first token of a sequence - fn head(&self, token: Token) -> Token<{RANK - 1}>; - /// Returns the length of a sequence - fn len(&self, token: Token) -> usize - where Token<{RANK - 1}>: Clone; - /// Returns the length of the longest identical prefix of the two sequences - fn coprefix(&self, a: Token, b: Token) -> usize - where Token<{RANK - 1}>: Clone; -} - -fn serialize_seq(seq: &[Token]) -> String { - let data: Vec = seq.iter() - .map(|t| u32::from(t.0.into_inner()).to_le_bytes().into_iter()) - .flatten() - .collect(); - BASE64.encode(data) -} - -fn deserialize_seq(string: &str) -> Vec> { - let data = BASE64.decode(string) - .expect("String is not valid base64"); - assert!(data.len() % 4 == 0, "Tokens should serialize to 3 bytes each"); - data.array_chunks::<4>().map(|a| { - let bytes = [a[0], a[1], a[2], a[3]]; - let nz32 = NonZeroU32::new(u32::from_le_bytes(bytes)) - .expect("Token representation should never be zero"); - Token(Spur::try_from_usize(u32::from(nz32) as usize).unwrap()) - }).collect() -} - -/// An interner that delegates the actual work to Lasso -#[derive(Clone)] -pub struct LassoInterner { - strings: Arc>, - slices: Arc> -} - -impl LassoInterner { - /// Create an empty interner. Called to create the singleton. - fn new() -> Self { - Self{ - slices: Arc::new(Mutex::new(Rodeo::new())), - strings: Arc::new(Mutex::new(Rodeo::new())) - } - } -} - -impl Interner for LassoInterner { - fn str2tok(&self, str: &str) -> Token { - let mut strings = self.strings.lock().unwrap(); - let key = strings.get_or_intern(str); - Token(key) - } - - fn tok2str<'a>(&'a self, token: Token) -> String { - let key = token.0; - let strings = self.strings.lock().unwrap(); - strings.resolve(&key).to_string() - } - - fn slc2tok(&self, slice: &[Token]) -> Token<{RANK + 1}> { - let data = serialize_seq(slice); - let mut slices = self.slices.lock().unwrap(); - let key = slices.get_or_intern(data); - Token(key) - } - - fn tok2slc<'a, const RANK: u8>(&'a self, token: Token) -> Vec> { - let key = token.0; - let slices = self.slices.lock().unwrap(); - let string = slices.resolve(&key); - deserialize_seq(string) - } - - fn head(&self, token: Token) -> Token<{RANK - 1}> { - let key = token.0; - let slices = self.slices.lock().unwrap(); - let string = slices.resolve(&key); - deserialize_seq(&string[0..5])[0] - } - - fn len(&self, token: Token) -> usize where Token<{RANK - 1}>: Clone { - let key = token.0; - let slices = self.slices.lock().unwrap(); - let string = slices.resolve(&key); - assert!(string.len() % 4 == 0, "Tokens should serialize to 3 characters"); - string.len() / 4 - } - - fn coprefix(&self, a: Token, b: Token) -> usize where Token<{RANK - 1}>: Clone { - let keya = a.0; - let keyb = b.0; - let slices = self.slices.lock().unwrap(); - let sa = slices.resolve(&keya); - let sb = slices.resolve(&keyb); - sa.bytes() - .zip(sb.bytes()) - .take_while(|(a, b)| a == b) - .count() / 4 - } -} - -/// Create an interner that inherits the singleton's data, and -/// block all future interaction with the singleton. -/// -/// DO NOT call within [dynamic] or elsewhere pre-main -pub fn mk_interner() -> impl Interner { - LassoInterner::new() -} - -pub trait StringLike: Clone + Eq + Hash { - fn into_str(self, i: &Interner) -> String; - fn into_tok(self, i: &Interner) -> Token; -} - -impl StringLike for String { - fn into_str(self, _i: &Interner) -> String {self} - fn into_tok(self, i: &Interner) -> Token {i.str2tok(&self)} -} - -impl StringLike for Token { - fn into_str(self, i: &Interner) -> String {i.tok2str(self)} - fn into_tok(self, _i: &Interner) -> Token {self} -} - -pub trait StringVLike: Clone + Eq + Hash { - fn into_strv(self, i: &Interner) -> Vec; - fn into_tok(self, i: &Interner) -> Token>>; - fn into_tokv(self, i: &Interner) -> Vec>; -} - -impl StringVLike for Vec { - fn into_strv(self, _i: &Interner) -> Vec {self} - fn into_tok(self, i: &Interner) -> Token>> { - let tokv = self.into_iter() - .map(|s| i.str2tok(&s)) - .collect::>(); - i.slc2tok(&tokv) - } - fn into_tokv(self, i: &Interner) -> Vec> { - self.into_iter() - .map(|s| i.str2tok(&s)) - .collect() - } -} - -impl StringVLike for Vec> { - fn into_strv(self, i: &Interner) -> Vec {i.tokv2strv(&self)} - fn into_tok(self, i: &Interner) -> Token>> {i.slc2tok(&self)} - fn into_tokv(self, _i: &Interner) -> Vec> {self} -} - -impl StringVLike for Token>> { - fn into_strv(self, i: &Interner) -> Vec {i.tok2strv(self)} - fn into_tok(self, _i: &Interner) -> Token>> {self} - fn into_tokv(self, i: &Interner) -> Vec> {i.tok2slc(self)} -} \ No newline at end of file