diff options
Diffstat (limited to 'src/eval')
| -rw-r--r-- | src/eval/array.rs | 2 | ||||
| -rw-r--r-- | src/eval/dict.rs | 40 | ||||
| -rw-r--r-- | src/eval/function.rs | 11 | ||||
| -rw-r--r-- | src/eval/mod.rs | 19 | ||||
| -rw-r--r-- | src/eval/ops.rs | 16 | ||||
| -rw-r--r-- | src/eval/str.rs | 164 | ||||
| -rw-r--r-- | src/eval/template.rs | 13 | ||||
| -rw-r--r-- | src/eval/value.rs | 26 | ||||
| -rw-r--r-- | src/eval/walk.rs | 18 |
9 files changed, 77 insertions, 232 deletions
diff --git a/src/eval/array.rs b/src/eval/array.rs index f6adee6d..912aa3c0 100644 --- a/src/eval/array.rs +++ b/src/eval/array.rs @@ -70,7 +70,7 @@ impl Array { /// Clear the array. pub fn clear(&mut self) { - if Rc::strong_count(&mut self.0) == 1 { + if Rc::strong_count(&self.0) == 1 { Rc::make_mut(&mut self.0).clear(); } else { *self = Self::new(); diff --git a/src/eval/dict.rs b/src/eval/dict.rs index e7a46b40..0d7198e1 100644 --- a/src/eval/dict.rs +++ b/src/eval/dict.rs @@ -4,9 +4,9 @@ use std::iter::FromIterator; use std::ops::{Add, AddAssign}; use std::rc::Rc; -use super::{Str, Value}; +use super::Value; use crate::diag::StrResult; -use crate::util::RcExt; +use crate::util::{EcoString, RcExt}; /// Create a new [`Dict`] from key-value pairs. #[allow(unused_macros)] @@ -21,7 +21,7 @@ macro_rules! dict { /// A dictionary from strings to values with clone-on-write value semantics. #[derive(Default, Clone, PartialEq)] -pub struct Dict(Rc<BTreeMap<Str, Value>>); +pub struct Dict(Rc<BTreeMap<EcoString, Value>>); impl Dict { /// Create a new, empty dictionary. @@ -30,7 +30,7 @@ impl Dict { } /// Create a new dictionary from a mapping of strings to values. - pub fn from_map(map: BTreeMap<Str, Value>) -> Self { + pub fn from_map(map: BTreeMap<EcoString, Value>) -> Self { Self(Rc::new(map)) } @@ -45,7 +45,7 @@ impl Dict { } /// Borrow the value the given `key` maps to. - pub fn get(&self, key: Str) -> StrResult<&Value> { + pub fn get(&self, key: EcoString) -> StrResult<&Value> { self.0.get(&key).ok_or_else(|| missing_key(&key)) } @@ -53,18 +53,18 @@ impl Dict { /// /// This inserts the key with [`None`](Value::None) as the value if not /// present so far. - pub fn get_mut(&mut self, key: Str) -> &mut Value { - Rc::make_mut(&mut self.0).entry(key.into()).or_default() + pub fn get_mut(&mut self, key: EcoString) -> &mut Value { + Rc::make_mut(&mut self.0).entry(key).or_default() } /// Insert a mapping from the given `key` to the given `value`. - pub fn insert(&mut self, key: Str, value: Value) { - Rc::make_mut(&mut self.0).insert(key.into(), value); + pub fn insert(&mut self, key: EcoString, value: Value) { + Rc::make_mut(&mut self.0).insert(key, value); } /// Clear the dictionary. pub fn clear(&mut self) { - if Rc::strong_count(&mut self.0) == 1 { + if Rc::strong_count(&self.0) == 1 { Rc::make_mut(&mut self.0).clear(); } else { *self = Self::new(); @@ -72,14 +72,14 @@ impl Dict { } /// Iterate over pairs of references to the contained keys and values. - pub fn iter(&self) -> std::collections::btree_map::Iter<Str, Value> { + pub fn iter(&self) -> std::collections::btree_map::Iter<EcoString, Value> { self.0.iter() } } /// The missing key access error message. #[cold] -fn missing_key(key: &Str) -> String { +fn missing_key(key: &EcoString) -> String { format!("dictionary does not contain key: {:?}", key) } @@ -119,21 +119,21 @@ impl AddAssign for Dict { } } -impl Extend<(Str, Value)> for Dict { - fn extend<T: IntoIterator<Item = (Str, Value)>>(&mut self, iter: T) { +impl Extend<(EcoString, Value)> for Dict { + fn extend<T: IntoIterator<Item = (EcoString, Value)>>(&mut self, iter: T) { Rc::make_mut(&mut self.0).extend(iter); } } -impl FromIterator<(Str, Value)> for Dict { - fn from_iter<T: IntoIterator<Item = (Str, Value)>>(iter: T) -> Self { +impl FromIterator<(EcoString, Value)> for Dict { + fn from_iter<T: IntoIterator<Item = (EcoString, Value)>>(iter: T) -> Self { Self(Rc::new(iter.into_iter().collect())) } } impl IntoIterator for Dict { - type Item = (Str, Value); - type IntoIter = std::collections::btree_map::IntoIter<Str, Value>; + type Item = (EcoString, Value); + type IntoIter = std::collections::btree_map::IntoIter<EcoString, Value>; fn into_iter(self) -> Self::IntoIter { Rc::take(self.0).into_iter() @@ -141,8 +141,8 @@ impl IntoIterator for Dict { } impl<'a> IntoIterator for &'a Dict { - type Item = (&'a Str, &'a Value); - type IntoIter = std::collections::btree_map::Iter<'a, Str, Value>; + type Item = (&'a EcoString, &'a Value); + type IntoIter = std::collections::btree_map::Iter<'a, EcoString, Value>; fn into_iter(self) -> Self::IntoIter { self.iter() diff --git a/src/eval/function.rs b/src/eval/function.rs index cbbc0b36..c83d8b2b 100644 --- a/src/eval/function.rs +++ b/src/eval/function.rs @@ -1,7 +1,7 @@ use std::fmt::{self, Debug, Formatter, Write}; use std::rc::Rc; -use super::{Cast, EvalContext, Str, Value}; +use super::{Cast, EvalContext, Value}; use crate::diag::{At, TypResult}; use crate::syntax::{Span, Spanned}; use crate::util::EcoString; @@ -52,7 +52,10 @@ impl Debug for Function { impl PartialEq for Function { fn eq(&self, other: &Self) -> bool { // We cast to thin pointers for comparison. - Rc::as_ptr(&self.0) as *const () == Rc::as_ptr(&other.0) as *const () + std::ptr::eq( + Rc::as_ptr(&self.0) as *const (), + Rc::as_ptr(&other.0) as *const (), + ) } } @@ -71,7 +74,7 @@ pub struct Arg { /// The span of the whole argument. pub span: Span, /// The name of the argument (`None` for positional arguments). - pub name: Option<Str>, + pub name: Option<EcoString>, /// The value of the argument. pub value: Spanned<Value>, } @@ -173,7 +176,7 @@ impl Args { } /// Reinterpret these arguments as actually being a dictionary key. - pub fn into_key(self) -> TypResult<Str> { + pub fn into_key(self) -> TypResult<EcoString> { self.into_castable("key") } diff --git a/src/eval/mod.rs b/src/eval/mod.rs index fda2184e..1ff497e8 100644 --- a/src/eval/mod.rs +++ b/src/eval/mod.rs @@ -5,8 +5,6 @@ mod array; #[macro_use] mod dict; #[macro_use] -mod str; -#[macro_use] mod value; mod capture; mod function; @@ -15,7 +13,6 @@ mod scope; mod template; mod walk; -pub use self::str::*; pub use array::*; pub use capture::*; pub use dict::*; @@ -31,6 +28,8 @@ use std::io; use std::mem; use std::path::PathBuf; +use unicode_segmentation::UnicodeSegmentation; + use crate::diag::{At, Error, StrResult, Trace, Tracepoint, TypResult}; use crate::geom::{Angle, Fractional, Length, Relative}; use crate::image::ImageStore; @@ -38,7 +37,7 @@ use crate::loading::Loader; use crate::source::{SourceId, SourceStore}; use crate::syntax::ast::*; use crate::syntax::{Span, Spanned}; -use crate::util::RefMutExt; +use crate::util::{EcoString, RefMutExt}; use crate::Context; /// Evaluate a parsed source file into a module. @@ -210,7 +209,7 @@ impl Eval for Lit { LitKind::Angle(v, unit) => Value::Angle(Angle::with_unit(v, unit)), LitKind::Percent(v) => Value::Relative(Relative::new(v / 100.0)), LitKind::Fractional(v) => Value::Fractional(Fractional::new(v)), - LitKind::Str(ref v) => Value::Str(v.into()), + LitKind::Str(ref v) => Value::Str(v.clone()), }) } } @@ -239,7 +238,7 @@ impl Eval for DictExpr { fn eval(&self, ctx: &mut EvalContext) -> TypResult<Self::Output> { self.items() - .map(|x| Ok((x.name().take().into(), x.expr().eval(ctx)?))) + .map(|x| Ok((x.name().take(), x.expr().eval(ctx)?))) .collect() } } @@ -401,7 +400,7 @@ impl Eval for CallArgs { CallArg::Named(named) => { items.push(Arg { span, - name: Some(named.name().take().into()), + name: Some(named.name().take()), value: Spanned::new(named.expr().eval(ctx)?, named.expr().span()), }); } @@ -600,7 +599,7 @@ impl Eval for ForExpr { match (key, value, iter) { (None, v, Value::Str(string)) => { - iter!(for (v => value) in string.iter()); + iter!(for (v => value) in string.graphemes(true)); } (None, v, Value::Array(array)) => { iter!(for (v => value) in array.into_iter()); @@ -629,7 +628,7 @@ impl Eval for ImportExpr { fn eval(&self, ctx: &mut EvalContext) -> TypResult<Self::Output> { let path = self.path(); - let resolved = path.eval(ctx)?.cast::<Str>().at(path.span())?; + let resolved = path.eval(ctx)?.cast::<EcoString>().at(path.span())?; let file = ctx.import(&resolved, path.span())?; let module = &ctx.modules[&file]; @@ -659,7 +658,7 @@ impl Eval for IncludeExpr { fn eval(&self, ctx: &mut EvalContext) -> TypResult<Self::Output> { let path = self.path(); - let resolved = path.eval(ctx)?.cast::<Str>().at(path.span())?; + let resolved = path.eval(ctx)?.cast::<EcoString>().at(path.span())?; let file = ctx.import(&resolved, path.span())?; let module = &ctx.modules[&file]; Ok(Value::Template(module.template.clone())) diff --git a/src/eval/ops.rs b/src/eval/ops.rs index 732bfb14..e40fa78d 100644 --- a/src/eval/ops.rs +++ b/src/eval/ops.rs @@ -1,7 +1,9 @@ use std::cmp::Ordering; +use std::convert::TryFrom; use super::Value; use crate::diag::StrResult; +use crate::util::EcoString; use Value::*; /// Bail with a type mismatch error. @@ -150,8 +152,8 @@ pub fn mul(lhs: Value, rhs: Value) -> StrResult<Value> { (Fractional(a), Float(b)) => Fractional(a * b), (Int(a), Fractional(b)) => Fractional(a as f64 * b), - (Str(a), Int(b)) => Str(a.repeat(b)?), - (Int(a), Str(b)) => Str(b.repeat(a)?), + (Str(a), Int(b)) => Str(repeat_str(a, b)?), + (Int(a), Str(b)) => Str(repeat_str(b, a)?), (Array(a), Int(b)) => Array(a.repeat(b)?), (Int(a), Array(b)) => Array(b.repeat(a)?), (Template(a), Int(b)) => Template(a.repeat(b)?), @@ -161,6 +163,16 @@ pub fn mul(lhs: Value, rhs: Value) -> StrResult<Value> { }) } +/// Repeat a string a number of times. +fn repeat_str(string: EcoString, n: i64) -> StrResult<EcoString> { + let n = usize::try_from(n) + .ok() + .and_then(|n| string.len().checked_mul(n).map(|_| n)) + .ok_or_else(|| format!("cannot repeat this string {} times", n))?; + + Ok(string.repeat(n)) +} + /// Compute the quotient of two values. pub fn div(lhs: Value, rhs: Value) -> StrResult<Value> { Ok(match (lhs, rhs) { diff --git a/src/eval/str.rs b/src/eval/str.rs deleted file mode 100644 index 800d1709..00000000 --- a/src/eval/str.rs +++ /dev/null @@ -1,164 +0,0 @@ -use std::borrow::Borrow; -use std::convert::TryFrom; -use std::fmt::{self, Debug, Formatter, Write}; -use std::ops::{Add, AddAssign, Deref}; - -use unicode_segmentation::UnicodeSegmentation; - -use crate::diag::StrResult; -use crate::util::EcoString; - -/// Create a new [`Str`] from a format string. -macro_rules! format_str { - ($($tts:tt)*) => {{ - use std::fmt::Write; - let mut s = $crate::eval::Str::new(); - write!(s, $($tts)*).unwrap(); - s - }}; -} - -/// A string value with inline storage and clone-on-write semantics. -#[derive(Default, Clone, Eq, PartialEq, Ord, PartialOrd)] -pub struct Str(EcoString); - -impl Str { - /// Create a new, empty string. - pub fn new() -> Self { - Self::default() - } - - /// Whether the string is empty. - pub fn is_empty(&self) -> bool { - self.0.is_empty() - } - - /// The length of the string in bytes. - pub fn len(&self) -> i64 { - self.0.len() as i64 - } - - /// Borrow this as a string slice. - pub fn as_str(&self) -> &str { - self.0.as_str() - } - - /// Return an iterator over the grapheme clusters as strings. - pub fn iter(&self) -> impl Iterator<Item = Str> + '_ { - self.graphemes(true).map(Into::into) - } - - /// Repeat this string `n` times. - pub fn repeat(&self, n: i64) -> StrResult<Self> { - let n = usize::try_from(n) - .ok() - .and_then(|n| self.0.len().checked_mul(n).map(|_| n)) - .ok_or_else(|| format!("cannot repeat this string {} times", n))?; - - Ok(self.0.repeat(n).into()) - } -} - -impl Deref for Str { - type Target = str; - - fn deref(&self) -> &str { - self.0.deref() - } -} - -impl Debug for Str { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - f.write_char('"')?; - for c in self.chars() { - match c { - '\\' => f.write_str(r"\\")?, - '"' => f.write_str(r#"\""#)?, - '\n' => f.write_str(r"\n")?, - '\r' => f.write_str(r"\r")?, - '\t' => f.write_str(r"\t")?, - _ => f.write_char(c)?, - } - } - f.write_char('"') - } -} - -impl Add for Str { - type Output = Self; - - fn add(mut self, rhs: Self) -> Self::Output { - self += rhs; - self - } -} - -impl AddAssign for Str { - fn add_assign(&mut self, rhs: Self) { - self.0.push_str(rhs.as_str()); - } -} - -impl Write for Str { - fn write_str(&mut self, s: &str) -> fmt::Result { - self.0.write_str(s) - } - - fn write_char(&mut self, c: char) -> fmt::Result { - self.0.write_char(c) - } -} - -impl AsRef<str> for Str { - fn as_ref(&self) -> &str { - self - } -} - -impl Borrow<str> for Str { - fn borrow(&self) -> &str { - self - } -} - -impl From<char> for Str { - fn from(c: char) -> Self { - Self(c.into()) - } -} - -impl From<&str> for Str { - fn from(s: &str) -> Self { - Self(s.into()) - } -} - -impl From<String> for Str { - fn from(s: String) -> Self { - Self(s.into()) - } -} - -impl From<EcoString> for Str { - fn from(s: EcoString) -> Self { - Self(s) - } -} - -impl From<&EcoString> for Str { - fn from(s: &EcoString) -> Self { - Self(s.clone()) - } -} - -impl From<Str> for EcoString { - fn from(s: Str) -> Self { - s.0 - } -} - -impl From<&Str> for EcoString { - fn from(s: &Str) -> Self { - s.0.clone() - } -} diff --git a/src/eval/template.rs b/src/eval/template.rs index 2622a1f0..18104638 100644 --- a/src/eval/template.rs +++ b/src/eval/template.rs @@ -5,7 +5,6 @@ use std::mem; use std::ops::{Add, AddAssign}; use std::rc::Rc; -use super::Str; use crate::diag::StrResult; use crate::geom::{Align, Dir, GenAxis, Length, Linear, Sides, Size}; use crate::layout::{BlockLevel, BlockNode, InlineLevel, InlineNode, PageNode}; @@ -214,20 +213,20 @@ impl AddAssign for Template { } } -impl Add<Str> for Template { +impl Add<EcoString> for Template { type Output = Self; - fn add(mut self, rhs: Str) -> Self::Output { - Rc::make_mut(&mut self.0).push(TemplateNode::Text(rhs.into())); + fn add(mut self, rhs: EcoString) -> Self::Output { + Rc::make_mut(&mut self.0).push(TemplateNode::Text(rhs)); self } } -impl Add<Template> for Str { +impl Add<Template> for EcoString { type Output = Template; fn add(self, mut rhs: Template) -> Self::Output { - Rc::make_mut(&mut rhs.0).insert(0, TemplateNode::Text(self.into())); + Rc::make_mut(&mut rhs.0).insert(0, TemplateNode::Text(self)); rhs } } @@ -491,7 +490,7 @@ impl ParBuilder { self.children.last_mut() { if prev_align == curr_align && Rc::ptr_eq(prev_props, curr_props) { - prev_text.push_str(&curr_text); + prev_text.push_str(curr_text); return; } } diff --git a/src/eval/value.rs b/src/eval/value.rs index 804f8d55..0fcc4bfc 100644 --- a/src/eval/value.rs +++ b/src/eval/value.rs @@ -3,7 +3,7 @@ use std::cmp::Ordering; use std::fmt::{self, Debug, Formatter}; use std::rc::Rc; -use super::{ops, Array, Dict, Function, Str, Template}; +use super::{ops, Array, Dict, Function, Template}; use crate::diag::StrResult; use crate::geom::{Angle, Color, Fractional, Length, Linear, Relative, RgbaColor}; use crate::syntax::Spanned; @@ -35,7 +35,7 @@ pub enum Value { /// A color value: `#f79143ff`. Color(Color), /// A string: `"string"`. - Str(Str), + Str(EcoString), /// An array of values: `(1, "hi", 12cm)`. Array(Array), /// A dictionary value: `(color: #f79143, pattern: dashed)`. @@ -63,7 +63,7 @@ impl Value { Self::Linear(_) => Linear::TYPE_NAME, Self::Fractional(_) => Fractional::TYPE_NAME, Self::Color(_) => Color::TYPE_NAME, - Self::Str(_) => Str::TYPE_NAME, + Self::Str(_) => EcoString::TYPE_NAME, Self::Array(_) => Array::TYPE_NAME, Self::Dict(_) => Dict::TYPE_NAME, Self::Template(_) => Template::TYPE_NAME, @@ -81,8 +81,8 @@ impl Value { } /// Return the debug representation of the value. - pub fn repr(&self) -> Str { - format_str!("{:?}", self) + pub fn repr(&self) -> EcoString { + format_eco!("{:?}", self) } /// Join the value with another value. @@ -163,17 +163,12 @@ impl From<String> for Value { } } -impl From<EcoString> for Value { - fn from(v: EcoString) -> Self { - Self::Str(v.into()) - } -} - impl From<Dynamic> for Value { fn from(v: Dynamic) -> Self { Self::Dyn(v) } } + /// A dynamic value. #[derive(Clone)] pub struct Dynamic(Rc<dyn Bounds>); @@ -338,7 +333,8 @@ macro_rules! dynamic { } castable! { - $type: <Self as $crate::eval::Type>::TYPE_NAME, + $type, + Expected: <Self as $crate::eval::Type>::TYPE_NAME, $($tts)* @this: Self => this.clone(), } @@ -354,8 +350,8 @@ macro_rules! dynamic { /// Make a type castable from a value. macro_rules! castable { ( - $type:ty: - $expected:expr, + $type:ty, + Expected: $expected:expr, $($pattern:pat => $out:expr,)* $(@$dyn_in:ident: $dyn_type:ty => $dyn_out:expr,)* ) => { @@ -398,7 +394,7 @@ primitive! { Relative: "relative", Relative } primitive! { Linear: "linear", Linear, Length(v) => v.into(), Relative(v) => v.into() } primitive! { Fractional: "fractional", Fractional } primitive! { Color: "color", Color } -primitive! { Str: "string", Str } +primitive! { EcoString: "string", Str } primitive! { Array: "array", Array } primitive! { Dict: "dictionary", Dict } primitive! { Template: "template", Template } diff --git a/src/eval/walk.rs b/src/eval/walk.rs index aab32f40..6d5df5ba 100644 --- a/src/eval/walk.rs +++ b/src/eval/walk.rs @@ -1,12 +1,12 @@ use std::rc::Rc; -use super::{Eval, EvalContext, Str, Template, Value}; +use super::{Eval, EvalContext, Template, Value}; use crate::diag::TypResult; use crate::geom::Spec; use crate::layout::BlockLevel; use crate::library::{GridNode, ParChild, ParNode, TrackSizing}; use crate::syntax::ast::*; -use crate::util::BoolExt; +use crate::util::{BoolExt, EcoString}; /// Walk markup, filling the currently built template. pub trait Walk { @@ -39,8 +39,8 @@ impl Walk for MarkupNode { Self::Enum(enum_) => enum_.walk(ctx)?, Self::Expr(expr) => match expr.eval(ctx)? { Value::None => {} - Value::Int(v) => ctx.template.text(format_str!("{}", v)), - Value::Float(v) => ctx.template.text(format_str!("{}", v)), + Value::Int(v) => ctx.template.text(format_eco!("{}", v)), + Value::Float(v) => ctx.template.text(format_eco!("{}", v)), Value::Str(v) => ctx.template.text(v), Value::Template(v) => ctx.template += v, // For values which can't be shown "naturally", we print the @@ -108,7 +108,7 @@ impl Walk for HeadingNode { impl Walk for ListNode { fn walk(&self, ctx: &mut EvalContext) -> TypResult<()> { let body = self.body().eval(ctx)?; - walk_item(ctx, Str::from('•'), body); + walk_item(ctx, EcoString::from('•'), body); Ok(()) } } @@ -116,19 +116,19 @@ impl Walk for ListNode { impl Walk for EnumNode { fn walk(&self, ctx: &mut EvalContext) -> TypResult<()> { let body = self.body().eval(ctx)?; - let label = format_str!("{}.", self.number().unwrap_or(1)); + let label = format_eco!("{}.", self.number().unwrap_or(1)); walk_item(ctx, label, body); Ok(()) } } -fn walk_item(ctx: &mut EvalContext, label: Str, body: Template) { +fn walk_item(ctx: &mut EvalContext, label: EcoString, body: Template) { ctx.template += Template::from_block(move |style| { let label = ParNode { dir: style.dir, leading: style.leading(), children: vec![ParChild::Text( - (&label).into(), + label.clone(), style.aligns.inline, Rc::clone(&style.text), )], @@ -138,7 +138,7 @@ fn walk_item(ctx: &mut EvalContext, label: Str, body: Template) { GridNode { tracks: Spec::new(vec![TrackSizing::Auto; 2], vec![]), gutter: Spec::new(vec![TrackSizing::Linear(spacing.into())], vec![]), - children: vec![label.pack(), body.to_stack(&style).pack()], + children: vec![label.pack(), body.to_stack(style).pack()], } }); } |
