From aafd3c95cacd829b647cfab1533de5d4833b9a04 Mon Sep 17 00:00:00 2001 From: Laurenz Date: Thu, 1 Oct 2020 13:15:10 +0200 Subject: =?UTF-8?q?Rename=20table=20to=20dict=20=E2=9C=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/compute/dict.rs | 411 +++++++++++++++++++++++++++++++++++++++++++++++++ src/compute/mod.rs | 2 +- src/compute/table.rs | 411 ------------------------------------------------- src/compute/value.rs | 88 +++++------ src/library/align.rs | 2 +- src/library/boxed.rs | 2 +- src/library/color.rs | 2 +- src/library/font.rs | 19 ++- src/library/page.rs | 4 +- src/library/spacing.rs | 6 +- src/parse/mod.rs | 38 ++--- src/parse/tests.rs | 70 ++++----- src/syntax/mod.rs | 4 +- src/syntax/tree.rs | 34 ++-- 14 files changed, 549 insertions(+), 544 deletions(-) create mode 100644 src/compute/dict.rs delete mode 100644 src/compute/table.rs (limited to 'src') diff --git a/src/compute/dict.rs b/src/compute/dict.rs new file mode 100644 index 00000000..e4df0048 --- /dev/null +++ b/src/compute/dict.rs @@ -0,0 +1,411 @@ +//! A key-value map that can also model array-like structures. + +use std::collections::BTreeMap; +use std::fmt::{self, Debug, Display, Formatter}; +use std::ops::Index; + +use crate::syntax::{Span, Spanned}; + +/// A dictionary data structure, which maps from integers (`u64`) or strings to +/// a generic value type. +/// +/// The dictionary can be used to model arrays by assigning values to successive +/// indices from `0..n`. The `push` method offers special support for this +/// pattern. +#[derive(Clone)] +pub struct Dict { + nums: BTreeMap, + strs: BTreeMap, + lowest_free: u64, +} + +impl Dict { + /// Create a new empty dictionary. + pub fn new() -> Self { + Self { + nums: BTreeMap::new(), + strs: BTreeMap::new(), + lowest_free: 0, + } + } + + /// The total number of entries in the dictionary. + pub fn len(&self) -> usize { + self.nums.len() + self.strs.len() + } + + /// Whether the dictionary contains no entries. + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + /// The first number key-value pair (with lowest number). + pub fn first(&self) -> Option<(u64, &V)> { + self.nums.iter().next().map(|(&k, v)| (k, v)) + } + + /// The last number key-value pair (with highest number). + pub fn last(&self) -> Option<(u64, &V)> { + self.nums.iter().next_back().map(|(&k, v)| (k, v)) + } + + /// Get a reference to the value with the given key. + pub fn get<'a, K>(&self, key: K) -> Option<&V> + where + K: Into>, + { + match key.into() { + BorrowedKey::Num(num) => self.nums.get(&num), + BorrowedKey::Str(string) => self.strs.get(string), + } + } + + /// Borrow the value with the given key mutably. + pub fn get_mut<'a, K>(&mut self, key: K) -> Option<&mut V> + where + K: Into>, + { + match key.into() { + BorrowedKey::Num(num) => self.nums.get_mut(&num), + BorrowedKey::Str(string) => self.strs.get_mut(string), + } + } + + /// Insert a value into the dictionary. + pub fn insert(&mut self, key: K, value: V) + where + K: Into, + { + match key.into() { + OwnedKey::Num(num) => { + self.nums.insert(num, value); + if self.lowest_free == num { + self.lowest_free += 1; + } + } + OwnedKey::Str(string) => { + self.strs.insert(string, value); + } + } + } + + /// Remove the value with the given key from the dictionary. + pub fn remove<'a, K>(&mut self, key: K) -> Option + where + K: Into>, + { + match key.into() { + BorrowedKey::Num(num) => { + self.lowest_free = self.lowest_free.min(num); + self.nums.remove(&num) + } + BorrowedKey::Str(string) => self.strs.remove(string), + } + } + + /// Append a value to the dictionary. + /// + /// This will associate the `value` with the lowest free number key (zero if + /// there is no number key so far). + pub fn push(&mut self, value: V) { + while self.nums.contains_key(&self.lowest_free) { + self.lowest_free += 1; + } + self.nums.insert(self.lowest_free, value); + self.lowest_free += 1; + } + + /// Iterator over all borrowed keys and values. + pub fn iter(&self) -> impl Iterator { + self.nums() + .map(|(&k, v)| (BorrowedKey::Num(k), v)) + .chain(self.strs().map(|(k, v)| (BorrowedKey::Str(k), v))) + } + + /// Iterate over all values in the dictionary. + pub fn values(&self) -> impl Iterator { + self.nums().map(|(_, v)| v).chain(self.strs().map(|(_, v)| v)) + } + + /// Iterate over the number key-value pairs. + pub fn nums(&self) -> std::collections::btree_map::Iter { + self.nums.iter() + } + + /// Iterate over the string key-value pairs. + pub fn strs(&self) -> std::collections::btree_map::Iter { + self.strs.iter() + } + + /// Move into an owned iterator over owned keys and values. + pub fn into_iter(self) -> impl Iterator { + self.nums + .into_iter() + .map(|(k, v)| (OwnedKey::Num(k), v)) + .chain(self.strs.into_iter().map(|(k, v)| (OwnedKey::Str(k), v))) + } + + /// Move into an owned iterator over all values in the dictionary. + pub fn into_values(self) -> impl Iterator { + self.nums + .into_iter() + .map(|(_, v)| v) + .chain(self.strs.into_iter().map(|(_, v)| v)) + } + + /// Iterate over the number key-value pairs. + pub fn into_nums(self) -> std::collections::btree_map::IntoIter { + self.nums.into_iter() + } + + /// Iterate over the string key-value pairs. + pub fn into_strs(self) -> std::collections::btree_map::IntoIter { + self.strs.into_iter() + } +} + +impl<'a, K, V> Index for Dict +where + K: Into>, +{ + type Output = V; + + fn index(&self, index: K) -> &Self::Output { + self.get(index).expect("key not in dict") + } +} + +impl Default for Dict { + fn default() -> Self { + Self::new() + } +} + +impl Eq for Dict {} + +impl PartialEq for Dict { + fn eq(&self, other: &Self) -> bool { + self.iter().eq(other.iter()) + } +} + +impl Debug for Dict { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + if self.is_empty() { + return f.write_str("()"); + } + + let mut builder = f.debug_tuple(""); + + struct Entry<'a>(bool, &'a dyn Display, &'a dyn Debug); + impl<'a> Debug for Entry<'a> { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + if self.0 { + f.write_str("\"")?; + } + self.1.fmt(f)?; + if self.0 { + f.write_str("\"")?; + } + if f.alternate() { + f.write_str(" = ")?; + } else { + f.write_str("=")?; + } + self.2.fmt(f) + } + } + + for (key, value) in self.nums() { + builder.field(&Entry(false, &key, &value)); + } + + for (key, value) in self.strs() { + builder.field(&Entry(key.contains(' '), &key, &value)); + } + + builder.finish() + } +} + +/// The owned variant of a dictionary key. +#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd)] +pub enum OwnedKey { + Num(u64), + Str(String), +} + +impl From> for OwnedKey { + fn from(key: BorrowedKey<'_>) -> Self { + match key { + BorrowedKey::Num(num) => Self::Num(num), + BorrowedKey::Str(string) => Self::Str(string.to_string()), + } + } +} + +impl From for OwnedKey { + fn from(num: u64) -> Self { + Self::Num(num) + } +} + +impl From for OwnedKey { + fn from(string: String) -> Self { + Self::Str(string) + } +} + +impl From<&'static str> for OwnedKey { + fn from(string: &'static str) -> Self { + Self::Str(string.to_string()) + } +} + +/// The borrowed variant of a dictionary key. +#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)] +pub enum BorrowedKey<'a> { + Num(u64), + Str(&'a str), +} + +impl From for BorrowedKey<'static> { + fn from(num: u64) -> Self { + Self::Num(num) + } +} + +impl<'a> From<&'a String> for BorrowedKey<'a> { + fn from(string: &'a String) -> Self { + Self::Str(&string) + } +} + +impl<'a> From<&'a str> for BorrowedKey<'a> { + fn from(string: &'a str) -> Self { + Self::Str(string) + } +} + +/// A dictionary entry which tracks key and value span. +#[derive(Clone, PartialEq)] +pub struct SpannedEntry { + pub key: Span, + pub val: Spanned, +} + +impl SpannedEntry { + /// Create a new entry. + pub fn new(key: Span, val: Spanned) -> Self { + Self { key, val } + } + + /// Create an entry with the same span for key and value. + pub fn val(val: Spanned) -> Self { + Self { key: val.span, val } + } + + /// Convert from `&SpannedEntry` to `SpannedEntry<&T>` + pub fn as_ref(&self) -> SpannedEntry<&V> { + SpannedEntry { key: self.key, val: self.val.as_ref() } + } + + /// Map the entry to a different value type. + pub fn map(self, f: impl FnOnce(V) -> U) -> SpannedEntry { + SpannedEntry { key: self.key, val: self.val.map(f) } + } +} + +impl Debug for SpannedEntry { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + if f.alternate() { + f.write_str("key")?; + self.key.fmt(f)?; + f.write_str(" ")?; + } + self.val.fmt(f) + } +} + +#[cfg(test)] +mod tests { + use super::Dict; + + #[test] + fn test_dict_different_key_types_dont_interfere() { + let mut dict = Dict::new(); + dict.insert(10, "hello"); + dict.insert("twenty", "there"); + assert_eq!(dict.len(), 2); + assert_eq!(dict[10], "hello"); + assert_eq!(dict["twenty"], "there"); + } + + #[test] + fn test_dict_push_skips_already_inserted_keys() { + let mut dict = Dict::new(); + dict.insert(2, "2"); + dict.push("0"); + dict.insert(3, "3"); + dict.push("1"); + dict.push("4"); + assert_eq!(dict.len(), 5); + assert_eq!(dict[0], "0"); + assert_eq!(dict[1], "1"); + assert_eq!(dict[2], "2"); + assert_eq!(dict[3], "3"); + assert_eq!(dict[4], "4"); + } + + #[test] + fn test_dict_push_remove_push_reuses_index() { + let mut dict = Dict::new(); + dict.push("0"); + dict.push("1"); + dict.push("2"); + dict.remove(1); + dict.push("a"); + dict.push("3"); + assert_eq!(dict.len(), 4); + assert_eq!(dict[0], "0"); + assert_eq!(dict[1], "a"); + assert_eq!(dict[2], "2"); + assert_eq!(dict[3], "3"); + } + + #[test] + fn test_dict_first_and_last_are_correct() { + let mut dict = Dict::new(); + assert_eq!(dict.first(), None); + assert_eq!(dict.last(), None); + dict.insert(4, "hi"); + dict.insert("string", "hi"); + assert_eq!(dict.first(), Some((4, &"hi"))); + assert_eq!(dict.last(), Some((4, &"hi"))); + dict.insert(2, "bye"); + assert_eq!(dict.first(), Some((2, &"bye"))); + assert_eq!(dict.last(), Some((4, &"hi"))); + } + + #[test] + fn test_dict_format_debug() { + let mut dict = Dict::new(); + assert_eq!(format!("{:?}", dict), "()"); + assert_eq!(format!("{:#?}", dict), "()"); + + dict.insert(10, "hello"); + dict.insert("twenty", "there"); + dict.insert("sp ace", "quotes"); + assert_eq!( + format!("{:?}", dict), + r#"(10="hello", "sp ace"="quotes", twenty="there")"#, + ); + assert_eq!(format!("{:#?}", dict).lines().collect::>(), [ + "(", + r#" 10 = "hello","#, + r#" "sp ace" = "quotes","#, + r#" twenty = "there","#, + ")", + ]); + } +} diff --git a/src/compute/mod.rs b/src/compute/mod.rs index ac278243..a67d65b6 100644 --- a/src/compute/mod.rs +++ b/src/compute/mod.rs @@ -1,5 +1,5 @@ //! Building blocks for the computational part. +pub mod dict; pub mod scope; -pub mod table; pub mod value; diff --git a/src/compute/table.rs b/src/compute/table.rs deleted file mode 100644 index 7abb565b..00000000 --- a/src/compute/table.rs +++ /dev/null @@ -1,411 +0,0 @@ -//! A key-value map that can also model array-like structures. - -use std::collections::BTreeMap; -use std::fmt::{self, Debug, Display, Formatter}; -use std::ops::Index; - -use crate::syntax::{Span, Spanned}; - -/// A table data structure, which maps from integers (`u64`) or strings to a -/// generic value type. -/// -/// The table can be used to model arrays by assigns values to successive -/// indices from `0..n`. The table type offers special support for this pattern -/// through the `push` method. -#[derive(Clone)] -pub struct Table { - nums: BTreeMap, - strs: BTreeMap, - lowest_free: u64, -} - -impl Table { - /// Create a new empty table. - pub fn new() -> Self { - Self { - nums: BTreeMap::new(), - strs: BTreeMap::new(), - lowest_free: 0, - } - } - - /// The total number of entries in the table. - pub fn len(&self) -> usize { - self.nums.len() + self.strs.len() - } - - /// Whether the table contains no entries. - pub fn is_empty(&self) -> bool { - self.len() == 0 - } - - /// The first number key-value pair (with lowest number). - pub fn first(&self) -> Option<(u64, &V)> { - self.nums.iter().next().map(|(&k, v)| (k, v)) - } - - /// The last number key-value pair (with highest number). - pub fn last(&self) -> Option<(u64, &V)> { - self.nums.iter().next_back().map(|(&k, v)| (k, v)) - } - - /// Get a reference to the value with the given key. - pub fn get<'a, K>(&self, key: K) -> Option<&V> - where - K: Into>, - { - match key.into() { - BorrowedKey::Num(num) => self.nums.get(&num), - BorrowedKey::Str(string) => self.strs.get(string), - } - } - - /// Borrow the value with the given key mutably. - pub fn get_mut<'a, K>(&mut self, key: K) -> Option<&mut V> - where - K: Into>, - { - match key.into() { - BorrowedKey::Num(num) => self.nums.get_mut(&num), - BorrowedKey::Str(string) => self.strs.get_mut(string), - } - } - - /// Insert a value into the table. - pub fn insert(&mut self, key: K, value: V) - where - K: Into, - { - match key.into() { - OwnedKey::Num(num) => { - self.nums.insert(num, value); - if self.lowest_free == num { - self.lowest_free += 1; - } - } - OwnedKey::Str(string) => { - self.strs.insert(string, value); - } - } - } - - /// Remove the value with the given key from the table. - pub fn remove<'a, K>(&mut self, key: K) -> Option - where - K: Into>, - { - match key.into() { - BorrowedKey::Num(num) => { - self.lowest_free = self.lowest_free.min(num); - self.nums.remove(&num) - } - BorrowedKey::Str(string) => self.strs.remove(string), - } - } - - /// Append a value to the table. - /// - /// This will associate the `value` with the lowest free number key (zero if - /// there is no number key so far). - pub fn push(&mut self, value: V) { - while self.nums.contains_key(&self.lowest_free) { - self.lowest_free += 1; - } - self.nums.insert(self.lowest_free, value); - self.lowest_free += 1; - } - - /// Iterator over all borrowed keys and values. - pub fn iter(&self) -> impl Iterator { - self.nums() - .map(|(&k, v)| (BorrowedKey::Num(k), v)) - .chain(self.strs().map(|(k, v)| (BorrowedKey::Str(k), v))) - } - - /// Iterate over all values in the table. - pub fn values(&self) -> impl Iterator { - self.nums().map(|(_, v)| v).chain(self.strs().map(|(_, v)| v)) - } - - /// Iterate over the number key-value pairs. - pub fn nums(&self) -> std::collections::btree_map::Iter { - self.nums.iter() - } - - /// Iterate over the string key-value pairs. - pub fn strs(&self) -> std::collections::btree_map::Iter { - self.strs.iter() - } - - /// Move into an owned iterator over owned keys and values. - pub fn into_iter(self) -> impl Iterator { - self.nums - .into_iter() - .map(|(k, v)| (OwnedKey::Num(k), v)) - .chain(self.strs.into_iter().map(|(k, v)| (OwnedKey::Str(k), v))) - } - - /// Move into an owned iterator over all values in the table. - pub fn into_values(self) -> impl Iterator { - self.nums - .into_iter() - .map(|(_, v)| v) - .chain(self.strs.into_iter().map(|(_, v)| v)) - } - - /// Iterate over the number key-value pairs. - pub fn into_nums(self) -> std::collections::btree_map::IntoIter { - self.nums.into_iter() - } - - /// Iterate over the string key-value pairs. - pub fn into_strs(self) -> std::collections::btree_map::IntoIter { - self.strs.into_iter() - } -} - -impl<'a, K, V> Index for Table -where - K: Into>, -{ - type Output = V; - - fn index(&self, index: K) -> &Self::Output { - self.get(index).expect("key not in table") - } -} - -impl Default for Table { - fn default() -> Self { - Self::new() - } -} - -impl Eq for Table {} - -impl PartialEq for Table { - fn eq(&self, other: &Self) -> bool { - self.iter().eq(other.iter()) - } -} - -impl Debug for Table { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - if self.is_empty() { - return f.write_str("()"); - } - - let mut builder = f.debug_tuple(""); - - struct Entry<'a>(bool, &'a dyn Display, &'a dyn Debug); - impl<'a> Debug for Entry<'a> { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - if self.0 { - f.write_str("\"")?; - } - self.1.fmt(f)?; - if self.0 { - f.write_str("\"")?; - } - if f.alternate() { - f.write_str(" = ")?; - } else { - f.write_str("=")?; - } - self.2.fmt(f) - } - } - - for (key, value) in self.nums() { - builder.field(&Entry(false, &key, &value)); - } - - for (key, value) in self.strs() { - builder.field(&Entry(key.contains(' '), &key, &value)); - } - - builder.finish() - } -} - -/// The owned variant of a table key. -#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd)] -pub enum OwnedKey { - Num(u64), - Str(String), -} - -impl From> for OwnedKey { - fn from(key: BorrowedKey<'_>) -> Self { - match key { - BorrowedKey::Num(num) => Self::Num(num), - BorrowedKey::Str(string) => Self::Str(string.to_string()), - } - } -} - -impl From for OwnedKey { - fn from(num: u64) -> Self { - Self::Num(num) - } -} - -impl From for OwnedKey { - fn from(string: String) -> Self { - Self::Str(string) - } -} - -impl From<&'static str> for OwnedKey { - fn from(string: &'static str) -> Self { - Self::Str(string.to_string()) - } -} - -/// The borrowed variant of a table key. -#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)] -pub enum BorrowedKey<'a> { - Num(u64), - Str(&'a str), -} - -impl From for BorrowedKey<'static> { - fn from(num: u64) -> Self { - Self::Num(num) - } -} - -impl<'a> From<&'a String> for BorrowedKey<'a> { - fn from(string: &'a String) -> Self { - Self::Str(&string) - } -} - -impl<'a> From<&'a str> for BorrowedKey<'a> { - fn from(string: &'a str) -> Self { - Self::Str(string) - } -} - -/// An table entry which tracks key and value span. -#[derive(Clone, PartialEq)] -pub struct SpannedEntry { - pub key: Span, - pub val: Spanned, -} - -impl SpannedEntry { - /// Create a new entry. - pub fn new(key: Span, val: Spanned) -> Self { - Self { key, val } - } - - /// Create an entry with the same span for key and value. - pub fn val(val: Spanned) -> Self { - Self { key: val.span, val } - } - - /// Convert from `&SpannedEntry` to `SpannedEntry<&T>` - pub fn as_ref(&self) -> SpannedEntry<&V> { - SpannedEntry { key: self.key, val: self.val.as_ref() } - } - - /// Map the entry to a different value type. - pub fn map(self, f: impl FnOnce(V) -> U) -> SpannedEntry { - SpannedEntry { key: self.key, val: self.val.map(f) } - } -} - -impl Debug for SpannedEntry { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - if f.alternate() { - f.write_str("key")?; - self.key.fmt(f)?; - f.write_str(" ")?; - } - self.val.fmt(f) - } -} - -#[cfg(test)] -mod tests { - use super::Table; - - #[test] - fn test_table_different_key_types_dont_interfere() { - let mut table = Table::new(); - table.insert(10, "hello"); - table.insert("twenty", "there"); - assert_eq!(table.len(), 2); - assert_eq!(table[10], "hello"); - assert_eq!(table["twenty"], "there"); - } - - #[test] - fn test_table_push_skips_already_inserted_keys() { - let mut table = Table::new(); - table.insert(2, "2"); - table.push("0"); - table.insert(3, "3"); - table.push("1"); - table.push("4"); - assert_eq!(table.len(), 5); - assert_eq!(table[0], "0"); - assert_eq!(table[1], "1"); - assert_eq!(table[2], "2"); - assert_eq!(table[3], "3"); - assert_eq!(table[4], "4"); - } - - #[test] - fn test_table_push_remove_push_reuses_index() { - let mut table = Table::new(); - table.push("0"); - table.push("1"); - table.push("2"); - table.remove(1); - table.push("a"); - table.push("3"); - assert_eq!(table.len(), 4); - assert_eq!(table[0], "0"); - assert_eq!(table[1], "a"); - assert_eq!(table[2], "2"); - assert_eq!(table[3], "3"); - } - - #[test] - fn test_table_first_and_last_are_correct() { - let mut table = Table::new(); - assert_eq!(table.first(), None); - assert_eq!(table.last(), None); - table.insert(4, "hi"); - table.insert("string", "hi"); - assert_eq!(table.first(), Some((4, &"hi"))); - assert_eq!(table.last(), Some((4, &"hi"))); - table.insert(2, "bye"); - assert_eq!(table.first(), Some((2, &"bye"))); - assert_eq!(table.last(), Some((4, &"hi"))); - } - - #[test] - fn test_table_format_debug() { - let mut table = Table::new(); - assert_eq!(format!("{:?}", table), "()"); - assert_eq!(format!("{:#?}", table), "()"); - - table.insert(10, "hello"); - table.insert("twenty", "there"); - table.insert("sp ace", "quotes"); - assert_eq!( - format!("{:?}", table), - r#"(10="hello", "sp ace"="quotes", twenty="there")"#, - ); - assert_eq!(format!("{:#?}", table).lines().collect::>(), [ - "(", - r#" 10 = "hello","#, - r#" "sp ace" = "quotes","#, - r#" twenty = "there","#, - ")", - ]); - } -} diff --git a/src/compute/value.rs b/src/compute/value.rs index e8e4cbe1..1fcc4be2 100644 --- a/src/compute/value.rs +++ b/src/compute/value.rs @@ -6,7 +6,7 @@ use std::rc::Rc; use fontdock::{FontStretch, FontStyle, FontWeight}; -use super::table::{SpannedEntry, Table}; +use super::dict::{Dict, SpannedEntry}; use crate::color::RgbaColor; use crate::layout::{Command, Commands, Dir, LayoutContext, SpecAlign}; use crate::length::{Length, ScaleLength}; @@ -29,8 +29,8 @@ pub enum Value { Length(Length), /// A color value with alpha channel: `#f79143ff`. Color(RgbaColor), - /// A table value: `(false, 12cm, greeting="hi")`. - Table(TableValue), + /// A dictionary value: `(false, 12cm, greeting="hi")`. + Dict(DictValue), /// A syntax tree containing typesetting content. Tree(SyntaxTree), /// An executable function. @@ -51,7 +51,7 @@ impl Value { Number(_) => "number", Length(_) => "length", Color(_) => "color", - Table(_) => "table", + Dict(_) => "dict", Tree(_) => "syntax tree", Func(_) => "function", Commands(_) => "commands", @@ -70,10 +70,10 @@ impl Spanned { Value::Tree(tree) => vec![Command::LayoutSyntaxTree(tree)], // Forward to each entry, separated with spaces. - Value::Table(table) => { + Value::Dict(dict) => { let mut commands = vec![]; let mut end = None; - for entry in table.into_values() { + for entry in dict.into_values() { if let Some(last_end) = end { let span = Span::new(last_end, entry.key.start); let tree = vec![SyntaxNode::Spacing.span_with(span)]; @@ -106,7 +106,7 @@ impl Debug for Value { Number(n) => n.fmt(f), Length(s) => s.fmt(f), Color(c) => c.fmt(f), - Table(t) => t.fmt(f), + Dict(t) => t.fmt(f), Tree(t) => t.fmt(f), Func(_) => f.pad(""), Commands(c) => c.fmt(f), @@ -124,7 +124,7 @@ impl PartialEq for Value { (Number(a), Number(b)) => a == b, (Length(a), Length(b)) => a == b, (Color(a), Color(b)) => a == b, - (Table(a), Table(b)) => a == b, + (Dict(a), Dict(b)) => a == b, (Tree(a), Tree(b)) => a == b, (Func(a), Func(b)) => Rc::ptr_eq(a, b), (Commands(a), Commands(b)) => a == b, @@ -135,7 +135,7 @@ impl PartialEq for Value { /// An executable function value. /// -/// The first argument is a table containing the arguments passed to the +/// The first argument is a dictionary containing the arguments passed to the /// function. The function may be asynchronous (as such it returns a dynamic /// future) and it may emit diagnostics, which are contained in the returned /// `Pass`. In the end, the function must evaluate to `Value`. Your typical @@ -144,17 +144,17 @@ impl PartialEq for Value { /// /// The dynamic function object is wrapped in an `Rc` to keep `Value` clonable. pub type FuncValue = - Rc) -> DynFuture>>; + Rc) -> DynFuture>>; -/// A table of values. +/// A dictionary of values. /// /// # Example /// ```typst /// (false, 12cm, greeting="hi") /// ``` -pub type TableValue = Table>; +pub type DictValue = Dict>; -impl TableValue { +impl DictValue { /// Retrieve and remove the matching value with the lowest number key, /// skipping and ignoring all non-matching entries with lower keys. pub fn take(&mut self) -> Option { @@ -341,7 +341,7 @@ impl_match!(bool, "bool", &Value::Bool(b) => b); impl_match!(f64, "number", &Value::Number(n) => n); impl_match!(Length, "length", &Value::Length(l) => l); impl_match!(SyntaxTree, "tree", Value::Tree(t) => t.clone()); -impl_match!(TableValue, "table", Value::Table(t) => t.clone()); +impl_match!(DictValue, "dict", Value::Dict(t) => t.clone()); impl_match!(FuncValue, "function", Value::Func(f) => f.clone()); impl_match!(ScaleLength, "number or length", &Value::Length(length) => ScaleLength::Absolute(length), @@ -437,60 +437,60 @@ mod tests { } #[test] - fn test_table_take_removes_correct_entry() { - let mut table = Table::new(); - table.insert(1, entry(Value::Bool(false))); - table.insert(2, entry(Value::Str("hi".to_string()))); - assert_eq!(table.take::(), Some("hi".to_string())); - assert_eq!(table.len(), 1); - assert_eq!(table.take::(), Some(false)); - assert!(table.is_empty()); + fn test_dict_take_removes_correct_entry() { + let mut dict = Dict::new(); + dict.insert(1, entry(Value::Bool(false))); + dict.insert(2, entry(Value::Str("hi".to_string()))); + assert_eq!(dict.take::(), Some("hi".to_string())); + assert_eq!(dict.len(), 1); + assert_eq!(dict.take::(), Some(false)); + assert!(dict.is_empty()); } #[test] - fn test_table_expect_errors_about_previous_entries() { + fn test_dict_expect_errors_about_previous_entries() { let mut f = Feedback::new(); - let mut table = Table::new(); - table.insert(1, entry(Value::Bool(false))); - table.insert(3, entry(Value::Str("hi".to_string()))); - table.insert(5, entry(Value::Bool(true))); + let mut dict = Dict::new(); + dict.insert(1, entry(Value::Bool(false))); + dict.insert(3, entry(Value::Str("hi".to_string()))); + dict.insert(5, entry(Value::Bool(true))); assert_eq!( - table.expect::("", Span::ZERO, &mut f), + dict.expect::("", Span::ZERO, &mut f), Some("hi".to_string()) ); assert_eq!(f.diagnostics, [error!( Span::ZERO, "expected string, found bool" )]); - assert_eq!(table.len(), 1); + assert_eq!(dict.len(), 1); } #[test] - fn test_table_take_with_key_removes_the_entry() { + fn test_dict_take_with_key_removes_the_entry() { let mut f = Feedback::new(); - let mut table = Table::new(); - table.insert(1, entry(Value::Bool(false))); - table.insert("hi", entry(Value::Bool(true))); - assert_eq!(table.take::(), Some(false)); - assert_eq!(table.take_key::("hi", &mut f), None); + let mut dict = Dict::new(); + dict.insert(1, entry(Value::Bool(false))); + dict.insert("hi", entry(Value::Bool(true))); + assert_eq!(dict.take::(), Some(false)); + assert_eq!(dict.take_key::("hi", &mut f), None); assert_eq!(f.diagnostics, [error!( Span::ZERO, "expected number, found bool" )]); - assert!(table.is_empty()); + assert!(dict.is_empty()); } #[test] - fn test_table_take_all_removes_the_correct_entries() { - let mut table = Table::new(); - table.insert(1, entry(Value::Bool(false))); - table.insert(3, entry(Value::Number(0.0))); - table.insert(7, entry(Value::Bool(true))); - assert_eq!(table.take_all_num::().collect::>(), [ + fn test_dict_take_all_removes_the_correct_entries() { + let mut dict = Dict::new(); + dict.insert(1, entry(Value::Bool(false))); + dict.insert(3, entry(Value::Number(0.0))); + dict.insert(7, entry(Value::Bool(true))); + assert_eq!(dict.take_all_num::().collect::>(), [ (1, false), (7, true) ],); - assert_eq!(table.len(), 1); - assert_eq!(table[3].val.v, Value::Number(0.0)); + assert_eq!(dict.len(), 1); + assert_eq!(dict[3].val.v, Value::Number(0.0)); } } diff --git a/src/library/align.rs b/src/library/align.rs index 55e0f65e..55259fd5 100644 --- a/src/library/align.rs +++ b/src/library/align.rs @@ -14,7 +14,7 @@ use super::*; /// - `vertical`: Any of `top`, `bottom` or `center`. /// /// There may not be two alignment specifications for the same axis. -pub async fn align(_: Span, mut args: TableValue, ctx: LayoutContext<'_>) -> Pass { +pub async fn align(_: Span, mut args: DictValue, ctx: LayoutContext<'_>) -> Pass { let mut f = Feedback::new(); let content = args.take::(); diff --git a/src/library/boxed.rs b/src/library/boxed.rs index 5d98760f..672e77d1 100644 --- a/src/library/boxed.rs +++ b/src/library/boxed.rs @@ -8,7 +8,7 @@ use crate::length::ScaleLength; /// - `height`: The height of the box (length of relative to parent's height). pub async fn boxed( _: Span, - mut args: TableValue, + mut args: DictValue, mut ctx: LayoutContext<'_>, ) -> Pass { let mut f = Feedback::new(); diff --git a/src/library/color.rs b/src/library/color.rs index 0d7e8535..43d9253f 100644 --- a/src/library/color.rs +++ b/src/library/color.rs @@ -2,7 +2,7 @@ use super::*; use crate::color::RgbaColor; /// `rgb`: Create an RGB(A) color. -pub async fn rgb(span: Span, mut args: TableValue, _: LayoutContext<'_>) -> Pass { +pub async fn rgb(span: Span, mut args: DictValue, _: LayoutContext<'_>) -> Pass { let mut f = Feedback::new(); let r = args.expect::>("red value", span, &mut f); diff --git a/src/library/font.rs b/src/library/font.rs index ed9360e0..e9f6f9b4 100644 --- a/src/library/font.rs +++ b/src/library/font.rs @@ -12,13 +12,18 @@ use crate::length::ScaleLength; /// # Keyword arguments /// - `style`: `normal`, `italic` or `oblique`. /// - `weight`: `100` - `900` or a name like `thin`. -/// - `width`: `normal`, `condensed`, `expanded`, ... -/// - Any other keyword argument whose value is a table of strings is a class -/// fallback definition like: +/// - `width`: `1` - `9` or a name like `condensed`. +/// - Any other keyword argument whose value is a dictionary of strings defines +/// a fallback class, for example: /// ```typst -/// serif = ("Source Serif Pro", "Noto Serif") +/// [font: serif = ("Source Serif Pro", "Noto Serif")] /// ``` -pub async fn font(_: Span, mut args: TableValue, ctx: LayoutContext<'_>) -> Pass { +/// This class can be used in the fallback list or other fallback classes as +/// long as the resulting fallback tree is acylic. +/// ```typst +/// [font: "My Serif", serif] +/// ``` +pub async fn font(_: Span, mut args: DictValue, ctx: LayoutContext<'_>) -> Pass { let mut f = Feedback::new(); let mut text = ctx.style.text.clone(); let mut updated_fallback = false; @@ -57,8 +62,8 @@ pub async fn font(_: Span, mut args: TableValue, ctx: LayoutContext<'_>) -> Pass text.variant.stretch = stretch; } - for (class, mut table) in args.take_all_str::() { - let fallback = table + for (class, mut dict) in args.take_all_str::() { + let fallback = dict .take_all_num_vals::() .map(|s| s.to_lowercase()) .collect(); diff --git a/src/library/page.rs b/src/library/page.rs index ee551064..b4f74e48 100644 --- a/src/library/page.rs +++ b/src/library/page.rs @@ -16,7 +16,7 @@ use crate::paper::{Paper, PaperClass}; /// - `top`: The top margin (length or relative to height). /// - `bottom`: The bottom margin (length or relative to height). /// - `flip`: Flips custom or paper-defined width and height (boolean). -pub async fn page(_: Span, mut args: TableValue, ctx: LayoutContext<'_>) -> Pass { +pub async fn page(_: Span, mut args: DictValue, ctx: LayoutContext<'_>) -> Pass { let mut f = Feedback::new(); let mut style = ctx.style.page; @@ -64,7 +64,7 @@ pub async fn page(_: Span, mut args: TableValue, ctx: LayoutContext<'_>) -> Pass } /// `pagebreak`: Ends the current page. -pub async fn pagebreak(_: Span, args: TableValue, _: LayoutContext<'_>) -> Pass { +pub async fn pagebreak(_: Span, args: DictValue, _: LayoutContext<'_>) -> Pass { let mut f = Feedback::new(); args.unexpected(&mut f); Pass::commands(vec![BreakPage], f) diff --git a/src/library/spacing.rs b/src/library/spacing.rs index 8b2f1622..aa2712d3 100644 --- a/src/library/spacing.rs +++ b/src/library/spacing.rs @@ -6,7 +6,7 @@ use crate::length::ScaleLength; /// /// # Positional arguments /// - The spacing (length or relative to font size). -pub async fn h(name: Span, args: TableValue, ctx: LayoutContext<'_>) -> Pass { +pub async fn h(name: Span, args: DictValue, ctx: LayoutContext<'_>) -> Pass { spacing(name, args, ctx, Horizontal) } @@ -14,13 +14,13 @@ pub async fn h(name: Span, args: TableValue, ctx: LayoutContext<'_>) -> Pass) -> Pass { +pub async fn v(name: Span, args: DictValue, ctx: LayoutContext<'_>) -> Pass { spacing(name, args, ctx, Vertical) } fn spacing( name: Span, - mut args: TableValue, + mut args: DictValue, ctx: LayoutContext<'_>, axis: SpecAxis, ) -> Pass { diff --git a/src/parse/mod.rs b/src/parse/mod.rs index b62bd5d3..75ca7eb4 100644 --- a/src/parse/mod.rs +++ b/src/parse/mod.rs @@ -14,7 +14,7 @@ use std::str::FromStr; use super::*; use crate::color::RgbaColor; -use crate::compute::table::SpannedEntry; +use crate::compute::dict::SpannedEntry; use crate::syntax::*; use crate::{Feedback, Pass}; @@ -199,13 +199,13 @@ impl Parser<'_> { self.skip_ws(); let mut args = match self.eatv() { - Some(Token::Colon) => self.parse_table_contents().0, + Some(Token::Colon) => self.parse_dict_contents().0, Some(_) => { self.expected_at("colon", name.span.end); while self.eat().is_some() {} - TableExpr::new() + DictExpr::new() } - None => TableExpr::new(), + None => DictExpr::new(), }; self.end_group(); @@ -243,17 +243,17 @@ impl Parser<'_> { fn parse_paren_call(&mut self, name: Spanned) -> Spanned { self.start_group(Group::Paren); - let args = self.parse_table_contents().0; + let args = self.parse_dict_contents().0; let args_span = self.end_group(); let span = Span::merge(name.span, args_span); CallExpr { name, args }.span_with(span) } } -// Tables. +// Dicts. impl Parser<'_> { - fn parse_table_contents(&mut self) -> (TableExpr, bool) { - let mut table = TableExpr::new(); + fn parse_dict_contents(&mut self) -> (DictExpr, bool) { + let mut dict = DictExpr::new(); let mut comma_and_keyless = true; while { @@ -292,12 +292,12 @@ impl Parser<'_> { let behind = val.span.end; if let Some(key) = key { comma_and_keyless = false; - table.insert(key.v.0, SpannedEntry::new(key.span, val)); + dict.insert(key.v.0, SpannedEntry::new(key.span, val)); self.feedback .decorations - .push(Decoration::TableKey.span_with(key.span)); + .push(Decoration::DictKey.span_with(key.span)); } else { - table.push(SpannedEntry::val(val)); + dict.push(SpannedEntry::val(val)); } if { @@ -311,8 +311,8 @@ impl Parser<'_> { comma_and_keyless = false; } - let coercable = comma_and_keyless && !table.is_empty(); - (table, coercable) + let coercable = comma_and_keyless && !dict.is_empty(); + (dict, coercable) } } @@ -421,18 +421,18 @@ impl Parser<'_> { } } - // This could be a table or a parenthesized expression. We parse as - // a table in any case and coerce the table into a value if it is - // coercable (length 1 and no trailing comma). + // This could be a dictionary or a parenthesized expression. We + // parse as a dictionary in any case and coerce into a value if + // that's coercable (length 1 and no trailing comma). Token::LeftParen => { self.start_group(Group::Paren); - let (table, coercable) = self.parse_table_contents(); + let (dict, coercable) = self.parse_dict_contents(); let span = self.end_group(); let expr = if coercable { - table.into_values().next().expect("table is coercable").val.v + dict.into_values().next().expect("dict is coercable").val.v } else { - Expr::Table(table) + Expr::Dict(dict) }; expr.span_with(span) diff --git a/src/parse/tests.rs b/src/parse/tests.rs index a753378e..e516af32 100644 --- a/src/parse/tests.rs +++ b/src/parse/tests.rs @@ -6,7 +6,7 @@ use std::fmt::Debug; use super::parse; use crate::color::RgbaColor; -use crate::compute::table::SpannedEntry; +use crate::compute::dict::SpannedEntry; use crate::length::Length; use crate::syntax::*; @@ -59,26 +59,26 @@ fn Str(string: &str) -> Expr { Expr::Str(string.to_string()) } -macro_rules! Table { - (@table=$table:expr,) => {}; - (@table=$table:expr, $key:expr => $value:expr $(, $($tts:tt)*)?) => {{ +macro_rules! Dict { + (@dict=$dict:expr,) => {}; + (@dict=$dict:expr, $key:expr => $value:expr $(, $($tts:tt)*)?) => {{ let key = Into::>::into($key); let val = Into::>::into($value); - $table.insert(key.v, SpannedEntry::new(key.span, val)); - Table![@table=$table, $($($tts)*)?]; + $dict.insert(key.v, SpannedEntry::new(key.span, val)); + Dict![@dict=$dict, $($($tts)*)?]; }}; - (@table=$table:expr, $value:expr $(, $($tts:tt)*)?) => { + (@dict=$dict:expr, $value:expr $(, $($tts:tt)*)?) => { let val = Into::>::into($value); - $table.push(SpannedEntry::val(val)); - Table![@table=$table, $($($tts)*)?]; + $dict.push(SpannedEntry::val(val)); + Dict![@dict=$dict, $($($tts)*)?]; }; (@$($tts:tt)*) => {{ #[allow(unused_mut)] - let mut table = TableExpr::new(); - Table![@table=table, $($tts)*]; - table + let mut dict = DictExpr::new(); + Dict![@dict=dict, $($tts)*]; + dict }}; - ($($tts:tt)*) => { Expr::Table(Table![@$($tts)*]) }; + ($($tts:tt)*) => { Expr::Dict(Dict![@$($tts)*]) }; } macro_rules! Tree { @@ -93,7 +93,7 @@ macro_rules! Call { let name = Into::>::into($name); CallExpr { name: name.map(|n| Ident(n.to_string())), - args: Table![@$($($tts)*)?], + args: Dict![@$($($tts)*)?], } }}; ($($tts:tt)*) => { Expr::Call(Call![@$($tts)*]) }; @@ -321,7 +321,7 @@ fn test_parse_function_names() { #[test] fn test_parse_chaining() { // Things the parser has to make sense of - t!("[hi: (5.0, 2.1 >> you]" => F!("hi"; Table![Num(5.0), Num(2.1)], Tree![F!("you")])); + t!("[hi: (5.0, 2.1 >> you]" => F!("hi"; Dict![Num(5.0), Num(2.1)], Tree![F!("you")])); t!("[box >>][Hi]" => F!("box"; Tree![T("Hi")])); t!("[box >> pad: 1pt][Hi]" => F!("box"; Tree![ F!("pad"; Len(Length::pt(1.0)), Tree!(T("Hi"))) @@ -416,7 +416,7 @@ fn test_parse_values() { #[test] fn test_parse_expressions() { - // Coerced table. + // Coerced dict. v!("(hi)" => Id("hi")); // Operations. @@ -458,19 +458,19 @@ fn test_parse_expressions() { } #[test] -fn test_parse_tables() { +fn test_parse_dicts() { // Okay. - v!("()" => Table![]); + v!("()" => Dict![]); v!("(false)" => Bool(false)); - v!("(true,)" => Table![Bool(true)]); - v!("(key=val)" => Table!["key" => Id("val")]); - v!("(1, 2)" => Table![Num(1.0), Num(2.0)]); - v!("(1, key=\"value\")" => Table![Num(1.0), "key" => Str("value")]); + v!("(true,)" => Dict![Bool(true)]); + v!("(key=val)" => Dict!["key" => Id("val")]); + v!("(1, 2)" => Dict![Num(1.0), Num(2.0)]); + v!("(1, key=\"value\")" => Dict![Num(1.0), "key" => Str("value")]); // Decorations. - d!("[val: key=hi]" => s(6, 9, TableKey)); - d!("[val: (key=hi)]" => s(7, 10, TableKey)); - d!("[val: f(key=hi)]" => s(8, 11, TableKey)); + d!("[val: key=hi]" => s(6, 9, DictKey)); + d!("[val: (key=hi)]" => s(7, 10, DictKey)); + d!("[val: f(key=hi)]" => s(8, 11, DictKey)); // Spanned with spacing around keyword arguments. ts!("[val: \n hi \n = /* //\n */ \"s\n\"]" => s(0, 30, F!( @@ -481,7 +481,7 @@ fn test_parse_tables() { } #[test] -fn test_parse_tables_compute_func_calls() { +fn test_parse_dicts_compute_func_calls() { v!("empty()" => Call!("empty")); v!("add ( 1 , 2 )" => Call!("add"; Num(1.0), Num(2.0))); v!("items(\"fire\", #f93a6d)" => Call!("items"; @@ -501,18 +501,18 @@ fn test_parse_tables_compute_func_calls() { e!("[val: lang(δΈ­ζ–‡]" => s(17, 17, "expected closing paren")); // Invalid name. - v!("πŸ‘ (\"abc\", 13e-5)" => Table!(Str("abc"), Num(13.0e-5))); + v!("πŸ‘ (\"abc\", 13e-5)" => Dict!(Str("abc"), Num(13.0e-5))); e!("[val: πŸ‘ (\"abc\", 13e-5)]" => s(6, 10, "expected value, found invalid token")); } #[test] -fn test_parse_tables_nested() { +fn test_parse_dicts_nested() { v!("(1, ( ab=(), d = (3, 14pt) )), false" => - Table![ + Dict![ Num(1.0), - Table!( - "ab" => Table![], - "d" => Table!(Num(3.0), Len(Length::pt(14.0))), + Dict!( + "ab" => Dict![], + "d" => Dict!(Num(3.0), Len(Length::pt(14.0))), ), ], Bool(false), @@ -520,17 +520,17 @@ fn test_parse_tables_nested() { } #[test] -fn test_parse_tables_errors() { +fn test_parse_dicts_errors() { // Expected value. e!("[val: (=)]" => s(7, 8, "expected value, found equals sign")); e!("[val: (,)]" => s(7, 8, "expected value, found comma")); - v!("(\x07 abc,)" => Table![Id("abc")]); + v!("(\x07 abc,)" => Dict![Id("abc")]); e!("[val: (\x07 abc,)]" => s(7, 8, "expected value, found invalid token")); e!("[val: (key=,)]" => s(11, 12, "expected value, found comma")); e!("[val: hi,)]" => s(9, 10, "expected value, found closing paren")); // Expected comma. - v!("(true false)" => Table![Bool(true), Bool(false)]); + v!("(true false)" => Dict![Bool(true), Bool(false)]); e!("[val: (true false)]" => s(11, 11, "expected comma")); // Expected closing paren. diff --git a/src/syntax/mod.rs b/src/syntax/mod.rs index fe887c2f..0809d33f 100644 --- a/src/syntax/mod.rs +++ b/src/syntax/mod.rs @@ -21,6 +21,6 @@ pub enum Decoration { Resolved, /// An invalid, unresolved name. Unresolved, - /// The key part of a key-value entry in a table. - TableKey, + /// A key in a dictionary. + DictKey, } diff --git a/src/syntax/tree.rs b/src/syntax/tree.rs index ee53d476..c4ce3ad2 100644 --- a/src/syntax/tree.rs +++ b/src/syntax/tree.rs @@ -8,8 +8,8 @@ use unicode_xid::UnicodeXID; use super::span::{SpanVec, SpanWith, Spanned}; use super::Decoration; use crate::color::RgbaColor; -use crate::compute::table::{SpannedEntry, Table}; -use crate::compute::value::{TableValue, Value}; +use crate::compute::dict::{Dict, SpannedEntry}; +use crate::compute::value::{DictValue, Value}; use crate::layout::LayoutContext; use crate::length::Length; use crate::{DynFuture, Feedback}; @@ -143,8 +143,8 @@ pub enum Expr { Length(Length), /// A color value with alpha channel: `#f79143ff`. Color(RgbaColor), - /// A table expression: `(false, 12cm, greeting="hi")`. - Table(TableExpr), + /// A dictionary expression: `(false, 12cm, greeting="hi")`. + Dict(DictExpr), /// A syntax tree containing typesetting content. Tree(SyntaxTree), /// A function call expression: `cmyk(37.7, 0, 3.9, 1.1)`. @@ -173,7 +173,7 @@ impl Expr { Number(_) => "number", Length(_) => "length", Color(_) => "color", - Table(_) => "table", + Dict(_) => "dictg", Tree(_) => "syntax tree", Call(_) => "function call", Neg(_) => "negation", @@ -194,7 +194,7 @@ impl Expr { &Number(n) => Value::Number(n), &Length(s) => Value::Length(s), &Color(c) => Value::Color(c), - Table(t) => Value::Table(t.eval(ctx, f).await), + Dict(t) => Value::Dict(t.eval(ctx, f).await), Tree(t) => Value::Tree(t.clone()), Call(call) => call.eval(ctx, f).await, Neg(_) => todo!("eval neg"), @@ -216,7 +216,7 @@ impl Debug for Expr { Number(n) => n.fmt(f), Length(s) => s.fmt(f), Color(c) => c.fmt(f), - Table(t) => t.fmt(f), + Dict(t) => t.fmt(f), Tree(t) => t.fmt(f), Call(c) => c.fmt(f), Neg(e) => write!(f, "-{:?}", e), @@ -282,32 +282,32 @@ pub fn is_ident(string: &str) -> bool { } } -/// A table of expressions. +/// A dictionary of expressions. /// /// # Example /// ```typst /// (false, 12cm, greeting="hi") /// ``` -pub type TableExpr = Table>; +pub type DictExpr = Dict>; -impl TableExpr { - /// Evaluate the table expression to a table value. +impl DictExpr { + /// Evaluate the dictionary expression to a dictionary value. pub fn eval<'a>( &'a self, ctx: &'a LayoutContext<'a>, f: &'a mut Feedback, - ) -> DynFuture<'a, TableValue> { + ) -> DynFuture<'a, DictValue> { Box::pin(async move { - let mut table = TableValue::new(); + let mut dict = DictValue::new(); for (key, entry) in self.iter() { let val = entry.val.v.eval(ctx, f).await; let spanned = val.span_with(entry.val.span); let entry = SpannedEntry::new(entry.key, spanned); - table.insert(key, entry); + dict.insert(key, entry); } - table + dict }) } } @@ -316,7 +316,7 @@ impl TableExpr { #[derive(Debug, Clone, PartialEq)] pub struct CallExpr { pub name: Spanned, - pub args: TableExpr, + pub args: DictExpr, } impl CallExpr { @@ -336,7 +336,7 @@ impl CallExpr { error!(@f, span, "unknown function"); f.decorations.push(Decoration::Unresolved.span_with(span)); } - Value::Table(args) + Value::Dict(args) } } } -- cgit v1.2.3