From 7d34a548ccd14debe0668e23454e1ced70e485ec Mon Sep 17 00:00:00 2001 From: Martin Haug Date: Mon, 1 Nov 2021 10:57:45 +0100 Subject: Reorganize syntax module --- src/syntax/expr.rs | 869 ----------------------------------------------------- 1 file changed, 869 deletions(-) delete mode 100644 src/syntax/expr.rs (limited to 'src/syntax/expr.rs') diff --git a/src/syntax/expr.rs b/src/syntax/expr.rs deleted file mode 100644 index 1439cbdb..00000000 --- a/src/syntax/expr.rs +++ /dev/null @@ -1,869 +0,0 @@ -use super::{Ident, Markup, NodeKind, RedNode, RedRef, Span, TypedNode}; -use crate::geom::{AngularUnit, LengthUnit}; -use crate::node; -use crate::util::EcoString; - -/// An expression. -#[derive(Debug, Clone, PartialEq)] -pub enum Expr { - /// An identifier: `left`. - Ident(Ident), - /// A literal: `1`, `true`, ... - Lit(Lit), - /// An array expression: `(1, "hi", 12cm)`. - Array(ArrayExpr), - /// A dictionary expression: `(thickness: 3pt, pattern: dashed)`. - Dict(DictExpr), - /// A template expression: `[*Hi* there!]`. - Template(TemplateExpr), - /// A grouped expression: `(1 + 2)`. - Group(GroupExpr), - /// A block expression: `{ let x = 1; x + 2 }`. - Block(BlockExpr), - /// A unary operation: `-x`. - Unary(UnaryExpr), - /// A binary operation: `a + b`. - Binary(BinaryExpr), - /// An invocation of a function: `f(x, y)`. - Call(CallExpr), - /// A closure expression: `(x, y) => z`. - Closure(ClosureExpr), - /// A with expression: `f with (x, y: 1)`. - With(WithExpr), - /// A let expression: `let x = 1`. - Let(LetExpr), - /// An if-else expression: `if x { y } else { z }`. - If(IfExpr), - /// A while loop expression: `while x { y }`. - While(WhileExpr), - /// A for loop expression: `for x in y { z }`. - For(ForExpr), - /// An import expression: `import a, b, c from "utils.typ"`. - Import(ImportExpr), - /// An include expression: `include "chapter1.typ"`. - Include(IncludeExpr), -} - -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::Call(_) - | Self::Let(_) - | Self::If(_) - | Self::While(_) - | Self::For(_) - | Self::Import(_) - | Self::Include(_) - ) - } - - /// Return the expression's span. - pub fn span(&self) -> Span { - match self { - Self::Ident(ident) => ident.span, - Self::Lit(lit) => lit.span(), - Self::Array(array) => array.span(), - Self::Dict(dict) => dict.span(), - Self::Template(template) => template.span(), - Self::Group(group) => group.span(), - Self::Block(block) => block.span(), - Self::Unary(unary) => unary.span(), - Self::Binary(binary) => binary.span(), - Self::Call(call) => call.span(), - Self::Closure(closure) => closure.span(), - Self::With(with) => with.span(), - Self::Let(let_) => let_.span(), - Self::If(if_) => if_.span(), - Self::While(while_) => while_.span(), - Self::For(for_) => for_.span(), - Self::Import(import) => import.span(), - Self::Include(include) => include.span(), - } - } -} - -impl TypedNode for Expr { - fn cast_from(node: RedRef) -> Option { - match node.kind() { - NodeKind::Ident(_) => node.cast().map(Self::Ident), - NodeKind::Array => node.cast().map(Self::Array), - NodeKind::Dict => node.cast().map(Self::Dict), - NodeKind::Template => node.cast().map(Self::Template), - NodeKind::Group => node.cast().map(Self::Group), - NodeKind::Block => node.cast().map(Self::Block), - NodeKind::Unary => node.cast().map(Self::Unary), - NodeKind::Binary => node.cast().map(Self::Binary), - NodeKind::Call => node.cast().map(Self::Call), - NodeKind::Closure => node.cast().map(Self::Closure), - NodeKind::WithExpr => node.cast().map(Self::With), - NodeKind::LetExpr => node.cast().map(Self::Let), - NodeKind::IfExpr => node.cast().map(Self::If), - NodeKind::WhileExpr => node.cast().map(Self::While), - NodeKind::ForExpr => node.cast().map(Self::For), - NodeKind::ImportExpr => node.cast().map(Self::Import), - NodeKind::IncludeExpr => node.cast().map(Self::Include), - _ => node.cast().map(Self::Lit), - } - } -} - -/// A literal: `1`, `true`, ... -#[derive(Debug, Clone, PartialEq)] -pub enum Lit { - /// The none literal: `none`. - None(Span), - /// The auto literal: `auto`. - Auto(Span), - /// A boolean literal: `true`, `false`. - Bool(Span, bool), - /// An integer literal: `120`. - Int(Span, i64), - /// A floating-point literal: `1.2`, `10e-4`. - Float(Span, f64), - /// A length literal: `12pt`, `3cm`. - Length(Span, f64, LengthUnit), - /// An angle literal: `1.5rad`, `90deg`. - Angle(Span, f64, AngularUnit), - /// A percent literal: `50%`. - /// - /// _Note_: `50%` is stored as `50.0` here, but as `0.5` in the - /// corresponding [value](crate::geom::Relative). - Percent(Span, f64), - /// A fraction unit literal: `1fr`. - Fractional(Span, f64), - /// A string literal: `"hello!"`. - Str(Span, EcoString), -} - -impl TypedNode for Lit { - fn cast_from(node: RedRef) -> Option { - match node.kind() { - NodeKind::None => Some(Self::None(node.span())), - NodeKind::Auto => Some(Self::Auto(node.span())), - NodeKind::Bool(b) => Some(Self::Bool(node.span(), *b)), - NodeKind::Int(i) => Some(Self::Int(node.span(), *i)), - NodeKind::Float(f) => Some(Self::Float(node.span(), *f)), - NodeKind::Length(f, unit) => Some(Self::Length(node.span(), *f, *unit)), - NodeKind::Angle(f, unit) => Some(Self::Angle(node.span(), *f, *unit)), - NodeKind::Percentage(f) => Some(Self::Percent(node.span(), *f)), - NodeKind::Fraction(f) => Some(Self::Fractional(node.span(), *f)), - NodeKind::Str(s) => Some(Self::Str(node.span(), s.string.clone())), - _ => None, - } - } -} - -impl Lit { - pub fn span(&self) -> Span { - match self { - Self::None(span) => *span, - Self::Auto(span) => *span, - Self::Bool(span, _) => *span, - Self::Int(span, _) => *span, - Self::Float(span, _) => *span, - Self::Length(span, _, _) => *span, - Self::Angle(span, _, _) => *span, - Self::Percent(span, _) => *span, - Self::Fractional(span, _) => *span, - Self::Str(span, _) => *span, - } - } -} - -node! { - /// An array expression: `(1, "hi", 12cm)`. - Array => ArrayExpr -} - -impl ArrayExpr { - /// The array items. - pub fn items<'a>(&'a self) -> impl Iterator + 'a { - self.0.children().filter_map(RedRef::cast) - } -} - -node! { - /// A dictionary expression: `(thickness: 3pt, pattern: dashed)`. - Dict => DictExpr -} - -impl DictExpr { - /// The named dictionary items. - pub fn items<'a>(&'a self) -> impl Iterator + 'a { - self.0.children().filter_map(RedRef::cast) - } -} - -node! { - /// A pair of a name and an expression: `pattern: dashed`. - Named -} - -impl Named { - /// The name: `pattern`. - pub fn name(&self) -> Ident { - self.0.cast_first_child().expect("named pair is missing name ident") - } - - /// The right-hand side of the pair: `dashed`. - pub fn expr(&self) -> Expr { - self.0 - .children() - .filter_map(RedRef::cast) - .nth(1) - .expect("named pair is missing expression") - } -} - -node! { - /// A template expression: `[*Hi* there!]`. - Template => TemplateExpr -} - -impl TemplateExpr { - /// The contents of the template. - pub fn body(&self) -> Markup { - self.0 - .cast_first_child() - .expect("template expression is missing body") - } -} - -node! { - /// A grouped expression: `(1 + 2)`. - Group => GroupExpr -} - -impl GroupExpr { - /// The wrapped expression. - pub fn expr(&self) -> Expr { - self.0 - .cast_first_child() - .expect("group expression is missing expression") - } -} - -node! { - /// A block expression: `{ let x = 1; x + 2 }`. - Block => BlockExpr -} - -impl BlockExpr { - /// The list of expressions contained in the block. - pub fn exprs<'a>(&'a self) -> impl Iterator + 'a { - self.0.children().filter_map(RedRef::cast) - } -} - -node! { - /// A unary operation: `-x`. - Unary => UnaryExpr -} - -impl UnaryExpr { - /// The operator: `-`. - pub fn op(&self) -> UnOp { - self.0 - .cast_first_child() - .expect("unary expression is missing operator") - } - - /// The expression to operator on: `x`. - pub fn expr(&self) -> Expr { - self.0 - .cast_first_child() - .expect("unary expression is missing expression") - } -} - -/// A unary operator. -#[derive(Debug, Copy, Clone, Eq, PartialEq)] -pub enum UnOp { - /// The plus operator: `+`. - Pos, - /// The negation operator: `-`. - Neg, - /// The boolean `not`. - Not, -} - -impl TypedNode for UnOp { - fn cast_from(node: RedRef) -> Option { - Self::from_token(node.kind()) - } -} - -impl UnOp { - /// Try to convert the token into a unary operation. - pub fn from_token(token: &NodeKind) -> Option { - Some(match token { - NodeKind::Plus => Self::Pos, - NodeKind::Minus => Self::Neg, - NodeKind::Not => Self::Not, - _ => return None, - }) - } - - /// The precedence of this operator. - pub fn precedence(self) -> usize { - match self { - Self::Pos | Self::Neg => 8, - Self::Not => 4, - } - } - - /// The string representation of this operation. - pub fn as_str(self) -> &'static str { - match self { - Self::Pos => "+", - Self::Neg => "-", - Self::Not => "not", - } - } -} - -node! { - /// A binary operation: `a + b`. - Binary => BinaryExpr -} - -impl BinaryExpr { - /// The binary operator: `+`. - pub fn op(&self) -> BinOp { - self.0 - .cast_first_child() - .expect("binary expression is missing operator") - } - - /// The left-hand side of the operation: `a`. - pub fn lhs(&self) -> Expr { - self.0 - .cast_first_child() - .expect("binary expression is missing left-hand side") - } - - /// The right-hand side of the operation: `b`. - pub fn rhs(&self) -> Expr { - self.0 - .children() - .filter_map(RedRef::cast) - .nth(1) - .expect("binary expression is missing right-hand side") - } -} - -/// A binary operator. -#[derive(Debug, Copy, Clone, Eq, PartialEq)] -pub enum BinOp { - /// The addition operator: `+`. - Add, - /// The subtraction operator: `-`. - Sub, - /// The multiplication operator: `*`. - Mul, - /// The division operator: `/`. - Div, - /// The short-circuiting boolean `and`. - And, - /// The short-circuiting boolean `or`. - Or, - /// The equality operator: `==`. - Eq, - /// The inequality operator: `!=`. - Neq, - /// The less-than operator: `<`. - Lt, - /// The less-than or equal operator: `<=`. - Leq, - /// The greater-than operator: `>`. - Gt, - /// The greater-than or equal operator: `>=`. - Geq, - /// The assignment operator: `=`. - Assign, - /// The add-assign operator: `+=`. - AddAssign, - /// The subtract-assign oeprator: `-=`. - SubAssign, - /// The multiply-assign operator: `*=`. - MulAssign, - /// The divide-assign operator: `/=`. - DivAssign, -} - -impl TypedNode for BinOp { - fn cast_from(node: RedRef) -> Option { - Self::from_token(node.kind()) - } -} - -impl BinOp { - /// Try to convert the token into a binary operation. - pub fn from_token(token: &NodeKind) -> Option { - Some(match token { - NodeKind::Plus => Self::Add, - NodeKind::Minus => Self::Sub, - NodeKind::Star => Self::Mul, - NodeKind::Slash => Self::Div, - NodeKind::And => Self::And, - NodeKind::Or => Self::Or, - NodeKind::EqEq => Self::Eq, - NodeKind::ExclEq => Self::Neq, - NodeKind::Lt => Self::Lt, - NodeKind::LtEq => Self::Leq, - NodeKind::Gt => Self::Gt, - NodeKind::GtEq => Self::Geq, - NodeKind::Eq => Self::Assign, - NodeKind::PlusEq => Self::AddAssign, - NodeKind::HyphEq => Self::SubAssign, - NodeKind::StarEq => Self::MulAssign, - NodeKind::SlashEq => Self::DivAssign, - _ => return None, - }) - } - - /// The precedence of this operator. - pub fn precedence(self) -> usize { - match self { - Self::Mul | Self::Div => 6, - Self::Add | Self::Sub => 5, - Self::Eq | Self::Neq | Self::Lt | Self::Leq | Self::Gt | Self::Geq => 4, - Self::And => 3, - Self::Or => 2, - Self::Assign - | Self::AddAssign - | Self::SubAssign - | Self::MulAssign - | Self::DivAssign => 1, - } - } - - /// The associativity of this operator. - pub fn associativity(self) -> Associativity { - match self { - Self::Add - | Self::Sub - | Self::Mul - | Self::Div - | Self::And - | Self::Or - | Self::Eq - | Self::Neq - | Self::Lt - | Self::Leq - | Self::Gt - | Self::Geq => Associativity::Left, - Self::Assign - | Self::AddAssign - | Self::SubAssign - | Self::MulAssign - | Self::DivAssign => Associativity::Right, - } - } - - /// The string representation of this operation. - pub fn as_str(self) -> &'static str { - match self { - Self::Add => "+", - Self::Sub => "-", - Self::Mul => "*", - Self::Div => "/", - Self::And => "and", - Self::Or => "or", - Self::Eq => "==", - Self::Neq => "!=", - Self::Lt => "<", - Self::Leq => "<=", - Self::Gt => ">", - Self::Geq => ">=", - Self::Assign => "=", - Self::AddAssign => "+=", - Self::SubAssign => "-=", - Self::MulAssign => "*=", - Self::DivAssign => "/=", - } - } -} - -/// The associativity of a binary operator. -#[derive(Debug, Copy, Clone, Eq, PartialEq)] -pub enum Associativity { - /// Left-associative: `a + b + c` is equivalent to `(a + b) + c`. - Left, - /// Right-associative: `a = b = c` is equivalent to `a = (b = c)`. - Right, -} - -node! { - /// An invocation of a function: `foo(...)`. - Call => CallExpr -} - -impl CallExpr { - /// The function to call. - pub fn callee(&self) -> Expr { - self.0.cast_first_child().expect("call expression is missing callee") - } - - /// The arguments to the function. - pub fn args(&self) -> CallArgs { - self.0 - .cast_first_child() - .expect("call expression is missing argument list") - } -} - -node! { - /// The arguments to a function: `12, draw: false`. - CallArgs -} - -impl CallArgs { - /// The positional and named arguments. - pub fn items<'a>(&'a self) -> impl Iterator + 'a { - self.0.children().filter_map(RedRef::cast) - } -} - -/// An argument to a function call. -#[derive(Debug, Clone, PartialEq)] -pub enum CallArg { - /// A positional argument: `12`. - Pos(Expr), - /// A named argument: `draw: false`. - Named(Named), - /// A spreaded argument: `..things`. - Spread(Expr), -} - -impl TypedNode for CallArg { - fn cast_from(node: RedRef) -> Option { - match node.kind() { - NodeKind::Named => Some(CallArg::Named( - node.cast().expect("named call argument is missing name"), - )), - NodeKind::ParameterSink => Some(CallArg::Spread( - node.cast_first_child() - .expect("call argument sink is missing expression"), - )), - _ => Some(CallArg::Pos(node.cast()?)), - } - } -} - -impl CallArg { - /// The name of this argument. - pub fn span(&self) -> Span { - match self { - Self::Named(named) => named.span(), - Self::Pos(expr) => expr.span(), - Self::Spread(expr) => expr.span(), - } - } -} - -node! { - /// A closure expression: `(x, y) => z`. - Closure => ClosureExpr -} - -impl ClosureExpr { - /// The name of the closure. - /// - /// This only exists if you use the function syntax sugar: `let f(x) = y`. - pub fn name(&self) -> Option { - // `first_convert_child` does not work here because of the Option in the - // Result. - self.0.cast_first_child() - } - - /// The parameter bindings. - pub fn params<'a>(&'a self) -> impl Iterator + 'a { - self.0 - .children() - .find(|x| x.kind() == &NodeKind::ClosureParams) - .expect("closure is missing parameter list") - .children() - .filter_map(RedRef::cast) - } - - /// The body of the closure. - pub fn body(&self) -> Expr { - // The filtering for the NodeKind is necessary here because otherwise, - // `first_convert_child` will use the Ident if present. - self.0.cast_last_child().expect("closure is missing body") - } - - /// The red node reference of the body of the closure. - pub fn body_ref(&self) -> RedRef { - self.0 - .children() - .filter(|x| x.cast::().is_some()) - .last() - .unwrap() - } -} - -/// An parameter to a closure. -#[derive(Debug, Clone, PartialEq)] -pub enum ClosureParam { - /// A positional parameter: `x`. - Pos(Ident), - /// A named parameter with a default value: `draw: false`. - Named(Named), - /// A parameter sink: `..args`. - Sink(Ident), -} - -impl TypedNode for ClosureParam { - fn cast_from(node: RedRef) -> Option { - match node.kind() { - NodeKind::Ident(i) => { - Some(ClosureParam::Pos(Ident::new(i, node.span()).unwrap())) - } - NodeKind::Named => Some(ClosureParam::Named( - node.cast().expect("named closure parameter is missing name"), - )), - NodeKind::ParameterSink => Some(ClosureParam::Sink( - node.cast_first_child() - .expect("closure parameter sink is missing identifier"), - )), - _ => Some(ClosureParam::Pos(node.cast()?)), - } - } -} - -node! { - /// A with expression: `f with (x, y: 1)`. - WithExpr -} - -impl WithExpr { - /// The function to apply the arguments to. - pub fn callee(&self) -> Expr { - self.0 - .cast_first_child() - .expect("with expression is missing callee expression") - } - - /// The arguments to apply to the function. - pub fn args(&self) -> CallArgs { - self.0 - .cast_first_child() - .expect("with expression is missing argument list") - } -} - -node! { - /// A let expression: `let x = 1`. - LetExpr -} - -impl LetExpr { - /// The binding to assign to. - pub fn binding(&self) -> Ident { - if let Some(c) = self.0.cast_first_child() { - c - } else if let Some(w) = self.0.typed_child(&NodeKind::WithExpr) { - // Can't do an `first_convert_child` here because the WithExpr's - // callee has to be an identifier. - w.cast_first_child() - .expect("with expression is missing an identifier callee") - } else if let Some(Expr::Closure(c)) = self.0.cast_last_child() { - c.name().expect("closure is missing an identifier name") - } else { - panic!("let expression is missing either an identifier or a with expression") - } - } - - /// The expression the binding is initialized with. - pub fn init(&self) -> Option { - if self.0.cast_first_child::().is_some() { - self.0.children().filter_map(RedRef::cast).nth(1) - } else { - Some( - self.0 - .cast_first_child() - .expect("let expression is missing a with expression"), - ) - } - } - - /// The red node reference for the expression the binding is initialized - /// with. - pub fn init_ref(&self) -> RedRef { - if self.0.cast_first_child::().is_some() { - self.0.children().filter(|x| x.cast::().is_some()).nth(1) - } else { - self.0.children().find(|x| x.cast::().is_some()) - } - .unwrap() - } -} - -node! { - /// An import expression: `import a, b, c from "utils.typ"`. - ImportExpr -} - -impl ImportExpr { - /// The items to be imported. - pub fn imports(&self) -> Imports { - self.0 - .cast_first_child() - .expect("import expression is missing import list") - } - - /// The location of the importable file. - pub fn path(&self) -> Expr { - self.0 - .cast_first_child() - .expect("import expression is missing path expression") - } -} - -/// The items that ought to be imported from a file. -#[derive(Debug, Clone, PartialEq)] -pub enum Imports { - /// All items in the scope of the file should be imported. - Wildcard, - /// The specified identifiers from the file should be imported. - Idents(Vec), -} - -impl TypedNode for Imports { - fn cast_from(node: RedRef) -> Option { - match node.kind() { - NodeKind::Star => Some(Imports::Wildcard), - NodeKind::ImportItems => { - let idents = node.children().filter_map(RedRef::cast).collect(); - Some(Imports::Idents(idents)) - } - _ => None, - } - } -} - -node! { - /// An include expression: `include "chapter1.typ"`. - IncludeExpr -} - -impl IncludeExpr { - /// The location of the file to be included. - pub fn path(&self) -> Expr { - self.0 - .cast_first_child() - .expect("include expression is missing path expression") - } -} - -node! { - /// An if-else expression: `if x { y } else { z }`. - IfExpr -} - -impl IfExpr { - /// The condition which selects the body to evaluate. - pub fn condition(&self) -> Expr { - self.0 - .cast_first_child() - .expect("if expression is missing condition expression") - } - - /// The expression to evaluate if the condition is true. - pub fn if_body(&self) -> Expr { - self.0 - .children() - .filter_map(RedRef::cast) - .nth(1) - .expect("if expression is missing if body") - } - - /// The expression to evaluate if the condition is false. - pub fn else_body(&self) -> Option { - self.0.children().filter_map(RedRef::cast).nth(2) - } -} - -node! { - /// A while loop expression: `while x { y }`. - WhileExpr -} - -impl WhileExpr { - /// The condition which selects whether to evaluate the body. - pub fn condition(&self) -> Expr { - self.0 - .cast_first_child() - .expect("while loop expression is missing condition expression") - } - - /// The expression to evaluate while the condition is true. - pub fn body(&self) -> Expr { - self.0 - .children() - .filter_map(RedRef::cast) - .nth(1) - .expect("while loop expression is missing body") - } -} - -node! { - /// A for loop expression: `for x in y { z }`. - ForExpr -} - -impl ForExpr { - /// The pattern to assign to. - pub fn pattern(&self) -> ForPattern { - self.0 - .cast_first_child() - .expect("for loop expression is missing pattern") - } - - /// The expression to iterate over. - pub fn iter(&self) -> Expr { - self.0 - .cast_first_child() - .expect("for loop expression is missing iterable expression") - } - - /// The expression to evaluate for each iteration. - pub fn body(&self) -> Expr { - self.0 - .children() - .filter_map(RedRef::cast) - .last() - .expect("for loop expression is missing body") - } - - /// The red node reference for the expression to evaluate for each iteration. - pub fn body_ref(&self) -> RedRef { - self.0 - .children() - .filter(|x| x.cast::().is_some()) - .last() - .unwrap() - } -} - -node! { - /// A for-in loop expression: `for x in y { z }`. - ForPattern -} - -impl ForPattern { - pub fn key(&self) -> Option { - let mut items: Vec<_> = self.0.children().filter_map(RedRef::cast).collect(); - if items.len() > 1 { Some(items.remove(0)) } else { None } - } - - pub fn value(&self) -> Ident { - self.0 - .cast_last_child() - .expect("for-in loop pattern is missing value") - } -} -- cgit v1.2.3