summaryrefslogtreecommitdiff
path: root/src/syntax/expr.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/syntax/expr.rs')
-rw-r--r--src/syntax/expr.rs349
1 files changed, 249 insertions, 100 deletions
diff --git a/src/syntax/expr.rs b/src/syntax/expr.rs
index c1af2335..6be9d632 100644
--- a/src/syntax/expr.rs
+++ b/src/syntax/expr.rs
@@ -118,6 +118,23 @@ impl Pretty for ExprDict {
}
}
+/// A pair of a name and an expression: `pattern: dashed`.
+#[derive(Debug, Clone, PartialEq)]
+pub struct Named {
+ /// The name: `pattern`.
+ pub name: Spanned<Ident>,
+ /// The right-hand side of the pair: `dashed`.
+ pub expr: Spanned<Expr>,
+}
+
+impl Pretty for Named {
+ fn pretty(&self, p: &mut Printer) {
+ p.push_str(&self.name.v);
+ p.push_str(": ");
+ self.expr.v.pretty(p);
+ }
+}
+
/// A template expression: `[*Hi* there!]`.
pub type ExprTemplate = Tree;
@@ -127,18 +144,246 @@ pub type ExprGroup = Box<Spanned<Expr>>;
/// A block expression: `{1 + 2}`.
pub type ExprBlock = Box<Spanned<Expr>>;
+/// A unary operation: `-x`.
+#[derive(Debug, Clone, PartialEq)]
+pub struct ExprUnary {
+ /// The operator: `-`.
+ pub op: Spanned<UnOp>,
+ /// The expression to operator on: `x`.
+ pub expr: Box<Spanned<Expr>>,
+}
+
+impl Pretty for ExprUnary {
+ fn pretty(&self, p: &mut Printer) {
+ self.op.v.pretty(p);
+ if self.op.v == UnOp::Not {
+ p.push_str(" ");
+ }
+ self.expr.v.pretty(p);
+ }
+}
+
+/// 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 UnOp {
+ /// Try to convert the token into a unary operation.
+ pub fn from_token(token: Token) -> Option<Self> {
+ Some(match token {
+ Token::Plus => Self::Pos,
+ Token::Hyph => Self::Neg,
+ Token::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",
+ }
+ }
+}
+
+impl Pretty for UnOp {
+ fn pretty(&self, p: &mut Printer) {
+ p.push_str(self.as_str());
+ }
+}
+
+/// A binary operation: `a + b`, `a / b`.
+#[derive(Debug, Clone, PartialEq)]
+pub struct ExprBinary {
+ /// The left-hand side of the operation: `a`.
+ pub lhs: Box<Spanned<Expr>>,
+ /// The operator: `+`.
+ pub op: Spanned<BinOp>,
+ /// The right-hand side of the operation: `b`.
+ pub rhs: Box<Spanned<Expr>>,
+}
+
+impl Pretty for ExprBinary {
+ fn pretty(&self, p: &mut Printer) {
+ self.lhs.v.pretty(p);
+ p.push_str(" ");
+ self.op.v.pretty(p);
+ p.push_str(" ");
+ self.rhs.v.pretty(p);
+ }
+}
+
+/// 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 BinOp {
+ /// Try to convert the token into a binary operation.
+ pub fn from_token(token: Token) -> Option<Self> {
+ Some(match token {
+ Token::Plus => Self::Add,
+ Token::Hyph => Self::Sub,
+ Token::Star => Self::Mul,
+ Token::Slash => Self::Div,
+ Token::And => Self::And,
+ Token::Or => Self::Or,
+ Token::EqEq => Self::Eq,
+ Token::BangEq => Self::Neq,
+ Token::Lt => Self::Lt,
+ Token::LtEq => Self::Leq,
+ Token::Gt => Self::Gt,
+ Token::GtEq => Self::Geq,
+ Token::Eq => Self::Assign,
+ Token::PlusEq => Self::AddAssign,
+ Token::HyphEq => Self::SubAssign,
+ Token::StarEq => Self::MulAssign,
+ Token::SlashEq => Self::DivAssign,
+ _ => return None,
+ })
+ }
+
+ /// The precedence of this operator.
+ pub fn precedence(self) -> usize {
+ match self {
+ Self::Mul | Self::Div => 7,
+ Self::Add | Self::Sub => 6,
+ Self::Eq | Self::Neq | Self::Lt | Self::Leq | Self::Gt | Self::Geq => 5,
+ 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 => "/=",
+ }
+ }
+}
+
+impl Pretty for BinOp {
+ fn pretty(&self, p: &mut Printer) {
+ p.push_str(self.as_str());
+ }
+}
+
+/// 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,
+}
+
/// An invocation of a function: `[foo ...]`, `foo(...)`.
#[derive(Debug, Clone, PartialEq)]
pub struct ExprCall {
- /// The name of the function.
- pub name: Spanned<Ident>,
+ /// The callee of the function.
+ pub callee: Box<Spanned<Expr>>,
/// The arguments to the function.
pub args: Spanned<ExprArgs>,
}
impl Pretty for ExprCall {
fn pretty(&self, p: &mut Printer) {
- p.push_str(&self.name.v);
+ self.callee.v.pretty(p);
p.push_str("(");
self.args.v.pretty(p);
p.push_str(")");
@@ -154,7 +399,7 @@ pub fn pretty_bracket_call(call: &ExprCall, p: &mut Printer, chained: bool) {
}
// Function name.
- p.push_str(&call.name.v);
+ call.callee.v.pretty(p);
// Find out whether this can be written with a body or as a chain.
//
@@ -216,102 +461,6 @@ impl Pretty for Argument {
}
}
-/// A pair of a name and an expression: `pattern: dashed`.
-#[derive(Debug, Clone, PartialEq)]
-pub struct Named {
- /// The name: `pattern`.
- pub name: Spanned<Ident>,
- /// The right-hand side of the pair: `dashed`.
- pub expr: Spanned<Expr>,
-}
-
-impl Pretty for Named {
- fn pretty(&self, p: &mut Printer) {
- p.push_str(&self.name.v);
- p.push_str(": ");
- self.expr.v.pretty(p);
- }
-}
-
-/// A unary operation: `-x`.
-#[derive(Debug, Clone, PartialEq)]
-pub struct ExprUnary {
- /// The operator: `-`.
- pub op: Spanned<UnOp>,
- /// The expression to operator on: `x`.
- pub expr: Box<Spanned<Expr>>,
-}
-
-impl Pretty for ExprUnary {
- fn pretty(&self, p: &mut Printer) {
- self.op.v.pretty(p);
- self.expr.v.pretty(p);
- }
-}
-
-/// A unary operator.
-#[derive(Debug, Copy, Clone, Eq, PartialEq)]
-pub enum UnOp {
- /// The plus operator: `+`.
- Pos,
- /// The negation operator: `-`.
- Neg,
-}
-
-impl Pretty for UnOp {
- fn pretty(&self, p: &mut Printer) {
- p.push_str(match self {
- Self::Pos => "+",
- Self::Neg => "-",
- });
- }
-}
-
-/// A binary operation: `a + b`, `a / b`.
-#[derive(Debug, Clone, PartialEq)]
-pub struct ExprBinary {
- /// The left-hand side of the operation: `a`.
- pub lhs: Box<Spanned<Expr>>,
- /// The operator: `+`.
- pub op: Spanned<BinOp>,
- /// The right-hand side of the operation: `b`.
- pub rhs: Box<Spanned<Expr>>,
-}
-
-impl Pretty for ExprBinary {
- fn pretty(&self, p: &mut Printer) {
- self.lhs.v.pretty(p);
- p.push_str(" ");
- self.op.v.pretty(p);
- p.push_str(" ");
- self.rhs.v.pretty(p);
- }
-}
-
-/// 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,
-}
-
-impl Pretty for BinOp {
- fn pretty(&self, p: &mut Printer) {
- p.push_str(match self {
- Self::Add => "+",
- Self::Sub => "-",
- Self::Mul => "*",
- Self::Div => "/",
- });
- }
-}
-
/// A let expression: `let x = 1`.
#[derive(Debug, Clone, PartialEq)]
pub struct ExprLet {