summaryrefslogtreecommitdiff
path: root/src/eval
diff options
context:
space:
mode:
Diffstat (limited to 'src/eval')
-rw-r--r--src/eval/array.rs12
-rw-r--r--src/eval/capture.rs1
-rw-r--r--src/eval/dict.rs24
-rw-r--r--src/eval/function.rs12
-rw-r--r--src/eval/mod.rs135
-rw-r--r--src/eval/scope.rs4
-rw-r--r--src/eval/state.rs6
-rw-r--r--src/eval/str.rs30
-rw-r--r--src/eval/template.rs14
-rw-r--r--src/eval/value.rs48
-rw-r--r--src/eval/walk.rs129
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()),
+ ],
+ }
+ });
+}