diff options
Diffstat (limited to 'src/eval')
| -rw-r--r-- | src/eval/array.rs | 12 | ||||
| -rw-r--r-- | src/eval/capture.rs | 1 | ||||
| -rw-r--r-- | src/eval/dict.rs | 24 | ||||
| -rw-r--r-- | src/eval/function.rs | 12 | ||||
| -rw-r--r-- | src/eval/mod.rs | 135 | ||||
| -rw-r--r-- | src/eval/scope.rs | 4 | ||||
| -rw-r--r-- | src/eval/state.rs | 6 | ||||
| -rw-r--r-- | src/eval/str.rs | 30 | ||||
| -rw-r--r-- | src/eval/template.rs | 14 | ||||
| -rw-r--r-- | src/eval/value.rs | 48 | ||||
| -rw-r--r-- | src/eval/walk.rs | 129 |
11 files changed, 209 insertions, 206 deletions
diff --git a/src/eval/array.rs b/src/eval/array.rs index e554b11e..acf44ab2 100644 --- a/src/eval/array.rs +++ b/src/eval/array.rs @@ -137,18 +137,18 @@ impl AddAssign for Array { } } -impl FromIterator<Value> for Array { - fn from_iter<T: IntoIterator<Item = Value>>(iter: T) -> Self { - Self(Rc::new(iter.into_iter().collect())) - } -} - impl Extend<Value> for Array { fn extend<T: IntoIterator<Item = Value>>(&mut self, iter: T) { Rc::make_mut(&mut self.0).extend(iter); } } +impl FromIterator<Value> for Array { + fn from_iter<T: IntoIterator<Item = Value>>(iter: T) -> Self { + Self(Rc::new(iter.into_iter().collect())) + } +} + impl IntoIterator for Array { type Item = Value; type IntoIter = std::vec::IntoIter<Value>; diff --git a/src/eval/capture.rs b/src/eval/capture.rs index a6e543f9..f0a2b729 100644 --- a/src/eval/capture.rs +++ b/src/eval/capture.rs @@ -5,7 +5,6 @@ use crate::syntax::visit::{immutable::visit_expr, Visit}; use crate::syntax::{Expr, Ident}; /// A visitor that captures variable slots. -#[derive(Debug)] pub struct CapturesVisitor<'a> { external: &'a Scopes<'a>, internal: Scopes<'a>, diff --git a/src/eval/dict.rs b/src/eval/dict.rs index 66baaec0..dfac04ed 100644 --- a/src/eval/dict.rs +++ b/src/eval/dict.rs @@ -82,6 +82,12 @@ fn missing_key(key: &Str) -> String { format!("dictionary does not contain key: {}", key) } +impl Debug for Dict { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + f.debug_map().entries(self.0.iter()).finish() + } +} + impl Display for Dict { fn fmt(&self, f: &mut Formatter) -> fmt::Result { f.write_char('(')?; @@ -100,12 +106,6 @@ impl Display for Dict { } } -impl Debug for Dict { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - f.debug_map().entries(self.0.iter()).finish() - } -} - impl Add for Dict { type Output = Self; @@ -124,18 +124,18 @@ impl AddAssign for Dict { } } -impl FromIterator<(Str, Value)> for Dict { - fn from_iter<T: IntoIterator<Item = (Str, Value)>>(iter: T) -> Self { - Self(Rc::new(iter.into_iter().collect())) - } -} - impl Extend<(Str, Value)> for Dict { fn extend<T: IntoIterator<Item = (Str, 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 { + Self(Rc::new(iter.into_iter().collect())) + } +} + impl IntoIterator for Dict { type Item = (Str, Value); type IntoIter = std::collections::btree_map::IntoIter<Str, Value>; diff --git a/src/eval/function.rs b/src/eval/function.rs index 7967090b..57364d11 100644 --- a/src/eval/function.rs +++ b/src/eval/function.rs @@ -38,6 +38,12 @@ impl Function { } } +impl Debug for Function { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + f.debug_struct("Function").field("name", &self.0.name).finish() + } +} + impl Display for Function { fn fmt(&self, f: &mut Formatter) -> fmt::Result { f.write_str("<function")?; @@ -49,12 +55,6 @@ impl Display for Function { } } -impl Debug for Function { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - f.debug_struct("Function").field("name", &self.0.name).finish() - } -} - impl PartialEq for Function { fn eq(&self, other: &Self) -> bool { // We cast to thin pointers for comparison. diff --git a/src/eval/mod.rs b/src/eval/mod.rs index f7a32127..b8561a87 100644 --- a/src/eval/mod.rs +++ b/src/eval/mod.rs @@ -13,6 +13,7 @@ mod scope; mod state; mod str; mod template; +mod walk; pub use self::str::*; pub use array::*; @@ -23,25 +24,24 @@ pub use scope::*; pub use state::*; pub use template::*; pub use value::*; +pub use walk::*; use std::cell::RefMut; use std::collections::HashMap; -use std::fmt::Write; use std::io; use std::mem; use std::path::PathBuf; use std::rc::Rc; use crate::diag::{At, Error, StrResult, Trace, Tracepoint, TypResult}; -use crate::geom::{Angle, Fractional, Gen, Length, Relative}; +use crate::geom::{Angle, Fractional, Length, Relative}; use crate::image::ImageStore; -use crate::layout::{ParChild, ParNode, StackChild, StackNode}; use crate::loading::Loader; use crate::parse::parse; use crate::source::{SourceId, SourceStore}; use crate::syntax::visit::Visit; use crate::syntax::*; -use crate::util::{EcoString, RefMutExt}; +use crate::util::RefMutExt; use crate::Context; /// Evaluate a parsed source file into a module. @@ -52,7 +52,7 @@ pub fn eval(ctx: &mut Context, source: SourceId, ast: &SyntaxTree) -> TypResult< } /// An evaluated module, ready for importing or instantiation. -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Default, Clone)] pub struct Module { /// The top-level definitions that were bound in this module. pub scope: Scope, @@ -717,128 +717,3 @@ impl Access for CallExpr { }) } } - -/// Walk a syntax node and fill the currently built template. -pub trait Walk { - /// Walk the node. - fn walk(&self, ctx: &mut EvalContext) -> TypResult<()>; -} - -impl Walk for SyntaxTree { - fn walk(&self, ctx: &mut EvalContext) -> TypResult<()> { - for node in self.iter() { - node.walk(ctx)?; - } - Ok(()) - } -} - -impl Walk for SyntaxNode { - fn walk(&self, ctx: &mut EvalContext) -> TypResult<()> { - match self { - Self::Space => ctx.template.space(), - Self::Linebreak(_) => ctx.template.linebreak(), - Self::Parbreak(_) => ctx.template.parbreak(), - Self::Strong(_) => { - ctx.template.modify(|state| state.font_mut().strong ^= true); - } - Self::Emph(_) => { - ctx.template.modify(|state| state.font_mut().emph ^= true); - } - Self::Text(text) => ctx.template.text(text), - Self::Raw(raw) => raw.walk(ctx)?, - Self::Heading(heading) => heading.walk(ctx)?, - Self::List(list) => list.walk(ctx)?, - Self::Enum(enum_) => enum_.walk(ctx)?, - Self::Expr(expr) => match expr.eval(ctx)? { - Value::None => {} - Value::Int(v) => ctx.template.text(v.to_string()), - Value::Float(v) => ctx.template.text(v.to_string()), - Value::Str(v) => ctx.template.text(v), - Value::Template(v) => ctx.template += v, - // For values which can't be shown "naturally", we print the - // representation in monospace. - other => ctx.template.monospace(other.to_string()), - }, - } - Ok(()) - } -} - -impl Walk for RawNode { - fn walk(&self, ctx: &mut EvalContext) -> TypResult<()> { - if self.block { - ctx.template.parbreak(); - } - - ctx.template.monospace(&self.text); - - if self.block { - ctx.template.parbreak(); - } - - Ok(()) - } -} - -impl Walk for HeadingNode { - fn walk(&self, ctx: &mut EvalContext) -> TypResult<()> { - let level = self.level; - let body = self.body.eval(ctx)?; - - ctx.template.parbreak(); - ctx.template.save(); - ctx.template.modify(move |state| { - let font = state.font_mut(); - let upscale = 1.6 - 0.1 * level as f64; - font.size *= upscale; - font.strong = true; - }); - ctx.template += body; - ctx.template.restore(); - ctx.template.parbreak(); - - Ok(()) - } -} - -impl Walk for ListItem { - fn walk(&self, ctx: &mut EvalContext) -> TypResult<()> { - let body = self.body.eval(ctx)?; - walk_item(ctx, '•'.into(), body); - Ok(()) - } -} - -impl Walk for EnumItem { - fn walk(&self, ctx: &mut EvalContext) -> TypResult<()> { - let body = self.body.eval(ctx)?; - let mut label = EcoString::new(); - write!(&mut label, "{}.", self.number.unwrap_or(1)).unwrap(); - walk_item(ctx, label, body); - Ok(()) - } -} - -/// Walk a list or enum item, converting it into a stack. -fn walk_item(ctx: &mut EvalContext, label: EcoString, body: Template) { - ctx.template += Template::from_block(move |state| { - let label = ParNode { - dir: state.dirs.cross, - line_spacing: state.line_spacing(), - children: vec![ParChild::Text( - label.clone(), - state.aligns.cross, - Rc::clone(&state.font), - )], - }; - StackNode { - dirs: Gen::new(state.dirs.main, state.dirs.cross), - children: vec![ - StackChild::Any(label.into(), Gen::default()), - StackChild::Spacing((state.font.size / 2.0).into()), - StackChild::Any(body.to_stack(&state).into(), Gen::default()), - ], - } - }); -} diff --git a/src/eval/scope.rs b/src/eval/scope.rs index 2968ca20..0d701687 100644 --- a/src/eval/scope.rs +++ b/src/eval/scope.rs @@ -12,7 +12,7 @@ use crate::util::EcoString; pub type Slot = Rc<RefCell<Value>>; /// A stack of scopes. -#[derive(Debug, Default, Clone, PartialEq)] +#[derive(Debug, Default, Clone)] pub struct Scopes<'a> { /// The active scope. pub top: Scope, @@ -65,7 +65,7 @@ impl<'a> Scopes<'a> { } /// A map from variable names to variable slots. -#[derive(Default, Clone, PartialEq)] +#[derive(Default, Clone)] pub struct Scope { /// The mapping from names to slots. values: HashMap<EcoString, Slot>, diff --git a/src/eval/state.rs b/src/eval/state.rs index 760a830a..05558915 100644 --- a/src/eval/state.rs +++ b/src/eval/state.rs @@ -63,7 +63,7 @@ impl Default for State { } /// Defines page properties. -#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] +#[derive(Debug, Clone, Eq, PartialEq, Hash)] pub struct PageState { /// The class of this page. pub class: PaperClass, @@ -220,7 +220,7 @@ impl Default for FontState { } /// Font family definitions. -#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] +#[derive(Debug, Clone, Eq, PartialEq, Hash)] pub struct FamilyState { /// The user-defined list of font families. pub list: Rc<Vec<FontFamily>>, @@ -250,7 +250,7 @@ impl Default for FamilyState { } /// Defines a line that is positioned over, under or on top of text. -#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] +#[derive(Debug, Clone, Eq, PartialEq, Hash)] pub struct LineState { /// Stroke color of the line, defaults to the text color if `None`. pub stroke: Option<Paint>, diff --git a/src/eval/str.rs b/src/eval/str.rs index 1a0e3e1f..a358cd9f 100644 --- a/src/eval/str.rs +++ b/src/eval/str.rs @@ -6,7 +6,7 @@ use crate::diag::StrResult; use crate::util::EcoString; /// A string value with inline storage and clone-on-write semantics. -#[derive(Default, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] +#[derive(Default, Clone, Eq, PartialEq, Ord, PartialOrd)] pub struct Str(EcoString); impl Str { @@ -46,6 +46,20 @@ impl Str { } } +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 { + Debug::fmt(&self.0, f) + } +} + impl Display for Str { fn fmt(&self, f: &mut Formatter) -> fmt::Result { f.write_char('"')?; @@ -63,20 +77,6 @@ impl Display for Str { } } -impl Debug for Str { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - Debug::fmt(&self.0, f) - } -} - -impl Deref for Str { - type Target = str; - - fn deref(&self) -> &str { - self.0.deref() - } -} - impl Add for Str { type Output = Self; diff --git a/src/eval/template.rs b/src/eval/template.rs index 2293796b..92b3eb86 100644 --- a/src/eval/template.rs +++ b/src/eval/template.rs @@ -160,15 +160,15 @@ impl Template { } } -impl Display for Template { +impl Debug for Template { fn fmt(&self, f: &mut Formatter) -> fmt::Result { - f.pad("<template>") + f.pad("Template { .. }") } } -impl Debug for Template { +impl Display for Template { fn fmt(&self, f: &mut Formatter) -> fmt::Result { - f.pad("Template { .. }") + f.pad("<template>") } } @@ -465,11 +465,11 @@ impl ParBuilder { } fn push_inner(&mut self, child: ParChild) { - if let ParChild::Text(curr_text, curr_props, curr_align) = &child { - if let Some(ParChild::Text(prev_text, prev_props, prev_align)) = + if let ParChild::Text(curr_text, curr_align, curr_props) = &child { + if let Some(ParChild::Text(prev_text, prev_align, prev_props)) = self.children.last_mut() { - if prev_align == curr_align && prev_props == curr_props { + if prev_align == curr_align && Rc::ptr_eq(prev_props, curr_props) { prev_text.push_str(&curr_text); return; } diff --git a/src/eval/value.rs b/src/eval/value.rs index 99efc2e5..5edf0362 100644 --- a/src/eval/value.rs +++ b/src/eval/value.rs @@ -144,6 +144,12 @@ impl From<usize> for Value { } } +impl From<RgbaColor> for Value { + fn from(v: RgbaColor) -> Self { + Self::Color(Color::Rgba(v)) + } +} + impl From<&str> for Value { fn from(v: &str) -> Self { Self::Str(v.into()) @@ -162,12 +168,6 @@ impl From<EcoString> for Value { } } -impl From<RgbaColor> for Value { - fn from(v: RgbaColor) -> Self { - Self::Color(Color::Rgba(v)) - } -} - impl From<Dynamic> for Value { fn from(v: Dynamic) -> Self { Self::Dyn(v) @@ -181,7 +181,7 @@ impl Dynamic { /// Create a new instance from any value that satisifies the required bounds. pub fn new<T>(any: T) -> Self where - T: Type + Debug + Display + Clone + PartialEq + 'static, + T: Type + Debug + Display + PartialEq + 'static, { Self(Rc::new(any)) } @@ -202,15 +202,15 @@ impl Dynamic { } } -impl Display for Dynamic { +impl Debug for Dynamic { fn fmt(&self, f: &mut Formatter) -> fmt::Result { - Display::fmt(&self.0, f) + Debug::fmt(&self.0, f) } } -impl Debug for Dynamic { +impl Display for Dynamic { fn fmt(&self, f: &mut Formatter) -> fmt::Result { - Debug::fmt(&self.0, f) + Display::fmt(&self.0, f) } } @@ -228,7 +228,7 @@ trait Bounds: Debug + Display + 'static { impl<T> Bounds for T where - T: Type + Debug + Display + Clone + PartialEq + 'static, + T: Type + Debug + Display + PartialEq + 'static, { fn as_any(&self) -> &dyn Any { self @@ -309,12 +309,6 @@ macro_rules! primitive { const TYPE_NAME: &'static str = $name; } - impl From<$type> for Value { - fn from(v: $type) -> Self { - Value::$variant(v) - } - } - impl Cast<Value> for $type { fn is(value: &Value) -> bool { matches!(value, Value::$variant(_) $(| Value::$other(_))*) @@ -332,6 +326,12 @@ macro_rules! primitive { } } } + + impl From<$type> for Value { + fn from(v: $type) -> Self { + Value::$variant(v) + } + } }; } @@ -342,17 +342,17 @@ macro_rules! dynamic { const TYPE_NAME: &'static str = $name; } - impl From<$type> for $crate::eval::Value { - fn from(v: $type) -> Self { - $crate::eval::Value::Dyn($crate::eval::Dynamic::new(v)) - } - } - castable! { $type: <Self as $crate::eval::Type>::TYPE_NAME, $($tts)* @this: Self => this.clone(), } + + impl From<$type> for $crate::eval::Value { + fn from(v: $type) -> Self { + $crate::eval::Value::Dyn($crate::eval::Dynamic::new(v)) + } + } }; } diff --git a/src/eval/walk.rs b/src/eval/walk.rs new file mode 100644 index 00000000..4c6a1605 --- /dev/null +++ b/src/eval/walk.rs @@ -0,0 +1,129 @@ +use std::fmt::Write; +use std::rc::Rc; + +use super::{Eval, EvalContext, Template, Value}; +use crate::diag::TypResult; +use crate::geom::Gen; +use crate::layout::{ParChild, ParNode, StackChild, StackNode}; +use crate::syntax::*; +use crate::util::EcoString; + +/// Walk a syntax node and fill the currently built template. +pub trait Walk { + /// Walk the node. + fn walk(&self, ctx: &mut EvalContext) -> TypResult<()>; +} + +impl Walk for SyntaxTree { + fn walk(&self, ctx: &mut EvalContext) -> TypResult<()> { + for node in self.iter() { + node.walk(ctx)?; + } + Ok(()) + } +} + +impl Walk for SyntaxNode { + fn walk(&self, ctx: &mut EvalContext) -> TypResult<()> { + match self { + Self::Space => ctx.template.space(), + Self::Linebreak(_) => ctx.template.linebreak(), + Self::Parbreak(_) => ctx.template.parbreak(), + Self::Strong(_) => ctx.template.modify(|s| s.font_mut().strong ^= true), + Self::Emph(_) => ctx.template.modify(|s| s.font_mut().emph ^= true), + Self::Text(text) => ctx.template.text(text), + Self::Raw(raw) => raw.walk(ctx)?, + Self::Heading(heading) => heading.walk(ctx)?, + Self::List(list) => list.walk(ctx)?, + Self::Enum(enum_) => enum_.walk(ctx)?, + Self::Expr(expr) => match expr.eval(ctx)? { + Value::None => {} + Value::Int(v) => ctx.template.text(v.to_string()), + Value::Float(v) => ctx.template.text(v.to_string()), + Value::Str(v) => ctx.template.text(v), + Value::Template(v) => ctx.template += v, + // For values which can't be shown "naturally", we print the + // representation in monospace. + other => ctx.template.monospace(other.to_string()), + }, + } + Ok(()) + } +} + +impl Walk for RawNode { + fn walk(&self, ctx: &mut EvalContext) -> TypResult<()> { + if self.block { + ctx.template.parbreak(); + } + + ctx.template.monospace(&self.text); + + if self.block { + ctx.template.parbreak(); + } + + Ok(()) + } +} + +impl Walk for HeadingNode { + fn walk(&self, ctx: &mut EvalContext) -> TypResult<()> { + let level = self.level; + let body = self.body.eval(ctx)?; + + ctx.template.parbreak(); + ctx.template.save(); + ctx.template.modify(move |state| { + let font = state.font_mut(); + let upscale = 1.6 - 0.1 * level as f64; + font.size *= upscale; + font.strong = true; + }); + ctx.template += body; + ctx.template.restore(); + ctx.template.parbreak(); + + Ok(()) + } +} + +impl Walk for ListNode { + fn walk(&self, ctx: &mut EvalContext) -> TypResult<()> { + let body = self.body.eval(ctx)?; + walk_item(ctx, '•'.into(), body); + Ok(()) + } +} + +impl Walk for EnumNode { + fn walk(&self, ctx: &mut EvalContext) -> TypResult<()> { + let body = self.body.eval(ctx)?; + let mut label = EcoString::new(); + write!(&mut label, "{}.", self.number.unwrap_or(1)).unwrap(); + walk_item(ctx, label, body); + Ok(()) + } +} + +fn walk_item(ctx: &mut EvalContext, label: EcoString, body: Template) { + ctx.template += Template::from_block(move |state| { + let label = ParNode { + dir: state.dirs.cross, + line_spacing: state.line_spacing(), + children: vec![ParChild::Text( + label.clone(), + state.aligns.cross, + Rc::clone(&state.font), + )], + }; + StackNode { + dirs: Gen::new(state.dirs.main, state.dirs.cross), + children: vec![ + StackChild::Any(label.into(), Gen::default()), + StackChild::Spacing((state.font.size / 2.0).into()), + StackChild::Any(body.to_stack(&state).into(), Gen::default()), + ], + } + }); +} |
