use self::SyntaxError::*;
use std::{
borrow::Cow,
fmt::{self, Debug, Formatter},
};
use swc_atoms::JsWord;
use swc_common::{
errors::{DiagnosticBuilder, Handler},
Span,
};
use token::Token;
#[derive(Copy, Clone)]
pub(crate) struct Eof<'a> {
pub last: Span,
pub handler: &'a Handler,
}
impl<'a> From<Eof<'a>> for DiagnosticBuilder<'a> {
fn from(Eof { handler, last }: Eof<'a>) -> Self {
handler.error("Unexpected eof").span(last)
}
}
impl<'a> Debug for Eof<'a> {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
Debug::fmt("<eof>", f)
}
}
pub(crate) struct ErrorToDiag<'a> {
pub handler: &'a Handler,
pub span: Span,
pub error: SyntaxError,
}
#[derive(Debug, Clone, PartialEq)]
pub(crate) struct Error {
pub span: Span,
pub error: SyntaxError,
}
#[derive(Debug, Clone, PartialEq)]
pub(crate) enum SyntaxError {
LegacyDecimal,
LegacyOctal,
InvalidIdentChar,
NonUtf8Char {
val: u32,
},
ExpectedDigit {
radix: u8,
},
UnterminatedBlockComment,
UnterminatedStrLit,
ExpectedUnicodeEscape,
EscapeInReservedWord {
word: JsWord,
},
UnterminatedRegxp,
UnterminatedTpl,
IdentAfterNum,
UnexpectedChar {
c: char,
},
InvalidStrEscape,
InvalidUnicodeEscape,
InvalidCodePoint,
ExpectedHexChars {
count: u8,
},
NumLitTerminatedWithExp,
LegacyCommentInModule,
InvalidIdentInStrict,
EvalAndArgumentsInStrict,
UnaryInExp {
left: String,
left_span: Span,
},
LineBreakInThrow,
LineBreakBeforeArrow,
Unexpected,
Expected(&'static Token),
ExpectedSemiForExprStmt {
expr: Span,
},
AwaitStar,
ReservedWordInObjShorthandOrPat,
MultipleDefault {
previous: Span,
},
CommaAfterRestElement,
NonLastRestParam,
SpreadInParenExpr,
EmptyParenExpr,
InvalidPat,
NotSimpleAssign,
ExpectedIdent,
ExpctedSemi,
DuplicateLabel(JsWord),
AsyncGenerator,
NonTopLevelImportExport,
ImportExportInScript,
PatVarWithoutInit,
WithInStrict,
ReturnNotAllowed,
TooManyVarInForInHead,
VarInitializerInForInHead,
LabelledGenerator,
YieldParamInGen,
AwaitForStmt,
}
impl<'a> From<ErrorToDiag<'a>> for Error {
#[inline(always)]
fn from(e: ErrorToDiag<'a>) -> Self {
Error {
span: e.span,
error: e.error,
}
}
}
impl<'a> From<ErrorToDiag<'a>> for DiagnosticBuilder<'a> {
#[inline(always)]
fn from(e: ErrorToDiag<'a>) -> Self {
let msg: Cow<'static, _> = match e.error {
LegacyDecimal => "Legacy decimal escape is not permitted in strict mode".into(),
LegacyOctal => "Legacy octal escape is not permitted in strict mode".into(),
InvalidIdentChar => "Invalid character in identifier".into(),
NonUtf8Char { val } => format!("Not an utf-8 character: {}", val).into(),
ExpectedDigit { radix } => format!(
"Expected {} digit",
match radix {
2 => "a binary",
8 => "an octal",
10 => "a decimal",
16 => "a hexadecimal",
_ => unreachable!(),
}
)
.into(),
UnterminatedBlockComment => "Unterminated block comment".into(),
UnterminatedStrLit => "Unterminated string constant".into(),
ExpectedUnicodeEscape => "Expected unicode escape".into(),
EscapeInReservedWord { ref word } => {
format!("Unexpected escape sequence in reserved word: {}", word).into()
}
UnterminatedRegxp => "Unterminated regexp literal".into(),
UnterminatedTpl => "Unterminated template".into(),
IdentAfterNum => "Identifier cannot follow number".into(),
UnexpectedChar { c } => format!("Unexpected character {:?}", c).into(),
InvalidStrEscape => "Invalid string escape".into(),
InvalidUnicodeEscape => "Invalid unciode escape".into(),
InvalidCodePoint => "Invalid unciode code point".into(),
ExpectedHexChars { count } => format!("Expected {} hex characters", count).into(),
LegacyCommentInModule => "Legacy comments cannot be used in module code".into(),
NumLitTerminatedWithExp => "Expected +, - or decimal digit after e".into(),
InvalidIdentInStrict => "'implements', 'interface', 'let', 'package', 'private', \
'protected', 'public', 'static', or 'yield' cannot be used \
as an identifier in strict mode"
.into(),
EvalAndArgumentsInStrict => "'eval' and 'arguments' cannot be used as a binding \
identifier in string mode"
.into(),
UnaryInExp { .. } => "** cannot be applied to unary expression".into(),
LineBreakInThrow => "LineBreak cannot follow 'throw'".into(),
LineBreakBeforeArrow => "Unexpected line break between arrow head and arrow".into(),
Unexpected => "Unexpected token".into(),
Expected(token) => format!("Expected {:?}", token).into(),
ExpectedSemiForExprStmt { .. } => "Expected ';', '}' or <eof>".into(),
AwaitStar => "await* has been removed from the async functions proposal. Use \
Promise.all() instead."
.into(),
ReservedWordInObjShorthandOrPat => {
"Cannot use a reserved word as a shorthand property".into()
}
MultipleDefault { .. } => "A switch block cannot have multiple defaults".into(),
CommaAfterRestElement => "Trailing comma isn't permitted after a rest element".into(),
NonLastRestParam => "Rest element must be final element".into(),
SpreadInParenExpr => "Parenthesized expression cannot contain spread operator".into(),
EmptyParenExpr => "Parenthized expression cannot be empty".into(),
InvalidPat => "Not a pattern".into(),
NotSimpleAssign => "Cannot assign to this".into(),
ExpectedIdent => "Expected ident".into(),
ExpctedSemi => "Expected ';' or line break".into(),
DuplicateLabel(ref label) => format!("Label {} is already declared", label).into(),
AsyncGenerator => "An async function cannot be generator".into(),
NonTopLevelImportExport => "'import', and 'export' are not permitted here".into(),
ImportExportInScript => {
"'import', and 'export' cannot be used outside of module code".into()
}
PatVarWithoutInit => "Destructuring bindings require initializers".into(),
WithInStrict => "With statement are not allowed in strict mode".into(),
ReturnNotAllowed => "Return statement is not allowed here".into(),
TooManyVarInForInHead => "Expected one variable binding".into(),
VarInitializerInForInHead => "Unexpected initializer in for in/of loop".into(),
LabelledGenerator => "Generator cannot be labelled".into(),
YieldParamInGen => "'yield' cannot be used as a parameter within generator".into(),
AwaitForStmt => "for await syntax is valid only for for-of statement".into(),
};
let d = e.handler.error(&msg).span(e.span);
let d = match e.error {
ExpectedSemiForExprStmt { expr } => d.span_note(
expr,
"This is the expression part of an expression statement",
),
MultipleDefault { previous } => {
d.span_note(previous, "previous default case is declared at here")
}
_ => d,
};
d
}
}