From cf9eed1091317235bbf1adaa768d9eeab4950507 Mon Sep 17 00:00:00 2001 From: daddinuz Date: Sun, 11 Aug 2024 17:38:04 +0200 Subject: [PATCH 1/8] add dependencies --- Cargo.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 54ac9ef..f02edf6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -65,9 +65,9 @@ dependencies = [ [[package]] name = "cpufeatures" -version = "0.2.12" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +checksum = "51e852e6dc9a5bed1fae92dd2375037bf2b768725bf3be87811edee3249d09ad" dependencies = [ "libc", ] @@ -240,9 +240,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.155" +version = "0.2.156" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" +checksum = "a5f43f184355eefb8d17fc948dbecf6c13be3c141f20d834ae842193a448c72a" [[package]] name = "libredox" @@ -523,9 +523,9 @@ checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "syn" -version = "2.0.72" +version = "2.0.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc4b9b9bf2add8093d3f2c0204471e951b2285580335de42f9d2534f3ae7a8af" +checksum = "1fceb41e3d546d0bd83421d3409b1460cc7444cd389341a4c880fe7a042cb3d7" dependencies = [ "proc-macro2", "quote", From 2b2a7fc2e7d150c8df53add34346d24bb4240229 Mon Sep 17 00:00:00 2001 From: daddinuz Date: Sat, 17 Aug 2024 00:31:50 +0200 Subject: [PATCH 2/8] remove Process and channels --- Cargo.lock | 57 ---------- examples/alice_n_bob.rat | 3 - examples/parallel-mergesort.rat | 13 --- rat/Cargo.toml | 1 - rat/src/builtin.rs | 188 -------------------------------- rat/src/evaluator.rs | 15 +-- rat/src/expression.rs | 12 -- rat/src/globals.rs | 96 ---------------- rat/src/lib.rs | 50 +-------- rat/src/process.rs | 57 ---------- rat/src/vocabulary.rs | 22 +--- 11 files changed, 4 insertions(+), 510 deletions(-) delete mode 100644 examples/alice_n_bob.rat delete mode 100644 examples/parallel-mergesort.rat delete mode 100644 rat/src/globals.rs delete mode 100644 rat/src/process.rs diff --git a/Cargo.lock b/Cargo.lock index f02edf6..ae41644 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -72,62 +72,6 @@ dependencies = [ "libc", ] -[[package]] -name = "crossbeam" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1137cd7e7fc0fb5d3c5a8678be38ec56e819125d8d7907411fe24ccb943faca8" -dependencies = [ - "crossbeam-channel", - "crossbeam-deque", - "crossbeam-epoch", - "crossbeam-queue", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-channel" -version = "0.5.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33480d6946193aa8033910124896ca395333cae7e2d1113d1fef6c3272217df2" -dependencies = [ - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-deque" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" -dependencies = [ - "crossbeam-epoch", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-epoch" -version = "0.9.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" -dependencies = [ - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-queue" -version = "0.3.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df0346b5d5e76ac2fe4e327c5fd1118d6be7c51dfb18f9b7922923f287471e35" -dependencies = [ - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-utils" -version = "0.8.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" - [[package]] name = "crypto-common" version = "0.1.6" @@ -415,7 +359,6 @@ dependencies = [ name = "rat" version = "0.1.0" dependencies = [ - "crossbeam", "dirs", "pest", "pest_derive", diff --git a/examples/alice_n_bob.rat b/examples/alice_n_bob.rat deleted file mode 100644 index 9d99a70..0000000 --- a/examples/alice_n_bob.rat +++ /dev/null @@ -1,3 +0,0 @@ -["alice" 'bob' send 'alice' recv say] spawn -["bob" 'alice' send 'bob' recv say] spawn -"press [enter] to continue\n" ask diff --git a/examples/parallel-mergesort.rat b/examples/parallel-mergesort.rat deleted file mode 100644 index 666ebaa..0000000 --- a/examples/parallel-mergesort.rat +++ /dev/null @@ -1,13 +0,0 @@ -: seq @ rat\seq ; -: math @ rat\math ; - -# with program forming -: seq-ms ← quote [seq\mergesort 'out' send] cat detach ; -: par-ms ← dup len math\halve split [seq-ms 'out' recv] unary2 seq\merge ; - -# with message passing -# : seq-ms ← ['in' recv seq\mergesort 'out' send] detach ; -# : par-ms ← dup len math\halve split [seq-ms 'in' send 'out' recv] unary2 seq\merge ; - -[-23714 36911 27209 -61081 4487 62986 43562 59953 -6002 -64976 6222 37230 1774 60450 35372 9313 -63141 -10099 -56599 37381 29627 17147 -56774 46348 25159 42717 -10426 -38088 -9482 -51818 -13225 -22274 -52566 -5587 -148 59711 51437 6343 50139 32437 27966 -34985 167 27161 -53411 -6759 -27066 -7772 49899 -24127 7940 61517 -14064 -4433 6018 42197 -24241 4939 23687 -27950 -60335 -483 -51116 -201 21847 -65149 46808 49486 -6132 4372 14587 60525 14700 8373 -48827 -64401 -53524 -28842 -10959 -56034 -64763 -54632 28581 -3277 5279 7684 -26031 32221 1723 59531 -34723 17671 3424 -30493 28938 -12043 -27853 -14788 -34395 -23175 39083 -3314 16725 -14123 5069 -59857 52477 -25028 9931 -27366 41663 10612 -46240 27308 7778 -12942 37028 -18502 59012 53713 60519 -49390 -15897 41667 55977 45961 39978 59934 23858 -23789 -17806 -14129 -36824 -57834 -28443 -22873 26639 -20046 -57731 -16443 -599 -2646 8985 -14817 -10395 -42440 -59983 3357 44965 -44840 36400 -10323 -39719 45791 -27538 15597 7872 -19558 54625 -10621 27469 -61915 -45654 -61333 10374 50181 5656 8559 -9822 -9340 23135 -11774 -28400 -44677 304 37783 -56801 -45383 59955 23509 55993 -61971 16262 -49607 39590 -27209 1339 -56543 -41882 64893 50150 -16153 -317 -16469 7629 19020 15578 46013 53541 -27485 60355 -28348 -63558 -45715 -43954 62904 -8753 29052 -56968 52829 31804 45589 -26416 30184 29918 -38968 19638 -24968 -24088 -9447 48799 -50660 43610 -50411 -47355 -59101 59279 34413 55334 -16776 50629 63673 -44714 -32217 -37943 -21810 -51476 33889 6583 65273 60878 -13805 59344 34343 -43042 25481 40781 -37723 -39856 -19967 -54323 -6219 -24811 -51108 4870 -20829] -par-ms say diff --git a/rat/Cargo.toml b/rat/Cargo.toml index b2dc1b6..2c3331f 100644 --- a/rat/Cargo.toml +++ b/rat/Cargo.toml @@ -12,7 +12,6 @@ rust-version = "1.77" version = "0.1.0" [dependencies] -crossbeam = { version = "0.8", features = ["crossbeam-channel"] } dirs = "5" pest = "2" pest_derive = "2" diff --git a/rat/src/builtin.rs b/rat/src/builtin.rs index 3dea91a..a6b36ba 100644 --- a/rat/src/builtin.rs +++ b/rat/src/builtin.rs @@ -15,7 +15,6 @@ use crate::expression::Expression; use crate::boolean::Boolean; use crate::decimal::Decimal; use crate::integer::Integer; -use crate::process::Process; use crate::quote::Quote; use crate::string::String; use crate::symbol::Symbol; @@ -1155,105 +1154,6 @@ pub fn dup(evaluator: &mut Evaluator) -> Result<(), Effect> { Ok(()) } -pub fn send(evaluator: &mut Evaluator) -> Result<(), Effect> { - match &evaluator.stack[..] { - [.., expression, Expression::Symbol(topic)] => { - let expression = expression.clone(); - - if evaluator.globals.broker.send(*topic, expression).is_err() { - evaluator.stack.push(Symbol::io_error().into()); - return Err(Effect::Raise); - } - - let top = evaluator.stack.len(); - evaluator.stack.truncate(top - 2); - Ok(()) - } - [.., _, _] => { - evaluator.stack.push(Symbol::type_error().into()); - Err(Effect::Raise) - } - _ => { - evaluator.stack.push(Symbol::stack_underflow().into()); - Err(Effect::Raise) - } - } -} - -pub fn recv(evaluator: &mut Evaluator) -> Result<(), Effect> { - match &evaluator.stack[..] { - [.., Expression::Symbol(topic)] => match evaluator.globals.broker.recv(*topic) { - Ok(expression) => { - *evaluator.stack.last_mut().unwrap() = expression; - Ok(()) - } - Err(_) => { - evaluator.stack.push(Symbol::io_error().into()); - Err(Effect::Raise) - } - }, - [.., _] => { - evaluator.stack.push(Symbol::type_error().into()); - Err(Effect::Raise) - } - _ => { - evaluator.stack.push(Symbol::stack_underflow().into()); - Err(Effect::Raise) - } - } -} - -pub fn spawn(evaluator: &mut Evaluator) -> Result<(), Effect> { - let stack = &mut evaluator.stack; - - match &mut stack[..] { - [.., Expression::Quote(quote)] => { - let quote = std::mem::take(quote); - stack.pop().unwrap(); - - let process = Process::spawn(evaluator.globals.clone(), quote); - stack.push(Expression::Process(process)); - - Ok(()) - } - [.., _] => { - evaluator.stack.push(Symbol::type_error().into()); - Err(Effect::Raise) - } - _ => { - evaluator.stack.push(Symbol::stack_underflow().into()); - Err(Effect::Raise) - } - } -} - -pub fn detach(evaluator: &mut Evaluator) -> Result<(), Effect> { - let stack = &mut evaluator.stack; - - match &mut stack[..] { - [.., Expression::Quote(quote)] => { - let quote = std::mem::take(quote); - stack.pop().unwrap(); - - let globals = evaluator.globals.clone(); - std::thread::spawn(move || { - let mut evaluator = Evaluator::with_globals(globals); - evaluator.evaluate(quote.iter().cloned()) - }); - - Ok(()) - } - [.., _] => { - evaluator.stack.push(Symbol::type_error().into()); - Err(Effect::Raise) - } - _ => { - evaluator.stack.push(Symbol::stack_underflow().into()); - Err(Effect::Raise) - } - } -} - pub fn ask(evaluator: &mut Evaluator) -> Result<(), Effect> { let stack = &mut evaluator.stack; @@ -1450,91 +1350,3 @@ fn binrec_aux( } } } - -pub fn parbinrec(evaluator: &mut Evaluator) -> Result<(), Effect> { - let stack = &mut evaluator.stack; - - match &mut stack[..] { - [.., Expression::Quote(check), Expression::Quote(leave), Expression::Quote(shard), Expression::Quote(merge)] => - { - let merge = std::mem::take(merge); - let shard = std::mem::take(shard); - let leave = std::mem::take(leave); - let check = std::mem::take(check); - - let top = stack.len(); - stack.truncate(top - 4); - - parbinrec_aux(evaluator, &check, &leave, &shard, &merge) - } - [.., _, _, _, _] => { - stack.push(Symbol::type_error().into()); - Err(Effect::Raise) - } - _ => { - stack.push(Symbol::stack_underflow().into()); - Err(Effect::Raise) - } - } -} - -fn parbinrec_aux( - evaluator: &mut Evaluator, - check: &Quote, - leave: &Quote, - shard: &Quote, - merge: &Quote, -) -> Result<(), Effect> { - evaluator.evaluate(check.iter().cloned())?; - - match evaluator.stack.pop() { - Some(Expression::Boolean(Boolean(false))) => { - evaluator.evaluate(shard.iter().cloned())?; - - let [expression1, expression2] = [ - evaluator.stack.pop().unwrap(), - evaluator.stack.pop().unwrap(), - ]; - - let [result1, result2] = std::thread::scope(|s| { - let globals = evaluator.globals.clone(); - let handle1 = s.spawn(|| { - let mut evaluator = Evaluator { - stack: vec![expression1], - globals, - }; - parbinrec_aux(&mut evaluator, check, leave, shard, merge)?; - Ok(evaluator.stack) - }); - - let globals = evaluator.globals.clone(); - let handle2 = s.spawn(|| { - let mut evaluator = Evaluator { - stack: vec![expression2], - globals, - }; - parbinrec_aux(&mut evaluator, check, leave, shard, merge)?; - Ok(evaluator.stack) - }); - - [handle1.join().unwrap(), handle2.join().unwrap()] - }); - - evaluator.stack.extend(result1?); - evaluator.stack.extend(result2?); - evaluator.evaluate(merge.iter().cloned()) - } - Some(Expression::Boolean(Boolean(true))) => evaluator.evaluate(leave.iter().cloned()), - Some(expression) => { - evaluator - .stack - .extend_from_slice(&[expression, Symbol::type_error().into()]); - - Err(Effect::Raise) - } - None => { - evaluator.stack.push(Symbol::stack_underflow().into()); - Err(Effect::Raise) - } - } -} diff --git a/rat/src/evaluator.rs b/rat/src/evaluator.rs index b347db3..ca27a25 100644 --- a/rat/src/evaluator.rs +++ b/rat/src/evaluator.rs @@ -4,29 +4,18 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -use std::sync::Arc; - use crate::effect::Effect; use crate::evaluate::Evaluate; use crate::expression::Expression; -use crate::globals::Globals; #[derive(Default)] pub struct Evaluator { pub stack: Vec, - pub globals: Arc, } impl Evaluator { - pub fn new() -> Self { - Default::default() - } - - pub fn with_globals(globals: Arc) -> Self { - Self { - stack: Vec::new(), - globals, - } + pub const fn new() -> Self { + Self { stack: Vec::new() } } } diff --git a/rat/src/expression.rs b/rat/src/expression.rs index b0037bd..5ba9080 100644 --- a/rat/src/expression.rs +++ b/rat/src/expression.rs @@ -13,7 +13,6 @@ use crate::evaluator::Evaluator; use crate::boolean::Boolean; use crate::decimal::Decimal; use crate::integer::Integer; -use crate::process::Process; use crate::quote::Quote; use crate::record::Record; use crate::string::String; @@ -25,7 +24,6 @@ pub enum Expression { Boolean(Boolean), Decimal(Decimal), Integer(Integer), - Process(Process), Quote(Quote), Record(Record), String(String), @@ -57,13 +55,6 @@ impl From for Expression { } } -impl From for Expression { - #[inline] - fn from(value: Process) -> Self { - Self::Process(value) - } -} - impl From for Expression { #[inline] fn from(value: Quote) -> Self { @@ -107,7 +98,6 @@ impl Evaluate for &mut Evaluator { Expression::Boolean(v) => self.evaluate(v), Expression::Decimal(v) => self.evaluate(v), Expression::Integer(v) => self.evaluate(v), - Expression::Process(v) => self.evaluate(v), Expression::Quote(v) => self.evaluate(v), Expression::Record(v) => self.evaluate(v), Expression::String(v) => self.evaluate(v), @@ -123,7 +113,6 @@ impl Display for Expression { Expression::Boolean(v) => Display::fmt(v, f), Expression::Decimal(v) => Display::fmt(v, f), Expression::Integer(v) => Display::fmt(v, f), - Expression::Process(v) => Display::fmt(v, f), Expression::Quote(v) => Display::fmt(v, f), Expression::Record(v) => Display::fmt(v, f), Expression::String(v) => Display::fmt(v, f), @@ -139,7 +128,6 @@ impl Debug for Expression { Expression::Boolean(v) => Debug::fmt(v, f), Expression::Decimal(v) => Debug::fmt(v, f), Expression::Integer(v) => Debug::fmt(v, f), - Expression::Process(v) => Debug::fmt(v, f), Expression::Quote(v) => Debug::fmt(v, f), Expression::Record(v) => Debug::fmt(v, f), Expression::String(v) => Debug::fmt(v, f), diff --git a/rat/src/globals.rs b/rat/src/globals.rs deleted file mode 100644 index 694e1fa..0000000 --- a/rat/src/globals.rs +++ /dev/null @@ -1,96 +0,0 @@ -/* - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - */ - -use std::collections::HashMap; -use std::error::Error; -use std::sync::RwLock; - -use crossbeam::channel::{self, Receiver, Sender}; - -use crate::expression::Expression; -use crate::symbol::Symbol; - -#[derive(Default)] -pub struct Globals { - pub broker: Broker, -} - -impl Globals { - pub fn new() -> Self { - Default::default() - } -} - -#[derive(Default)] -pub struct Broker { - channels: RwLock>, -} - -impl Broker { - pub fn new() -> Self { - Default::default() - } - - pub fn send(&self, topic: Symbol, expression: Expression) -> Result<(), impl Error> { - // IMPORTANT: we must release any lock before performing send or recv operations. - // keeping any lock active while performing a recv operation may lead to deadlocks. - // we must to minimize the scope of active locks. - - let sender = 'block: { - // optimistically try to get the channel if it exists. - if let Some(channel) = self.channels.read().unwrap().get(&topic) { - break 'block channel.sender.clone(); - } - - // if it does not exist, create it. - self.channels - .write() - .unwrap() - .entry(topic) - .or_default() - .sender - .clone() - }; - - sender.send(expression) - } - - pub fn recv(&self, topic: Symbol) -> Result { - // IMPORTANT: we must release any lock before performing send or recv operations. - // keeping any lock active while performing a recv operation may lead to deadlocks. - // we must to minimize the scope of active locks. - - let receiver = 'block: { - // optimistically try to get the channel if it exists. - if let Some(channel) = self.channels.read().unwrap().get(&topic) { - break 'block channel.receiver.clone(); - } - - // if it does not exist, create it. - self.channels - .write() - .unwrap() - .entry(topic) - .or_default() - .receiver - .clone() - }; - - receiver.recv() - } -} - -struct Channel { - sender: Sender, - receiver: Receiver, -} - -impl Default for Channel { - fn default() -> Self { - let (sender, receiver) = channel::unbounded(); - Self { sender, receiver } - } -} diff --git a/rat/src/lib.rs b/rat/src/lib.rs index d533111..ca29c56 100644 --- a/rat/src/lib.rs +++ b/rat/src/lib.rs @@ -12,7 +12,6 @@ pub(crate) mod codegen; pub mod boolean; pub mod decimal; pub mod integer; -pub mod process; pub mod quote; pub mod record; pub mod string; @@ -25,7 +24,6 @@ pub mod builtin; pub mod effect; pub mod evaluate; pub mod evaluator; -pub mod globals; pub mod locution; pub mod parser; pub mod vocabulary; @@ -113,53 +111,7 @@ mod test { } #[test] - fn it_works4() { - let mut evaluator = Evaluator::default(); - evaluator - .evaluate( - [ - Expression::Quote( - [ - Expression::Integer(Integer(8)), - Expression::Integer(Integer(12)), - Expression::Verb(Verb(builtin::add)), - Expression::Symbol(Symbol::new("out")), - Expression::Verb(Verb(builtin::send)), - ] - .into_iter() - .collect(), - ), - Expression::Verb(Verb(builtin::detach)), - Expression::Quote( - [ - Expression::Integer(Integer(10)), - Expression::Integer(Integer(12)), - Expression::Verb(Verb(builtin::add)), - Expression::Symbol(Symbol::new("out")), - Expression::Verb(Verb(builtin::send)), - ] - .into_iter() - .collect(), - ), - Expression::Verb(Verb(builtin::detach)), - Expression::Symbol(Symbol::new("out")), - Expression::Verb(Verb(builtin::recv)), - Expression::Symbol(Symbol::new("out")), - Expression::Verb(Verb(builtin::recv)), - Expression::Verb(Verb(builtin::add)), - ] - .into_iter(), - ) - .unwrap(); - - assert!(matches!( - evaluator.stack.as_slice(), - &[Expression::Integer(Integer(42))] - )); - } - - #[test] - fn it_works5() { + fn it_works3() { let mut evaluator = Evaluator::default(); evaluator .evaluate( diff --git a/rat/src/process.rs b/rat/src/process.rs deleted file mode 100644 index 34c7990..0000000 --- a/rat/src/process.rs +++ /dev/null @@ -1,57 +0,0 @@ -/* - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - */ - -use std::fmt::{Debug, Display}; -use std::hash::Hash; -use std::sync::Arc; -use std::thread::{self}; - -use crate::effect::Effect; -use crate::evaluate::Evaluate; -use crate::evaluator::Evaluator; -use crate::expression::Expression; -use crate::globals::Globals; -use crate::quote::Quote; - -#[derive(Clone, PartialEq, Eq, Hash)] -pub struct Process { - quote: Quote, -} - -impl Process { - pub fn spawn(globals: Arc, quote: Quote) -> Self { - { - let quote = quote.clone(); - thread::spawn(move || { - let mut evaluator = Evaluator::with_globals(globals); - evaluator.evaluate(quote) - }); - } - - Self { quote } - } -} - -impl Evaluate for &mut Evaluator { - type Output = Result<(), Effect>; - - fn evaluate(self, value: Process) -> Self::Output { - self.stack.push(Expression::Process(value)); - Ok(()) - } -} - -impl Display for Process { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - Debug::fmt(self, f) - } -} - -impl Debug for Process { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "${:?}", self.quote) - } -} diff --git a/rat/src/vocabulary.rs b/rat/src/vocabulary.rs index 028a1f3..9909309 100644 --- a/rat/src/vocabulary.rs +++ b/rat/src/vocabulary.rs @@ -135,7 +135,7 @@ impl Vocabulary { } } -static PRELUDE: [(&Word, &[Expression]); 68] = [ +static PRELUDE: [(&Word, &[Expression]); 63] = [ (word_literal("neg"), &[Expression::Verb(Verb(builtin::neg))]), ( word_literal("incr"), @@ -284,22 +284,6 @@ static PRELUDE: [(&Word, &[Expression]); 68] = [ ), (word_literal("pop"), &[Expression::Verb(Verb(builtin::pop))]), (word_literal("dup"), &[Expression::Verb(Verb(builtin::dup))]), - ( - word_literal("send"), - &[Expression::Verb(Verb(builtin::send))], - ), - ( - word_literal("recv"), - &[Expression::Verb(Verb(builtin::recv))], - ), - ( - word_literal("spawn"), - &[Expression::Verb(Verb(builtin::spawn))], - ), - ( - word_literal("detach"), - &[Expression::Verb(Verb(builtin::detach))], - ), (word_literal("ask"), &[Expression::Verb(Verb(builtin::ask))]), (word_literal("say"), &[Expression::Verb(Verb(builtin::say))]), ( @@ -314,10 +298,6 @@ static PRELUDE: [(&Word, &[Expression]); 68] = [ word_literal("binrec"), &[Expression::Verb(Verb(builtin::binrec))], ), - ( - word_literal("parbinrec"), - &[Expression::Verb(Verb(builtin::parbinrec))], - ), ]; const fn word_literal(literal: &str) -> &Word { From 62a740a10fb472eb47b47ac7cbf5146854f9c7b7 Mon Sep 17 00:00:00 2001 From: daddinuz Date: Sat, 17 Aug 2024 13:29:29 +0200 Subject: [PATCH 3/8] update build.rs --- rat-cli/build.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/rat-cli/build.rs b/rat-cli/build.rs index 6dd73bf..ec10bb7 100644 --- a/rat-cli/build.rs +++ b/rat-cli/build.rs @@ -2,22 +2,22 @@ use std::fs; use std::path::Path; fn main() { - let source_path = Path::new(env!("CARGO_MANIFEST_DIR")) + let crate_lib_path = Path::new(env!("CARGO_MANIFEST_DIR")) .parent() .unwrap() .join("lib"); - println!("cargo::rerun-if-changed={}", source_path.display()); + println!("cargo::rerun-if-changed={}", crate_lib_path.display()); - let destination_path = rat::home_dir().join("lib"); + let host_lib_path = rat::home_dir().join("lib"); - fs::create_dir_all(&destination_path).unwrap(); + fs::create_dir_all(&host_lib_path).unwrap(); - for entry in fs::read_dir(source_path).unwrap() { + for entry in fs::read_dir(crate_lib_path).unwrap() { let entry = entry.unwrap(); if entry.file_type().unwrap().is_file() { - fs::copy(entry.path(), destination_path.join(entry.file_name())).unwrap(); + fs::copy(entry.path(), host_lib_path.join(entry.file_name())).unwrap(); } } } From e2ab479d25204adc66e83871561bd416244f4901 Mon Sep 17 00:00:00 2001 From: daddinuz Date: Fri, 23 Aug 2024 22:44:38 +0200 Subject: [PATCH 4/8] remove record --- Cargo.lock | 60 ++--- rat/src/expression.rs | 12 - rat/src/grammar.pest | 14 +- rat/src/lib.rs | 1 - rat/src/parser.rs | 49 ---- rat/src/record.rs | 506 ------------------------------------------ 6 files changed, 31 insertions(+), 611 deletions(-) delete mode 100644 rat/src/record.rs diff --git a/Cargo.lock b/Cargo.lock index ae41644..fb02f8b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -65,9 +65,9 @@ dependencies = [ [[package]] name = "cpufeatures" -version = "0.2.13" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51e852e6dc9a5bed1fae92dd2375037bf2b768725bf3be87811edee3249d09ad" +checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0" dependencies = [ "libc", ] @@ -131,9 +131,9 @@ dependencies = [ [[package]] name = "error-code" -version = "3.2.0" +version = "3.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0474425d51df81997e2f90a21591180b38eccf27292d755f3e30750225c175b" +checksum = "a5d9305ccc6942a704f4335694ecd3de2ea531b114ac2d51f5f843750787a92f" [[package]] name = "fd-lock" @@ -184,9 +184,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.156" +version = "0.2.158" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5f43f184355eefb8d17fc948dbecf6c13be3c141f20d834ae842193a448c72a" +checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" [[package]] name = "libredox" @@ -284,9 +284,9 @@ dependencies = [ [[package]] name = "pest" -version = "2.7.11" +version = "2.7.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd53dff83f26735fdc1ca837098ccf133605d794cdae66acfc2bfac3ec809d95" +checksum = "fdbef9d1d47087a895abd220ed25eb4ad973a5e26f6a4367b038c25e28dfc2d9" dependencies = [ "memchr", "thiserror", @@ -295,9 +295,9 @@ dependencies = [ [[package]] name = "pest_derive" -version = "2.7.11" +version = "2.7.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a548d2beca6773b1c244554d36fcf8548a8a58e74156968211567250e48e49a" +checksum = "4d3a6e3394ec80feb3b6393c725571754c6188490265c61aaf260810d6b95aa0" dependencies = [ "pest", "pest_generator", @@ -305,9 +305,9 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.7.11" +version = "2.7.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c93a82e8d145725dcbaf44e5ea887c8a869efdcc28706df2d08c69e17077183" +checksum = "94429506bde1ca69d1b5601962c73f4172ab4726571a59ea95931218cb0e930e" dependencies = [ "pest", "pest_meta", @@ -318,9 +318,9 @@ dependencies = [ [[package]] name = "pest_meta" -version = "2.7.11" +version = "2.7.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a941429fea7e08bedec25e4f6785b6ffaacc6b755da98df5ef3e7dcf4a124c4f" +checksum = "ac8a071862e93690b6e34e9a5fb8e33ff3734473ac0245b27232222c4906a33f" dependencies = [ "once_cell", "pest", @@ -338,9 +338,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.36" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" dependencies = [ "proc-macro2", ] @@ -376,18 +376,18 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.3" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4" +checksum = "0884ad60e090bf1345b93da0a5de8923c93884cd03f40dfcfddd3b4bee661853" dependencies = [ "bitflags", ] [[package]] name = "redox_users" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd283d9651eeda4b2a83a43c1c91b266c40fd76ecd39a50a8c630ae69dc72891" +checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" dependencies = [ "getrandom", "libredox", @@ -396,9 +396,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.34" +version = "0.38.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" +checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811" dependencies = [ "bitflags", "errno", @@ -466,9 +466,9 @@ checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "syn" -version = "2.0.74" +version = "2.0.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fceb41e3d546d0bd83421d3409b1460cc7444cd389341a4c880fe7a042cb3d7" +checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed" dependencies = [ "proc-macro2", "quote", @@ -509,21 +509,21 @@ checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" [[package]] name = "unicode-ident" -version = "1.0.12" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" [[package]] name = "unicode-segmentation" -version = "1.11.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" [[package]] name = "unicode-width" -version = "0.1.13" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" +checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" [[package]] name = "ustr" diff --git a/rat/src/expression.rs b/rat/src/expression.rs index 5ba9080..d7c44c2 100644 --- a/rat/src/expression.rs +++ b/rat/src/expression.rs @@ -14,7 +14,6 @@ use crate::boolean::Boolean; use crate::decimal::Decimal; use crate::integer::Integer; use crate::quote::Quote; -use crate::record::Record; use crate::string::String; use crate::symbol::Symbol; use crate::verb::Verb; @@ -25,7 +24,6 @@ pub enum Expression { Decimal(Decimal), Integer(Integer), Quote(Quote), - Record(Record), String(String), Symbol(Symbol), Verb(Verb), @@ -62,13 +60,6 @@ impl From for Expression { } } -impl From for Expression { - #[inline] - fn from(value: Record) -> Self { - Self::Record(value) - } -} - impl From for Expression { #[inline] fn from(value: String) -> Self { @@ -99,7 +90,6 @@ impl Evaluate for &mut Evaluator { Expression::Decimal(v) => self.evaluate(v), Expression::Integer(v) => self.evaluate(v), Expression::Quote(v) => self.evaluate(v), - Expression::Record(v) => self.evaluate(v), Expression::String(v) => self.evaluate(v), Expression::Symbol(v) => self.evaluate(v), Expression::Verb(v) => self.evaluate(v), @@ -114,7 +104,6 @@ impl Display for Expression { Expression::Decimal(v) => Display::fmt(v, f), Expression::Integer(v) => Display::fmt(v, f), Expression::Quote(v) => Display::fmt(v, f), - Expression::Record(v) => Display::fmt(v, f), Expression::String(v) => Display::fmt(v, f), Expression::Symbol(v) => Display::fmt(v, f), Expression::Verb(v) => Display::fmt(v, f), @@ -129,7 +118,6 @@ impl Debug for Expression { Expression::Decimal(v) => Debug::fmt(v, f), Expression::Integer(v) => Debug::fmt(v, f), Expression::Quote(v) => Debug::fmt(v, f), - Expression::Record(v) => Debug::fmt(v, f), Expression::String(v) => Debug::fmt(v, f), Expression::Symbol(v) => Debug::fmt(v, f), Expression::Verb(v) => Debug::fmt(v, f), diff --git a/rat/src/grammar.pest b/rat/src/grammar.pest index e6ff776..7b4812c 100644 --- a/rat/src/grammar.pest +++ b/rat/src/grammar.pest @@ -31,7 +31,7 @@ Locution = @{ } Expression = { - (Boolean | Decimal | Integer | Quote | Record | String | Symbol) + (Boolean | Decimal | Integer | Quote | String | Symbol) } Boolean = @{ @@ -50,10 +50,6 @@ Quote = { LeftSquareBracket ~ Phrase? ~ RightSquareBracket } -Record = { - LeftCurlyBracket ~ (Expression ~ Equal ~ Expression)? ~ (Comma ~ Expression ~ Equal ~ Expression)* ~ Comma? ~ RightCurlyBracket -} - String = ${ "\"" ~ StringUnicodeScalarValue* ~ "\"" } @@ -98,14 +94,6 @@ Semicolon = @{ ";" } -LeftCurlyBracket = @{ - "{" -} - -RightCurlyBracket = @{ - "}" -} - LeftSquareBracket = @{ "[" } diff --git a/rat/src/lib.rs b/rat/src/lib.rs index ca29c56..c249e9f 100644 --- a/rat/src/lib.rs +++ b/rat/src/lib.rs @@ -13,7 +13,6 @@ pub mod boolean; pub mod decimal; pub mod integer; pub mod quote; -pub mod record; pub mod string; pub mod symbol; pub mod verb; diff --git a/rat/src/parser.rs b/rat/src/parser.rs index 3ecb36a..aed6bb5 100644 --- a/rat/src/parser.rs +++ b/rat/src/parser.rs @@ -21,7 +21,6 @@ use crate::expression::Expression; use crate::integer::Integer; use crate::locution::{Locution, OwnedLocution}; use crate::quote::Quote; -use crate::record::Record; use crate::string::String; use crate::symbol::Symbol; use crate::vocabulary::{Definition, Visibility, Vocabulary}; @@ -258,23 +257,6 @@ impl FromStr for Quote { } } -impl FromStr for Record { - type Err = ParseError; - - fn from_str(s: &str) -> Result { - check_token_boundary(s)?; - - let mut pairs = Grammar::parse(Rule::Record, s).map_err(with_origin(Origin::Unknown))?; - assert_eq!(pairs.len(), 1); - - parse_record( - &mut Default::default(), - Origin::Unknown, - pairs.next().unwrap(), - ) - } -} - impl FromStr for String { type Err = ParseError; @@ -437,7 +419,6 @@ fn parse_expression( Rule::Decimal => parse_decimal(origin, pair).map(Expression::Decimal), Rule::Integer => parse_integer(origin, pair).map(Expression::Integer), Rule::Quote => parse_quote(parser, origin, pair).map(Expression::Quote), - Rule::Record => parse_record(parser, origin, pair).map(Expression::Record), Rule::String => parse_string(origin, pair).map(Expression::String), Rule::Symbol => parse_symbol(origin, pair).map(Expression::Symbol), rule => unreachable!("unexpected rule: `{rule:?}`"), @@ -524,36 +505,6 @@ fn parse_quote(parser: &mut Parser, origin: Origin, pair: PestPair) -> Result Result { - assert_eq!(pair.as_rule(), Rule::Record); - - let mut key = None; - let mut value = None; - let mut record = Record::new(); - - for pair in pair.into_inner() { - match pair.as_rule() { - Rule::Expression => { - let exp = parse_expression(parser, origin, pair)?; - if key.is_none() { - key = Some(exp); - } else { - value = Some(exp); - } - } - Rule::RightCurlyBracket => break, - Rule::Comma | Rule::Equal | Rule::LeftCurlyBracket => (), - rule => unreachable!("unexpected rule: `{rule:?}`"), - } - - if value.is_some() { - record.insert(key.take().unwrap(), value.take().unwrap()); - } - } - - Ok(record) -} - fn parse_string(origin: Origin, pair: PestPair) -> Result { assert_eq!(pair.as_rule(), Rule::String); pair.into_inner() diff --git a/rat/src/record.rs b/rat/src/record.rs deleted file mode 100644 index ee87c02..0000000 --- a/rat/src/record.rs +++ /dev/null @@ -1,506 +0,0 @@ -/* - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - */ - -use std::borrow::Borrow; -use std::collections::HashMap; -use std::fmt::{Debug, Display}; -use std::hash::{BuildHasher, DefaultHasher, Hash, Hasher, RandomState}; -use std::sync::{Arc, OnceLock}; - -use crate::effect::Effect; -use crate::evaluate::Evaluate; -use crate::evaluator::Evaluator; -use crate::expression::Expression; - -#[derive(Clone, PartialEq, Eq)] -pub struct Record { - entries: Option>>, -} - -impl FromIterator<(Expression, Expression)> for Record { - fn from_iter>(entries: T) -> Self { - let mut entries = entries.into_iter().peekable(); - Self { - entries: entries - .peek() - .is_some() - .then(|| Arc::new(entries.collect())), - } - } -} - -impl Default for Record { - fn default() -> Self { - Self::new() - } -} - -impl Record { - pub const fn new() -> Self { - Self { entries: None } - } - - pub fn insert(&mut self, key: Expression, value: Expression) -> Option { - Arc::make_mut(self.entries.get_or_insert_with(Default::default)).insert(key, value) - } - - pub fn contains_key(&self, key: &Q) -> bool - where - Expression: Borrow, - Q: ?Sized + Hash + Eq, - { - self.entries - .as_ref() - .map(|e| e.contains_key(key)) - .unwrap_or(false) - } - - pub fn get(&self, key: &Q) -> Option<&Expression> - where - Expression: Borrow, - Q: ?Sized + Hash + Eq, - { - self.entries.as_ref().and_then(|e| e.get(key)) - } - - pub fn remove(&mut self, key: &Q) -> Option - where - Expression: Borrow, - Q: ?Sized + Hash + Eq, - { - self.entries - .as_mut() - .map(Arc::make_mut) - .and_then(|e| e.remove(key)) - } - - pub fn len(&self) -> usize { - self.entries.as_deref().map(HashMap::len).unwrap_or(0) - } - - pub fn is_empty(&self) -> bool { - self.entries - .as_deref() - .map(HashMap::is_empty) - .unwrap_or(true) - } - - pub fn keys(&self) -> Keys { - Keys::from_delegate( - self.entries - .as_deref() - .unwrap_or_else(empty_hash_map) - .keys(), - ) - } - - pub fn values(&self) -> Values { - Values::from_delegate( - self.entries - .as_deref() - .unwrap_or_else(empty_hash_map) - .values(), - ) - } - - pub fn iter(&self) -> Iter { - Iter::from_delegate( - self.entries - .as_deref() - .unwrap_or_else(empty_hash_map) - .iter(), - ) - } - - pub fn into_keys(self) -> IntoKeys { - IntoKeys::from_delegate( - self.entries - .map(|arc| Arc::try_unwrap(arc).unwrap_or_else(|arc| (*arc).clone())) - .unwrap_or_default() - .into_keys(), - ) - } - - pub fn into_values(self) -> IntoValues { - IntoValues::from_delegate( - self.entries - .map(|arc| Arc::try_unwrap(arc).unwrap_or_else(|arc| (*arc).clone())) - .unwrap_or_default() - .into_values(), - ) - } -} - -impl Extend<(Expression, Expression)> for Record { - fn extend>(&mut self, iter: T) { - Arc::make_mut(self.entries.get_or_insert_with(Default::default)).extend(iter); - } -} - -impl Hash for Record { - fn hash(&self, state: &mut H) { - let hasher_builder = global_hasher_builder(); - let hash = self - .entries - .iter() - .flat_map(|e| e.iter()) - .map(|pair| hasher_builder.hash_one(pair)) - .fold(18446744073709551557_u64, |l, r| l ^ r); - state.write_u64(hash); - } -} - -impl Evaluate for &mut Evaluator { - type Output = Result<(), Effect>; - - fn evaluate(self, value: Record) -> Self::Output { - self.stack.push(Expression::Record(value)); - Ok(()) - } -} - -impl Display for Record { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{{")?; - - let mut items = self.iter(); - items.next().map(|(k, v)| write!(f, "{k} = {v}")); - items.try_for_each(|(k, v)| write!(f, ", {k} = {v}"))?; - - write!(f, "}}") - } -} - -impl Debug for Record { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{{")?; - - let mut items = self.iter(); - items.next().map(|(k, v)| write!(f, "{k:?} = {v:?}")); - items.try_for_each(|(k, v)| write!(f, ", {k:?} = {v:?}"))?; - - write!(f, "}}") - } -} - -fn global_hasher_builder<'a>() -> &'a impl BuildHasher { - static INSTANCE: OnceLock = OnceLock::new(); - INSTANCE.get_or_init(Default::default) -} - -fn empty_hash_map<'a>() -> &'a HashMap { - static INSTANCE: OnceLock> = OnceLock::new(); - INSTANCE.get_or_init(Default::default) -} - -pub struct Keys<'a> { - delegate: std::collections::hash_map::Keys<'a, Expression, Expression>, -} - -impl<'a> Keys<'a> { - fn from_delegate( - delegate: std::collections::hash_map::Keys<'a, Expression, Expression>, - ) -> Self { - Self { delegate } - } -} - -impl<'a> Iterator for Keys<'a> { - type Item = as Iterator>::Item; - - fn next(&mut self) -> Option { - self.delegate.next() - } - - fn size_hint(&self) -> (usize, Option) { - self.delegate.size_hint() - } - - fn count(self) -> usize - where - Self: Sized, - { - self.delegate.count() - } - - fn last(self) -> Option - where - Self: Sized, - { - self.delegate.last() - } - - fn nth(&mut self, n: usize) -> Option { - self.delegate.nth(n) - } -} - -impl<'a> std::iter::FusedIterator for Keys<'a> {} - -impl<'a> ExactSizeIterator for Keys<'a> { - fn len(&self) -> usize { - self.delegate.len() - } -} - -pub struct Values<'a> { - delegate: std::collections::hash_map::Values<'a, Expression, Expression>, -} - -impl<'a> Values<'a> { - fn from_delegate( - delegate: std::collections::hash_map::Values<'a, Expression, Expression>, - ) -> Self { - Self { delegate } - } -} - -impl<'a> Iterator for Values<'a> { - type Item = as Iterator>::Item; - fn next(&mut self) -> Option { - self.delegate.next() - } - fn size_hint(&self) -> (usize, Option) { - self.delegate.size_hint() - } - fn count(self) -> usize - where - Self: Sized, - { - self.delegate.count() - } - fn last(self) -> Option - where - Self: Sized, - { - self.delegate.last() - } - fn nth(&mut self, n: usize) -> Option { - self.delegate.nth(n) - } -} - -impl<'a> std::iter::FusedIterator for Values<'a> {} - -impl<'a> ExactSizeIterator for Values<'a> { - fn len(&self) -> usize { - self.delegate.len() - } -} - -pub struct Iter<'a> { - delegate: std::collections::hash_map::Iter<'a, Expression, Expression>, -} - -impl<'a> Iter<'a> { - fn from_delegate( - delegate: std::collections::hash_map::Iter<'a, Expression, Expression>, - ) -> Self { - Self { delegate } - } -} - -impl<'a> Iterator for Iter<'a> { - type Item = as Iterator>::Item; - - fn next(&mut self) -> Option { - self.delegate.next() - } - - fn size_hint(&self) -> (usize, Option) { - self.delegate.size_hint() - } - - fn count(self) -> usize - where - Self: Sized, - { - self.delegate.count() - } - - fn last(self) -> Option - where - Self: Sized, - { - self.delegate.last() - } - - fn nth(&mut self, n: usize) -> Option { - self.delegate.nth(n) - } -} - -impl<'a> std::iter::FusedIterator for Iter<'a> {} - -impl<'a> ExactSizeIterator for Iter<'a> { - fn len(&self) -> usize { - self.delegate.len() - } -} - -pub struct IntoKeys { - delegate: std::collections::hash_map::IntoKeys, -} - -impl IntoKeys { - fn from_delegate( - delegate: std::collections::hash_map::IntoKeys, - ) -> Self { - Self { delegate } - } -} - -impl Iterator for IntoKeys { - type Item = as Iterator>::Item; - - fn next(&mut self) -> Option { - self.delegate.next() - } - - fn size_hint(&self) -> (usize, Option) { - self.delegate.size_hint() - } - - fn count(self) -> usize - where - Self: Sized, - { - self.delegate.count() - } - - fn last(self) -> Option - where - Self: Sized, - { - self.delegate.last() - } - - fn nth(&mut self, n: usize) -> Option { - self.delegate.nth(n) - } -} - -impl std::iter::FusedIterator for IntoKeys {} - -impl ExactSizeIterator for IntoKeys { - fn len(&self) -> usize { - self.delegate.len() - } -} - -pub struct IntoValues { - delegate: std::collections::hash_map::IntoValues, -} - -impl IntoValues { - fn from_delegate( - delegate: std::collections::hash_map::IntoValues, - ) -> Self { - Self { delegate } - } -} - -impl Iterator for IntoValues { - type Item = as Iterator>::Item; - - fn next(&mut self) -> Option { - self.delegate.next() - } - - fn size_hint(&self) -> (usize, Option) { - self.delegate.size_hint() - } - - fn count(self) -> usize - where - Self: Sized, - { - self.delegate.count() - } - - fn last(self) -> Option - where - Self: Sized, - { - self.delegate.last() - } - - fn nth(&mut self, n: usize) -> Option { - self.delegate.nth(n) - } -} - -impl std::iter::FusedIterator for IntoValues {} - -impl ExactSizeIterator for IntoValues { - fn len(&self) -> usize { - self.delegate.len() - } -} - -pub struct IntoIter { - delegate: std::collections::hash_map::IntoIter, -} - -impl IntoIter { - fn from_delegate( - delegate: std::collections::hash_map::IntoIter, - ) -> Self { - Self { delegate } - } -} - -impl Iterator for IntoIter { - type Item = as Iterator>::Item; - - fn next(&mut self) -> Option { - self.delegate.next() - } - - fn size_hint(&self) -> (usize, Option) { - self.delegate.size_hint() - } - - fn count(self) -> usize - where - Self: Sized, - { - self.delegate.count() - } - - fn last(self) -> Option - where - Self: Sized, - { - self.delegate.last() - } - - fn nth(&mut self, n: usize) -> Option { - self.delegate.nth(n) - } -} - -impl std::iter::FusedIterator for IntoIter {} - -impl ExactSizeIterator for IntoIter { - fn len(&self) -> usize { - self.delegate.len() - } -} - -impl IntoIterator for Record { - type Item = (Expression, Expression); - type IntoIter = IntoIter; - - fn into_iter(self) -> Self::IntoIter { - IntoIter::from_delegate( - self.entries - .map(|arc| Arc::try_unwrap(arc).unwrap_or_else(|arc| (*arc).clone())) - .unwrap_or_default() - .into_iter(), - ) - } -} From 33deedac4202a5a764be9bcd328ef3f8c503e444 Mon Sep 17 00:00:00 2001 From: daddinuz Date: Sun, 22 Sep 2024 11:55:23 +0200 Subject: [PATCH 5/8] rename Effect to RuntimeError, rename Vocabulary to Definition --- rat/src/boolean.rs | 4 +- rat/src/builtin.rs | 358 +++++++++++++++++++++--------------------- rat/src/decimal.rs | 4 +- rat/src/dictionary.rs | 308 ++++++++++++++++++++++++++++++++++++ rat/src/error.rs | 8 + rat/src/evaluator.rs | 8 +- rat/src/expression.rs | 6 +- rat/src/integer.rs | 4 +- rat/src/lib.rs | 4 +- rat/src/parser.rs | 42 ++--- rat/src/quote.rs | 4 +- rat/src/string.rs | 4 +- rat/src/symbol.rs | 4 +- rat/src/verb.rs | 6 +- 14 files changed, 540 insertions(+), 224 deletions(-) create mode 100644 rat/src/dictionary.rs create mode 100644 rat/src/error.rs diff --git a/rat/src/boolean.rs b/rat/src/boolean.rs index 0412269..aa5f33d 100644 --- a/rat/src/boolean.rs +++ b/rat/src/boolean.rs @@ -8,7 +8,7 @@ use std::fmt::{Debug, Display}; use std::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Not}; use crate::codegen; -use crate::effect::Effect; +use crate::error::RuntimeError; use crate::evaluate::Evaluate; use crate::evaluator::Evaluator; use crate::expression::Expression; @@ -31,7 +31,7 @@ impl From for bool { } impl Evaluate for &mut Evaluator { - type Output = Result<(), Effect>; + type Output = Result<(), RuntimeError>; fn evaluate(self, value: Boolean) -> Self::Output { self.stack.push(Expression::Boolean(value)); diff --git a/rat/src/builtin.rs b/rat/src/builtin.rs index a6b36ba..3d32e6c 100644 --- a/rat/src/builtin.rs +++ b/rat/src/builtin.rs @@ -6,7 +6,7 @@ use std::io::{self, Write}; -use crate::effect::Effect; +use crate::error::RuntimeError; use crate::evaluate::Evaluate; use crate::evaluator::Evaluator; @@ -19,7 +19,7 @@ use crate::quote::Quote; use crate::string::String; use crate::symbol::Symbol; -pub fn neg(evaluator: &mut Evaluator) -> Result<(), Effect> { +pub fn neg(evaluator: &mut Evaluator) -> Result<(), RuntimeError> { let stack = &mut evaluator.stack; match &mut stack[..] { @@ -33,16 +33,16 @@ pub fn neg(evaluator: &mut Evaluator) -> Result<(), Effect> { } [.., _] => { stack.push(Symbol::type_error().into()); - Err(Effect::Raise) + Err(RuntimeError) } _ => { stack.push(Symbol::stack_underflow().into()); - Err(Effect::Raise) + Err(RuntimeError) } } } -pub fn incr(evaluator: &mut Evaluator) -> Result<(), Effect> { +pub fn incr(evaluator: &mut Evaluator) -> Result<(), RuntimeError> { let stack = &mut evaluator.stack; match &mut stack[..] { @@ -56,16 +56,16 @@ pub fn incr(evaluator: &mut Evaluator) -> Result<(), Effect> { } [.., _] => { stack.push(Symbol::type_error().into()); - Err(Effect::Raise) + Err(RuntimeError) } _ => { stack.push(Symbol::stack_underflow().into()); - Err(Effect::Raise) + Err(RuntimeError) } } } -pub fn decr(evaluator: &mut Evaluator) -> Result<(), Effect> { +pub fn decr(evaluator: &mut Evaluator) -> Result<(), RuntimeError> { let stack = &mut evaluator.stack; match &mut stack[..] { @@ -79,16 +79,16 @@ pub fn decr(evaluator: &mut Evaluator) -> Result<(), Effect> { } [.., _] => { stack.push(Symbol::type_error().into()); - Err(Effect::Raise) + Err(RuntimeError) } _ => { stack.push(Symbol::stack_underflow().into()); - Err(Effect::Raise) + Err(RuntimeError) } } } -pub fn add(evaluator: &mut Evaluator) -> Result<(), Effect> { +pub fn add(evaluator: &mut Evaluator) -> Result<(), RuntimeError> { let stack = &mut evaluator.stack; match stack[..] { @@ -104,16 +104,16 @@ pub fn add(evaluator: &mut Evaluator) -> Result<(), Effect> { } [.., _, _] => { stack.push(Symbol::type_error().into()); - Err(Effect::Raise) + Err(RuntimeError) } _ => { stack.push(Symbol::stack_underflow().into()); - Err(Effect::Raise) + Err(RuntimeError) } } } -pub fn sub(evaluator: &mut Evaluator) -> Result<(), Effect> { +pub fn sub(evaluator: &mut Evaluator) -> Result<(), RuntimeError> { let stack = &mut evaluator.stack; match stack[..] { @@ -129,16 +129,16 @@ pub fn sub(evaluator: &mut Evaluator) -> Result<(), Effect> { } [.., _, _] => { stack.push(Symbol::type_error().into()); - Err(Effect::Raise) + Err(RuntimeError) } _ => { stack.push(Symbol::stack_underflow().into()); - Err(Effect::Raise) + Err(RuntimeError) } } } -pub fn mul(evaluator: &mut Evaluator) -> Result<(), Effect> { +pub fn mul(evaluator: &mut Evaluator) -> Result<(), RuntimeError> { let stack = &mut evaluator.stack; match stack[..] { @@ -154,22 +154,22 @@ pub fn mul(evaluator: &mut Evaluator) -> Result<(), Effect> { } [.., _, _] => { stack.push(Symbol::type_error().into()); - Err(Effect::Raise) + Err(RuntimeError) } _ => { stack.push(Symbol::stack_underflow().into()); - Err(Effect::Raise) + Err(RuntimeError) } } } -pub fn div(evaluator: &mut Evaluator) -> Result<(), Effect> { +pub fn div(evaluator: &mut Evaluator) -> Result<(), RuntimeError> { let stack = &mut evaluator.stack; match stack[..] { [.., Expression::Integer(_), Expression::Integer(Integer::ZERO)] => { stack.push(Symbol::divide_by_zero().into()); - Err(Effect::Raise) + Err(RuntimeError) } [.., Expression::Integer(ref mut lhs), Expression::Integer(rhs)] => { *lhs /= rhs; @@ -183,22 +183,22 @@ pub fn div(evaluator: &mut Evaluator) -> Result<(), Effect> { } [.., _, _] => { stack.push(Symbol::type_error().into()); - Err(Effect::Raise) + Err(RuntimeError) } _ => { stack.push(Symbol::stack_underflow().into()); - Err(Effect::Raise) + Err(RuntimeError) } } } -pub fn rem(evaluator: &mut Evaluator) -> Result<(), Effect> { +pub fn rem(evaluator: &mut Evaluator) -> Result<(), RuntimeError> { let stack = &mut evaluator.stack; match stack[..] { [.., Expression::Integer(_), Expression::Integer(Integer::ZERO)] => { stack.push(Symbol::divide_by_zero().into()); - Err(Effect::Raise) + Err(RuntimeError) } [.., Expression::Integer(ref mut lhs), Expression::Integer(rhs)] => { *lhs %= rhs; @@ -212,16 +212,16 @@ pub fn rem(evaluator: &mut Evaluator) -> Result<(), Effect> { } [.., _, _] => { stack.push(Symbol::type_error().into()); - Err(Effect::Raise) + Err(RuntimeError) } _ => { stack.push(Symbol::stack_underflow().into()); - Err(Effect::Raise) + Err(RuntimeError) } } } -pub fn eq(evaluator: &mut Evaluator) -> Result<(), Effect> { +pub fn eq(evaluator: &mut Evaluator) -> Result<(), RuntimeError> { let stack = &mut evaluator.stack; match stack[..] { @@ -232,12 +232,12 @@ pub fn eq(evaluator: &mut Evaluator) -> Result<(), Effect> { } _ => { stack.push(Symbol::stack_underflow().into()); - Err(Effect::Raise) + Err(RuntimeError) } } } -pub fn ne(evaluator: &mut Evaluator) -> Result<(), Effect> { +pub fn ne(evaluator: &mut Evaluator) -> Result<(), RuntimeError> { let stack = &mut evaluator.stack; match stack[..] { @@ -248,12 +248,12 @@ pub fn ne(evaluator: &mut Evaluator) -> Result<(), Effect> { } _ => { stack.push(Symbol::stack_underflow().into()); - Err(Effect::Raise) + Err(RuntimeError) } } } -pub fn gt(evaluator: &mut Evaluator) -> Result<(), Effect> { +pub fn gt(evaluator: &mut Evaluator) -> Result<(), RuntimeError> { let stack = &mut evaluator.stack; match stack[..] { @@ -275,16 +275,16 @@ pub fn gt(evaluator: &mut Evaluator) -> Result<(), Effect> { }, [.., _, _] => { stack.push(Symbol::type_error().into()); - Err(Effect::Raise) + Err(RuntimeError) } _ => { stack.push(Symbol::stack_underflow().into()); - Err(Effect::Raise) + Err(RuntimeError) } } } -pub fn ge(evaluator: &mut Evaluator) -> Result<(), Effect> { +pub fn ge(evaluator: &mut Evaluator) -> Result<(), RuntimeError> { let stack = &mut evaluator.stack; match stack[..] { @@ -306,16 +306,16 @@ pub fn ge(evaluator: &mut Evaluator) -> Result<(), Effect> { }, [.., _, _] => { stack.push(Symbol::type_error().into()); - Err(Effect::Raise) + Err(RuntimeError) } _ => { stack.push(Symbol::stack_underflow().into()); - Err(Effect::Raise) + Err(RuntimeError) } } } -pub fn lt(evaluator: &mut Evaluator) -> Result<(), Effect> { +pub fn lt(evaluator: &mut Evaluator) -> Result<(), RuntimeError> { let stack = &mut evaluator.stack; match stack[..] { @@ -337,16 +337,16 @@ pub fn lt(evaluator: &mut Evaluator) -> Result<(), Effect> { }, [.., _, _] => { stack.push(Symbol::type_error().into()); - Err(Effect::Raise) + Err(RuntimeError) } _ => { stack.push(Symbol::stack_underflow().into()); - Err(Effect::Raise) + Err(RuntimeError) } } } -pub fn le(evaluator: &mut Evaluator) -> Result<(), Effect> { +pub fn le(evaluator: &mut Evaluator) -> Result<(), RuntimeError> { let stack = &mut evaluator.stack; match stack[..] { @@ -368,16 +368,16 @@ pub fn le(evaluator: &mut Evaluator) -> Result<(), Effect> { }, [.., _, _] => { stack.push(Symbol::type_error().into()); - Err(Effect::Raise) + Err(RuntimeError) } _ => { stack.push(Symbol::stack_underflow().into()); - Err(Effect::Raise) + Err(RuntimeError) } } } -pub fn positive(evaluator: &mut Evaluator) -> Result<(), Effect> { +pub fn positive(evaluator: &mut Evaluator) -> Result<(), RuntimeError> { let stack = &mut evaluator.stack; match &stack[..] { @@ -391,16 +391,16 @@ pub fn positive(evaluator: &mut Evaluator) -> Result<(), Effect> { } [.., _] => { stack.push(Symbol::type_error().into()); - Err(Effect::Raise) + Err(RuntimeError) } _ => { stack.push(Symbol::stack_underflow().into()); - Err(Effect::Raise) + Err(RuntimeError) } } } -pub fn zero(evaluator: &mut Evaluator) -> Result<(), Effect> { +pub fn zero(evaluator: &mut Evaluator) -> Result<(), RuntimeError> { let stack = &mut evaluator.stack; match &stack[..] { @@ -414,16 +414,16 @@ pub fn zero(evaluator: &mut Evaluator) -> Result<(), Effect> { } [.., _] => { stack.push(Symbol::type_error().into()); - Err(Effect::Raise) + Err(RuntimeError) } _ => { stack.push(Symbol::stack_underflow().into()); - Err(Effect::Raise) + Err(RuntimeError) } } } -pub fn negative(evaluator: &mut Evaluator) -> Result<(), Effect> { +pub fn negative(evaluator: &mut Evaluator) -> Result<(), RuntimeError> { let stack = &mut evaluator.stack; match &stack[..] { @@ -437,16 +437,16 @@ pub fn negative(evaluator: &mut Evaluator) -> Result<(), Effect> { } [.., _] => { stack.push(Symbol::type_error().into()); - Err(Effect::Raise) + Err(RuntimeError) } _ => { stack.push(Symbol::stack_underflow().into()); - Err(Effect::Raise) + Err(RuntimeError) } } } -pub fn not(evaluator: &mut Evaluator) -> Result<(), Effect> { +pub fn not(evaluator: &mut Evaluator) -> Result<(), RuntimeError> { let stack = &mut evaluator.stack; match &mut stack[..] { @@ -456,16 +456,16 @@ pub fn not(evaluator: &mut Evaluator) -> Result<(), Effect> { } [.., _] => { stack.push(Symbol::type_error().into()); - Err(Effect::Raise) + Err(RuntimeError) } _ => { stack.push(Symbol::stack_underflow().into()); - Err(Effect::Raise) + Err(RuntimeError) } } } -pub fn and(evaluator: &mut Evaluator) -> Result<(), Effect> { +pub fn and(evaluator: &mut Evaluator) -> Result<(), RuntimeError> { let stack = &mut evaluator.stack; match stack[..] { @@ -476,16 +476,16 @@ pub fn and(evaluator: &mut Evaluator) -> Result<(), Effect> { } [.., _, _] => { stack.push(Symbol::type_error().into()); - Err(Effect::Raise) + Err(RuntimeError) } _ => { stack.push(Symbol::stack_underflow().into()); - Err(Effect::Raise) + Err(RuntimeError) } } } -pub fn or(evaluator: &mut Evaluator) -> Result<(), Effect> { +pub fn or(evaluator: &mut Evaluator) -> Result<(), RuntimeError> { let stack = &mut evaluator.stack; match stack[..] { @@ -496,16 +496,16 @@ pub fn or(evaluator: &mut Evaluator) -> Result<(), Effect> { } [.., _, _] => { stack.push(Symbol::type_error().into()); - Err(Effect::Raise) + Err(RuntimeError) } _ => { stack.push(Symbol::stack_underflow().into()); - Err(Effect::Raise) + Err(RuntimeError) } } } -pub fn bitwise_not(evaluator: &mut Evaluator) -> Result<(), Effect> { +pub fn bitwise_not(evaluator: &mut Evaluator) -> Result<(), RuntimeError> { let stack = &mut evaluator.stack; match &mut stack[..] { @@ -519,16 +519,16 @@ pub fn bitwise_not(evaluator: &mut Evaluator) -> Result<(), Effect> { } [.., _] => { stack.push(Symbol::type_error().into()); - Err(Effect::Raise) + Err(RuntimeError) } _ => { stack.push(Symbol::stack_underflow().into()); - Err(Effect::Raise) + Err(RuntimeError) } } } -pub fn bitwise_and(evaluator: &mut Evaluator) -> Result<(), Effect> { +pub fn bitwise_and(evaluator: &mut Evaluator) -> Result<(), RuntimeError> { let stack = &mut evaluator.stack; match stack[..] { @@ -544,16 +544,16 @@ pub fn bitwise_and(evaluator: &mut Evaluator) -> Result<(), Effect> { } [.., _, _] => { stack.push(Symbol::type_error().into()); - Err(Effect::Raise) + Err(RuntimeError) } _ => { stack.push(Symbol::stack_underflow().into()); - Err(Effect::Raise) + Err(RuntimeError) } } } -pub fn bitwise_xor(evaluator: &mut Evaluator) -> Result<(), Effect> { +pub fn bitwise_xor(evaluator: &mut Evaluator) -> Result<(), RuntimeError> { let stack = &mut evaluator.stack; match stack[..] { @@ -569,16 +569,16 @@ pub fn bitwise_xor(evaluator: &mut Evaluator) -> Result<(), Effect> { } [.., _, _] => { stack.push(Symbol::type_error().into()); - Err(Effect::Raise) + Err(RuntimeError) } _ => { stack.push(Symbol::stack_underflow().into()); - Err(Effect::Raise) + Err(RuntimeError) } } } -pub fn bitwise_or(evaluator: &mut Evaluator) -> Result<(), Effect> { +pub fn bitwise_or(evaluator: &mut Evaluator) -> Result<(), RuntimeError> { let stack = &mut evaluator.stack; match stack[..] { @@ -594,16 +594,16 @@ pub fn bitwise_or(evaluator: &mut Evaluator) -> Result<(), Effect> { } [.., _, _] => { stack.push(Symbol::type_error().into()); - Err(Effect::Raise) + Err(RuntimeError) } _ => { stack.push(Symbol::stack_underflow().into()); - Err(Effect::Raise) + Err(RuntimeError) } } } -pub fn shl(evaluator: &mut Evaluator) -> Result<(), Effect> { +pub fn shl(evaluator: &mut Evaluator) -> Result<(), RuntimeError> { let stack = &mut evaluator.stack; match stack[..] { @@ -614,16 +614,16 @@ pub fn shl(evaluator: &mut Evaluator) -> Result<(), Effect> { } [.., _, _] => { stack.push(Symbol::type_error().into()); - Err(Effect::Raise) + Err(RuntimeError) } _ => { stack.push(Symbol::stack_underflow().into()); - Err(Effect::Raise) + Err(RuntimeError) } } } -pub fn shr(evaluator: &mut Evaluator) -> Result<(), Effect> { +pub fn shr(evaluator: &mut Evaluator) -> Result<(), RuntimeError> { let stack = &mut evaluator.stack; match stack[..] { @@ -634,16 +634,16 @@ pub fn shr(evaluator: &mut Evaluator) -> Result<(), Effect> { } [.., _, _] => { stack.push(Symbol::type_error().into()); - Err(Effect::Raise) + Err(RuntimeError) } _ => { stack.push(Symbol::stack_underflow().into()); - Err(Effect::Raise) + Err(RuntimeError) } } } -pub fn ushr(evaluator: &mut Evaluator) -> Result<(), Effect> { +pub fn ushr(evaluator: &mut Evaluator) -> Result<(), RuntimeError> { let stack = &mut evaluator.stack; match stack[..] { @@ -654,16 +654,16 @@ pub fn ushr(evaluator: &mut Evaluator) -> Result<(), Effect> { } [.., _, _] => { stack.push(Symbol::type_error().into()); - Err(Effect::Raise) + Err(RuntimeError) } _ => { stack.push(Symbol::stack_underflow().into()); - Err(Effect::Raise) + Err(RuntimeError) } } } -pub fn cat(evaluator: &mut Evaluator) -> Result<(), Effect> { +pub fn cat(evaluator: &mut Evaluator) -> Result<(), RuntimeError> { let stack = &mut evaluator.stack; match &mut stack[..] { @@ -675,55 +675,55 @@ pub fn cat(evaluator: &mut Evaluator) -> Result<(), Effect> { } [.., _, _] => { stack.push(Symbol::type_error().into()); - Err(Effect::Raise) + Err(RuntimeError) } _ => { stack.push(Symbol::stack_underflow().into()); - Err(Effect::Raise) + Err(RuntimeError) } } } -pub fn quote(evaluator: &mut Evaluator) -> Result<(), Effect> { +pub fn quote(evaluator: &mut Evaluator) -> Result<(), RuntimeError> { let stack = &mut evaluator.stack; let expression = stack.pop().ok_or_else(|| { stack.push(Symbol::stack_underflow().into()); - Effect::Raise + RuntimeError })?; stack.push(Expression::Quote(Quote::from([expression]))); Ok(()) } -pub fn unquote(evaluator: &mut Evaluator) -> Result<(), Effect> { +pub fn unquote(evaluator: &mut Evaluator) -> Result<(), RuntimeError> { match evaluator.stack.pop() { Some(Expression::Quote(quote)) => evaluator.evaluate(quote.iter().cloned()), Some(expression) => { evaluator .stack .extend_from_slice(&[expression, Symbol::type_error().into()]); - Err(Effect::Raise) + Err(RuntimeError) } _ => { evaluator.stack.push(Symbol::stack_underflow().into()); - Err(Effect::Raise) + Err(RuntimeError) } } } -pub fn eval(evaluator: &mut Evaluator) -> Result<(), Effect> { +pub fn eval(evaluator: &mut Evaluator) -> Result<(), RuntimeError> { let stack = &mut evaluator.stack; match stack.pop() { Some(expression) => evaluator.evaluate(expression), _ => { stack.push(Symbol::stack_underflow().into()); - Err(Effect::Raise) + Err(RuntimeError) } } } -pub fn i(evaluator: &mut Evaluator) -> Result<(), Effect> { +pub fn i(evaluator: &mut Evaluator) -> Result<(), RuntimeError> { let stack = &mut evaluator.stack; match &stack[..] { @@ -731,23 +731,23 @@ pub fn i(evaluator: &mut Evaluator) -> Result<(), Effect> { [.., _] => eval(evaluator), _ => { stack.push(Symbol::stack_underflow().into()); - Err(Effect::Raise) + Err(RuntimeError) } } } -pub fn x(evaluator: &mut Evaluator) -> Result<(), Effect> { +pub fn x(evaluator: &mut Evaluator) -> Result<(), RuntimeError> { let stack = &mut evaluator.stack; let expression = stack.last().cloned().ok_or_else(|| { stack.push(Symbol::stack_underflow().into()); - Effect::Raise + RuntimeError })?; stack.push(expression); i(evaluator) } -pub fn unary2(evaluator: &mut Evaluator) -> Result<(), Effect> { +pub fn unary2(evaluator: &mut Evaluator) -> Result<(), RuntimeError> { let stack = &mut evaluator.stack; let top = stack.len(); @@ -764,16 +764,16 @@ pub fn unary2(evaluator: &mut Evaluator) -> Result<(), Effect> { } [.., _, _, _] => { stack.push(Symbol::type_error().into()); - Err(Effect::Raise) + Err(RuntimeError) } _ => { stack.push(Symbol::stack_underflow().into()); - Err(Effect::Raise) + Err(RuntimeError) } } } -pub fn dip(evaluator: &mut Evaluator) -> Result<(), Effect> { +pub fn dip(evaluator: &mut Evaluator) -> Result<(), RuntimeError> { match &evaluator.stack[..] { [.., _, Expression::Quote(_)] => { let top = evaluator.stack.len(); @@ -784,16 +784,16 @@ pub fn dip(evaluator: &mut Evaluator) -> Result<(), Effect> { } [.., _, _] => { evaluator.stack.push(Symbol::type_error().into()); - Err(Effect::Raise) + Err(RuntimeError) } _ => { evaluator.stack.push(Symbol::stack_underflow().into()); - Err(Effect::Raise) + Err(RuntimeError) } } } -pub fn r#if(evaluator: &mut Evaluator) -> Result<(), Effect> { +pub fn r#if(evaluator: &mut Evaluator) -> Result<(), RuntimeError> { let stack = &mut evaluator.stack; match stack[..] { @@ -811,16 +811,16 @@ pub fn r#if(evaluator: &mut Evaluator) -> Result<(), Effect> { } [.., _, _, _] => { evaluator.stack.push(Symbol::type_error().into()); - Err(Effect::Raise) + Err(RuntimeError) } _ => { evaluator.stack.push(Symbol::stack_underflow().into()); - Err(Effect::Raise) + Err(RuntimeError) } } } -pub fn r#else(evaluator: &mut Evaluator) -> Result<(), Effect> { +pub fn r#else(evaluator: &mut Evaluator) -> Result<(), RuntimeError> { let stack = &mut evaluator.stack; match stack[..] { @@ -838,16 +838,16 @@ pub fn r#else(evaluator: &mut Evaluator) -> Result<(), Effect> { } [.., _, _] => { evaluator.stack.push(Symbol::type_error().into()); - Err(Effect::Raise) + Err(RuntimeError) } _ => { evaluator.stack.push(Symbol::stack_underflow().into()); - Err(Effect::Raise) + Err(RuntimeError) } } } -pub fn if_else(evaluator: &mut Evaluator) -> Result<(), Effect> { +pub fn if_else(evaluator: &mut Evaluator) -> Result<(), RuntimeError> { let stack = &mut evaluator.stack; match stack[..] { @@ -860,20 +860,20 @@ pub fn if_else(evaluator: &mut Evaluator) -> Result<(), Effect> { } [.., _, _, _] => { evaluator.stack.push(Symbol::type_error().into()); - Err(Effect::Raise) + Err(RuntimeError) } _ => { evaluator.stack.push(Symbol::stack_underflow().into()); - Err(Effect::Raise) + Err(RuntimeError) } } } -pub fn raise(_: &mut Evaluator) -> Result<(), Effect> { - Err(Effect::Raise) +pub fn raise(_: &mut Evaluator) -> Result<(), RuntimeError> { + Err(RuntimeError) } -pub fn r#try(evaluator: &mut Evaluator) -> Result<(), Effect> { +pub fn r#try(evaluator: &mut Evaluator) -> Result<(), RuntimeError> { match &evaluator.stack[..] { [.., Expression::Quote(_), Expression::Quote(_), _] => { let guarded = evaluator.stack.pop(); @@ -881,7 +881,7 @@ pub fn r#try(evaluator: &mut Evaluator) -> Result<(), Effect> { let len = evaluator.stack.len(); match unquote(evaluator) { - Err(Effect::Raise) if evaluator.stack.last() == guarded.as_ref() => { + Err(RuntimeError) if evaluator.stack.last() == guarded.as_ref() => { evaluator.stack.truncate(len); evaluator.stack[len - 1] = guard; unquote(evaluator) @@ -891,62 +891,62 @@ pub fn r#try(evaluator: &mut Evaluator) -> Result<(), Effect> { } [.., _, _, _] => { evaluator.stack.push(Symbol::type_error().into()); - Err(Effect::Raise) + Err(RuntimeError) } _ => { evaluator.stack.push(Symbol::stack_underflow().into()); - Err(Effect::Raise) + Err(RuntimeError) } } } -pub fn first(evaluator: &mut Evaluator) -> Result<(), Effect> { +pub fn first(evaluator: &mut Evaluator) -> Result<(), RuntimeError> { let stack = &mut evaluator.stack; match &stack[..] { [.., Expression::Quote(quote)] => { let expression = quote.first().cloned().ok_or_else(|| { stack.push(Symbol::out_of_range().into()); - Effect::Raise + RuntimeError })?; *stack.last_mut().unwrap() = expression; Ok(()) } [.., _] => { stack.push(Symbol::type_error().into()); - Err(Effect::Raise) + Err(RuntimeError) } _ => { stack.push(Symbol::stack_underflow().into()); - Err(Effect::Raise) + Err(RuntimeError) } } } -pub fn last(evaluator: &mut Evaluator) -> Result<(), Effect> { +pub fn last(evaluator: &mut Evaluator) -> Result<(), RuntimeError> { let stack = &mut evaluator.stack; match &stack[..] { [.., Expression::Quote(quote)] => { let expression = quote.last().cloned().ok_or_else(|| { stack.push(Symbol::out_of_range().into()); - Effect::Raise + RuntimeError })?; *stack.last_mut().unwrap() = expression; Ok(()) } [.., _] => { stack.push(Symbol::type_error().into()); - Err(Effect::Raise) + Err(RuntimeError) } _ => { stack.push(Symbol::stack_underflow().into()); - Err(Effect::Raise) + Err(RuntimeError) } } } -pub fn prefix(evaluator: &mut Evaluator) -> Result<(), Effect> { +pub fn prefix(evaluator: &mut Evaluator) -> Result<(), RuntimeError> { let stack = &mut evaluator.stack; match &stack[..] { @@ -965,16 +965,16 @@ pub fn prefix(evaluator: &mut Evaluator) -> Result<(), Effect> { } [.., _] => { stack.push(Symbol::type_error().into()); - Err(Effect::Raise) + Err(RuntimeError) } _ => { stack.push(Symbol::stack_underflow().into()); - Err(Effect::Raise) + Err(RuntimeError) } } } -pub fn suffix(evaluator: &mut Evaluator) -> Result<(), Effect> { +pub fn suffix(evaluator: &mut Evaluator) -> Result<(), RuntimeError> { let stack = &mut evaluator.stack; match &stack[..] { @@ -985,16 +985,16 @@ pub fn suffix(evaluator: &mut Evaluator) -> Result<(), Effect> { } [.., _] => { stack.push(Symbol::type_error().into()); - Err(Effect::Raise) + Err(RuntimeError) } _ => { stack.push(Symbol::stack_underflow().into()); - Err(Effect::Raise) + Err(RuntimeError) } } } -pub fn at(evaluator: &mut Evaluator) -> Result<(), Effect> { +pub fn at(evaluator: &mut Evaluator) -> Result<(), RuntimeError> { let stack = &mut evaluator.stack; match stack[..] { @@ -1003,7 +1003,7 @@ pub fn at(evaluator: &mut Evaluator) -> Result<(), Effect> { if at.is_negative() || (at as usize) >= quote_len { stack.push(Symbol::out_of_range().into()); - return Err(Effect::Raise); + return Err(RuntimeError); } let expression = quote[at as usize].clone(); @@ -1014,16 +1014,16 @@ pub fn at(evaluator: &mut Evaluator) -> Result<(), Effect> { } [.., _, _] => { stack.push(Symbol::type_error().into()); - Err(Effect::Raise) + Err(RuntimeError) } _ => { stack.push(Symbol::stack_underflow().into()); - Err(Effect::Raise) + Err(RuntimeError) } } } -pub fn split(evaluator: &mut Evaluator) -> Result<(), Effect> { +pub fn split(evaluator: &mut Evaluator) -> Result<(), RuntimeError> { let stack = &mut evaluator.stack; match stack[..] { @@ -1032,7 +1032,7 @@ pub fn split(evaluator: &mut Evaluator) -> Result<(), Effect> { if at.is_negative() || (at as usize) >= quote_len { stack.push(Symbol::out_of_range().into()); - return Err(Effect::Raise); + return Err(RuntimeError); } *stack.last_mut().unwrap() = quote.split(at as usize).into(); @@ -1040,16 +1040,16 @@ pub fn split(evaluator: &mut Evaluator) -> Result<(), Effect> { } [.., _, _] => { stack.push(Symbol::type_error().into()); - Err(Effect::Raise) + Err(RuntimeError) } _ => { stack.push(Symbol::stack_underflow().into()); - Err(Effect::Raise) + Err(RuntimeError) } } } -pub fn len(evaluator: &mut Evaluator) -> Result<(), Effect> { +pub fn len(evaluator: &mut Evaluator) -> Result<(), RuntimeError> { let stack = &mut evaluator.stack; match &stack[..] { @@ -1063,29 +1063,29 @@ pub fn len(evaluator: &mut Evaluator) -> Result<(), Effect> { } [.., _] => { stack.push(Symbol::type_error().into()); - Err(Effect::Raise) + Err(RuntimeError) } _ => { stack.push(Symbol::stack_underflow().into()); - Err(Effect::Raise) + Err(RuntimeError) } } } -pub fn swap(evaluator: &mut Evaluator) -> Result<(), Effect> { +pub fn swap(evaluator: &mut Evaluator) -> Result<(), RuntimeError> { let stack = &mut evaluator.stack; let top = stack.len(); if top < 2 { stack.push(Symbol::stack_underflow().into()); - return Err(Effect::Raise); + return Err(RuntimeError); } stack.swap(top - 1, top - 2); Ok(()) } -pub fn rollup(evaluator: &mut Evaluator) -> Result<(), Effect> { +pub fn rollup(evaluator: &mut Evaluator) -> Result<(), RuntimeError> { let stack = &mut evaluator.stack; match &mut stack[..] { @@ -1096,12 +1096,12 @@ pub fn rollup(evaluator: &mut Evaluator) -> Result<(), Effect> { } _ => { stack.push(Symbol::stack_underflow().into()); - Err(Effect::Raise) + Err(RuntimeError) } } } -pub fn rolldown(evaluator: &mut Evaluator) -> Result<(), Effect> { +pub fn rolldown(evaluator: &mut Evaluator) -> Result<(), RuntimeError> { let stack = &mut evaluator.stack; match &mut stack[..] { @@ -1112,12 +1112,12 @@ pub fn rolldown(evaluator: &mut Evaluator) -> Result<(), Effect> { } _ => { stack.push(Symbol::stack_underflow().into()); - Err(Effect::Raise) + Err(RuntimeError) } } } -pub fn rotate(evaluator: &mut Evaluator) -> Result<(), Effect> { +pub fn rotate(evaluator: &mut Evaluator) -> Result<(), RuntimeError> { let stack = &mut evaluator.stack; match &mut stack[..] { @@ -1127,34 +1127,34 @@ pub fn rotate(evaluator: &mut Evaluator) -> Result<(), Effect> { } _ => { stack.push(Symbol::stack_underflow().into()); - Err(Effect::Raise) + Err(RuntimeError) } } } -pub fn pop(evaluator: &mut Evaluator) -> Result<(), Effect> { +pub fn pop(evaluator: &mut Evaluator) -> Result<(), RuntimeError> { let stack = &mut evaluator.stack; if stack.pop().is_none() { stack.push(Symbol::stack_underflow().into()); - return Err(Effect::Raise); + return Err(RuntimeError); } Ok(()) } -pub fn dup(evaluator: &mut Evaluator) -> Result<(), Effect> { +pub fn dup(evaluator: &mut Evaluator) -> Result<(), RuntimeError> { let stack = &mut evaluator.stack; let expression = stack.last().cloned().ok_or_else(|| { stack.push(Symbol::stack_underflow().into()); - Effect::Raise + RuntimeError })?; stack.push(expression); Ok(()) } -pub fn ask(evaluator: &mut Evaluator) -> Result<(), Effect> { +pub fn ask(evaluator: &mut Evaluator) -> Result<(), RuntimeError> { let stack = &mut evaluator.stack; match &stack[..] { @@ -1163,23 +1163,23 @@ pub fn ask(evaluator: &mut Evaluator) -> Result<(), Effect> { write!(stdout_lock, "{prompt}").map_err(|_| { stack.push(Symbol::io_error().into()); - Effect::Raise + RuntimeError })?; stdout_lock.flush().map_err(|_| { stack.push(Symbol::io_error().into()); - Effect::Raise + RuntimeError })?; stack.pop(); } [.., _] => { evaluator.stack.push(Symbol::type_error().into()); - return Err(Effect::Raise); + return Err(RuntimeError); } _ => { evaluator.stack.push(Symbol::stack_underflow().into()); - return Err(Effect::Raise); + return Err(RuntimeError); } } @@ -1187,34 +1187,34 @@ pub fn ask(evaluator: &mut Evaluator) -> Result<(), Effect> { io::stdin().read_line(&mut buf).map_err(|_| { stack.push(Symbol::io_error().into()); - Effect::Raise + RuntimeError })?; stack.push(Expression::String(String::from_utf8(&buf))); Ok(()) } -pub fn say(evaluator: &mut Evaluator) -> Result<(), Effect> { +pub fn say(evaluator: &mut Evaluator) -> Result<(), RuntimeError> { let stack = &mut evaluator.stack; let expression = stack.pop().ok_or_else(|| { stack.push(Symbol::stack_underflow().into()); - Effect::Raise + RuntimeError })?; writeln!(io::stdout(), "{expression}").map_err(|_| { stack.push(Symbol::io_error().into()); - Effect::Raise + RuntimeError }) } -pub fn show(evaluator: &mut Evaluator) -> Result<(), Effect> { +pub fn show(evaluator: &mut Evaluator) -> Result<(), RuntimeError> { let stack = &mut evaluator.stack; let mut stdout = io::stdout().lock(); write!(stdout, "#>>>").map_err(|_| { stack.push(Symbol::io_error().into()); - Effect::Raise + RuntimeError })?; stack @@ -1222,16 +1222,16 @@ pub fn show(evaluator: &mut Evaluator) -> Result<(), Effect> { .try_for_each(|e| write!(stdout, " {e:?}")) .map_err(|_| { stack.push(Symbol::io_error().into()); - Effect::Raise + RuntimeError })?; writeln!(stdout).map_err(|_| { stack.push(Symbol::io_error().into()); - Effect::Raise + RuntimeError }) } -pub fn linrec(evaluator: &mut Evaluator) -> Result<(), Effect> { +pub fn linrec(evaluator: &mut Evaluator) -> Result<(), RuntimeError> { let stack = &mut evaluator.stack; match &mut stack[..] { @@ -1249,11 +1249,11 @@ pub fn linrec(evaluator: &mut Evaluator) -> Result<(), Effect> { } [.., _, _, _, _] => { stack.push(Symbol::type_error().into()); - Err(Effect::Raise) + Err(RuntimeError) } _ => { stack.push(Symbol::stack_underflow().into()); - Err(Effect::Raise) + Err(RuntimeError) } } } @@ -1264,7 +1264,7 @@ fn linrec_aux( leave: &Quote, shard: &Quote, merge: &Quote, -) -> Result<(), Effect> { +) -> Result<(), RuntimeError> { evaluator.evaluate(check.iter().cloned())?; match evaluator.stack.pop() { @@ -1279,16 +1279,16 @@ fn linrec_aux( .stack .extend_from_slice(&[expression, Symbol::type_error().into()]); - Err(Effect::Raise) + Err(RuntimeError) } None => { evaluator.stack.push(Symbol::stack_underflow().into()); - Err(Effect::Raise) + Err(RuntimeError) } } } -pub fn binrec(evaluator: &mut Evaluator) -> Result<(), Effect> { +pub fn binrec(evaluator: &mut Evaluator) -> Result<(), RuntimeError> { let stack = &mut evaluator.stack; match &mut stack[..] { @@ -1306,11 +1306,11 @@ pub fn binrec(evaluator: &mut Evaluator) -> Result<(), Effect> { } [.., _, _, _, _] => { stack.push(Symbol::type_error().into()); - Err(Effect::Raise) + Err(RuntimeError) } _ => { stack.push(Symbol::stack_underflow().into()); - Err(Effect::Raise) + Err(RuntimeError) } } } @@ -1321,7 +1321,7 @@ fn binrec_aux( leave: &Quote, shard: &Quote, merge: &Quote, -) -> Result<(), Effect> { +) -> Result<(), RuntimeError> { evaluator.evaluate(check.iter().cloned())?; match evaluator.stack.pop() { @@ -1342,11 +1342,11 @@ fn binrec_aux( .stack .extend_from_slice(&[expression, Symbol::type_error().into()]); - Err(Effect::Raise) + Err(RuntimeError) } None => { evaluator.stack.push(Symbol::stack_underflow().into()); - Err(Effect::Raise) + Err(RuntimeError) } } } diff --git a/rat/src/decimal.rs b/rat/src/decimal.rs index 248c9bf..3dfc724 100644 --- a/rat/src/decimal.rs +++ b/rat/src/decimal.rs @@ -13,7 +13,7 @@ use std::ops::{ }; use crate::codegen; -use crate::effect::Effect; +use crate::error::RuntimeError; use crate::evaluate::Evaluate; use crate::evaluator::Evaluator; use crate::expression::Expression; @@ -77,7 +77,7 @@ impl Decimal { } impl Evaluate for &mut Evaluator { - type Output = Result<(), Effect>; + type Output = Result<(), RuntimeError>; fn evaluate(self, value: Decimal) -> Self::Output { self.stack.push(Expression::Decimal(value)); diff --git a/rat/src/dictionary.rs b/rat/src/dictionary.rs new file mode 100644 index 0000000..c189036 --- /dev/null +++ b/rat/src/dictionary.rs @@ -0,0 +1,308 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +use std::borrow::Borrow; +use std::collections::HashMap; +use std::fmt::Debug; +use std::hash::Hash; +use std::sync::Arc; + +use crate::boolean::Boolean; +use crate::builtin; +use crate::decimal::Decimal; +use crate::expression::Expression; +use crate::locution::Locution; +use crate::verb::Verb; +use crate::word::{OwnedWord, Word}; + +#[derive(Debug)] +pub enum Definition { + Phrase { + phrase: Arc<[Expression]>, + visibility: Visibility, + }, + Dictionary { + dictionary: Arc, + visibility: Visibility, + }, +} + +impl Definition { + pub fn is_intern(&self) -> bool { + Visibility::Intern + == match self { + Definition::Phrase { visibility, .. } => *visibility, + Definition::Dictionary { visibility, .. } => *visibility, + } + } + + pub fn is_extern(&self) -> bool { + !self.is_intern() + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub enum Visibility { + Extern, + Intern, +} + +#[derive(Debug, Default)] +pub struct Dictionary { + definitions: HashMap, +} + +impl Dictionary { + pub fn new() -> Self { + Self { + definitions: HashMap::new(), + } + } + + pub fn with_prelude() -> Self { + Self { + definitions: PRELUDE + .into_iter() + .map(|(word, phrase)| { + ( + word.into(), + Definition::Phrase { + phrase: phrase.into(), + visibility: Visibility::Intern, + }, + ) + }) + .collect(), + } + } + + pub fn define(&mut self, word: OwnedWord, definition: Definition) -> Option { + self.definitions.insert(word, definition) + } + + pub fn get(&self, word: &W) -> Option<&Definition> + where + OwnedWord: Borrow, + W: ?Sized + Eq + Hash, + { + self.definitions.get(word) + } + + pub fn lookup(&self, locution: &Locution) -> Option<&[Expression]> { + let mut words = locution.words(); + let mut dictionary = self; + let mut is_first_word = true; + + while let Some(word) = words.next() { + let definition = dictionary.get(word)?; + + if !is_first_word && definition.is_intern() { + break; + } + + match definition { + Definition::Phrase { phrase, .. } => { + if words.next().is_some() { + break; + } + + return Some(phrase); + } + Definition::Dictionary { + dictionary: next_dictionary, + .. + } => dictionary = next_dictionary, + } + + is_first_word = false; + } + + None + } + + pub fn definitions(&self) -> impl Iterator { + self.definitions.iter() + } + + pub fn retain(&mut self, mut f: F) + where + F: FnMut(&Word, &Definition) -> bool, + { + self.definitions.retain(|w, d| f(w, d)); + } +} + +static PRELUDE: [(&Word, &[Expression]); 63] = [ + (word_literal("neg"), &[Expression::Verb(Verb(builtin::neg))]), + ( + word_literal("incr"), + &[Expression::Verb(Verb(builtin::incr))], + ), + ( + word_literal("decr"), + &[Expression::Verb(Verb(builtin::decr))], + ), + (word_literal("add"), &[Expression::Verb(Verb(builtin::add))]), + (word_literal("sub"), &[Expression::Verb(Verb(builtin::sub))]), + (word_literal("mul"), &[Expression::Verb(Verb(builtin::mul))]), + (word_literal("div"), &[Expression::Verb(Verb(builtin::div))]), + (word_literal("rem"), &[Expression::Verb(Verb(builtin::rem))]), + (word_literal("eq"), &[Expression::Verb(Verb(builtin::eq))]), + (word_literal("ne"), &[Expression::Verb(Verb(builtin::ne))]), + (word_literal("gt"), &[Expression::Verb(Verb(builtin::gt))]), + (word_literal("ge"), &[Expression::Verb(Verb(builtin::ge))]), + (word_literal("lt"), &[Expression::Verb(Verb(builtin::lt))]), + (word_literal("le"), &[Expression::Verb(Verb(builtin::le))]), + ( + word_literal("positive?"), + &[Expression::Verb(Verb(builtin::positive))], + ), + ( + word_literal("zero?"), + &[Expression::Verb(Verb(builtin::zero))], + ), + ( + word_literal("negative?"), + &[Expression::Verb(Verb(builtin::negative))], + ), + (word_literal("nan"), &[Expression::Decimal(Decimal::NAN)]), + ( + word_literal("inf"), + &[Expression::Decimal(Decimal::INFINITY)], + ), + ( + word_literal("-inf"), + &[Expression::Decimal(Decimal::NEG_INFINITY)], + ), + ( + word_literal("false"), + &[Expression::Boolean(Boolean(false))], + ), + (word_literal("true"), &[Expression::Boolean(Boolean(true))]), + (word_literal("not"), &[Expression::Verb(Verb(builtin::not))]), + (word_literal("and"), &[Expression::Verb(Verb(builtin::and))]), + (word_literal("or"), &[Expression::Verb(Verb(builtin::or))]), + ( + word_literal("bit-not"), + &[Expression::Verb(Verb(builtin::bitwise_not))], + ), + ( + word_literal("bit-and"), + &[Expression::Verb(Verb(builtin::bitwise_and))], + ), + ( + word_literal("bit-xor"), + &[Expression::Verb(Verb(builtin::bitwise_xor))], + ), + ( + word_literal("bit-or"), + &[Expression::Verb(Verb(builtin::bitwise_or))], + ), + (word_literal("shl"), &[Expression::Verb(Verb(builtin::shl))]), + (word_literal("shr"), &[Expression::Verb(Verb(builtin::shr))]), + ( + word_literal("ushr"), + &[Expression::Verb(Verb(builtin::ushr))], + ), + (word_literal("cat"), &[Expression::Verb(Verb(builtin::cat))]), + ( + word_literal("quote"), + &[Expression::Verb(Verb(builtin::quote))], + ), + ( + word_literal("unquote"), + &[Expression::Verb(Verb(builtin::unquote))], + ), + ( + word_literal("eval"), + &[Expression::Verb(Verb(builtin::eval))], + ), + (word_literal("i"), &[Expression::Verb(Verb(builtin::i))]), + (word_literal("x"), &[Expression::Verb(Verb(builtin::x))]), + (word_literal("dip"), &[Expression::Verb(Verb(builtin::dip))]), + ( + word_literal("unary2"), + &[Expression::Verb(Verb(builtin::unary2))], + ), + (word_literal("if"), &[Expression::Verb(Verb(builtin::r#if))]), + ( + word_literal("else"), + &[Expression::Verb(Verb(builtin::r#else))], + ), + ( + word_literal("if-else"), + &[Expression::Verb(Verb(builtin::if_else))], + ), + ( + word_literal("raise"), + &[Expression::Verb(Verb(builtin::raise))], + ), + ( + word_literal("try"), + &[Expression::Verb(Verb(builtin::r#try))], + ), + ( + word_literal("first"), + &[Expression::Verb(Verb(builtin::first))], + ), + ( + word_literal("last"), + &[Expression::Verb(Verb(builtin::last))], + ), + ( + word_literal("prefix"), + &[Expression::Verb(Verb(builtin::prefix))], + ), + ( + word_literal("suffix"), + &[Expression::Verb(Verb(builtin::suffix))], + ), + (word_literal("at"), &[Expression::Verb(Verb(builtin::at))]), + ( + word_literal("split"), + &[Expression::Verb(Verb(builtin::split))], + ), + (word_literal("len"), &[Expression::Verb(Verb(builtin::len))]), + ( + word_literal("swap"), + &[Expression::Verb(Verb(builtin::swap))], + ), + ( + word_literal("rollup"), + &[Expression::Verb(Verb(builtin::rollup))], + ), + ( + word_literal("rolldown"), + &[Expression::Verb(Verb(builtin::rolldown))], + ), + ( + word_literal("rotate"), + &[Expression::Verb(Verb(builtin::rotate))], + ), + (word_literal("pop"), &[Expression::Verb(Verb(builtin::pop))]), + (word_literal("dup"), &[Expression::Verb(Verb(builtin::dup))]), + (word_literal("ask"), &[Expression::Verb(Verb(builtin::ask))]), + (word_literal("say"), &[Expression::Verb(Verb(builtin::say))]), + ( + word_literal("show"), + &[Expression::Verb(Verb(builtin::show))], + ), + ( + word_literal("linrec"), + &[Expression::Verb(Verb(builtin::linrec))], + ), + ( + word_literal("binrec"), + &[Expression::Verb(Verb(builtin::binrec))], + ), +]; + +const fn word_literal(literal: &str) -> &Word { + match Word::try_from_literal(literal) { + Ok(word) => word, + Err(_) => panic!("invalid word literal"), + } +} diff --git a/rat/src/error.rs b/rat/src/error.rs new file mode 100644 index 0000000..de14ab4 --- /dev/null +++ b/rat/src/error.rs @@ -0,0 +1,8 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub struct RuntimeError; diff --git a/rat/src/evaluator.rs b/rat/src/evaluator.rs index ca27a25..bf38c82 100644 --- a/rat/src/evaluator.rs +++ b/rat/src/evaluator.rs @@ -4,7 +4,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -use crate::effect::Effect; +use crate::error::RuntimeError; use crate::evaluate::Evaluate; use crate::expression::Expression; @@ -14,8 +14,8 @@ pub struct Evaluator { } impl Evaluator { - pub const fn new() -> Self { - Self { stack: Vec::new() } + pub fn new() -> Self { + Default::default() } } @@ -23,7 +23,7 @@ impl Evaluate for &mut Evaluator where I: Iterator, { - type Output = Result<(), Effect>; + type Output = Result<(), RuntimeError>; fn evaluate(self, mut expressions: I) -> Self::Output { expressions.try_for_each(|e| self.evaluate(e)) diff --git a/rat/src/expression.rs b/rat/src/expression.rs index d7c44c2..76c365d 100644 --- a/rat/src/expression.rs +++ b/rat/src/expression.rs @@ -6,7 +6,7 @@ use std::fmt::{Debug, Display}; -use crate::effect::Effect; +use crate::error::RuntimeError; use crate::evaluate::Evaluate; use crate::evaluator::Evaluator; @@ -30,7 +30,7 @@ pub enum Expression { } const _: [(); 16] = [(); std::mem::size_of::()]; -const _: [(); 1] = [(); std::mem::size_of::>()]; +const _: [(); 1] = [(); std::mem::size_of::>()]; impl From for Expression { #[inline] @@ -82,7 +82,7 @@ impl From for Expression { } impl Evaluate for &mut Evaluator { - type Output = Result<(), Effect>; + type Output = Result<(), RuntimeError>; fn evaluate(self, expression: Expression) -> Self::Output { match expression { diff --git a/rat/src/integer.rs b/rat/src/integer.rs index faa1c45..7f08d65 100644 --- a/rat/src/integer.rs +++ b/rat/src/integer.rs @@ -12,7 +12,7 @@ use std::ops::{ use crate::codegen; use crate::decimal::Decimal; -use crate::effect::Effect; +use crate::error::RuntimeError; use crate::evaluate::Evaluate; use crate::evaluator::Evaluator; use crate::expression::Expression; @@ -77,7 +77,7 @@ impl Integer { } impl Evaluate for &mut Evaluator { - type Output = Result<(), Effect>; + type Output = Result<(), RuntimeError>; fn evaluate(self, value: Integer) -> Self::Output { self.stack.push(Expression::Integer(value)); diff --git a/rat/src/lib.rs b/rat/src/lib.rs index c249e9f..c875533 100644 --- a/rat/src/lib.rs +++ b/rat/src/lib.rs @@ -20,12 +20,12 @@ pub mod verb; pub mod expression; pub mod builtin; -pub mod effect; +pub mod dictionary; +pub mod error; pub mod evaluate; pub mod evaluator; pub mod locution; pub mod parser; -pub mod vocabulary; pub mod word; use std::env; diff --git a/rat/src/parser.rs b/rat/src/parser.rs index aed6bb5..38aabcb 100644 --- a/rat/src/parser.rs +++ b/rat/src/parser.rs @@ -17,25 +17,25 @@ use std::{env, fs}; use crate::boolean::Boolean; use crate::decimal::Decimal; +use crate::dictionary::{Definition, Dictionary, Visibility}; use crate::expression::Expression; use crate::integer::Integer; use crate::locution::{Locution, OwnedLocution}; use crate::quote::Quote; use crate::string::String; use crate::symbol::Symbol; -use crate::vocabulary::{Definition, Visibility, Vocabulary}; use crate::word::{OwnedWord, Word}; #[derive(Debug, Default)] pub struct Parser { - vocabulary: Vocabulary, - cache: HashMap>, + dictionary: Dictionary, + cache: HashMap>, } -impl From for Parser { - fn from(vocabulary: Vocabulary) -> Self { +impl From for Parser { + fn from(dictionary: Dictionary) -> Self { Self { - vocabulary, + dictionary, cache: Default::default(), } } @@ -48,13 +48,13 @@ impl Parser { pub fn with_prelude() -> Self { Self { - vocabulary: Vocabulary::with_prelude(), + dictionary: Dictionary::with_prelude(), cache: Default::default(), } } - pub fn vocabulary(&self) -> &Vocabulary { - &self.vocabulary + pub fn dictionary(&self) -> &Dictionary { + &self.dictionary } pub fn parse(&mut self, origin: Origin, source: &str) -> Result, ParseError> { @@ -82,11 +82,11 @@ impl Parser { locution: &Locution, visibility: Visibility, ) -> Result<(), ImportError> { - if let Some(vocabulary) = self.cache.get(locution) { - self.vocabulary.define( + if let Some(dictionary) = self.cache.get(locution) { + self.dictionary.define( word.to_owned(), - Definition::Vocabulary { - vocabulary: vocabulary.clone(), + Definition::Dictionary { + dictionary: dictionary.clone(), visibility, }, ); @@ -135,15 +135,15 @@ impl Parser { .parse(Origin::Path(path.as_path()), &source) .map_err(|e| ImportError::new(format!("`{}`\n{}", locution, e)))?; - parser.vocabulary.retain(|_, d| d.is_extern()); + parser.dictionary.retain(|_, d| d.is_extern()); - let vocabulary = Arc::new(parser.vocabulary); + let dictionary = Arc::new(parser.dictionary); - self.cache.insert(locution.to_owned(), vocabulary.clone()); - self.vocabulary.define( + self.cache.insert(locution.to_owned(), dictionary.clone()); + self.dictionary.define( word.to_owned(), - Definition::Vocabulary { - vocabulary, + Definition::Dictionary { + dictionary, visibility, }, ); @@ -382,7 +382,7 @@ fn parse_definition(parser: &mut Parser, origin: Origin, pair: PestPair) -> Resu Rule::LeftArrow => { let phrase = parse_phrase(parser, origin, pairs.next().unwrap())?; - parser.vocabulary.define( + parser.dictionary.define( word.to_owned(), Definition::Phrase { phrase: phrase.into(), @@ -439,7 +439,7 @@ fn parse_phrase( let span = pair.as_span(); let locution = parse_locution(origin, pair)?; parser - .vocabulary + .dictionary .lookup(locution) .map(|expressions| phrase.extend_from_slice(expressions)) .ok_or_else(|| parse_error(origin, span, undefined_locution(locution)))?; diff --git a/rat/src/quote.rs b/rat/src/quote.rs index 3514b24..1e3a792 100644 --- a/rat/src/quote.rs +++ b/rat/src/quote.rs @@ -8,7 +8,7 @@ use std::fmt::{Debug, Display}; use std::ops::Deref; use std::sync::Arc; -use crate::effect::Effect; +use crate::error::RuntimeError; use crate::evaluate::Evaluate; use crate::evaluator::Evaluator; use crate::expression::Expression; @@ -94,7 +94,7 @@ impl Quote { } impl Evaluate for &mut Evaluator { - type Output = Result<(), Effect>; + type Output = Result<(), RuntimeError>; fn evaluate(self, value: Quote) -> Self::Output { self.stack.push(Expression::Quote(value)); diff --git a/rat/src/string.rs b/rat/src/string.rs index 4cc90b5..b906754 100644 --- a/rat/src/string.rs +++ b/rat/src/string.rs @@ -8,7 +8,7 @@ use std::fmt::{Debug, Display}; use std::ops::Deref; use std::sync::Arc; -use crate::effect::Effect; +use crate::error::RuntimeError; use crate::evaluate::Evaluate; use crate::evaluator::Evaluator; use crate::expression::Expression; @@ -69,7 +69,7 @@ impl String { } impl Evaluate for &mut Evaluator { - type Output = Result<(), Effect>; + type Output = Result<(), RuntimeError>; fn evaluate(self, value: String) -> Self::Output { self.stack.push(Expression::String(value)); diff --git a/rat/src/symbol.rs b/rat/src/symbol.rs index e4533f5..0ff5695 100644 --- a/rat/src/symbol.rs +++ b/rat/src/symbol.rs @@ -6,7 +6,7 @@ use ustr::Ustr; -use crate::effect::Effect; +use crate::error::RuntimeError; use crate::evaluate::Evaluate; use crate::evaluator::Evaluator; use crate::expression::Expression; @@ -54,7 +54,7 @@ impl Symbol { } impl Evaluate for &mut Evaluator { - type Output = Result<(), Effect>; + type Output = Result<(), RuntimeError>; fn evaluate(self, value: Symbol) -> Self::Output { self.stack.push(Expression::Symbol(value)); diff --git a/rat/src/verb.rs b/rat/src/verb.rs index f7e59dc..51497c1 100644 --- a/rat/src/verb.rs +++ b/rat/src/verb.rs @@ -6,15 +6,15 @@ use std::fmt::{Debug, Display}; -use crate::effect::Effect; +use crate::error::RuntimeError; use crate::evaluate::Evaluate; use crate::evaluator::Evaluator; #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct Verb(pub fn(&mut Evaluator) -> Result<(), Effect>); +pub struct Verb(pub fn(&mut Evaluator) -> Result<(), RuntimeError>); impl Evaluate for &mut Evaluator { - type Output = Result<(), Effect>; + type Output = Result<(), RuntimeError>; fn evaluate(self, Verb(verb): Verb) -> Self::Output { verb(self) From 66ed5d3a28829d7c7032699f26f20937ac4a8c16 Mon Sep 17 00:00:00 2001 From: daddinuz Date: Tue, 15 Oct 2024 00:05:55 +0200 Subject: [PATCH 6/8] refactored grammar --- Cargo.lock | 52 ++--- examples/closure.rat | 2 + examples/fact.rat | 2 +- examples/fib.rat | 2 +- examples/person.rat | 4 + examples/towards_zero.rat | 6 +- lib/math.rat | 10 +- lib/seq.rat | 10 +- lib/std.rat | 18 +- rat-cli/Cargo.toml | 2 +- rat/Cargo.toml | 2 +- rat/src/builtin.rs | 44 ++++ rat/src/dictionary.rs | 42 ++-- rat/src/grammar.pest | 81 ++----- rat/src/{locution.rs => identifier.rs} | 60 ++--- rat/src/lib.rs | 2 +- rat/src/parser.rs | 252 ++++++++++---------- rat/src/quote.rs | 8 + rat/src/symbol.rs | 2 +- rat/src/vocabulary.rs | 308 ------------------------- rat/src/word.rs | 31 +-- 21 files changed, 321 insertions(+), 619 deletions(-) create mode 100644 examples/closure.rat create mode 100644 examples/person.rat rename rat/src/{locution.rs => identifier.rs} (65%) delete mode 100644 rat/src/vocabulary.rs diff --git a/Cargo.lock b/Cargo.lock index fb02f8b..f8cb9de 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,9 +17,9 @@ dependencies = [ [[package]] name = "autocfg" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "bitflags" @@ -184,9 +184,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.158" +version = "0.2.159" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" +checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5" [[package]] name = "libredox" @@ -249,9 +249,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.19.0" +version = "1.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" [[package]] name = "option-ext" @@ -284,9 +284,9 @@ dependencies = [ [[package]] name = "pest" -version = "2.7.13" +version = "2.7.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdbef9d1d47087a895abd220ed25eb4ad973a5e26f6a4367b038c25e28dfc2d9" +checksum = "879952a81a83930934cbf1786752d6dedc3b1f29e8f8fb2ad1d0a36f377cf442" dependencies = [ "memchr", "thiserror", @@ -295,9 +295,9 @@ dependencies = [ [[package]] name = "pest_derive" -version = "2.7.13" +version = "2.7.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d3a6e3394ec80feb3b6393c725571754c6188490265c61aaf260810d6b95aa0" +checksum = "d214365f632b123a47fd913301e14c946c61d1c183ee245fa76eb752e59a02dd" dependencies = [ "pest", "pest_generator", @@ -305,9 +305,9 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.7.13" +version = "2.7.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94429506bde1ca69d1b5601962c73f4172ab4726571a59ea95931218cb0e930e" +checksum = "eb55586734301717aea2ac313f50b2eb8f60d2fc3dc01d190eefa2e625f60c4e" dependencies = [ "pest", "pest_meta", @@ -318,9 +318,9 @@ dependencies = [ [[package]] name = "pest_meta" -version = "2.7.13" +version = "2.7.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac8a071862e93690b6e34e9a5fb8e33ff3734473ac0245b27232222c4906a33f" +checksum = "b75da2a70cf4d9cb76833c990ac9cd3923c9a8905a8929789ce347c84564d03d" dependencies = [ "once_cell", "pest", @@ -329,9 +329,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.86" +version = "1.0.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +checksum = "b3e4daa0dcf6feba26f985457cdf104d4b4256fc5a09547140f3631bb076b19a" dependencies = [ "unicode-ident", ] @@ -376,9 +376,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.4" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0884ad60e090bf1345b93da0a5de8923c93884cd03f40dfcfddd3b4bee661853" +checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" dependencies = [ "bitflags", ] @@ -466,9 +466,9 @@ checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "syn" -version = "2.0.77" +version = "2.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed" +checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590" dependencies = [ "proc-macro2", "quote", @@ -477,18 +477,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.63" +version = "1.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" +checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.63" +version = "1.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" +checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3" dependencies = [ "proc-macro2", "quote", @@ -503,9 +503,9 @@ checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "ucd-trie" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" +checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" [[package]] name = "unicode-ident" diff --git a/examples/closure.rat b/examples/closure.rat new file mode 100644 index 0000000..6bb2c0f --- /dev/null +++ b/examples/closure.rat @@ -0,0 +1,2 @@ +: make-adder = [$x add] bind ; +40 2 make-adder i say diff --git a/examples/fact.rat b/examples/fact.rat index 56ff0b9..35f4592 100644 --- a/examples/fact.rat +++ b/examples/fact.rat @@ -1,2 +1,2 @@ -: fact ← [dup zero?] [incr] [dup decr] [mul] linrec ; +: fact = [dup zero?] [incr] [dup decr] [mul] linrec ; 5 fact say diff --git a/examples/fib.rat b/examples/fib.rat index 2817e2a..9dfa846 100644 --- a/examples/fib.rat +++ b/examples/fib.rat @@ -1,2 +1,2 @@ -: fib ← [dup 3 lt] [pop 1] [decr dup decr] [add] binrec ; +: fib = [dup 3 lt?] [pop 1] [decr dup decr] [add] binrec ; 30 fib say diff --git a/examples/person.rat b/examples/person.rat new file mode 100644 index 0000000..f65f70a --- /dev/null +++ b/examples/person.rat @@ -0,0 +1,4 @@ +: ^new = [$first-name $last-name $age] bind ; +: ^first-name = 0 at ; +: ^last-name = 1 at ; +: ^age = 2 at ; diff --git a/examples/towards_zero.rat b/examples/towards_zero.rat index ba4acaa..3311a68 100644 --- a/examples/towards_zero.rat +++ b/examples/towards_zero.rat @@ -1,13 +1,13 @@ : std @ rat\std ; -: small? ← 1 lt ; +: small? = 1 lt? ; # with recursion -: f ← std\over small? [pop] [[dup decr] dip dup i] if-else ; +: f = std\over small? [pop] [[dup decr] dip dup i] if-else ; 10 [f] f # with combinators -: f ← [dup small?] [] [dup decr] [] linrec ; +: f = [dup small?] [] [dup decr] [] linrec ; 10 f show diff --git a/lib/math.rat b/lib/math.rat index e8ce558..24226e1 100644 --- a/lib/math.rat +++ b/lib/math.rat @@ -4,8 +4,8 @@ : std @ rat\std ; -÷ abs ← dup negative? [neg] if ; -÷ halve ← 1 shr ; -÷ double ← 1 shl ; -÷ square ← dup mul ; -÷ pow ← [dup quote [mul] cat] dip std\times ; +: ^abs = dup negative? [neg] if ; +: ^halve = 1 shr ; +: ^double = 1 shl ; +: ^square = dup mul ; +: ^pow = [dup quote [mul] cat] dip std\times ; diff --git a/lib/seq.rat b/lib/seq.rat index 6cedbba..30c2eb8 100644 --- a/lib/seq.rat +++ b/lib/seq.rat @@ -5,13 +5,13 @@ : std @ rat\std ; : math @ rat\math ; -÷ empty? ← len zero? ; +: ^empty? = len zero? ; -÷ merge ← +: ^merge = [std\dup2 [empty?] unary2 or] [dup empty? [pop] [std\popd] if-else] [ - std\dup2 [first] unary2 lt + std\dup2 [first] unary2 lt? [[[first quote] [suffix] std\bi] dip] [[first quote] [suffix] std\bi std\swapd] if-else @@ -20,8 +20,8 @@ linrec ; -÷ mergesort ← - [dup len 1 le] +: ^mergesort = + [dup len 1 le?] [] [dup len math\halve split] [merge] diff --git a/lib/std.rat b/lib/std.rat index 9ba3a15..9ef9d11 100644 --- a/lib/std.rat +++ b/lib/std.rat @@ -2,17 +2,17 @@ # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. -÷ popd ← swap pop ; -÷ dupd ← [dup] dip ; -÷ swapd ← [swap] dip ; +: ^popd = swap pop ; +: ^dupd = [dup] dip ; +: ^swapd = [swap] dip ; -÷ over ← dupd swap ; -÷ overd ← [over] dip ; +: ^over = dupd swap ; +: ^overd = [over] dip ; -÷ dup2 ← over over ; +: ^dup2 = over over ; -÷ bi ← [[quote] dip over [cat] dip] dip cat [i] dip i ; +: ^bi = [[quote] dip over [cat] dip] dip cat [i] dip i ; -÷ case ← swap at i ; +: ^case = swap at i ; -÷ times ← [dup 1 lt] [pop pop] [[dup [i] dip] dip decr] [] linrec ; +: ^times = [dup 1 lt?] [pop pop] [[dup [i] dip] dip decr] [] linrec ; diff --git a/rat-cli/Cargo.toml b/rat-cli/Cargo.toml index b0d5022..bf4de66 100644 --- a/rat-cli/Cargo.toml +++ b/rat-cli/Cargo.toml @@ -8,7 +8,7 @@ keywords = ["rat", "rust", "programming-language", "concatenative", "concurrency license = "MPL-2.0" name = "rat-cli" repository = "https://github.com/daddinuz/rat" -rust-version = "1.77" +rust-version = "1.80" version = "0.1.0" [build-dependencies] diff --git a/rat/Cargo.toml b/rat/Cargo.toml index 2c3331f..153c3e9 100644 --- a/rat/Cargo.toml +++ b/rat/Cargo.toml @@ -8,7 +8,7 @@ keywords = ["rat", "rust", "programming-language", "concatenative", "concurrency license = "MPL-2.0" name = "rat" repository = "https://github.com/daddinuz/rat" -rust-version = "1.77" +rust-version = "1.80" version = "0.1.0" [dependencies] diff --git a/rat/src/builtin.rs b/rat/src/builtin.rs index 3d32e6c..af9367f 100644 --- a/rat/src/builtin.rs +++ b/rat/src/builtin.rs @@ -1350,3 +1350,47 @@ fn binrec_aux( } } } + +pub fn bind(evaluator: &mut Evaluator) -> Result<(), RuntimeError> { + match evaluator.stack.pop() { + Some(Expression::Quote(quote)) => { + let mut top = evaluator.stack.len(); + let expression = quote + .iter() + .rev() + .map(|e| match e { + Expression::Symbol(_) => { + top -= 1; + evaluator.stack.get(top).cloned().ok_or(RuntimeError) + } + _ => Ok(e.clone()), + }) + .collect::, _>>() + .map(|mut q| { + q.reverse(); + Expression::Quote(Quote::from(q)) + }) + .inspect_err(|_| { + evaluator.stack.extend_from_slice(&[ + Expression::Quote(quote), + Symbol::stack_underflow().into(), + ]); + })?; + + evaluator.stack.truncate(top); + evaluator.stack.push(expression); + Ok(()) + } + Some(expression) => { + evaluator + .stack + .extend_from_slice(&[expression, Symbol::type_error().into()]); + + Err(RuntimeError) + } + None => { + evaluator.stack.push(Symbol::stack_underflow().into()); + Err(RuntimeError) + } + } +} diff --git a/rat/src/dictionary.rs b/rat/src/dictionary.rs index c189036..85f48c3 100644 --- a/rat/src/dictionary.rs +++ b/rat/src/dictionary.rs @@ -14,14 +14,14 @@ use crate::boolean::Boolean; use crate::builtin; use crate::decimal::Decimal; use crate::expression::Expression; -use crate::locution::Locution; +use crate::identifier::Identifier; use crate::verb::Verb; use crate::word::{OwnedWord, Word}; #[derive(Debug)] pub enum Definition { - Phrase { - phrase: Arc<[Expression]>, + Body { + body: Arc<[Expression]>, visibility: Visibility, }, Dictionary { @@ -34,7 +34,7 @@ impl Definition { pub fn is_intern(&self) -> bool { Visibility::Intern == match self { - Definition::Phrase { visibility, .. } => *visibility, + Definition::Body { visibility, .. } => *visibility, Definition::Dictionary { visibility, .. } => *visibility, } } @@ -66,11 +66,11 @@ impl Dictionary { Self { definitions: PRELUDE .into_iter() - .map(|(word, phrase)| { + .map(|(word, body)| { ( word.into(), - Definition::Phrase { - phrase: phrase.into(), + Definition::Body { + body: body.into(), visibility: Visibility::Intern, }, ) @@ -91,8 +91,8 @@ impl Dictionary { self.definitions.get(word) } - pub fn lookup(&self, locution: &Locution) -> Option<&[Expression]> { - let mut words = locution.words(); + pub fn lookup(&self, identifier: &Identifier) -> Option<&[Expression]> { + let mut words = identifier.words(); let mut dictionary = self; let mut is_first_word = true; @@ -104,12 +104,12 @@ impl Dictionary { } match definition { - Definition::Phrase { phrase, .. } => { + Definition::Body { body, .. } => { if words.next().is_some() { break; } - return Some(phrase); + return Some(body); } Definition::Dictionary { dictionary: next_dictionary, @@ -135,7 +135,7 @@ impl Dictionary { } } -static PRELUDE: [(&Word, &[Expression]); 63] = [ +static PRELUDE: [(&Word, &[Expression]); 64] = [ (word_literal("neg"), &[Expression::Verb(Verb(builtin::neg))]), ( word_literal("incr"), @@ -150,12 +150,12 @@ static PRELUDE: [(&Word, &[Expression]); 63] = [ (word_literal("mul"), &[Expression::Verb(Verb(builtin::mul))]), (word_literal("div"), &[Expression::Verb(Verb(builtin::div))]), (word_literal("rem"), &[Expression::Verb(Verb(builtin::rem))]), - (word_literal("eq"), &[Expression::Verb(Verb(builtin::eq))]), - (word_literal("ne"), &[Expression::Verb(Verb(builtin::ne))]), - (word_literal("gt"), &[Expression::Verb(Verb(builtin::gt))]), - (word_literal("ge"), &[Expression::Verb(Verb(builtin::ge))]), - (word_literal("lt"), &[Expression::Verb(Verb(builtin::lt))]), - (word_literal("le"), &[Expression::Verb(Verb(builtin::le))]), + (word_literal("eq?"), &[Expression::Verb(Verb(builtin::eq))]), + (word_literal("ne?"), &[Expression::Verb(Verb(builtin::ne))]), + (word_literal("gt?"), &[Expression::Verb(Verb(builtin::gt))]), + (word_literal("ge?"), &[Expression::Verb(Verb(builtin::ge))]), + (word_literal("lt?"), &[Expression::Verb(Verb(builtin::lt))]), + (word_literal("le?"), &[Expression::Verb(Verb(builtin::le))]), ( word_literal("positive?"), &[Expression::Verb(Verb(builtin::positive))], @@ -174,7 +174,7 @@ static PRELUDE: [(&Word, &[Expression]); 63] = [ &[Expression::Decimal(Decimal::INFINITY)], ), ( - word_literal("-inf"), + word_literal("neg-inf"), &[Expression::Decimal(Decimal::NEG_INFINITY)], ), ( @@ -298,6 +298,10 @@ static PRELUDE: [(&Word, &[Expression]); 63] = [ word_literal("binrec"), &[Expression::Verb(Verb(builtin::binrec))], ), + ( + word_literal("bind"), + &[Expression::Verb(Verb(builtin::bind))], + ), ]; const fn word_literal(literal: &str) -> &Word { diff --git a/rat/src/grammar.pest b/rat/src/grammar.pest index 7b4812c..9f14771 100644 --- a/rat/src/grammar.pest +++ b/rat/src/grammar.pest @@ -5,33 +5,38 @@ */ Program = _{ - SOI ~ (Definition | Phrase)* ~ EOI + SOI ~ (Statement | Expression)* ~ EOI } -Definition = { - (Division | Colon) ~ Word ~ ((At ~ Locution) | (LeftArrow ~ Phrase)) ~ Semicolon +Statement = { + (Define | Import) } -Phrase = { - (Locution | Expression)+ +Define = { + // equal sign is optional for backward compatibility with forth + ":" ~ Export? ~ Word ~ "="? ~ Expression+ ~ ";" +} + +Import = { + ":" ~ Export? ~ Word ~ "@" ~ Identifier ~ ";" +} + +Export = @{ + "^" | "↑" } Word = @{ - // TODO: this must always be kept in sync with `Word` - ( ("-" | '0'..'9' | "_")* - ~ ('A'..'Z' | 'a'..'z') - ~ ("-" | '0'..'9' | 'A'..'Z' | "_" | 'a'..'z')* - ~ ("!" | "?")? - ) + ASCII_ALPHA ~ (ASCII_ALPHANUMERIC | "-" | "_")* ~ ("!" | "?")? } -Locution = @{ - // TODO: this must always be kept in sync with `Locution` +Identifier = @{ Word ~ ("\\" ~ Word)* } Expression = { (Boolean | Decimal | Integer | Quote | String | Symbol) + | /* actually not part of expression */ + Identifier } Boolean = @{ @@ -39,7 +44,7 @@ Boolean = @{ } Decimal = @{ - ("+" | "-")? ~ "∞" | "0.NaN" | (((ASCII_NONZERO_DIGIT ~ ASCII_DIGIT*) | "0") ~ ((^"e" ~ ("+" | "-") ~ ASCII_DIGIT+) | "." ~ ASCII_DIGIT* ~ (^"e" ~ ("+" | "-") ~ ASCII_DIGIT+) | "." ~ ASCII_DIGIT+)) + ("+" | "-")? ~ ("∞" | "0.NaN" | (((ASCII_NONZERO_DIGIT ~ ASCII_DIGIT*) | "0") ~ ((^"e" ~ ("+" | "-") ~ ASCII_DIGIT+) | "." ~ ASCII_DIGIT* ~ (^"e" ~ ("+" | "-") ~ ASCII_DIGIT+) | "." ~ ASCII_DIGIT+))) } Integer = @{ @@ -47,59 +52,19 @@ Integer = @{ } Quote = { - LeftSquareBracket ~ Phrase? ~ RightSquareBracket + "[" ~ Expression* ~ "]" } String = ${ - "\"" ~ StringUnicodeScalarValue* ~ "\"" + "\"" ~ UnicodeScalarValue* ~ "\"" } -StringUnicodeScalarValue = @{ +UnicodeScalarValue = @{ (!("\"" | "\\" | NEWLINE) ~ ANY | "\\" ~ ("\"" | "'" | "\\" | "n" | "r" | "t" | ("u{" ~ ASCII_HEX_DIGIT{1, 4} ~ "}"))) } Symbol = ${ - "'" ~ SymbolUnicodeScalarValue* ~ "'" -} - -SymbolUnicodeScalarValue = @{ - (!("'" | "\\" | NEWLINE) ~ ANY | "\\" ~ ("\"" | "'" | "\\" | "n" | "r" | "t" | ("u{" ~ ASCII_HEX_DIGIT{1, 4} ~ "}"))) -} - -At = @{ - "@" -} - -Colon = @{ - ":" -} - -Comma = @{ - "," -} - -Division = @{ - "÷" -} - -Equal = @{ - "=" -} - -LeftArrow = @{ - "←" -} - -Semicolon = @{ - ";" -} - -LeftSquareBracket = @{ - "[" -} - -RightSquareBracket = @{ - "]" + "$" ~ (Identifier | String) } WHITESPACE = _{ NEWLINE | "\t" | " " } diff --git a/rat/src/locution.rs b/rat/src/identifier.rs similarity index 65% rename from rat/src/locution.rs rename to rat/src/identifier.rs index ba417df..8be6de4 100644 --- a/rat/src/locution.rs +++ b/rat/src/identifier.rs @@ -14,26 +14,26 @@ use crate::word::Word; #[derive(PartialEq, Eq, PartialOrd, Ord, Hash)] #[repr(transparent)] -pub struct Locution(str); +pub struct Identifier(str); -impl ToOwned for Locution { - type Owned = OwnedLocution; +impl ToOwned for Identifier { + type Owned = OwnedIdentifier; fn to_owned(&self) -> Self::Owned { let Self(inner) = self; - OwnedLocution { + OwnedIdentifier { inner: inner.into(), } } } -impl Locution { +impl Identifier { /// Whitespaces are not allowed in `literal`. // TODO: this must always be kept in sync with `grammar.pest` - pub const fn try_from_literal(literal: &str) -> Result<&Self, InvalidLocutionLiteral> { + pub const fn try_from_literal(literal: &str) -> Result<&Self, InvalidIdentifierLiteral> { let bytes = literal.as_bytes(); if bytes.is_empty() { - return Err(InvalidLocutionLiteral); + return Err(InvalidIdentifierLiteral); } let mut start = 0; @@ -43,7 +43,7 @@ impl Locution { if b'\\' == c { if !Word::is_valid(bytes, start, end) { - return Err(InvalidLocutionLiteral); + return Err(InvalidIdentifierLiteral); } start = end + 1; @@ -53,13 +53,13 @@ impl Locution { } if !Word::is_valid(bytes, start, end) { - return Err(InvalidLocutionLiteral); + return Err(InvalidIdentifierLiteral); } - let locution = literal as *const str as *const Self; - // Safety: `Locution` is a `repr(transparent)` wrapper around `str` + let identifier = literal as *const str as *const Self; + // Safety: `Identifier` is a `repr(transparent)` wrapper around `str` // have a look at: https://stackoverflow.com/a/72106272 - Ok(unsafe { &*locution }) + Ok(unsafe { &*identifier }) } #[inline] @@ -74,65 +74,65 @@ impl Locution { } } -impl Display for Locution { +impl Display for Identifier { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{}", self.as_str()) } } -impl Debug for Locution { +impl Debug for Identifier { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{:?}", self.as_str()) } } #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct OwnedLocution { +pub struct OwnedIdentifier { inner: Arc, } -impl From<&Locution> for OwnedLocution { - fn from(locution: &Locution) -> Self { - locution.to_owned() +impl From<&Identifier> for OwnedIdentifier { + fn from(identifier: &Identifier) -> Self { + identifier.to_owned() } } -impl Deref for OwnedLocution { - type Target = Locution; +impl Deref for OwnedIdentifier { + type Target = Identifier; fn deref(&self) -> &Self::Target { self.borrow() } } -impl Borrow for OwnedLocution { - fn borrow(&self) -> &Locution { - let locution = self.inner.as_ref() as *const str as *const Locution; - // Safety: `Locution` is a `repr(transparent)` wrapper around `str` +impl Borrow for OwnedIdentifier { + fn borrow(&self) -> &Identifier { + let identifier = self.inner.as_ref() as *const str as *const Identifier; + // Safety: `Identifier` is a `repr(transparent)` wrapper around `str` // have a look at: https://stackoverflow.com/a/72106272 - unsafe { &*locution } + unsafe { &*identifier } } } -impl Display for OwnedLocution { +impl Display for OwnedIdentifier { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{}", self.as_str()) } } -impl Debug for OwnedLocution { +impl Debug for OwnedIdentifier { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{:?}", self.as_str()) } } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct InvalidLocutionLiteral; +pub struct InvalidIdentifierLiteral; -impl Display for InvalidLocutionLiteral { +impl Display for InvalidIdentifierLiteral { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { Debug::fmt(self, f) } } -impl Error for InvalidLocutionLiteral {} +impl Error for InvalidIdentifierLiteral {} diff --git a/rat/src/lib.rs b/rat/src/lib.rs index c875533..933ce05 100644 --- a/rat/src/lib.rs +++ b/rat/src/lib.rs @@ -24,7 +24,7 @@ pub mod dictionary; pub mod error; pub mod evaluate; pub mod evaluator; -pub mod locution; +pub mod identifier; pub mod parser; pub mod word; diff --git a/rat/src/parser.rs b/rat/src/parser.rs index 38aabcb..8a15b8e 100644 --- a/rat/src/parser.rs +++ b/rat/src/parser.rs @@ -19,8 +19,8 @@ use crate::boolean::Boolean; use crate::decimal::Decimal; use crate::dictionary::{Definition, Dictionary, Visibility}; use crate::expression::Expression; +use crate::identifier::{Identifier, OwnedIdentifier}; use crate::integer::Integer; -use crate::locution::{Locution, OwnedLocution}; use crate::quote::Quote; use crate::string::String; use crate::symbol::Symbol; @@ -29,7 +29,7 @@ use crate::word::{OwnedWord, Word}; #[derive(Debug, Default)] pub struct Parser { dictionary: Dictionary, - cache: HashMap>, + cache: HashMap>, } impl From for Parser { @@ -63,11 +63,8 @@ impl Parser { for pair in pairs { match pair.as_rule() { - Rule::Definition => parse_definition(self, origin, pair)?, - Rule::Phrase => { - let phrase = parse_phrase(self, origin, pair)?; - program.extend(phrase.into_iter()); - } + Rule::Statement => parse_statement(self, origin, pair)?, + Rule::Expression => parse_expressions(self, origin, pair, &mut program)?, Rule::EOI => break, rule => unreachable!("unexpected rule: `{rule:?}`"), } @@ -79,10 +76,10 @@ impl Parser { fn import( &mut self, word: &Word, - locution: &Locution, + identifier: &Identifier, visibility: Visibility, ) -> Result<(), ImportError> { - if let Some(dictionary) = self.cache.get(locution) { + if let Some(dictionary) = self.cache.get(identifier) { self.dictionary.define( word.to_owned(), Definition::Dictionary { @@ -94,21 +91,21 @@ impl Parser { return Ok(()); } - let mut words = locution.words(); + let mut words = identifier.words(); - let mut path = if locution.as_str().starts_with("rat\\") { + let mut path = if identifier.as_str().starts_with("rat\\") { words.next(); crate::home_dir().join("lib") } else { env::current_dir() - .map_err(|error| ImportError::new(format!("`{}` {}", locution, error)))? + .map_err(|error| ImportError::new(format!("`{}` {}", identifier, error)))? }; for word in words { if !path.is_dir() { return Err(ImportError::new(format!( "`{}` {} is not a directory", - locution, + identifier, path.display() ))); } @@ -121,25 +118,25 @@ impl Parser { if !path.is_file() { return Err(ImportError::new(format!( "`{}` {} is not a regular file", - locution, + identifier, path.display() ))); } let source = fs::read_to_string(&path) - .map_err(|e| ImportError::new(format!("`{}` {} {}", locution, path.display(), e)))?; + .map_err(|e| ImportError::new(format!("`{}` {} {}", identifier, path.display(), e)))?; let mut parser = Parser::with_prelude(); parser .parse(Origin::Path(path.as_path()), &source) - .map_err(|e| ImportError::new(format!("`{}`\n{}", locution, e)))?; + .map_err(|e| ImportError::new(format!("`{}`\n{}", identifier, e)))?; parser.dictionary.retain(|_, d| d.is_extern()); let dictionary = Arc::new(parser.dictionary); - self.cache.insert(locution.to_owned(), dictionary.clone()); + self.cache.insert(identifier.to_owned(), dictionary.clone()); self.dictionary.define( word.to_owned(), Definition::Dictionary { @@ -188,16 +185,17 @@ impl FromStr for OwnedWord { } } -impl FromStr for OwnedLocution { +impl FromStr for OwnedIdentifier { type Err = ParseError; fn from_str(s: &str) -> Result { check_token_boundary(s)?; - let mut pairs = Grammar::parse(Rule::Locution, s).map_err(with_origin(Origin::Unknown))?; + let mut pairs = + Grammar::parse(Rule::Identifier, s).map_err(with_origin(Origin::Unknown))?; assert_eq!(pairs.len(), 1); - parse_locution(Origin::Unknown, pairs.next().unwrap()).map(ToOwned::to_owned) + parse_identifier(Origin::Unknown, pairs.next().unwrap()).map(ToOwned::to_owned) } } @@ -358,42 +356,63 @@ fn parse_error(origin: Origin, span: PestSpan, message: impl Display) -> ParseEr .into() } -fn parse_definition(parser: &mut Parser, origin: Origin, pair: PestPair) -> Result<(), ParseError> { - assert_eq!(pair.as_rule(), Rule::Definition); - let span = pair.as_span(); - let mut pairs = pair.into_inner(); +fn parse_statement(parser: &mut Parser, origin: Origin, pair: PestPair) -> Result<(), ParseError> { + assert_eq!(pair.as_rule(), Rule::Statement); + let pair = pair.into_inner().next().unwrap(); - let visibility = match pairs.next().unwrap().as_rule() { - Rule::Division => Visibility::Extern, - Rule::Colon => Visibility::Intern, + match pair.as_rule() { + Rule::Define => parse_define(parser, origin, pair), + Rule::Import => parse_import(parser, origin, pair), rule => unreachable!("unexpected rule: `{rule:?}`"), + } +} + +fn parse_define(parser: &mut Parser, origin: Origin, pair: PestPair) -> Result<(), ParseError> { + assert_eq!(pair.as_rule(), Rule::Define); + let mut pairs = pair.into_inner().peekable(); + + let visibility = match pairs.peek().unwrap().as_rule() { + Rule::Export => { + pairs.next().unwrap(); + Visibility::Extern + } + _ => Visibility::Intern, }; let word = pairs.next().map(|p| parse_word(origin, p)).unwrap()?; + let mut expressions = Vec::new(); + pairs.try_for_each(|p| parse_expressions(parser, origin, p, &mut expressions))?; + + parser.dictionary.define( + word.to_owned(), + Definition::Body { + body: expressions.into(), + visibility, + }, + ); - match pairs.next().unwrap().as_rule() { - Rule::At => { - let locution = parse_locution(origin, pairs.next().unwrap())?; + Ok(()) +} - parser - .import(word, locution, visibility) - .map_err(|e| parse_error(origin, span, e)) +fn parse_import(parser: &mut Parser, origin: Origin, pair: PestPair) -> Result<(), ParseError> { + assert_eq!(pair.as_rule(), Rule::Import); + let span = pair.as_span(); + let mut pairs = pair.into_inner().peekable(); + + let visibility = match pairs.peek().unwrap().as_rule() { + Rule::Export => { + pairs.next().unwrap(); + Visibility::Extern } - Rule::LeftArrow => { - let phrase = parse_phrase(parser, origin, pairs.next().unwrap())?; + _ => Visibility::Intern, + }; - parser.dictionary.define( - word.to_owned(), - Definition::Phrase { - phrase: phrase.into(), - visibility, - }, - ); + let word = pairs.next().map(|p| parse_word(origin, p)).unwrap()?; + let identifier = parse_identifier(origin, pairs.next().unwrap())?; - Ok(()) - } - rule => unreachable!("unexpected rule: `{rule:?}`"), - } + parser + .import(word, identifier, visibility) + .map_err(|e| parse_error(origin, span, e)) } fn parse_word<'a>(origin: Origin, pair: PestPair<'a>) -> Result<&'a Word, ParseError> { @@ -401,58 +420,38 @@ fn parse_word<'a>(origin: Origin, pair: PestPair<'a>) -> Result<&'a Word, ParseE Word::try_from_literal(pair.as_str()).map_err(|e| parse_error(origin, pair.as_span(), e)) } -fn parse_locution<'a>(origin: Origin, pair: PestPair<'a>) -> Result<&'a Locution, ParseError> { - assert_eq!(pair.as_rule(), Rule::Locution); - Locution::try_from_literal(pair.as_str()).map_err(|e| parse_error(origin, pair.as_span(), e)) +fn parse_identifier<'a>(origin: Origin, pair: PestPair<'a>) -> Result<&'a Identifier, ParseError> { + assert_eq!(pair.as_rule(), Rule::Identifier); + Identifier::try_from_literal(pair.as_str()).map_err(|e| parse_error(origin, pair.as_span(), e)) } -fn parse_expression( +fn parse_expressions( parser: &mut Parser, origin: Origin, pair: PestPair, -) -> Result { + buf: &mut Vec, +) -> Result<(), ParseError> { assert_eq!(pair.as_rule(), Rule::Expression); let pair = pair.into_inner().next().unwrap(); match pair.as_rule() { - Rule::Boolean => parse_boolean(origin, pair).map(Expression::Boolean), - Rule::Decimal => parse_decimal(origin, pair).map(Expression::Decimal), - Rule::Integer => parse_integer(origin, pair).map(Expression::Integer), - Rule::Quote => parse_quote(parser, origin, pair).map(Expression::Quote), - Rule::String => parse_string(origin, pair).map(Expression::String), - Rule::Symbol => parse_symbol(origin, pair).map(Expression::Symbol), - rule => unreachable!("unexpected rule: `{rule:?}`"), - } -} - -fn parse_phrase( - parser: &mut Parser, - origin: Origin, - pair: PestPair, -) -> Result, ParseError> { - assert_eq!(pair.as_rule(), Rule::Phrase); - let mut phrase = Vec::new(); - - for pair in pair.into_inner() { - match pair.as_rule() { - Rule::Locution => { - let span = pair.as_span(); - let locution = parse_locution(origin, pair)?; - parser - .dictionary - .lookup(locution) - .map(|expressions| phrase.extend_from_slice(expressions)) - .ok_or_else(|| parse_error(origin, span, undefined_locution(locution)))?; - } - Rule::Expression => { - let expression = parse_expression(parser, origin, pair)?; - phrase.push(expression); - } - rule => unreachable!("unexpected rule: `{rule:?}`"), + Rule::Boolean => parse_boolean(origin, pair).map(|e| buf.push(Expression::Boolean(e))), + Rule::Decimal => parse_decimal(origin, pair).map(|e| buf.push(Expression::Decimal(e))), + Rule::Integer => parse_integer(origin, pair).map(|e| buf.push(Expression::Integer(e))), + Rule::Quote => parse_quote(parser, origin, pair).map(|e| buf.push(Expression::Quote(e))), + Rule::String => parse_string(origin, pair).map(|e| buf.push(Expression::String(e))), + Rule::Symbol => parse_symbol(origin, pair).map(|e| buf.push(Expression::Symbol(e))), + Rule::Identifier => { + let span = pair.as_span(); + let identifier = parse_identifier(origin, pair)?; + parser + .dictionary + .lookup(identifier) + .map(|expressions| buf.extend_from_slice(expressions)) + .ok_or_else(|| parse_error(origin, span, undefined_identifier(identifier))) } + rule => unreachable!("unexpected rule: `{rule:?}`"), } - - Ok(phrase) } fn parse_boolean(_: Origin, pair: PestPair) -> Result { @@ -488,21 +487,11 @@ fn parse_integer(origin: Origin, pair: PestPair) -> Result fn parse_quote(parser: &mut Parser, origin: Origin, pair: PestPair) -> Result { assert_eq!(pair.as_rule(), Rule::Quote); - let mut quote = Quote::new(); - - for pair in pair.into_inner() { - match pair.as_rule() { - Rule::Phrase => { - let phrase = parse_phrase(parser, origin, pair)?; - quote.extend(phrase.into_iter()); - } - Rule::LeftSquareBracket => (), - Rule::RightSquareBracket => break, - rule => unreachable!("unexpected rule: `{rule:?}`"), - } - } + let mut expressions = Vec::new(); + pair.into_inner() + .try_for_each(|pair| parse_expressions(parser, origin, pair, &mut expressions))?; - Ok(quote) + Ok(expressions.into_iter().collect()) } fn parse_string(origin: Origin, pair: PestPair) -> Result { @@ -514,16 +503,19 @@ fn parse_string(origin: Origin, pair: PestPair) -> Result { fn parse_symbol(origin: Origin, pair: PestPair) -> Result { assert_eq!(pair.as_rule(), Rule::Symbol); - pair.into_inner() - .map(|p| parse_unicode_scalar_value(origin, p)) - .collect() + let pair = pair.into_inner().next().unwrap(); + match pair.as_rule() { + Rule::Identifier => Ok(pair.as_str().chars().collect()), + Rule::String => pair + .into_inner() + .map(|p| parse_unicode_scalar_value(origin, p)) + .collect(), + rule => unreachable!("unexpected rule: `{rule:?}`"), + } } fn parse_unicode_scalar_value(origin: Origin, pair: PestPair) -> Result { - assert!( - Rule::StringUnicodeScalarValue == pair.as_rule() - || Rule::SymbolUnicodeScalarValue == pair.as_rule() - ); + assert_eq!(pair.as_rule(), Rule::UnicodeScalarValue); match pair.as_str() { "\\n" => Ok('\n'), @@ -572,8 +564,8 @@ fn check_token_boundary(s: &str) -> Result<(), ParseError> { Ok(()) } -fn undefined_locution(locution: &Locution) -> StdString { - format!("undefined locution: `{locution}`") +fn undefined_identifier(identifier: &Identifier) -> StdString { + format!("undefined identifier: `{identifier}`") } #[cfg(test)] @@ -583,8 +575,8 @@ mod test { use crate::boolean::Boolean; use crate::decimal::Decimal; use crate::expression::Expression; + use crate::identifier::{Identifier, OwnedIdentifier}; use crate::integer::Integer; - use crate::locution::{Locution, OwnedLocution}; use crate::quote::Quote; use crate::string::String; use crate::symbol::Symbol; @@ -601,14 +593,14 @@ mod test { } #[test] - fn parse_locution() { - assert!(Locution::try_from_literal(" math\\abs").is_err()); - assert!(Locution::try_from_literal("math\\abs ").is_err()); - assert!(Locution::try_from_literal("math\\").is_err()); - assert!(Locution::try_from_literal("\\abs").is_err()); + fn parse_identifier() { + assert!(Identifier::try_from_literal(" math\\abs").is_err()); + assert!(Identifier::try_from_literal("math\\abs ").is_err()); + assert!(Identifier::try_from_literal("math\\").is_err()); + assert!(Identifier::try_from_literal("\\abs").is_err()); assert_eq!( - Locution::try_from_literal("math\\abs").unwrap(), - "math\\abs".parse::().unwrap().borrow() + Identifier::try_from_literal("math\\abs").unwrap(), + "math\\abs".parse::().unwrap().borrow() ); } @@ -639,10 +631,10 @@ mod test { #[test] fn parse_quote() { - assert!(" [⊥ ⊤ 42 3.14 'hello' \"world\" []]" + assert!(" [⊥ ⊤ 42 3.14 $hello \"world\" []]" .parse::() .is_err()); - assert!("[⊥ ⊤ 42 3.14 'hello' \"world\" []] " + assert!("[⊥ ⊤ 42 3.14 $hello \"world\" []] " .parse::() .is_err()); assert_eq!( @@ -657,7 +649,7 @@ mod test { ] .into_iter() .collect::(), - "[⊥ ⊤ 42 3.14 'hello' \"world\" []]" + "[⊥ ⊤ 42 3.14 $hello \"world\" []]" .parse::() .unwrap() ); @@ -682,14 +674,22 @@ mod test { #[test] fn parse_symbol() { - assert!(" 'hello'".parse::().is_err()); - assert!("'hello' ".parse::().is_err()); + assert!(" $hello".parse::().is_err()); + assert!("$hello ".parse::().is_err()); + assert!(" $\"hello\"".parse::().is_err()); + assert!("$\"hello\" ".parse::().is_err()); assert_eq!( Symbol::from_iter("hello".chars()), - "'hello'".parse().unwrap() + "$hello".parse().unwrap() ); - assert_eq!(Symbol::from_iter("a\"a".chars()), "'a\"a'".parse().unwrap()); - assert_eq!(Symbol::from_iter("a'a".chars()), "'a\\'a'".parse().unwrap()); + assert_eq!( + Symbol::from_iter("a\tstring".chars()), + "$\"a\tstring\"".parse().unwrap() + ); + assert_eq!( + Symbol::from_iter("a\tstring".chars()), + r#"$"a\tstring""#.parse().unwrap() + ); } } diff --git a/rat/src/quote.rs b/rat/src/quote.rs index 1e3a792..8319b62 100644 --- a/rat/src/quote.rs +++ b/rat/src/quote.rs @@ -31,6 +31,14 @@ impl FromIterator for Quote { } } +impl From> for Quote { + fn from(value: Vec) -> Self { + Self { + inner: Some(Arc::new(value)), + } + } +} + impl From<[Expression; N]> for Quote { fn from(value: [Expression; N]) -> Self { Self::from_iter(value) diff --git a/rat/src/symbol.rs b/rat/src/symbol.rs index 0ff5695..16b94ce 100644 --- a/rat/src/symbol.rs +++ b/rat/src/symbol.rs @@ -72,7 +72,7 @@ impl Display for Symbol { impl Debug for Symbol { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let Self(s) = self; - write!(f, "'{}'", s) + write!(f, "$\"{}\"", s) } } diff --git a/rat/src/vocabulary.rs b/rat/src/vocabulary.rs deleted file mode 100644 index 9909309..0000000 --- a/rat/src/vocabulary.rs +++ /dev/null @@ -1,308 +0,0 @@ -/* - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - */ - -use std::borrow::Borrow; -use std::collections::HashMap; -use std::fmt::Debug; -use std::hash::Hash; -use std::sync::Arc; - -use crate::boolean::Boolean; -use crate::builtin; -use crate::decimal::Decimal; -use crate::expression::Expression; -use crate::locution::Locution; -use crate::verb::Verb; -use crate::word::{OwnedWord, Word}; - -#[derive(Debug)] -pub enum Definition { - Phrase { - phrase: Arc<[Expression]>, - visibility: Visibility, - }, - Vocabulary { - vocabulary: Arc, - visibility: Visibility, - }, -} - -impl Definition { - pub fn is_intern(&self) -> bool { - Visibility::Intern - == match self { - Definition::Phrase { visibility, .. } => *visibility, - Definition::Vocabulary { visibility, .. } => *visibility, - } - } - - pub fn is_extern(&self) -> bool { - !self.is_intern() - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub enum Visibility { - Extern, - Intern, -} - -#[derive(Debug, Default)] -pub struct Vocabulary { - definitions: HashMap, -} - -impl Vocabulary { - pub fn new() -> Self { - Self { - definitions: HashMap::new(), - } - } - - pub fn with_prelude() -> Self { - Self { - definitions: PRELUDE - .into_iter() - .map(|(word, phrase)| { - ( - word.into(), - Definition::Phrase { - phrase: phrase.into(), - visibility: Visibility::Intern, - }, - ) - }) - .collect(), - } - } - - pub fn define(&mut self, word: OwnedWord, definition: Definition) -> Option { - self.definitions.insert(word, definition) - } - - pub fn get(&self, word: &W) -> Option<&Definition> - where - OwnedWord: Borrow, - W: ?Sized + Eq + Hash, - { - self.definitions.get(word) - } - - pub fn lookup(&self, locution: &Locution) -> Option<&[Expression]> { - let mut words = locution.words(); - let mut vocabulary = self; - let mut is_first_word = true; - - while let Some(word) = words.next() { - let definition = vocabulary.get(word)?; - - if !is_first_word && definition.is_intern() { - break; - } - - match definition { - Definition::Phrase { phrase, .. } => { - if words.next().is_some() { - break; - } - - return Some(phrase); - } - Definition::Vocabulary { - vocabulary: next_vocabulary, - .. - } => vocabulary = next_vocabulary, - } - - is_first_word = false; - } - - None - } - - pub fn definitions(&self) -> impl Iterator { - self.definitions.iter() - } - - pub fn retain(&mut self, mut f: F) - where - F: FnMut(&Word, &Definition) -> bool, - { - self.definitions.retain(|w, d| f(w, d)); - } -} - -static PRELUDE: [(&Word, &[Expression]); 63] = [ - (word_literal("neg"), &[Expression::Verb(Verb(builtin::neg))]), - ( - word_literal("incr"), - &[Expression::Verb(Verb(builtin::incr))], - ), - ( - word_literal("decr"), - &[Expression::Verb(Verb(builtin::decr))], - ), - (word_literal("add"), &[Expression::Verb(Verb(builtin::add))]), - (word_literal("sub"), &[Expression::Verb(Verb(builtin::sub))]), - (word_literal("mul"), &[Expression::Verb(Verb(builtin::mul))]), - (word_literal("div"), &[Expression::Verb(Verb(builtin::div))]), - (word_literal("rem"), &[Expression::Verb(Verb(builtin::rem))]), - (word_literal("eq"), &[Expression::Verb(Verb(builtin::eq))]), - (word_literal("ne"), &[Expression::Verb(Verb(builtin::ne))]), - (word_literal("gt"), &[Expression::Verb(Verb(builtin::gt))]), - (word_literal("ge"), &[Expression::Verb(Verb(builtin::ge))]), - (word_literal("lt"), &[Expression::Verb(Verb(builtin::lt))]), - (word_literal("le"), &[Expression::Verb(Verb(builtin::le))]), - ( - word_literal("positive?"), - &[Expression::Verb(Verb(builtin::positive))], - ), - ( - word_literal("zero?"), - &[Expression::Verb(Verb(builtin::zero))], - ), - ( - word_literal("negative?"), - &[Expression::Verb(Verb(builtin::negative))], - ), - (word_literal("nan"), &[Expression::Decimal(Decimal::NAN)]), - ( - word_literal("inf"), - &[Expression::Decimal(Decimal::INFINITY)], - ), - ( - word_literal("-inf"), - &[Expression::Decimal(Decimal::NEG_INFINITY)], - ), - ( - word_literal("false"), - &[Expression::Boolean(Boolean(false))], - ), - (word_literal("true"), &[Expression::Boolean(Boolean(true))]), - (word_literal("not"), &[Expression::Verb(Verb(builtin::not))]), - (word_literal("and"), &[Expression::Verb(Verb(builtin::and))]), - (word_literal("or"), &[Expression::Verb(Verb(builtin::or))]), - ( - word_literal("bit-not"), - &[Expression::Verb(Verb(builtin::bitwise_not))], - ), - ( - word_literal("bit-and"), - &[Expression::Verb(Verb(builtin::bitwise_and))], - ), - ( - word_literal("bit-xor"), - &[Expression::Verb(Verb(builtin::bitwise_xor))], - ), - ( - word_literal("bit-or"), - &[Expression::Verb(Verb(builtin::bitwise_or))], - ), - (word_literal("shl"), &[Expression::Verb(Verb(builtin::shl))]), - (word_literal("shr"), &[Expression::Verb(Verb(builtin::shr))]), - ( - word_literal("ushr"), - &[Expression::Verb(Verb(builtin::ushr))], - ), - (word_literal("cat"), &[Expression::Verb(Verb(builtin::cat))]), - ( - word_literal("quote"), - &[Expression::Verb(Verb(builtin::quote))], - ), - ( - word_literal("unquote"), - &[Expression::Verb(Verb(builtin::unquote))], - ), - ( - word_literal("eval"), - &[Expression::Verb(Verb(builtin::eval))], - ), - (word_literal("i"), &[Expression::Verb(Verb(builtin::i))]), - (word_literal("x"), &[Expression::Verb(Verb(builtin::x))]), - (word_literal("dip"), &[Expression::Verb(Verb(builtin::dip))]), - ( - word_literal("unary2"), - &[Expression::Verb(Verb(builtin::unary2))], - ), - (word_literal("if"), &[Expression::Verb(Verb(builtin::r#if))]), - ( - word_literal("else"), - &[Expression::Verb(Verb(builtin::r#else))], - ), - ( - word_literal("if-else"), - &[Expression::Verb(Verb(builtin::if_else))], - ), - ( - word_literal("raise"), - &[Expression::Verb(Verb(builtin::raise))], - ), - ( - word_literal("try"), - &[Expression::Verb(Verb(builtin::r#try))], - ), - ( - word_literal("first"), - &[Expression::Verb(Verb(builtin::first))], - ), - ( - word_literal("last"), - &[Expression::Verb(Verb(builtin::last))], - ), - ( - word_literal("prefix"), - &[Expression::Verb(Verb(builtin::prefix))], - ), - ( - word_literal("suffix"), - &[Expression::Verb(Verb(builtin::suffix))], - ), - (word_literal("at"), &[Expression::Verb(Verb(builtin::at))]), - ( - word_literal("split"), - &[Expression::Verb(Verb(builtin::split))], - ), - (word_literal("len"), &[Expression::Verb(Verb(builtin::len))]), - ( - word_literal("swap"), - &[Expression::Verb(Verb(builtin::swap))], - ), - ( - word_literal("rollup"), - &[Expression::Verb(Verb(builtin::rollup))], - ), - ( - word_literal("rolldown"), - &[Expression::Verb(Verb(builtin::rolldown))], - ), - ( - word_literal("rotate"), - &[Expression::Verb(Verb(builtin::rotate))], - ), - (word_literal("pop"), &[Expression::Verb(Verb(builtin::pop))]), - (word_literal("dup"), &[Expression::Verb(Verb(builtin::dup))]), - (word_literal("ask"), &[Expression::Verb(Verb(builtin::ask))]), - (word_literal("say"), &[Expression::Verb(Verb(builtin::say))]), - ( - word_literal("show"), - &[Expression::Verb(Verb(builtin::show))], - ), - ( - word_literal("linrec"), - &[Expression::Verb(Verb(builtin::linrec))], - ), - ( - word_literal("binrec"), - &[Expression::Verb(Verb(builtin::binrec))], - ), -]; - -const fn word_literal(literal: &str) -> &Word { - match Word::try_from_literal(literal) { - Ok(word) => word, - Err(_) => panic!("invalid word literal"), - } -} diff --git a/rat/src/word.rs b/rat/src/word.rs index 37b3e26..87f447e 100644 --- a/rat/src/word.rs +++ b/rat/src/word.rs @@ -25,36 +25,19 @@ impl ToOwned for Word { impl Word { pub(crate) const fn is_valid(bytes: &[u8], start: usize, end: usize) -> bool { - if !(start < end && start < bytes.len() && end <= bytes.len()) { + if !(start < end + && start < bytes.len() + && end <= bytes.len() + && bytes[start].is_ascii_alphabetic()) + { return false; } - let mut i = start; - - while i < end { - let c = bytes[i]; - - if !(c == b'-' || c.is_ascii_digit() || c == b'_') { - break; - } - - i += 1; - } - - while i < end { - let c = bytes[i]; - - if !c.is_ascii_alphabetic() { - break; - } - - i += 1; - } - + let mut i = start + 1; while i < end { let c = bytes[i]; - if !(c == b'-' || c.is_ascii_alphanumeric() || c == b'_') { + if !(c.is_ascii_alphanumeric() || c == b'-' || c == b'_') { break; } From 398ab4b89aac993ddee6f169da759b597d536b09 Mon Sep 17 00:00:00 2001 From: daddinuz Date: Tue, 15 Oct 2024 23:26:51 +0200 Subject: [PATCH 7/8] add test to ensure that word and grammar are aligned --- .cargo/config.toml | 2 ++ rat/src/lib.rs | 24 ++++++++++++++++++++++++ 2 files changed, 26 insertions(+) create mode 100644 .cargo/config.toml diff --git a/.cargo/config.toml b/.cargo/config.toml new file mode 100644 index 0000000..4768414 --- /dev/null +++ b/.cargo/config.toml @@ -0,0 +1,2 @@ +[env] +CARGO_WORKSPACE_DIR = { value = "", relative = true } diff --git a/rat/src/lib.rs b/rat/src/lib.rs index 933ce05..c1f61fd 100644 --- a/rat/src/lib.rs +++ b/rat/src/lib.rs @@ -60,6 +60,9 @@ mod test { use crate::symbol::Symbol; use crate::verb::Verb; + use std::path::Path; + use std::process::Command; + #[test] fn it_works1() { let mut evaluator = Evaluator::default(); @@ -153,4 +156,25 @@ mod test { ] ); } + + #[test] + fn word_and_grammar_are_aligned() { + let grammar_path = Path::new(env!("CARGO_WORKSPACE_DIR")).join("rat/src/grammar.pest"); + let word_path = Path::new(env!("CARGO_WORKSPACE_DIR")).join("rat/src/word.rs"); + let output = Command::new("md5sum") + .arg(&grammar_path) + .arg(&word_path) + .output() + .unwrap(); + + assert_eq!( + &output.stdout, + format!( + "4157267b6044a122719d246a9dcde1da {}\nab5aa40ceddd0bc08fbf445cd9fe054e {}\n", + grammar_path.display(), + word_path.display() + ) + .as_bytes() + ); + } } From 9b028296ea6fc890ba9303fd2ac6d93db6fcdb54 Mon Sep 17 00:00:00 2001 From: daddinuz Date: Tue, 15 Oct 2024 23:35:08 +0200 Subject: [PATCH 8/8] Create rust.yml --- .github/workflows/rust.yml | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 .github/workflows/rust.yml diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml new file mode 100644 index 0000000..8d2a520 --- /dev/null +++ b/.github/workflows/rust.yml @@ -0,0 +1,20 @@ +name: Rust + +on: + push: + branches: [ "main", "dev" ] + pull_request: + branches: [ "main", "dev" ] + +env: + CARGO_TERM_COLOR: always + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Build + run: cargo build --verbose + - name: Run tests + run: cargo test --verbose