summaryrefslogtreecommitdiff
path: root/src/eval
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2020-10-03 17:56:56 +0200
committerLaurenz <laurmaedje@gmail.com>2020-10-03 17:56:56 +0200
commit91d14d2a221f619738e4534c1b4266633ce5789d (patch)
treec10b288b9473153fede116204cc861c89dad71a1 /src/eval
parent95bae5725cf6495644e2593f8492f1cd0e5bd3c1 (diff)
Evaluate expressions 🧮
Diffstat (limited to 'src/eval')
-rw-r--r--src/eval/dict.rs86
-rw-r--r--src/eval/value.rs4
2 files changed, 68 insertions, 22 deletions
diff --git a/src/eval/dict.rs b/src/eval/dict.rs
index 7f4426ff..b0d5fb82 100644
--- a/src/eval/dict.rs
+++ b/src/eval/dict.rs
@@ -2,6 +2,7 @@
use std::collections::BTreeMap;
use std::fmt::{self, Debug, Display, Formatter};
+use std::iter::Extend;
use std::ops::Index;
use crate::syntax::{Span, Spanned};
@@ -117,9 +118,7 @@ impl<V> Dict<V> {
/// Iterator over all borrowed keys and values.
pub fn iter(&self) -> impl Iterator<Item = (RefKey, &V)> {
- self.nums()
- .map(|(&k, v)| (RefKey::Num(k), v))
- .chain(self.strs().map(|(k, v)| (RefKey::Str(k), v)))
+ self.into_iter()
}
/// Iterate over all values in the dictionary.
@@ -137,14 +136,6 @@ impl<V> Dict<V> {
self.strs.iter()
}
- /// Move into an owned iterator over owned keys and values.
- pub fn into_iter(self) -> impl Iterator<Item = (DictKey, V)> {
- self.nums
- .into_iter()
- .map(|(k, v)| (DictKey::Num(k), v))
- .chain(self.strs.into_iter().map(|(k, v)| (DictKey::Str(k), v)))
- }
-
/// Move into an owned iterator over all values in the dictionary.
pub fn into_values(self) -> impl Iterator<Item = V> {
self.nums
@@ -164,17 +155,6 @@ impl<V> Dict<V> {
}
}
-impl<'a, K, V> Index<K> for Dict<V>
-where
- K: Into<RefKey<'a>>,
-{
- type Output = V;
-
- fn index(&self, index: K) -> &Self::Output {
- self.get(index).expect("key not in dict")
- }
-}
-
impl<V> Default for Dict<V> {
fn default() -> Self {
Self::new()
@@ -189,6 +169,68 @@ impl<V: PartialEq> PartialEq for Dict<V> {
}
}
+impl<V> IntoIterator for Dict<V> {
+ type Item = (DictKey, V);
+ type IntoIter = std::iter::Chain<
+ std::iter::Map<
+ std::collections::btree_map::IntoIter<u64, V>,
+ fn((u64, V)) -> (DictKey, V),
+ >,
+ std::iter::Map<
+ std::collections::btree_map::IntoIter<String, V>,
+ fn((String, V)) -> (DictKey, V),
+ >,
+ >;
+
+ fn into_iter(self) -> Self::IntoIter {
+ let nums = self.nums.into_iter().map((|(k, v)| (DictKey::Num(k), v)) as _);
+ let strs = self.strs.into_iter().map((|(k, v)| (DictKey::Str(k), v)) as _);
+ nums.chain(strs)
+ }
+}
+
+impl<'a, V> IntoIterator for &'a Dict<V> {
+ type Item = (RefKey<'a>, &'a V);
+ type IntoIter = std::iter::Chain<
+ std::iter::Map<
+ std::collections::btree_map::Iter<'a, u64, V>,
+ fn((&'a u64, &'a V)) -> (RefKey<'a>, &'a V),
+ >,
+ std::iter::Map<
+ std::collections::btree_map::Iter<'a, String, V>,
+ fn((&'a String, &'a V)) -> (RefKey<'a>, &'a V),
+ >,
+ >;
+
+ fn into_iter(self) -> Self::IntoIter {
+ let strs = self.strs().map((|(k, v): (&'a String, _)| (RefKey::Str(k), v)) as _);
+ let nums = self.nums().map((|(k, v): (&u64, _)| (RefKey::Num(*k), v)) as _);
+ nums.chain(strs)
+ }
+}
+
+impl<V> Extend<(DictKey, V)> for Dict<V> {
+ fn extend<T>(&mut self, iter: T)
+ where
+ T: IntoIterator<Item = (DictKey, V)>,
+ {
+ for (key, value) in iter.into_iter() {
+ self.insert(key, value);
+ }
+ }
+}
+
+impl<'a, K, V> Index<K> for Dict<V>
+where
+ K: Into<RefKey<'a>>,
+{
+ type Output = V;
+
+ fn index(&self, index: K) -> &Self::Output {
+ self.get(index).expect("key not in dict")
+ }
+}
+
impl<V: Debug> Debug for Dict<V> {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
if self.is_empty() {
diff --git a/src/eval/value.rs b/src/eval/value.rs
index 51bc55ab..85ac2367 100644
--- a/src/eval/value.rs
+++ b/src/eval/value.rs
@@ -17,6 +17,8 @@ use crate::{DynFuture, Feedback, Pass};
/// A computational value.
#[derive(Clone, PartialEq)]
pub enum Value {
+ /// The result of invalid operations.
+ Error,
/// An identifier: `ident`.
Ident(Ident),
/// A boolean: `true, false`.
@@ -54,6 +56,7 @@ impl Value {
/// The natural-language name of this value for use in error messages.
pub fn name(&self) -> &'static str {
match self {
+ Self::Error => "error",
Self::Ident(_) => "identifier",
Self::Bool(_) => "bool",
Self::Int(_) => "integer",
@@ -111,6 +114,7 @@ impl Spanned<Value> {
impl Debug for Value {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self {
+ Self::Error => f.pad("<error>"),
Self::Ident(i) => i.fmt(f),
Self::Bool(b) => b.fmt(f),
Self::Int(i) => i.fmt(f),