Skip to content

Commit

Permalink
Merge pull request #13 from Fee0/feat/optional-chaining
Browse files Browse the repository at this point in the history
added support for optional chaining and optional calls
  • Loading branch information
FreeMasen authored Apr 27, 2024
2 parents b8f33b4 + 233648e commit e5cd232
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 7 deletions.
10 changes: 7 additions & 3 deletions src/expr.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use crate::pat::Pat;
use crate::{AssignOp, BinaryOp, IntoAllocated, LogicalOp, PropKind, UnaryOp, UpdateOp};
use crate::{
AssignOp, BinaryOp, IntoAllocated, LogicalOp, MemberIndexer, PropKind, UnaryOp, UpdateOp,
};
use crate::{Class, Func, FuncArg, FuncBody, Ident};

#[cfg(feature = "serde")]
Expand Down Expand Up @@ -408,7 +410,7 @@ where
pub struct MemberExpr<T> {
pub object: Box<Expr<T>>,
pub property: Box<Expr<T>>,
pub computed: bool,
pub indexer: MemberIndexer,
}

impl<T> IntoAllocated for MemberExpr<T>
Expand All @@ -421,7 +423,7 @@ where
MemberExpr {
object: self.object.into_allocated(),
property: self.property.into_allocated(),
computed: self.computed,
indexer: self.indexer,
}
}
}
Expand Down Expand Up @@ -460,6 +462,7 @@ where
#[derive(PartialEq, Debug, Clone)]
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
pub struct CallExpr<T> {
pub optional: bool,
pub callee: Box<Expr<T>>,
pub arguments: Vec<Expr<T>>,
}
Expand All @@ -472,6 +475,7 @@ where

fn into_allocated(self) -> Self::Allocated {
CallExpr {
optional: self.optional,
callee: self.callee.into_allocated(),
arguments: self
.arguments
Expand Down
11 changes: 11 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,17 @@ impl<T> Class<T> {
}
}

/// The ways to access the member of a value
/// Either a Period `.`, Computed `[ ]`, Optional `?.` or optional computed `?.[ ]`
#[derive(Debug, Clone, PartialEq, Copy)]
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
pub enum MemberIndexer {
Period,
Computed,
Optional,
OptionalComputed,
}

/// The kind of variable being defined (`var`/`let`/`const`)
#[derive(Debug, Clone, PartialEq, Copy)]
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
Expand Down
16 changes: 14 additions & 2 deletions src/spanned/convert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,7 @@ mod decl {
}

mod expr {
use crate::spanned::expr::MemberIndexer;
use crate::spanned::{
expr::Boolean,
tokens::{QuasiQuote, Quote},
Expand Down Expand Up @@ -409,13 +410,23 @@ mod expr {
}
}

impl From<MemberIndexer> for crate::MemberIndexer {
fn from(other: MemberIndexer) -> Self {
match other {
MemberIndexer::Period(_) => crate::MemberIndexer::Period,
MemberIndexer::Computed { .. } => crate::MemberIndexer::Computed,
MemberIndexer::Optional(_) => crate::MemberIndexer::Optional,
MemberIndexer::OptionalComputed { .. } => crate::MemberIndexer::OptionalComputed,
}
}
}

impl<T> From<MemberExpr<T>> for crate::expr::MemberExpr<T> {
fn from(other: MemberExpr<T>) -> Self {
let computed = other.computed();
Self {
object: Box::new(From::from(*other.object)),
property: Box::new(From::from(*other.property)),
computed,
indexer: From::from(other.indexer),
}
}
}
Expand All @@ -433,6 +444,7 @@ mod expr {
impl<T> From<CallExpr<T>> for crate::expr::CallExpr<T> {
fn from(other: CallExpr<T>) -> Self {
Self {
optional: other.optional.is_some(),
callee: Box::new(From::from(*other.callee)),
arguments: other.arguments.into_iter().map(|e| e.item.into()).collect(),
}
Expand Down
32 changes: 30 additions & 2 deletions src/spanned/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ use crate::IntoAllocated;
use super::tokens::{
self, AssignOp, Asterisk, Async, Await, BinaryOp, CloseBrace, CloseBracket, CloseParen, Colon,
Comma, Ellipsis, False, FatArrow, ForwardSlash, Get, LogicalOp, New, Null, OpenBrace,
OpenBracket, OpenParen, Period, QuasiQuote, QuestionMark, Quote, Set, Static, Super, This,
Token, True, UnaryOp, UpdateOp, Yield,
OpenBracket, OpenParen, Period, QuasiQuote, QuestionMark, QuestionMarkDot, Quote, Set, Static,
Super, This, Token, True, UnaryOp, UpdateOp, Yield,
};
use super::{FuncArgEntry, ListEntry, Node, Slice, SourceLocation};
#[cfg(feature = "serde")]
Expand Down Expand Up @@ -970,6 +970,7 @@ where
impl<T> MemberExpr<T> {
pub fn computed(&self) -> bool {
matches!(self.indexer, MemberIndexer::Computed { .. })
|| matches!(self.indexer, MemberIndexer::OptionalComputed { .. })
}
}

Expand All @@ -986,6 +987,15 @@ impl<T> Node for MemberExpr<T> {
}
}

/// An indexer
/// Either a Period ".", Computed "[..]", Optional "?." or optional computed "?.[..]"
/// ```js
/// var a = {b: 'c'};
/// a.b
/// a["b"]
/// a?.b
/// a?.["b"]
/// ```
#[derive(PartialEq, Debug, Clone, Copy)]
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
pub enum MemberIndexer {
Expand All @@ -994,6 +1004,12 @@ pub enum MemberIndexer {
open_bracket: OpenBracket,
close_bracket: CloseBracket,
},
Optional(QuestionMarkDot),
OptionalComputed {
optional: QuestionMarkDot,
open_bracket: OpenBracket,
close_bracket: CloseBracket,
},
}

impl Node for MemberIndexer {
Expand All @@ -1007,6 +1023,15 @@ impl Node for MemberIndexer {
start: open_bracket.start(),
end: close_bracket.end(),
},
MemberIndexer::Optional(inner) => inner.loc(),
MemberIndexer::OptionalComputed {
optional,
open_bracket: _,
close_bracket,
} => SourceLocation {
start: optional.start(),
end: close_bracket.end(),
},
}
}
}
Expand Down Expand Up @@ -1080,11 +1105,13 @@ impl<T> Node for ConditionalExpr<T> {
/// Calling a function or method
/// ```js
/// Math.random()
/// Math.random?.()
/// ```
#[derive(PartialEq, Debug, Clone)]
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
pub struct CallExpr<T> {
pub callee: Box<Expr<T>>,
pub optional: Option<QuestionMarkDot>,
pub open_paren: OpenParen,
pub arguments: Vec<ListEntry<Expr<T>>>,
pub close_paren: CloseParen,
Expand All @@ -1099,6 +1126,7 @@ where
fn into_allocated(self) -> Self::Allocated {
CallExpr {
callee: self.callee.into_allocated(),
optional: self.optional,
open_paren: self.open_paren,
arguments: self
.arguments
Expand Down

0 comments on commit e5cd232

Please sign in to comment.