summaryrefslogtreecommitdiff
path: root/src/syntax/lit.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/syntax/lit.rs')
-rw-r--r--src/syntax/lit.rs99
1 files changed, 99 insertions, 0 deletions
diff --git a/src/syntax/lit.rs b/src/syntax/lit.rs
new file mode 100644
index 00000000..e9807a17
--- /dev/null
+++ b/src/syntax/lit.rs
@@ -0,0 +1,99 @@
+//! Literals.
+
+use super::{Expr, Ident, SpanWith, Spanned, SynTree};
+use crate::color::RgbaColor;
+use crate::compute::dict::{DictKey, SpannedEntry};
+use crate::compute::value::{DictValue, Value};
+use crate::layout::LayoutContext;
+use crate::length::Length;
+use crate::{DynFuture, Feedback};
+
+/// A literal.
+#[derive(Debug, Clone, PartialEq)]
+pub enum Lit {
+ /// A identifier literal: `left`.
+ Ident(Ident),
+ /// A boolean literal: `true`, `false`.
+ Bool(bool),
+ /// An integer literal: `120`.
+ Int(i64),
+ /// A floating-point literal: `1.2`, `10e-4`.
+ Float(f64),
+ /// A percent literal: `50%`.
+ Percent(f64),
+ /// A length literal: `12pt`, `3cm`.
+ Length(Length),
+ /// A color literal: `#ffccee`.
+ Color(RgbaColor),
+ /// A string literal: `"hello!"`.
+ Str(String),
+ /// A dictionary literal: `(false, 12cm, greeting = "hi")`.
+ Dict(LitDict),
+ /// A content literal: `{*Hello* there!}`.
+ Content(SynTree),
+}
+
+impl Lit {
+ /// Evaluate the dictionary literal to a dictionary value.
+ pub async fn eval<'a>(
+ &'a self,
+ ctx: &'a LayoutContext<'a>,
+ f: &'a mut Feedback,
+ ) -> Value {
+ match *self {
+ Lit::Ident(ref i) => Value::Ident(i.clone()),
+ Lit::Bool(b) => Value::Bool(b),
+ Lit::Int(i) => Value::Number(i as f64),
+ Lit::Float(f) => Value::Number(f as f64),
+ Lit::Percent(p) => Value::Number(p as f64 / 100.0),
+ Lit::Length(l) => Value::Length(l),
+ Lit::Color(c) => Value::Color(c),
+ Lit::Str(ref s) => Value::Str(s.clone()),
+ Lit::Dict(ref d) => Value::Dict(d.eval(ctx, f).await),
+ Lit::Content(ref c) => Value::Tree(c.clone()),
+ }
+ }
+}
+
+/// A dictionary literal: `(false, 12cm, greeting = "hi")`.
+#[derive(Debug, Default, Clone, PartialEq)]
+pub struct LitDict(pub Vec<LitDictEntry>);
+
+impl LitDict {
+ /// Create an empty dict literal.
+ pub fn new() -> Self {
+ Self(vec![])
+ }
+
+ /// Evaluate the dictionary literal to a dictionary value.
+ pub fn eval<'a>(
+ &'a self,
+ ctx: &'a LayoutContext<'a>,
+ f: &'a mut Feedback,
+ ) -> DynFuture<'a, DictValue> {
+ Box::pin(async move {
+ let mut dict = DictValue::new();
+
+ for entry in &self.0 {
+ let val = entry.value.v.eval(ctx, f).await;
+ let spanned = val.span_with(entry.value.span);
+ if let Some(key) = &entry.key {
+ dict.insert(&key.v, SpannedEntry::new(key.span, spanned));
+ } else {
+ dict.push(SpannedEntry::val(spanned));
+ }
+ }
+
+ dict
+ })
+ }
+}
+
+/// An entry in a dictionary literal: `false` or `greeting = "hi"`.
+#[derive(Debug, Clone, PartialEq)]
+pub struct LitDictEntry {
+ /// The key of the entry if there was one: `greeting`.
+ pub key: Option<Spanned<DictKey>>,
+ /// The value of the entry: `"hi"`.
+ pub value: Spanned<Expr>,
+}