Actually just three programming languages in a trenchcoat
1use crate::Spanned;
2use source_span::Span;
3use std::fmt::{self, Display};
4
5#[derive(Clone, Debug)]
6pub enum ErrorKind {
7 Unknown(String),
8 KwNotInExpression,
9 RuleRightArrow,
10 MatchStatementExpressionCase,
11 TripleDot { dot: Span },
12 IfExpressionRestriction,
13 TaggedTemplateMissingIdentifier,
14 TaggedTemplateNotIdentifier,
15 DoMissingParameterList,
16 DoUnnecessaryBangOParen,
17}
18
19impl ErrorKind {
20 pub(crate) fn at(self, span: Span) -> SyntaxError {
21 SyntaxError { span, kind: self }
22 }
23}
24
25#[derive(Clone, Debug)]
26pub struct SyntaxError {
27 span: Span,
28 kind: ErrorKind,
29}
30
31impl Spanned for SyntaxError {
32 fn span(&self) -> Span {
33 self.span
34 }
35}
36
37impl SyntaxError {
38 pub(crate) fn new(span: Span, message: impl std::fmt::Display) -> Self {
39 Self {
40 span,
41 kind: ErrorKind::Unknown(message.to_string()),
42 }
43 }
44
45 pub(crate) fn new_spanless(message: impl std::fmt::Display) -> Self {
46 Self {
47 span: Span::default(),
48 kind: ErrorKind::Unknown(message.to_string()),
49 }
50 }
51
52 pub fn kind(&self) -> &ErrorKind {
53 &self.kind
54 }
55}
56
57impl std::error::Error for SyntaxError {}
58
59impl Display for SyntaxError {
60 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
61 write!(f, "syntax error ({}): ", self.span)?;
62 match &self.kind {
63 ErrorKind::Unknown(message) => write!(f, "{message}")?,
64 ErrorKind::KwNotInExpression => {
65 write!(f, "keyword `not` cannot be used in an expression")?
66 }
67 ErrorKind::RuleRightArrow => {
68 write!(f, "right arrow following rule should be a left arrow")?
69 }
70 ErrorKind::MatchStatementExpressionCase => {
71 write!(f, "case in match statement should be a block")?
72 }
73 ErrorKind::TripleDot { .. } => write!(f, "triple `...` should be `..`")?,
74 ErrorKind::IfExpressionRestriction => {
75 write!(f, "an `if` expression must have an `else` clause")?
76 }
77 ErrorKind::TaggedTemplateMissingIdentifier => write!(
78 f,
79 "the $ operator prefixing a tagged template requires a tag identifier"
80 )?,
81 ErrorKind::TaggedTemplateNotIdentifier => write!(
82 f,
83 "the $ operator prefixing a tagged template requires a tag identifier"
84 )?,
85 ErrorKind::DoMissingParameterList => {
86 write!(f, "a `do` closure requires a parameter list, even if empty")?
87 }
88 ErrorKind::DoUnnecessaryBangOParen => {
89 write!(f, "a `do` closure definition does not use `!`")?
90 }
91 }
92
93 Ok(())
94 }
95}
96
97pub type SyntaxResult<T> = Result<T, SyntaxError>;