1use std::borrow::Cow;
2
3pub mod decl;
4pub mod expr;
5pub mod pat;
6pub mod stmt;
7
8use decl::Decl;
9use expr::{Expr, Lit, Prop};
10use pat::Pat;
11use stmt::Stmt;
12
13use self::pat::RestPat;
14
15pub trait Node {
16 fn loc(&self) -> SourceLocation;
17}
18
19#[derive(Debug, Clone, PartialEq)]
20pub struct Ident<'a> {
21 pub slice: Slice<'a>,
22}
23
24impl<'a> Node for Ident<'a> {
25 fn loc(&self) -> SourceLocation {
26 self.slice.loc
27 }
28}
29
30impl<'a> From<Ident<'a>> for crate::Ident<'a> {
31 fn from(other: Ident<'a>) -> Self {
32 Self {
33 name: other.slice.source,
34 }
35 }
36}
37
38impl<'a> From<Slice<'a>> for Ident<'a> {
39 fn from(slice: Slice<'a>) -> Self {
40 Self { slice }
41 }
42}
43
44impl<'a> Ident<'a> {
45 pub fn name(&self) -> Cow<'a, str> {
46 self.slice.source.clone()
47 }
48}
49
50#[derive(Debug, Clone, PartialEq)]
56pub enum Program<'a> {
57 Mod(Vec<ProgramPart<'a>>),
59 Script(Vec<ProgramPart<'a>>),
61}
62
63impl<'a> From<Program<'a>> for crate::Program<'a> {
64 fn from(other: Program<'a>) -> Self {
65 match other {
66 Program::Mod(inner) => Self::Mod(inner.into_iter().map(From::from).collect()),
67 Program::Script(inner) => Self::Script(inner.into_iter().map(From::from).collect()),
68 }
69 }
70}
71
72impl<'a> Node for Program<'a> {
73 fn loc(&self) -> SourceLocation {
74 match self {
75 Self::Mod(inner) => inner.loc(),
76 Self::Script(inner) => inner.loc(),
77 }
78 }
79}
80
81impl<'a> Program<'a> {
82 pub fn module(parts: Vec<ProgramPart<'a>>) -> Self {
83 Program::Mod(parts)
84 }
85 pub fn script(parts: Vec<ProgramPart<'a>>) -> Self {
86 Program::Script(parts)
87 }
88}
89
90impl<'a> Node for Vec<ProgramPart<'a>> {
91 fn loc(&self) -> SourceLocation {
92 let start = self
93 .first()
94 .map(|p| p.loc())
95 .unwrap_or_else(SourceLocation::zero);
96 let end = self.last().map(|p| p.loc()).unwrap_or(start);
97 SourceLocation {
98 start: start.start,
99 end: end.end,
100 }
101 }
102}
103
104#[derive(Debug, Clone, PartialEq)]
107pub enum ProgramPart<'a> {
108 Dir(Dir<'a>),
110 Decl(Decl<'a>),
112 Stmt(Stmt<'a>),
114}
115
116impl<'a> From<ProgramPart<'a>> for crate::ProgramPart<'a> {
117 fn from(other: ProgramPart<'a>) -> Self {
118 match other {
119 ProgramPart::Dir(inner) => Self::Dir(inner.into()),
120 ProgramPart::Decl(inner) => Self::Decl(inner.into()),
121 ProgramPart::Stmt(inner) => Self::Stmt(inner.into()),
122 }
123 }
124}
125
126impl<'a> Node for ProgramPart<'a> {
127 fn loc(&self) -> SourceLocation {
128 match self {
129 Self::Dir(inner) => inner.loc(),
130 Self::Decl(inner) => inner.loc(),
131 Self::Stmt(inner) => inner.loc(),
132 }
133 }
134}
135
136impl<'a> ProgramPart<'a> {
137 pub fn decl(inner: Decl<'a>) -> Self {
138 ProgramPart::Decl(inner)
139 }
140 pub fn stmt(inner: Stmt<'a>) -> Self {
141 ProgramPart::Stmt(inner)
142 }
143}
144
145#[derive(Debug, Clone, PartialEq)]
148pub struct Dir<'a> {
149 pub expr: Lit<'a>,
150 pub dir: Cow<'a, str>,
151 pub semi_colon: Option<Slice<'a>>,
152}
153
154impl<'a> From<Dir<'a>> for crate::Dir<'a> {
155 fn from(other: Dir<'a>) -> Self {
156 Self {
157 expr: other.expr.into(),
158 dir: other.dir,
159 }
160 }
161}
162
163impl<'a> Node for Dir<'a> {
164 fn loc(&self) -> SourceLocation {
165 self.expr.loc()
166 }
167}
168
169#[derive(PartialEq, Debug, Clone)]
180pub struct Func<'a> {
181 pub keyword: Slice<'a>,
182 pub id: Option<Ident<'a>>,
183 pub open_paren: Slice<'a>,
184 pub params: Vec<ListEntry<'a, FuncArg<'a>>>,
185 pub close_paren: Slice<'a>,
186 pub body: FuncBody<'a>,
187 pub star: Option<Slice<'a>>,
188 pub keyword_async: Option<Slice<'a>>,
189}
190
191impl<'a> Func<'a> {
192 pub fn is_async(&self) -> bool {
193 self.keyword_async.is_some()
194 }
195 pub fn generator(&self) -> bool {
196 self.star.is_some()
197 }
198}
199
200impl<'a> From<Func<'a>> for crate::Func<'a> {
201 fn from(other: Func<'a>) -> Self {
202 Self {
203 generator: other.generator(),
204 is_async: other.is_async(),
205 id: other.id.map(From::from),
206 params: other
207 .params
208 .into_iter()
209 .map(|e| From::from(e.item))
210 .collect(),
211 body: other.body.into(),
212 }
213 }
214}
215
216impl<'a> Node for Func<'a> {
217 fn loc(&self) -> SourceLocation {
218 let start = if let Some(keyword) = &self.keyword_async {
219 keyword.loc.start
220 } else {
221 self.keyword.loc.start
222 };
223 let end = self.body.close_brace.loc.end.clone();
224 SourceLocation { start, end }
225 }
226}
227
228#[derive(Debug, Clone, PartialEq)]
229pub struct FuncArgEntry<'a> {
230 pub value: FuncArg<'a>,
231 pub comma: Option<Slice<'a>>,
232}
233
234impl<'a> From<FuncArgEntry<'a>> for crate::FuncArg<'a> {
235 fn from(other: FuncArgEntry<'a>) -> Self {
236 other.value.into()
237 }
238}
239
240impl<'a> Node for FuncArgEntry<'a> {
241 fn loc(&self) -> SourceLocation {
242 if let Some(comma) = &self.comma {
243 return SourceLocation {
244 start: self.value.loc().start,
245 end: comma.loc.end,
246 };
247 }
248 self.value.loc()
249 }
250}
251
252#[derive(Debug, Clone, PartialEq)]
254pub enum FuncArg<'a> {
255 Expr(Expr<'a>),
256 Pat(Pat<'a>),
257 Rest(Box<RestPat<'a>>),
258}
259
260impl<'a> From<FuncArg<'a>> for crate::FuncArg<'a> {
261 fn from(other: FuncArg<'a>) -> Self {
262 match other {
263 FuncArg::Expr(inner) => Self::Expr(inner.into()),
264 FuncArg::Pat(inner) => Self::Pat(inner.into()),
265 FuncArg::Rest(inner) => {
266 Self::Pat(crate::pat::Pat::RestElement(Box::new(inner.pat.into())))
267 }
268 }
269 }
270}
271
272impl<'a> Node for FuncArg<'a> {
273 fn loc(&self) -> SourceLocation {
274 match self {
275 FuncArg::Expr(inner) => inner.loc(),
276 FuncArg::Pat(inner) => inner.loc(),
277 FuncArg::Rest(inner) => inner.loc(),
278 }
279 }
280}
281
282#[derive(Debug, Clone, PartialEq)]
284pub struct FuncBody<'a> {
285 pub open_brace: Slice<'a>,
286 pub stmts: Vec<ProgramPart<'a>>,
287 pub close_brace: Slice<'a>,
288}
289
290impl<'a> From<FuncBody<'a>> for crate::FuncBody<'a> {
291 fn from(other: FuncBody<'a>) -> Self {
292 Self(other.stmts.into_iter().map(From::from).collect())
293 }
294}
295
296impl<'a> Node for FuncBody<'a> {
297 fn loc(&self) -> SourceLocation {
298 SourceLocation {
299 start: self.open_brace.loc.start,
300 end: self.close_brace.loc.end,
301 }
302 }
303}
304
305#[derive(PartialEq, Debug, Clone)]
332pub struct Class<'a> {
333 pub keyword: Slice<'a>,
334 pub id: Option<Ident<'a>>,
335 pub super_class: Option<SuperClass<'a>>,
336 pub body: ClassBody<'a>,
337}
338
339impl<'a> From<Class<'a>> for crate::Class<'a> {
340 fn from(other: Class<'a>) -> Self {
341 Self {
342 id: other.id.map(From::from),
343 super_class: other.super_class.map(|e| Box::new(From::from(e.expr))),
344 body: other.body.into(),
345 }
346 }
347}
348
349impl<'a> Node for Class<'a> {
350 fn loc(&self) -> SourceLocation {
351 SourceLocation {
352 start: self.keyword.loc.start,
353 end: self.body.close_brace.loc.end,
354 }
355 }
356}
357
358#[derive(PartialEq, Debug, Clone)]
359pub struct SuperClass<'a> {
360 pub keyword_extends: Slice<'a>,
361 pub expr: Expr<'a>,
362}
363
364#[derive(Debug, Clone, PartialEq)]
365pub struct ClassBody<'a> {
366 pub open_brace: Slice<'a>,
367 pub props: Vec<Prop<'a>>,
368 pub close_brace: Slice<'a>,
369}
370
371impl<'a> From<ClassBody<'a>> for crate::ClassBody<'a> {
372 fn from(other: ClassBody<'a>) -> Self {
373 Self(other.props.into_iter().map(From::from).collect())
374 }
375}
376
377impl<'a> Node for ClassBody<'a> {
378 fn loc(&self) -> SourceLocation {
379 let start = self.open_brace.loc.start;
380 let end = self.close_brace.loc.end;
381 SourceLocation { start, end }
382 }
383}
384
385#[derive(Debug, Clone, PartialEq)]
387pub enum VarKind<'a> {
388 Var(Option<Slice<'a>>),
389 Let(Slice<'a>),
390 Const(Slice<'a>),
391}
392
393impl<'a> From<VarKind<'a>> for crate::VarKind {
394 fn from(other: VarKind<'a>) -> Self {
395 match other {
396 VarKind::Var(_) => Self::Var,
397 VarKind::Let(_) => Self::Let,
398 VarKind::Const(_) => Self::Const,
399 }
400 }
401}
402
403impl<'a> Node for VarKind<'a> {
404 fn loc(&self) -> SourceLocation {
405 match self {
406 VarKind::Var(Some(slice)) => slice.loc,
407 VarKind::Let(slice) => slice.loc,
408 VarKind::Const(slice) => slice.loc,
409 _ => SourceLocation::zero(),
410 }
411 }
412}
413
414impl<'a> VarKind<'a> {
415 pub fn is_var(&self) -> bool {
416 matches!(self, VarKind::Var(_))
417 }
418}
419
420#[derive(Debug, Clone, PartialEq)]
422pub enum AssignOp<'a> {
423 Equal(Slice<'a>),
424 PlusEqual(Slice<'a>),
425 MinusEqual(Slice<'a>),
426 TimesEqual(Slice<'a>),
427 DivEqual(Slice<'a>),
428 ModEqual(Slice<'a>),
429 LeftShiftEqual(Slice<'a>),
430 RightShiftEqual(Slice<'a>),
431 UnsignedRightShiftEqual(Slice<'a>),
432 OrEqual(Slice<'a>),
433 XOrEqual(Slice<'a>),
434 AndEqual(Slice<'a>),
435 PowerOfEqual(Slice<'a>),
436}
437
438impl<'a> From<AssignOp<'a>> for crate::AssignOp {
439 fn from(other: AssignOp<'a>) -> Self {
440 match other {
441 AssignOp::Equal(_) => Self::Equal,
442 AssignOp::PlusEqual(_) => Self::PlusEqual,
443 AssignOp::MinusEqual(_) => Self::MinusEqual,
444 AssignOp::TimesEqual(_) => Self::TimesEqual,
445 AssignOp::DivEqual(_) => Self::DivEqual,
446 AssignOp::ModEqual(_) => Self::ModEqual,
447 AssignOp::LeftShiftEqual(_) => Self::LeftShiftEqual,
448 AssignOp::RightShiftEqual(_) => Self::RightShiftEqual,
449 AssignOp::UnsignedRightShiftEqual(_) => Self::UnsignedRightShiftEqual,
450 AssignOp::OrEqual(_) => Self::OrEqual,
451 AssignOp::XOrEqual(_) => Self::XOrEqual,
452 AssignOp::AndEqual(_) => Self::AndEqual,
453 AssignOp::PowerOfEqual(_) => Self::PowerOfEqual,
454 }
455 }
456}
457
458impl<'a> Node for AssignOp<'a> {
459 fn loc(&self) -> SourceLocation {
460 match self {
461 AssignOp::Equal(slice) => slice.loc,
462 AssignOp::PlusEqual(slice) => slice.loc,
463 AssignOp::MinusEqual(slice) => slice.loc,
464 AssignOp::TimesEqual(slice) => slice.loc,
465 AssignOp::DivEqual(slice) => slice.loc,
466 AssignOp::ModEqual(slice) => slice.loc,
467 AssignOp::LeftShiftEqual(slice) => slice.loc,
468 AssignOp::RightShiftEqual(slice) => slice.loc,
469 AssignOp::UnsignedRightShiftEqual(slice) => slice.loc,
470 AssignOp::OrEqual(slice) => slice.loc,
471 AssignOp::XOrEqual(slice) => slice.loc,
472 AssignOp::AndEqual(slice) => slice.loc,
473 AssignOp::PowerOfEqual(slice) => slice.loc,
474 }
475 }
476}
477
478#[derive(Debug, Clone, PartialEq)]
480pub enum LogicalOp<'a> {
481 Or(Slice<'a>),
482 And(Slice<'a>),
483}
484
485impl<'a> From<LogicalOp<'a>> for crate::LogicalOp {
486 fn from(other: LogicalOp<'a>) -> Self {
487 match other {
488 LogicalOp::Or(_) => Self::Or,
489 LogicalOp::And(_) => Self::And,
490 }
491 }
492}
493
494impl<'a> Node for LogicalOp<'a> {
495 fn loc(&self) -> SourceLocation {
496 match self {
497 LogicalOp::Or(slice) => slice.loc,
498 LogicalOp::And(slice) => slice.loc,
499 }
500 }
501}
502
503#[derive(Debug, Clone, PartialEq)]
505pub enum BinaryOp<'a> {
506 Equal(Slice<'a>),
507 NotEqual(Slice<'a>),
508 StrictEqual(Slice<'a>),
509 StrictNotEqual(Slice<'a>),
510 LessThan(Slice<'a>),
511 GreaterThan(Slice<'a>),
512 LessThanEqual(Slice<'a>),
513 GreaterThanEqual(Slice<'a>),
514 LeftShift(Slice<'a>),
515 RightShift(Slice<'a>),
516 UnsignedRightShift(Slice<'a>),
517 Plus(Slice<'a>),
518 Minus(Slice<'a>),
519 Times(Slice<'a>),
520 Over(Slice<'a>),
521 Mod(Slice<'a>),
522 Or(Slice<'a>),
523 XOr(Slice<'a>),
524 And(Slice<'a>),
525 In(Slice<'a>),
526 InstanceOf(Slice<'a>),
527 PowerOf(Slice<'a>),
528}
529
530impl<'a> From<BinaryOp<'a>> for crate::BinaryOp {
531 fn from(other: BinaryOp<'a>) -> Self {
532 match other {
533 BinaryOp::Equal(_) => Self::Equal,
534 BinaryOp::NotEqual(_) => Self::NotEqual,
535 BinaryOp::StrictEqual(_) => Self::StrictEqual,
536 BinaryOp::StrictNotEqual(_) => Self::StrictNotEqual,
537 BinaryOp::LessThan(_) => Self::LessThan,
538 BinaryOp::GreaterThan(_) => Self::GreaterThan,
539 BinaryOp::LessThanEqual(_) => Self::LessThanEqual,
540 BinaryOp::GreaterThanEqual(_) => Self::GreaterThanEqual,
541 BinaryOp::LeftShift(_) => Self::LeftShift,
542 BinaryOp::RightShift(_) => Self::RightShift,
543 BinaryOp::UnsignedRightShift(_) => Self::UnsignedRightShift,
544 BinaryOp::Plus(_) => Self::Plus,
545 BinaryOp::Minus(_) => Self::Minus,
546 BinaryOp::Times(_) => Self::Times,
547 BinaryOp::Over(_) => Self::Over,
548 BinaryOp::Mod(_) => Self::Mod,
549 BinaryOp::Or(_) => Self::Or,
550 BinaryOp::XOr(_) => Self::XOr,
551 BinaryOp::And(_) => Self::And,
552 BinaryOp::In(_) => Self::In,
553 BinaryOp::InstanceOf(_) => Self::InstanceOf,
554 BinaryOp::PowerOf(_) => Self::PowerOf,
555 }
556 }
557}
558
559impl<'a> Node for BinaryOp<'a> {
560 fn loc(&self) -> SourceLocation {
561 match self {
562 BinaryOp::Equal(slice) => slice.loc,
563 BinaryOp::NotEqual(slice) => slice.loc,
564 BinaryOp::StrictEqual(slice) => slice.loc,
565 BinaryOp::StrictNotEqual(slice) => slice.loc,
566 BinaryOp::LessThan(slice) => slice.loc,
567 BinaryOp::GreaterThan(slice) => slice.loc,
568 BinaryOp::LessThanEqual(slice) => slice.loc,
569 BinaryOp::GreaterThanEqual(slice) => slice.loc,
570 BinaryOp::LeftShift(slice) => slice.loc,
571 BinaryOp::RightShift(slice) => slice.loc,
572 BinaryOp::UnsignedRightShift(slice) => slice.loc,
573 BinaryOp::Plus(slice) => slice.loc,
574 BinaryOp::Minus(slice) => slice.loc,
575 BinaryOp::Times(slice) => slice.loc,
576 BinaryOp::Over(slice) => slice.loc,
577 BinaryOp::Mod(slice) => slice.loc,
578 BinaryOp::Or(slice) => slice.loc,
579 BinaryOp::XOr(slice) => slice.loc,
580 BinaryOp::And(slice) => slice.loc,
581 BinaryOp::In(slice) => slice.loc,
582 BinaryOp::InstanceOf(slice) => slice.loc,
583 BinaryOp::PowerOf(slice) => slice.loc,
584 }
585 }
586}
587
588#[derive(Debug, Clone, PartialEq)]
590pub enum UpdateOp<'a> {
591 Increment(Slice<'a>),
592 Decrement(Slice<'a>),
593}
594
595impl<'a> From<UpdateOp<'a>> for crate::UpdateOp {
596 fn from(other: UpdateOp<'a>) -> Self {
597 match other {
598 UpdateOp::Increment(_) => Self::Increment,
599 UpdateOp::Decrement(_) => Self::Decrement,
600 }
601 }
602}
603
604impl<'a> Node for UpdateOp<'a> {
605 fn loc(&self) -> SourceLocation {
606 match self {
607 UpdateOp::Increment(slice) => slice.loc,
608 UpdateOp::Decrement(slice) => slice.loc,
609 }
610 }
611}
612
613#[derive(Debug, Clone, PartialEq)]
616pub enum UnaryOp<'a> {
617 Minus(Slice<'a>),
618 Plus(Slice<'a>),
619 Not(Slice<'a>),
620 Tilde(Slice<'a>),
621 TypeOf(Slice<'a>),
622 Void(Slice<'a>),
623 Delete(Slice<'a>),
624}
625
626impl<'a> From<UnaryOp<'a>> for crate::UnaryOp {
627 fn from(other: UnaryOp<'a>) -> Self {
628 match other {
629 UnaryOp::Minus(_) => Self::Minus,
630 UnaryOp::Plus(_) => Self::Plus,
631 UnaryOp::Not(_) => Self::Not,
632 UnaryOp::Tilde(_) => Self::Tilde,
633 UnaryOp::TypeOf(_) => Self::TypeOf,
634 UnaryOp::Void(_) => Self::Void,
635 UnaryOp::Delete(_) => Self::Delete,
636 }
637 }
638}
639
640impl<'a> Node for UnaryOp<'a> {
641 fn loc(&self) -> SourceLocation {
642 match self {
643 UnaryOp::Minus(slice) => slice.loc,
644 UnaryOp::Plus(slice) => slice.loc,
645 UnaryOp::Not(slice) => slice.loc,
646 UnaryOp::Tilde(slice) => slice.loc,
647 UnaryOp::TypeOf(slice) => slice.loc,
648 UnaryOp::Void(slice) => slice.loc,
649 UnaryOp::Delete(slice) => slice.loc,
650 }
651 }
652}
653
654#[derive(Debug, Clone, PartialEq)]
655pub struct Slice<'a> {
656 pub source: Cow<'a, str>,
657 pub loc: SourceLocation,
658}
659
660#[derive(Debug, Clone, PartialEq, Copy)]
661pub struct SourceLocation {
662 pub start: Position,
663 pub end: Position,
664}
665
666impl SourceLocation {
667 pub fn new(start_line: usize, start_column: usize, end_line: usize, end_column: usize) -> Self {
668 Self {
669 start: Position {
670 line: start_line,
671 column: start_column,
672 },
673 end: Position {
674 line: end_line,
675 column: end_column,
676 },
677 }
678 }
679 fn zero() -> Self {
680 Self::new(0, 0, 0, 0)
681 }
682}
683
684impl core::cmp::PartialOrd for SourceLocation {
685 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
686 match self.start.partial_cmp(&other.start) {
687 Some(core::cmp::Ordering::Equal) => {}
688 ord => return ord,
689 }
690 self.end.partial_cmp(&other.end)
691 }
692}
693
694#[derive(Debug, Clone, PartialEq, Copy)]
695pub struct Position {
696 pub line: usize,
697 pub column: usize,
698}
699
700impl std::cmp::PartialOrd for Position {
701 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
702 let line = self.line.partial_cmp(&other.line)?;
703 if matches!(line, core::cmp::Ordering::Equal) {
704 return self.column.partial_cmp(&other.column);
705 }
706 Some(line)
707 }
708}
709
710impl std::ops::Add for Position {
711 type Output = Self;
712
713 fn add(self, rhs: Self) -> Self::Output {
714 Self {
715 line: self.line + rhs.line,
716 column: self.column + rhs.column,
717 }
718 }
719}
720
721impl std::ops::Sub for Position {
722 type Output = Self;
723
724 fn sub(self, rhs: Self) -> Self::Output {
725 Self {
726 line: self.line - rhs.line,
727 column: self.column - rhs.column,
728 }
729 }
730}
731
732#[derive(Debug, Clone, PartialEq)]
733pub struct ListEntry<'a, T> {
734 pub item: T,
735 pub comma: Option<Slice<'a>>,
736}
737
738impl<'a, T> ListEntry<'a, T> {
739 pub fn no_comma(item: T) -> Self {
740 Self { item, comma: None }
741 }
742}
743
744impl<'a, T> Node for ListEntry<'a, T>
745where
746 T: Node,
747{
748 fn loc(&self) -> SourceLocation {
749 if let Some(comma) = &self.comma {
750 return SourceLocation {
751 start: self.item.loc().start,
752 end: comma.loc.end,
753 };
754 }
755 self.item.loc()
756 }
757}