diff --git a/src/model/eval.rs b/src/model/eval.rs index 703028618..789df0c7b 100644 --- a/src/model/eval.rs +++ b/src/model/eval.rs @@ -270,8 +270,9 @@ impl Eval for ast::Expr { Self::SmartQuote(v) => v.eval(vm).map(Value::Content), Self::Strong(v) => v.eval(vm).map(Value::Content), Self::Emph(v) => v.eval(vm).map(Value::Content), - Self::Link(v) => v.eval(vm).map(Value::Content), Self::Raw(v) => v.eval(vm).map(Value::Content), + Self::Link(v) => v.eval(vm).map(Value::Content), + Self::Label(v) => v.eval(vm), Self::Ref(v) => v.eval(vm).map(Value::Content), Self::Heading(v) => v.eval(vm).map(Value::Content), Self::List(v) => v.eval(vm).map(Value::Content), @@ -281,8 +282,14 @@ impl Eval for ast::Expr { Self::Script(v) => v.eval(vm).map(Value::Content), Self::Frac(v) => v.eval(vm).map(Value::Content), Self::AlignPoint(v) => v.eval(vm).map(Value::Content), - Self::Lit(v) => v.eval(vm), Self::Ident(v) => v.eval(vm), + Self::None(v) => v.eval(vm), + Self::Auto(v) => v.eval(vm), + Self::Bool(v) => v.eval(vm), + Self::Int(v) => v.eval(vm), + Self::Float(v) => v.eval(vm), + Self::Numeric(v) => v.eval(vm), + Self::Str(v) => v.eval(vm), Self::Code(v) => v.eval(vm), Self::Content(v) => v.eval(vm).map(Value::Content), Self::Math(v) => v.eval(vm).map(Value::Content), @@ -435,6 +442,14 @@ impl Eval for ast::Link { } } +impl Eval for ast::Label { + type Output = Value; + + fn eval(&self, _: &mut Vm) -> SourceResult { + Ok(Value::Label(Label(self.get().clone()))) + } +} + impl Eval for ast::Ref { type Output = Content; @@ -531,29 +546,6 @@ impl Eval for ast::AlignPoint { } } -impl Eval for ast::Lit { - type Output = Value; - - fn eval(&self, _: &mut Vm) -> SourceResult { - Ok(match self.kind() { - ast::LitKind::None => Value::None, - ast::LitKind::Auto => Value::Auto, - ast::LitKind::Bool(v) => Value::Bool(v), - ast::LitKind::Int(v) => Value::Int(v), - ast::LitKind::Float(v) => Value::Float(v), - ast::LitKind::Numeric(v, unit) => match unit { - Unit::Length(unit) => Abs::with_unit(v, unit).into(), - Unit::Angle(unit) => Angle::with_unit(v, unit).into(), - Unit::Em => Em::new(v).into(), - Unit::Fr => Fr::new(v).into(), - Unit::Percent => Ratio::new(v / 100.0).into(), - }, - ast::LitKind::Str(v) => Value::Str(v.into()), - ast::LitKind::Label(v) => Value::Label(Label(v)), - }) - } -} - impl Eval for ast::Ident { type Output = Value; @@ -578,6 +570,69 @@ impl ast::Ident { } } +impl Eval for ast::None { + type Output = Value; + + fn eval(&self, _: &mut Vm) -> SourceResult { + Ok(Value::None) + } +} + +impl Eval for ast::Auto { + type Output = Value; + + fn eval(&self, _: &mut Vm) -> SourceResult { + Ok(Value::Auto) + } +} + +impl Eval for ast::Bool { + type Output = Value; + + fn eval(&self, _: &mut Vm) -> SourceResult { + Ok(Value::Bool(self.get())) + } +} + +impl Eval for ast::Int { + type Output = Value; + + fn eval(&self, _: &mut Vm) -> SourceResult { + Ok(Value::Int(self.get())) + } +} + +impl Eval for ast::Float { + type Output = Value; + + fn eval(&self, _: &mut Vm) -> SourceResult { + Ok(Value::Float(self.get())) + } +} + +impl Eval for ast::Numeric { + type Output = Value; + + fn eval(&self, _: &mut Vm) -> SourceResult { + let (v, unit) = self.get(); + Ok(match unit { + Unit::Length(unit) => Abs::with_unit(v, unit).into(), + Unit::Angle(unit) => Angle::with_unit(v, unit).into(), + Unit::Em => Em::new(v).into(), + Unit::Fr => Fr::new(v).into(), + Unit::Percent => Ratio::new(v / 100.0).into(), + }) + } +} + +impl Eval for ast::Str { + type Output = Value; + + fn eval(&self, _: &mut Vm) -> SourceResult { + Ok(Value::Str(self.get().clone().into())) + } +} + impl Eval for ast::CodeBlock { type Output = Value; diff --git a/src/syntax/ast.rs b/src/syntax/ast.rs index 4ef0b2a61..3b3186e45 100644 --- a/src/syntax/ast.rs +++ b/src/syntax/ast.rs @@ -37,7 +37,7 @@ macro_rules! node { if matches!(node.kind(), $variants) { Some(Self(node.clone())) } else { - None + Option::None } } @@ -97,6 +97,8 @@ pub enum Expr { Raw(Raw), /// A hyperlink: `https://typst.org`. Link(Link), + /// A label: ``. + Label(Label), /// A reference: `@target`. Ref(Ref), /// A section heading: `= Introduction`. @@ -117,10 +119,22 @@ pub enum Expr { Frac(Frac), /// An alignment point in a math formula: `&`, `&&`. AlignPoint(AlignPoint), - /// A literal: `1`, `true`, ... - Lit(Lit), /// An identifier: `left`. Ident(Ident), + /// The `none` literal. + None(None), + /// The `auto` literal. + Auto(Auto), + /// A boolean: `true`, `false`. + Bool(Bool), + /// An integer: `120`. + Int(Int), + /// A floating-point number: `1.2`, `10e-4`. + Float(Float), + /// A numeric value with a unit: `12pt`, `3cm`, `2em`, `90deg`, `50%`. + Numeric(Numeric), + /// A quoted string: `"..."`. + Str(Str), /// A code block: `{ let x = 1; x + 2 }`. Code(CodeBlock), /// A content block: `[*Hi* there!]`. @@ -189,6 +203,7 @@ impl AstNode for Expr { SyntaxKind::Emph => node.cast().map(Self::Emph), SyntaxKind::Raw(_) => node.cast().map(Self::Raw), SyntaxKind::Link(_) => node.cast().map(Self::Link), + SyntaxKind::Label(_) => node.cast().map(Self::Label), SyntaxKind::Ref(_) => node.cast().map(Self::Ref), SyntaxKind::Heading => node.cast().map(Self::Heading), SyntaxKind::ListItem => node.cast().map(Self::List), @@ -200,6 +215,13 @@ impl AstNode for Expr { SyntaxKind::Frac => node.cast().map(Self::Frac), SyntaxKind::AlignPoint => node.cast().map(Self::AlignPoint), SyntaxKind::Ident(_) => node.cast().map(Self::Ident), + SyntaxKind::None => node.cast().map(Self::None), + SyntaxKind::Auto => node.cast().map(Self::Auto), + SyntaxKind::Bool(_) => node.cast().map(Self::Bool), + SyntaxKind::Int(_) => node.cast().map(Self::Int), + SyntaxKind::Float(_) => node.cast().map(Self::Float), + SyntaxKind::Numeric(_, _) => node.cast().map(Self::Numeric), + SyntaxKind::Str(_) => node.cast().map(Self::Str), SyntaxKind::CodeBlock => node.cast().map(Self::Code), SyntaxKind::ContentBlock => node.cast().map(Self::Content), SyntaxKind::Parenthesized => node.cast().map(Self::Parenthesized), @@ -222,7 +244,7 @@ impl AstNode for Expr { SyntaxKind::LoopBreak => node.cast().map(Self::Break), SyntaxKind::LoopContinue => node.cast().map(Self::Continue), SyntaxKind::FuncReturn => node.cast().map(Self::Return), - _ => node.cast().map(Self::Lit), + _ => Option::None, } } @@ -239,6 +261,7 @@ impl AstNode for Expr { Self::Emph(v) => v.as_untyped(), Self::Raw(v) => v.as_untyped(), Self::Link(v) => v.as_untyped(), + Self::Label(v) => v.as_untyped(), Self::Ref(v) => v.as_untyped(), Self::Heading(v) => v.as_untyped(), Self::List(v) => v.as_untyped(), @@ -249,10 +272,16 @@ impl AstNode for Expr { Self::Script(v) => v.as_untyped(), Self::Frac(v) => v.as_untyped(), Self::AlignPoint(v) => v.as_untyped(), - Self::Lit(v) => v.as_untyped(), + Self::Ident(v) => v.as_untyped(), + Self::None(v) => v.as_untyped(), + Self::Auto(v) => v.as_untyped(), + Self::Bool(v) => v.as_untyped(), + Self::Int(v) => v.as_untyped(), + Self::Float(v) => v.as_untyped(), + Self::Numeric(v) => v.as_untyped(), + Self::Str(v) => v.as_untyped(), Self::Code(v) => v.as_untyped(), Self::Content(v) => v.as_untyped(), - Self::Ident(v) => v.as_untyped(), Self::Array(v) => v.as_untyped(), Self::Dict(v) => v.as_untyped(), Self::Parenthesized(v) => v.as_untyped(), @@ -277,25 +306,6 @@ impl AstNode for Expr { } } -impl Expr { - /// Whether the expression can be shortened in markup with a hashtag. - pub fn has_short_form(&self) -> bool { - matches!( - self, - Self::Ident(_) - | Self::FuncCall(_) - | Self::Let(_) - | Self::Set(_) - | Self::Show(_) - | Self::Conditional(_) - | Self::While(_) - | Self::For(_) - | Self::Import(_) - | Self::Include(_) - ) - } -} - node! { /// Whitespace. Space @@ -463,6 +473,21 @@ impl Link { } } +node! { + /// A label: ``. + Label +} + +impl Label { + /// Get the label's text. + pub fn get(&self) -> &EcoString { + match self.0.kind() { + SyntaxKind::Label(v) => v, + _ => panic!("label is of wrong kind"), + } + } +} + node! { /// A reference: `@target`. Ref @@ -522,7 +547,7 @@ impl EnumItem { pub fn number(&self) -> Option { self.0.children().find_map(|node| match node.kind() { SyntaxKind::EnumNumbering(num) => Some(*num), - _ => None, + _ => Option::None, }) } @@ -649,53 +674,124 @@ impl AlignPoint { } node! { - /// A literal: `1`, `true`, ... - Lit: SyntaxKind::None - | SyntaxKind::Auto - | SyntaxKind::Bool(_) - | SyntaxKind::Int(_) - | SyntaxKind::Float(_) - | SyntaxKind::Numeric(_, _) - | SyntaxKind::Str(_) - | SyntaxKind::Label(_) + /// An identifier: `it`. + Ident } -impl Lit { - /// The kind of literal. - pub fn kind(&self) -> LitKind { - match *self.0.kind() { - SyntaxKind::None => LitKind::None, - SyntaxKind::Auto => LitKind::Auto, - SyntaxKind::Bool(v) => LitKind::Bool(v), - SyntaxKind::Int(v) => LitKind::Int(v), - SyntaxKind::Float(v) => LitKind::Float(v), - SyntaxKind::Numeric(v, unit) => LitKind::Numeric(v, unit), - SyntaxKind::Str(ref v) => LitKind::Str(v.clone()), - SyntaxKind::Label(ref v) => LitKind::Label(v.clone()), - _ => panic!("literal is of wrong kind"), +impl Ident { + /// Get the identifier. + pub fn get(&self) -> &EcoString { + match self.0.kind() { + SyntaxKind::Ident(id) => id, + _ => panic!("identifier is of wrong kind"), + } + } + + /// Take out the container identifier. + pub fn take(self) -> EcoString { + match self.0.take() { + SyntaxKind::Ident(id) => id, + _ => panic!("identifier is of wrong kind"), + } + } + + /// Get the identifier as a string slice. + pub fn as_str(&self) -> &str { + self.get() + } +} + +impl Deref for Ident { + type Target = str; + + fn deref(&self) -> &Self::Target { + self.as_str() + } +} + +node! { + /// The `none` literal. + None +} + +node! { + /// The `auto` literal. + Auto +} + +node! { + /// A boolean: `true`, `false`. + Bool +} + +impl Bool { + /// Get the value. + pub fn get(&self) -> bool { + match self.0.kind() { + SyntaxKind::Bool(v) => *v, + _ => panic!("boolean is of wrong kind"), } } } -/// The kind of a literal. -#[derive(Debug, Clone, PartialEq)] -pub enum LitKind { - /// The none literal: `none`. - None, - /// The auto literal: `auto`. - Auto, - /// A boolean: `true`, `false`. - Bool(bool), +node! { /// An integer: `120`. - Int(i64), + Int +} + +impl Int { + /// Get the value. + pub fn get(&self) -> i64 { + match self.0.kind() { + SyntaxKind::Int(v) => *v, + _ => panic!("integer is of wrong kind"), + } + } +} + +node! { /// A floating-point number: `1.2`, `10e-4`. - Float(f64), + Float +} + +impl Float { + /// Get the value. + pub fn get(&self) -> f64 { + match self.0.kind() { + SyntaxKind::Float(v) => *v, + _ => panic!("float is of wrong kind"), + } + } +} + +node! { /// A numeric value with a unit: `12pt`, `3cm`, `2em`, `90deg`, `50%`. - Numeric(f64, Unit), + Numeric +} + +impl Numeric { + /// Get the value and unit. + pub fn get(&self) -> (f64, Unit) { + match self.0.kind() { + SyntaxKind::Numeric(v, unit) => (*v, *unit), + _ => panic!("numeric is of wrong kind"), + } + } +} + +node! { /// A quoted string: `"..."`. - Str(EcoString), - /// A label: ``. - Label(EcoString), + Str +} + +impl Str { + /// Get the value. + pub fn get(&self) -> &EcoString { + match self.0.kind() { + SyntaxKind::Str(v) => v, + _ => panic!("string is of wrong kind"), + } + } } node! { @@ -802,7 +898,7 @@ impl AstNode for DictItem { SyntaxKind::Named => node.cast().map(Self::Named), SyntaxKind::Keyed => node.cast().map(Self::Keyed), SyntaxKind::Spread => node.cast_first_child().map(Self::Spread), - _ => None, + _ => Option::None, } } @@ -844,7 +940,7 @@ impl Keyed { .children() .find_map(|node| match node.kind() { SyntaxKind::Str(key) => Some(key.clone()), - _ => None, + _ => Option::None, }) .expect("keyed pair is missing key") } @@ -893,7 +989,7 @@ impl UnOp { SyntaxKind::Plus => Self::Pos, SyntaxKind::Minus => Self::Neg, SyntaxKind::Not => Self::Not, - _ => return None, + _ => return Option::None, }) } @@ -929,7 +1025,7 @@ impl Binary { .find_map(|node| match node.kind() { SyntaxKind::Not => { not = true; - None + Option::None } SyntaxKind::In if not => Some(BinOp::NotIn), _ => BinOp::from_token(node.kind()), @@ -1017,7 +1113,7 @@ impl BinOp { SyntaxKind::HyphEq => Self::SubAssign, SyntaxKind::StarEq => Self::MulAssign, SyntaxKind::SlashEq => Self::DivAssign, - _ => return None, + _ => return Option::None, }) } @@ -1253,7 +1349,7 @@ impl AstNode for Param { SyntaxKind::Ident(_) => node.cast().map(Self::Pos), SyntaxKind::Named => node.cast().map(Self::Named), SyntaxKind::Spread => node.cast_first_child().map(Self::Sink), - _ => None, + _ => Option::None, } } @@ -1419,7 +1515,7 @@ impl ForPattern { if children.next().is_some() { key } else { - None + Option::None } } @@ -1448,7 +1544,7 @@ impl ModuleImport { let items = node.children().filter_map(SyntaxNode::cast).collect(); Some(Imports::Items(items)) } - _ => None, + _ => Option::None, }) } } @@ -1495,39 +1591,3 @@ impl FuncReturn { self.0.cast_last_child() } } - -node! { - /// An identifier: `it`. - Ident -} - -impl Ident { - /// Get the identifier. - pub fn get(&self) -> &EcoString { - match self.0.kind() { - SyntaxKind::Ident(id) => id, - _ => panic!("identifier is of wrong kind"), - } - } - - /// Take out the container identifier. - pub fn take(self) -> EcoString { - match self.0.take() { - SyntaxKind::Ident(id) => id, - _ => panic!("identifier is of wrong kind"), - } - } - - /// Get the identifier as a string slice. - pub fn as_str(&self) -> &str { - self.get() - } -} - -impl Deref for Ident { - type Target = str; - - fn deref(&self) -> &Self::Target { - self.as_str() - } -}