diff --git a/Cargo.lock b/Cargo.lock index 84d723c16..b54d4c12d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -537,6 +537,7 @@ version = "0.0.0" dependencies = [ "bitflags", "compact_str", + "miette", "num-bigint", "ordered-float", "oxc_allocator", diff --git a/crates/oxc_ast/Cargo.toml b/crates/oxc_ast/Cargo.toml index 7a591a9ce..e6249e77f 100644 --- a/crates/oxc_ast/Cargo.toml +++ b/crates/oxc_ast/Cargo.toml @@ -17,6 +17,7 @@ compact_str = { workspace = true, features = ["serde"] } thiserror = { workspace = true } serde = { workspace = true, features = ["derive"] } serde_json = { workspace = true, optional = true } +miette = { workspace = true } num-bigint = "0.4.3" ryu-js = "0.2.2" diff --git a/crates/oxc_ast/src/node.rs b/crates/oxc_ast/src/node.rs index eebb26883..eaf383067 100644 --- a/crates/oxc_ast/src/node.rs +++ b/crates/oxc_ast/src/node.rs @@ -3,29 +3,40 @@ use std::{ ops::Range, }; +use miette::{SourceOffset, SourceSpan}; use serde::Serialize; #[allow(clippy::wildcard_imports)] use crate::ast::*; -pub type Span = Range; +pub type Span = Range; #[derive(Debug, Default, Clone, Copy, Serialize, PartialEq, Eq)] pub struct Node { - pub start: usize, - pub end: usize, + pub start: u32, + pub end: u32, } impl Node { #[must_use] #[inline] - pub const fn new(start: usize, end: usize) -> Self { + pub const fn new(start: u32, end: u32) -> Self { Self { start, end } } #[must_use] pub const fn range(&self) -> Span { - self.start..self.end + (self.start)..(self.end) + } + + #[must_use] + pub const fn len(&self) -> u32 { + self.end - self.start + } + + #[must_use] + pub const fn is_empty(&self) -> bool { + self.len() == 0 } } @@ -36,6 +47,12 @@ impl Hash for Node { } } +impl From for SourceSpan { + fn from(val: Node) -> Self { + Self::new(SourceOffset::from(val.start as usize), SourceOffset::from(val.len() as usize)) + } +} + pub trait GetNode { #[must_use] fn node(&self) -> Node; diff --git a/crates/oxc_diagnostics/src/lib.rs b/crates/oxc_diagnostics/src/lib.rs index ac0f6a3cb..8c3a257d0 100644 --- a/crates/oxc_diagnostics/src/lib.rs +++ b/crates/oxc_diagnostics/src/lib.rs @@ -2,7 +2,7 @@ use std::{cell::RefCell, ops::Deref, rc::Rc}; -use oxc_ast::{Atom, Span}; +use oxc_ast::{Atom, Node}; use thiserror::Error; pub type Result = std::result::Result; @@ -30,120 +30,120 @@ impl Diagnostics { pub enum Diagnostic { #[error("This file panicked")] #[diagnostic()] - Panic(#[label("")] Span), + Panic(#[label("")] Node), #[error("Flow is not supported")] #[diagnostic()] - Flow(#[label("")] Span), + Flow(#[label("")] Node), /* Lexer */ #[error("Syntax Error")] #[diagnostic()] - UnexpectedToken(#[label("Unexpected Token")] Span), + UnexpectedToken(#[label("Unexpected Token")] Node), #[error("Syntax Error")] #[diagnostic()] - ExpectToken(&'static str, &'static str, #[label("Expect `{0}` here, but found `{1}`")] Span), + ExpectToken(&'static str, &'static str, #[label("Expect `{0}` here, but found `{1}`")] Node), #[error("Invalid escape sequence")] - InvalidEscapeSequence(#[label("Invalid escape sequence")] Span), + InvalidEscapeSequence(#[label("Invalid escape sequence")] Node), #[error("Invalid escape sequence")] - NonOctalDecimalEscapeSequence(#[label("\\8 and \\9 are not allowed in strict mode")] Span), + NonOctalDecimalEscapeSequence(#[label("\\8 and \\9 are not allowed in strict mode")] Node), #[error("Invalid Unicode escape sequence")] - UnicodeEscapeSequence(#[label("Invalid Unicode escape sequence")] Span), + UnicodeEscapeSequence(#[label("Invalid Unicode escape sequence")] Node), #[error("Invalid Character `{0}`")] - InvalidCharacter(char, #[label("Invalid Character `{0}`")] Span), + InvalidCharacter(char, #[label("Invalid Character `{0}`")] Node), #[error("Invalid characters after number")] - InvalidNumberEnd(#[label("Invalid characters after number")] Span), + InvalidNumberEnd(#[label("Invalid characters after number")] Node), #[error("Unterminated multiLine comment")] - UnterminatedMultiLineComment(#[label("Unterminated multiLine comment")] Span), + UnterminatedMultiLineComment(#[label("Unterminated multiLine comment")] Node), #[error("Unterminated string")] - UnterminatedString(#[label("Unterminated string")] Span), + UnterminatedString(#[label("Unterminated string")] Node), #[error("Unexpected flag {0} in regular expression literal")] - RegExpFlag(char, #[label("Unexpected flag {0} in regular expression literal")] Span), + RegExpFlag(char, #[label("Unexpected flag {0} in regular expression literal")] Node), #[error("Flag {0} is mentioned twice in regular expression literal")] RegExpFlagTwice( char, - #[label("Flag {0} is mentioned twice in regular expression literal")] Span, + #[label("Flag {0} is mentioned twice in regular expression literal")] Node, ), #[error("The 'u' and 'v' regular expression flags cannot be enabled at the same time")] RegExpFlagUAndV( #[label("The 'u' and 'v' regular expression flags cannot be enabled at the same time")] - Span, + Node, ), #[error("Unexpected end of file")] - UnexpectedEnd(#[label("Unexpected end of file")] Span), + UnexpectedEnd(#[label("Unexpected end of file")] Node), #[error("Unterminated regular expression")] - UnterminatedRegExp(#[label("Unterminated regular expression")] Span), + UnterminatedRegExp(#[label("Unterminated regular expression")] Node), #[error("Invalid Number")] - InvalidNumber(&'static str, #[label("{0}")] Span), + InvalidNumber(&'static str, #[label("{0}")] Node), #[error("Keywords cannot contain escape characters")] #[diagnostic()] - EscapedKeyword(#[label("keyword cannot contain escape characters")] Span), + EscapedKeyword(#[label("keyword cannot contain escape characters")] Node), /* Syntax Errors */ #[error("Automatic Semicolon Insertion")] #[diagnostic(help("Try insert a semicolon here"))] AutoSemicolonInsertion( #[label("Expected a semicolon or an implicit semicolon after a statement, but found none")] - Span, + Node, ), #[error("Octal literals are not allowed in strict mode")] #[diagnostic(help("for octal literals use the '0o' prefix instead"))] LegacyOctal( - #[label("'0'-prefixed octal literals and octal escape sequences are deprecated")] Span, + #[label("'0'-prefixed octal literals and octal escape sequences are deprecated")] Node, ), #[error("Decimals with leading zeros are not allowed in strict mode")] #[diagnostic(help("remove the leading zero"))] - LeadingZeroDecimal(#[label("Decimals with leading zeros are not allowed in strict mode")] Span), + LeadingZeroDecimal(#[label("Decimals with leading zeros are not allowed in strict mode")] Node), #[error("Line terminator not permitted before arrow")] #[diagnostic()] - LineterminatorBeforeArrow(#[label("Line terminator not permitted before arrow")] Span), + LineterminatorBeforeArrow(#[label("Line terminator not permitted before arrow")] Node), #[error("Unexpected new.target expression")] #[diagnostic(help( "new.target is only allowed in constructors and functions invoked using thew `new` operator" ))] - NewTarget(#[label("new.target expression is not allowed here")] Span), + NewTarget(#[label("new.target expression is not allowed here")] Node), #[error("The only valid meta property for new is new.target")] #[diagnostic()] - NewTargetProperty(#[label("The only valid meta property for new is new.target")] Span), + NewTargetProperty(#[label("The only valid meta property for new is new.target")] Node), #[error("Unexpected import.meta expression")] #[diagnostic(help("import.meta is only allowed in module code"))] - ImportMeta(#[label("import.meta expression is not allowed here")] Span), + ImportMeta(#[label("import.meta expression is not allowed here")] Node), #[error("The only valid meta property for import is import.meta")] #[diagnostic()] - ImportMetaProperty(#[label("The only valid meta property for import is import.meta")] Span), + ImportMetaProperty(#[label("The only valid meta property for import is import.meta")] Node), #[error("Illegal break statement")] #[diagnostic(help( "A `break` statement can only be used within an enclosing iteration or switch statement." ))] - InvalidBreak(#[label("break statement is not allowed here")] Span), + InvalidBreak(#[label("break statement is not allowed here")] Node), #[error("Illegal continue statement: no surrounding iteration statement")] #[diagnostic(help( "A `continue` statement can only be used within an enclosing `for`, `while` or `do while` " ))] - InvalidContinue(#[label("continue statement is not allowed here")] Span), + InvalidContinue(#[label("continue statement is not allowed here")] Node), #[error( "A `{0}` statement can only jump to a label of an enclosing `for`, `while` or `do while` statement." @@ -151,349 +151,349 @@ pub enum Diagnostic { #[diagnostic()] InvalidLabelNonIteration( &'static str, - #[label("This is an non-iteration statement")] Span, - #[label("for this label")] Span, + #[label("This is an non-iteration statement")] Node, + #[label("for this label")] Node, ), #[error("Use of undefined label")] #[diagnostic()] - InvalidLabelTarget(#[label("This label is used, but not defined")] Span), + InvalidLabelTarget(#[label("This label is used, but not defined")] Node), #[error("Jump target cannot cross function boundary.")] #[diagnostic()] - InvalidLabelJumpTarget(#[label("Jump target cannot cross function boundary.")] Span), + InvalidLabelJumpTarget(#[label("Jump target cannot cross function boundary.")] Node), #[error("Unexpected '{0}' strict mode")] #[diagnostic()] - UnexpectedIdentifierAssign(Atom, #[label("Cannot assign to '{0}' in strict mode")] Span), + UnexpectedIdentifierAssign(Atom, #[label("Cannot assign to '{0}' in strict mode")] Node), #[error("Invalid left-hand side in assignment")] #[diagnostic()] - UnexpectedLhsAssign(#[label("Invalid left-hand side in assignment")] Span), + UnexpectedLhsAssign(#[label("Invalid left-hand side in assignment")] Node), #[error("The keyword '{0}' is reserved")] #[diagnostic()] - ReservedKeyword(Atom, #[label("{0} is reserved")] Span), + ReservedKeyword(Atom, #[label("{0} is reserved")] Node), #[error("Identifier `{0}` has already been declared")] #[diagnostic()] Redeclaration( Atom, - #[label("`{0}` has already been declared here")] Span, - #[label("It can not be redeclared here")] Span, + #[label("`{0}` has already been declared here")] Node, + #[label("It can not be redeclared here")] Node, ), #[error("{0} is disallowed as a lexically bound name")] #[diagnostic()] - DisallowedLexicalName(Atom, #[label("{0} is disallowed as a lexically bound name")] Span), + DisallowedLexicalName(Atom, #[label("{0} is disallowed as a lexically bound name")] Node), #[error("`let` cannot be declared as a variable name inside of a `{0}` declaration")] #[diagnostic()] - InvalidLetDeclaration(String, #[label("Rename the let identifier here")] Span), + InvalidLetDeclaration(String, #[label("Rename the let identifier here")] Node), #[error("Missing initializer in destructuring declaration")] #[diagnostic()] InvalidDestrucuringDeclaration( - #[label("Missing initializer in destructuring declaration")] Span, + #[label("Missing initializer in destructuring declaration")] Node, ), #[error("Missing initializer in const declaration")] #[diagnostic()] - MissinginitializerInConst(#[label("const declaration need an initializer")] Span), + MissinginitializerInConst(#[label("const declaration need an initializer")] Node), #[error("Functions cannot be labelled")] #[diagnostic(help("This is not allowed in strict mode starting with ECMAScript 2015."))] - FunctionsCannotBeLabelled(#[label("Functions cannot be labelled")] Span), + FunctionsCannotBeLabelled(#[label("Functions cannot be labelled")] Node), #[error("Cannot use {0} outside a method")] - MethodCode(&'static str, #[label("Cannot use {0} outside a method")] Span), + MethodCode(&'static str, #[label("Cannot use {0} outside a method")] Node), #[error("Cannot use {0} outside a module")] #[diagnostic()] - ModuleCode(&'static str, #[label("Cannot use {0} outside a module")] Span), + ModuleCode(&'static str, #[label("Cannot use {0} outside a module")] Node), #[error("Lexical declaration cannot appear in a single-statement context")] #[diagnostic(help("Wrap this declaration in a block statement"))] - LexicalDeclarationSingleStatement(#[label("Lexical declaration is not allowed here")] Span), + LexicalDeclarationSingleStatement(#[label("Lexical declaration is not allowed here")] Node), #[error("Invalid function declaration")] #[diagnostic(help( "In strict mode code, functions can only be declared at top level or inside a block" ))] - FunctionDeclarationStrict(#[label("function declaration is not allowed here")] Span), + FunctionDeclarationStrict(#[label("function declaration is not allowed here")] Node), #[error("Async functions can only be declared at the top level or inside a block")] #[diagnostic()] AsyncFunctionDeclaration( - #[label("Async functions can only be declared at the top level or inside a block")] Span, + #[label("Async functions can only be declared at the top level or inside a block")] Node, ), #[error("Generators can only be declared at the top level or inside a block")] #[diagnostic()] GeneratorFunctionDeclaration( - #[label("Generators can only be declared at the top level or inside a block")] Span, + #[label("Generators can only be declared at the top level or inside a block")] Node, ), #[error("Invalid function declaration")] #[diagnostic(help( "In non-strict mode code, functions can only be declared at top level, inside a block, or as the body of an if statement" ))] - FunctionDeclarationNonStrict(#[label("function declaration is not allowed here")] Span), + FunctionDeclarationNonStrict(#[label("function declaration is not allowed here")] Node), #[error("`await` is only allowed within async functions and at the top levels of modules")] #[diagnostic()] AwaitExpression( #[label("`await` is only allowed within async functions and at the top levels of modules")] - Span, + Node, ), #[error("A 'yield' expression is only allowed in a generator body.")] #[diagnostic()] - YieldExpression(#[label("A 'yield' expression is only allowed in a generator body.")] Span), + YieldExpression(#[label("A 'yield' expression is only allowed in a generator body.")] Node), #[error("Invalid class declaration")] #[diagnostic()] - ClassDeclaration(#[label("Classes can only be declared at top level or inside a block")] Span), + ClassDeclaration(#[label("Classes can only be declared at top level or inside a block")] Node), #[error("Rest element must be last element")] #[diagnostic()] - RestElement(#[label("Rest element must be last element")] Span), + RestElement(#[label("Rest element must be last element")] Node), #[error("Spread must be last element")] #[diagnostic()] - SpreadLastElement(#[label("Spread must be last element")] Span), + SpreadLastElement(#[label("Spread must be last element")] Node), #[error("Unexpected trailing comma after rest element")] #[diagnostic()] - RestElementTraillingComma(#[label("Unexpected trailing comma after rest element")] Span), + RestElementTraillingComma(#[label("Unexpected trailing comma after rest element")] Node), #[error("Invalid rest argument")] #[diagnostic(help("Expected identifier in rest argument"))] - InvalidRestArgument(#[label("Invalid rest argument")] Span), + InvalidRestArgument(#[label("Invalid rest argument")] Node), #[error("Invalid parenthesized parameter")] #[diagnostic(help("remove the parentheses"))] - InvalidParenthesizedParameter(#[label("Invliad parenthesized parameter")] Span), + InvalidParenthesizedParameter(#[label("Invliad parenthesized parameter")] Node), #[error("Invalid parenthesized pattern")] #[diagnostic()] - InvalidParenthesizedPattern(#[label("Invliad parenthesized pattern")] Span), + InvalidParenthesizedPattern(#[label("Invliad parenthesized pattern")] Node), #[error("Invalid assignment")] #[diagnostic()] - InvalidAssignment(#[label("Cannot assign to this expression")] Span), + InvalidAssignment(#[label("Cannot assign to this expression")] Node), #[error("Optional chaining cannot appear in the callee of new expressions")] #[diagnostic()] NewOptionalChain( - #[label("Optional chaining cannot appear in the callee of new expressions")] Span, + #[label("Optional chaining cannot appear in the callee of new expressions")] Node, ), #[error("The left-hand side of a `for...of` statement may not be `async`")] #[diagnostic()] ForLoopAsyncOf( - #[label("The left-hand side of a `for...of` statement may not be `async`")] Span, + #[label("The left-hand side of a `for...of` statement may not be `async`")] Node, ), #[error("await can only be used in conjunction with `for...of` statements")] #[diagnostic()] - ForAwait(#[label("await can only be used in conjunction with `for...of` statements")] Span), + ForAwait(#[label("await can only be used in conjunction with `for...of` statements")] Node), #[error("Cannot use new with dynamic import")] #[diagnostic()] - NewDynamicImport(#[label("Cannot use new with dynamic import")] Span), + NewDynamicImport(#[label("Cannot use new with dynamic import")] Node), #[error("'{0}' declaration can only be used at the top level of a module")] #[diagnostic()] - TopLevel(&'static str, #[label("'{0}' declaration can only appear at the top level")] Span), + TopLevel(&'static str, #[label("'{0}' declaration can only appear at the top level")] Node), #[error("Duplicated export '{0}'")] #[diagnostic()] DuplicateExport( Atom, - #[label("Export has already been declared here")] Span, - #[label("It cannot be redeclared here")] Span, + #[label("Export has already been declared here")] Node, + #[label("It cannot be redeclared here")] Node, ), #[error("Unexpected private field")] #[diagnostic(help( "Private names are only allowed in property accesses (`obj.#field`) or in `in` expressions (`#field in obj`)." ))] - UnexpectedPrivateIdentifier(#[label("Unexpected private field")] Span), + UnexpectedPrivateIdentifier(#[label("Unexpected private field")] Node), #[error("Classes can't have an element named '#constructor'")] #[diagnostic()] - PrivateNameConstructor(#[label("Classes can't have an element named '#constructor'")] Span), + PrivateNameConstructor(#[label("Classes can't have an element named '#constructor'")] Node), #[error("Private field '{0}' must be declared in an enclosing class")] #[diagnostic()] PrivateFieldUndeclared( Atom, - #[label("Private field '{0}' must be declared in an enclosing class")] Span, + #[label("Private field '{0}' must be declared in an enclosing class")] Node, ), #[error("Unexpected private identifier")] #[diagnostic()] PrivateNotInClass( Atom, - #[label("Private identifier '#{0}' is not allowed outside class bodies")] Span, + #[label("Private identifier '#{0}' is not allowed outside class bodies")] Node, ), #[error("Classes may not have a static property named prototype")] #[diagnostic()] - StaticPrototype(#[label("Classes may not have a static property named prototype")] Span), + StaticPrototype(#[label("Classes may not have a static property named prototype")] Node), #[error("Constructor can't have get/set modifier")] #[diagnostic()] - ConstructorGetterSetter(#[label("Constructor can't have get/set modifier")] Span), + ConstructorGetterSetter(#[label("Constructor can't have get/set modifier")] Node), #[error("Constructor can't be an async method")] #[diagnostic()] - ConstructorAsync(#[label("Constructor can't be an async method")] Span), + ConstructorAsync(#[label("Constructor can't be an async method")] Node), #[error("Cannot use `{0}` as an identifier in an async context")] #[diagnostic()] - IdentifierAsync(&'static str, #[label("{0} cannot be used here")] Span), + IdentifierAsync(&'static str, #[label("{0} cannot be used here")] Node), #[error("Cannot use `{0}` as an identifier in a generator context")] #[diagnostic()] - IdentifierGenerator(&'static str, #[label("{0} cannot be used here")] Span), + IdentifierGenerator(&'static str, #[label("{0} cannot be used here")] Node), #[error("Constructor can't be a generator")] #[diagnostic()] - ConstructorGenerator(#[label("Constructor can't be a generator")] Span), + ConstructorGenerator(#[label("Constructor can't be a generator")] Node), #[error("Classes can't have a field named 'constructor'")] #[diagnostic()] - FieldConstructor(#[label("Classes can't have a field named 'constructor'")] Span), + FieldConstructor(#[label("Classes can't have a field named 'constructor'")] Node), #[error("Multiple constructor implementations are not allowed.")] #[diagnostic()] DuplicateConstructor( - #[label("constructor has already been declared here")] Span, - #[label("it cannot be redeclared here")] Span, + #[label("constructor has already been declared here")] Node, + #[label("it cannot be redeclared here")] Node, ), #[error("An export name cannot include a unicode lone surrogate")] #[diagnostic()] - ExportLoneSurrogate(#[label("An export name cannot include a unicode lone surrogate")] Span), + ExportLoneSurrogate(#[label("An export name cannot include a unicode lone surrogate")] Node), #[error("A string literal cannot be used as an exported binding without `from`")] #[diagnostic(help("Did you mean `export {{ '{0}' as '{1}' }} from 'some-module'`?"))] ExportNamedString( Atom, Atom, - #[label("A string literal cannot be used as an exported binding without `from`")] Span, + #[label("A string literal cannot be used as an exported binding without `from`")] Node, ), #[error("Bad escape sequence in untagged template literal")] #[diagnostic()] - TemplateLiteral(#[label("Bad escape sequence in untagged template literal")] Span), + TemplateLiteral(#[label("Bad escape sequence in untagged template literal")] Node), #[error("Delete of an unqualified identifier in strict mode.")] #[diagnostic()] - DeleteOfUnqualified(#[label("Delete of an unqualified identifier in strict mode")] Span), + DeleteOfUnqualified(#[label("Delete of an unqualified identifier in strict mode")] Node), #[error("'with' statements are not allowed")] #[diagnostic()] - WithStatement(#[label("'with' statements are not allowed")] Span), + WithStatement(#[label("'with' statements are not allowed")] Node), #[error("Private fields can not be deleted")] #[diagnostic()] - DeletePrivateField(#[label("Private fields can not be deleted")] Span), + DeletePrivateField(#[label("Private fields can not be deleted")] Node), #[error("Empty parenthesized expression")] #[diagnostic()] - EmptyParenthesizedExpression(#[label("Expected an expression here")] Span), + EmptyParenthesizedExpression(#[label("Expected an expression here")] Node), #[error("Undefined export")] #[diagnostic()] - UndefinedExport(Atom, #[label("Export '{0}' is not defined")] Span), + UndefinedExport(Atom, #[label("Export '{0}' is not defined")] Node), #[error("Logical expressions and coalesce expressions cannot be mixed")] #[diagnostic(help("Wrap either expression by parentheses"))] - MixedCoalesce(#[label("Logical expressions and coalesce expressions cannot be mixed")] Span), + MixedCoalesce(#[label("Logical expressions and coalesce expressions cannot be mixed")] Node), #[error("'Unexpected `{0}`")] #[diagnostic()] - UnexpectedKeyword(&'static str, #[label("'{0}' keyword is unexpected here")] Span), + UnexpectedKeyword(&'static str, #[label("'{0}' keyword is unexpected here")] Node), #[error("{0} loop variable declaration may not have an initializer")] #[diagnostic()] UnexpectedInitializerInForLoopHead( &'static str, - #[label("{0} loop variable declaration may not have an initializer")] Span, + #[label("{0} loop variable declaration may not have an initializer")] Node, ), #[error("Only a single declaration is allowed in a `for...{0}` statement")] #[diagnostic()] MultipleDeclarationInForLoopHead( &'static str, - #[label("Only a single declaration is allowed in a `for...{0}` statement")] Span, + #[label("Only a single declaration is allowed in a `for...{0}` statement")] Node, ), #[error("Illegal newline after {0}")] #[diagnostic()] IllegalNewline( &'static str, - #[label("{0} starts here")] Span, - #[label("A newline is not expected here")] Span, + #[label("{0} starts here")] Node, + #[label("A newline is not expected here")] Node, ), #[error("Duplicate parameter name not allowed in this context")] #[diagnostic()] - DuplicateParameter(#[label("Duplicate parameter name not allowed in this context")] Span), + DuplicateParameter(#[label("Duplicate parameter name not allowed in this context")] Node), #[error("Illegal 'use strict' directive in function with non-simple parameter list")] #[diagnostic()] IllegalUseStrict( - #[label("Illegal 'use strict' directive in function with non-simple parameter list")] Span, + #[label("Illegal 'use strict' directive in function with non-simple parameter list")] Node, ), #[error("'arguments' is not allowed in {0}")] #[diagnostic()] - UnexpectedArguments(&'static str, #[label("'arguments' is not allowed in {0}")] Span), + UnexpectedArguments(&'static str, #[label("'arguments' is not allowed in {0}")] Node), #[error("Unexpected {0} expression")] #[diagnostic()] - UnexpectedExpression(&'static str, #[label("Unexpected {0} expression")] Span), + UnexpectedExpression(&'static str, #[label("Unexpected {0} expression")] Node), #[error("Unexpected exponentiation expression")] #[diagnostic(help("Wrap {0} expression in parentheses to enforce operator precedence"))] - UnexpectedExponential(&'static str, #[label("Unexpected exponentiation expression")] Span), + UnexpectedExponential(&'static str, #[label("Unexpected exponentiation expression")] Node), #[error("Tagged template expressions are not permitted in an optional chain")] #[diagnostic()] OptionalChainTaggedTemplate( - #[label("Tagged template expressions are not permitted in an optional chain")] Span, + #[label("Tagged template expressions are not permitted in an optional chain")] Node, ), #[error("A 'get' accessor must not have any formal parameters.")] #[diagnostic()] - GetterParameters(#[label("A 'get' accessor must not have any formal parameters.")] Span), + GetterParameters(#[label("A 'get' accessor must not have any formal parameters.")] Node), #[error("A 'set' accessor must have exactly one parameter.")] #[diagnostic()] - SetterParameters(#[label("A 'set' accessor must have exactly one parameter.")] Span), + SetterParameters(#[label("A 'set' accessor must have exactly one parameter.")] Node), #[error("A 'set' accessor function argument must not be a rest parameter")] #[diagnostic()] SetterParametersRestPattern( - #[label("A 'set' accessor function argument must not be a rest parameter")] Span, + #[label("A 'set' accessor function argument must not be a rest parameter")] Node, ), #[error("{0} expression not allowed in formal parameter")] #[diagnostic()] AwaitOrYieldInParameter( &'static str, - #[label("{0} expression not allowed in formal parameter")] Span, + #[label("{0} expression not allowed in formal parameter")] Node, ), #[error("Invalid assignment in object literal")] #[diagnostic(help( "Did you mean to use a ':'? An '=' can only follow a property name when the containing object literal is part of a destructuring pattern." ))] - CoverInitializedNameError(#[label("Assignment is not allowed here")] Span), + CoverInitializedNameError(#[label("Assignment is not allowed here")] Node), #[error("Super calls are not permitted outside constructors or in nested functions inside constructors. ")] @@ -502,7 +502,7 @@ pub enum Diagnostic { #[label( "Super calls are not permitted outside constructors or in nested functions inside constructors." )] - Span, + Node, ), #[error("'super' can only be referenced in members of derived classes or object literal expressions. @@ -511,98 +511,98 @@ pub enum Diagnostic { UnexpectedSuperReference( #[label("'super' can only be referenced in members of derived classes or object literal expressions. ")] - Span, + Node, ), #[error("'super' can only be used with function calls or in property accesses")] #[diagnostic(help("replace with `super()` or `super.prop` or `super[prop]`"))] UnexpectedSuper( - #[label("'super' can only be used with function calls or in property accesses ")] Span, + #[label("'super' can only be used with function calls or in property accesses ")] Node, ), #[error("'super' can only be referenced in a derived class.")] #[diagnostic(help("either remove this super, or extend the class"))] SuperWithoutDerivedClass( - #[label("'super' can only be referenced in a derived class.")] Span, - #[label("class does not have `extends`")] Span, + #[label("'super' can only be referenced in a derived class.")] Node, + #[label("class does not have `extends`")] Node, ), #[error("Private fields cannot be accessed on super")] #[diagnostic()] - SuperPrivate(#[label("Private fields cannot be accessed on super")] Span), + SuperPrivate(#[label("Private fields cannot be accessed on super")] Node), #[error("Expected function name")] #[diagnostic(help("Function name is required in function declaration or named export"))] - ExpectFunctionName(#[label("Function name is required here")] Span), + ExpectFunctionName(#[label("Function name is required here")] Node), #[error("Missing catch or finally clause")] #[diagnostic()] - ExpectCatchFinally(#[label("Expected `catch` or `finally` here")] Span), + ExpectCatchFinally(#[label("Expected `catch` or `finally` here")] Node), #[error("Cannot assign to '{0}' because it is a {1}")] #[diagnostic()] CannotAssignTo( Atom, &'static str, - #[label("Cannot assign to '{0}' because this is a {1}")] Span, + #[label("Cannot assign to '{0}' because this is a {1}")] Node, ), #[error("A rest parameter cannot have an initializer")] #[diagnostic()] ARestParameterCannotHaveAnInitializer( - #[label("A rest parameter cannot have an initializer")] Span, + #[label("A rest parameter cannot have an initializer")] Node, ), /* TypeScript */ #[error("TS1015: Parameter cannot have question mark and initializer")] #[diagnostic()] ParameterCannotHaveQuestionMarkAndInitializer( - #[label("Parameter cannot have question mark and initializer")] Span, + #[label("Parameter cannot have question mark and initializer")] Node, ), #[error("TS1047: A rest parameter cannot be optional")] #[diagnostic()] - ARestParameterCannotBeOptional(#[label("A rest parameter cannot be optional")] Span), + ARestParameterCannotBeOptional(#[label("A rest parameter cannot be optional")] Node), #[error("TS1095: A 'set' accessor cannot have a return type annotation")] #[diagnostic()] ASetAccessorCannotHaveAReturnTypeAnnotation( - #[label("A 'set' accessor cannot have a return type annotation")] Span, + #[label("A 'set' accessor cannot have a return type annotation")] Node, ), #[error("TS1098: Type parameter list cannot be empty")] #[diagnostic()] - TypeParameterListCannotBeEmpty(#[label("Type parameter list cannot be empty")] Span), + TypeParameterListCannotBeEmpty(#[label("Type parameter list cannot be empty")] Node), #[error("TS1099: Type argument list cannot be empty")] #[diagnostic()] - TypeArgumentListCannotBeEmpty(#[label("Type argument list cannot be empty")] Span), + TypeArgumentListCannotBeEmpty(#[label("Type argument list cannot be empty")] Node), #[error("TS1108: A 'return' statement can only be used within a function body")] #[diagnostic()] ReturnStatementOnlyInFunctionBody( - #[label("A 'return' statement can only be used within a function body.")] Span, + #[label("A 'return' statement can only be used within a function body.")] Node, ), #[error("TS1164: Computed property names are not allowed in enums")] #[diagnostic()] ComputedPropertyNamesAreNotAllowedInEnums( - #[label("Computed property names are not allowed in enums")] Span, + #[label("Computed property names are not allowed in enums")] Node, ), #[error("TS1313: The body of an 'if' statement cannot be the empty statement")] #[diagnostic()] TheBodyOfAnIfStatementCannotBeTheEmptyStatement( - #[label("The body of an 'if' statement cannot be the empty statement")] Span, + #[label("The body of an 'if' statement cannot be the empty statement")] Node, ), #[error("TS1317: A parameter property cannot be declared using a rest parameter")] #[diagnostic()] AParameterPropertyCannotBeDeclaredUsingARestParameter( - #[label("A parameter property cannot be declared using a rest parameter")] Span, + #[label("A parameter property cannot be declared using a rest parameter")] Node, ), #[error("TS2452: An enum member cannot have a numeric name")] #[diagnostic()] - AnEnumMemberCannotHaveANumericName(#[label("An enum member cannot have a numeric name")] Span), + AnEnumMemberCannotHaveANumericName(#[label("An enum member cannot have a numeric name")] Node), } diff --git a/crates/oxc_parser/src/cursor.rs b/crates/oxc_parser/src/cursor.rs index 7d1904031..9e5fcd0f0 100644 --- a/crates/oxc_parser/src/cursor.rs +++ b/crates/oxc_parser/src/cursor.rs @@ -9,7 +9,7 @@ use crate::Parser; pub struct ParserCheckpoint<'a> { lexer: LexerCheckpoint<'a>, cur_token: Token, - prev_node_end: usize, + prev_node_end: u32, errors_pos: usize, } @@ -42,7 +42,8 @@ impl<'a> Parser<'a> { /// Get current source text #[must_use] pub fn cur_src(&self) -> &'a str { - unsafe { self.source.get_unchecked(self.cur_token().range()) } + let range = self.cur_token().node().range(); + unsafe { self.source.get_unchecked(range.start as usize..range.end as usize) } } /// Get current atom @@ -100,8 +101,8 @@ impl<'a> Parser<'a> { // in IdentifierName hence such escapes cannot be used to write an Identifier // whose code point sequence is the same as a ReservedWord. if self.cur_token().escaped && kind.is_all_keyword() { - let range = self.cur_token().range(); - self.error(Diagnostic::EscapedKeyword(range)); + let node = self.cur_token().node(); + self.error(Diagnostic::EscapedKeyword(node)); } self.prev_token_end = self.token.end; self.token = self.lexer.next_token(); @@ -139,8 +140,8 @@ impl<'a> Parser<'a> { /// # Errors pub fn asi(&mut self) -> Result<()> { if !self.can_insert_semicolon() { - let range = self.prev_token_end..self.cur_token().start; - return Err(Diagnostic::AutoSemicolonInsertion(range)); + let node = Node::new(self.prev_token_end, self.cur_token().start); + return Err(Diagnostic::AutoSemicolonInsertion(node)); } if self.at(Kind::Semicolon) { self.advance(Kind::Semicolon); @@ -169,17 +170,17 @@ impl<'a> Parser<'a> { } #[must_use] - pub const fn current_range(&self) -> std::ops::Range { + pub const fn current_range(&self) -> Node { let cur_token = self.cur_token(); match self.cur_kind() { Kind::Eof => { if self.prev_token_end < cur_token.end { - self.prev_token_end..self.prev_token_end + Node::new(self.prev_token_end, self.prev_token_end) } else { - self.prev_token_end - 1..self.prev_token_end + Node::new(self.prev_token_end - 1, self.prev_token_end) } } - _ => cur_token.range(), + _ => cur_token.node(), } } diff --git a/crates/oxc_parser/src/js/binding.rs b/crates/oxc_parser/src/js/binding.rs index 5b8aec7c3..00a176c39 100644 --- a/crates/oxc_parser/src/js/binding.rs +++ b/crates/oxc_parser/src/js/binding.rs @@ -57,9 +57,9 @@ impl<'a> Parser<'a> { if self.at(Kind::Comma) { let error = if self.peek_at(Kind::RBrack) { - Diagnostic::RestElementTraillingComma(self.cur_token().range()) + Diagnostic::RestElementTraillingComma(self.cur_token().node()) } else { - Diagnostic::RestElement(node.range()) + Diagnostic::RestElement(node) }; self.error(error); } diff --git a/crates/oxc_parser/src/js/class.rs b/crates/oxc_parser/src/js/class.rs index da3b941ef..a66a19175 100644 --- a/crates/oxc_parser/src/js/class.rs +++ b/crates/oxc_parser/src/js/class.rs @@ -18,7 +18,10 @@ impl<'a> Parser<'a> { let decl = self.parse_class_declaration(/* declare */ false)?; if stmt_ctx.is_single_statement() { - self.error(Diagnostic::ClassDeclaration(decl.node.start..decl.body.node.start)); + self.error(Diagnostic::ClassDeclaration(Node::new( + decl.node.start, + decl.body.node.start, + ))); } Ok(self.ast.class_declaration(decl)) @@ -238,7 +241,7 @@ impl<'a> Parser<'a> { if let PropertyKey::PrivateIdentifier(private_ident) = &key { if private_ident.name == "constructor" { - self.error(Diagnostic::PrivateNameConstructor(private_ident.node.range())); + self.error(Diagnostic::PrivateNameConstructor(private_ident.node)); } } @@ -264,17 +267,17 @@ impl<'a> Parser<'a> { )?; if let Some((name, node)) = definition.prop_name() { if r#static && name == "prototype" { - self.error(Diagnostic::StaticPrototype(node.range())); + self.error(Diagnostic::StaticPrototype(node)); } if !r#static && name == "constructor" { if kind == MethodDefinitionKind::Get || kind == MethodDefinitionKind::Set { - self.error(Diagnostic::ConstructorGetterSetter(node.range())); + self.error(Diagnostic::ConstructorGetterSetter(node)); } if r#async { - self.error(Diagnostic::ConstructorAsync(node.range())); + self.error(Diagnostic::ConstructorAsync(node)); } if generator { - self.error(Diagnostic::ConstructorGenerator(node.range())); + self.error(Diagnostic::ConstructorGenerator(node)); } } } @@ -295,10 +298,10 @@ impl<'a> Parser<'a> { )?; if let Some((name, node)) = definition.prop_name() { if name == "constructor" { - self.error(Diagnostic::FieldConstructor(node.range())); + self.error(Diagnostic::FieldConstructor(node)); } if r#static && name == "prototype" { - self.error(Diagnostic::StaticPrototype(node.range())); + self.error(Diagnostic::StaticPrototype(node)); } } Ok(definition) @@ -344,17 +347,17 @@ impl<'a> Parser<'a> { let value = self.parse_method(r#async, generator)?; if kind == MethodDefinitionKind::Get && !value.params.is_empty() { - self.error(Diagnostic::GetterParameters(value.params.node.range())); + self.error(Diagnostic::GetterParameters(value.params.node)); } if kind == MethodDefinitionKind::Set { if value.params.items.len() != 1 { - self.error(Diagnostic::SetterParameters(value.params.node.range())); + self.error(Diagnostic::SetterParameters(value.params.node)); } if value.params.items.len() == 1 { if let BindingPatternKind::RestElement(elem) = &value.params.items[0].pattern.kind { - self.error(Diagnostic::SetterParametersRestPattern(elem.node.range())); + self.error(Diagnostic::SetterParametersRestPattern(elem.node)); } } } diff --git a/crates/oxc_parser/src/js/declaration.rs b/crates/oxc_parser/src/js/declaration.rs index d03feac85..9f4ebc6f9 100644 --- a/crates/oxc_parser/src/js/declaration.rs +++ b/crates/oxc_parser/src/js/declaration.rs @@ -92,10 +92,10 @@ impl<'a> Parser<'a> { // BindingPattern[?Yield, ?Await] Initializer[?In, ?Yield, ?Await] // the grammar forbids `let []`, `let {}` if !matches!(id.kind, BindingPatternKind::BindingIdentifier(_)) { - self.error(Diagnostic::InvalidDestrucuringDeclaration(id.node().range())); + self.error(Diagnostic::InvalidDestrucuringDeclaration(id.node())); } else if kind == VariableDeclarationKind::Const && !self.ctx.has_ambient() { // It is a Syntax Error if Initializer is not present and IsConstantDeclaration of the LexicalDeclaration containing this LexicalBinding is true. - self.error(Diagnostic::MissinginitializerInConst(id.node().range())); + self.error(Diagnostic::MissinginitializerInConst(id.node())); } } diff --git a/crates/oxc_parser/src/js/expression.rs b/crates/oxc_parser/src/js/expression.rs index 7104f3fa5..e65fbcceb 100644 --- a/crates/oxc_parser/src/js/expression.rs +++ b/crates/oxc_parser/src/js/expression.rs @@ -191,7 +191,7 @@ impl<'a> Parser<'a> { expressions.remove(0) } else { if expressions.is_empty() { - self.error(Diagnostic::EmptyParenthesizedExpression(list.node.range())); + self.error(Diagnostic::EmptyParenthesizedExpression(list.node)); } self.ast.sequence_expression(list.node, expressions) }; @@ -376,7 +376,7 @@ impl<'a> Parser<'a> { // It is a Syntax Error if any source text is matched by this production. // https://tc39.es/ecma262/#sec-left-hand-side-expressions-static-semantics-early-errors if in_optional_chain { - self.error(Diagnostic::OptionalChainTaggedTemplate(quasi.node.range())); + self.error(Diagnostic::OptionalChainTaggedTemplate(quasi.node)); } Ok(self.ast.tagged_template_expression(node, lhs, quasi, type_parameters)) } @@ -384,7 +384,7 @@ impl<'a> Parser<'a> { pub fn parse_template_element(&mut self, tagged: bool) -> TemplateElement { let node = self.start_node(); let cur_kind = self.cur_kind(); - let end_offset = match cur_kind { + let end_offset: u32 = match cur_kind { Kind::TemplateHead | Kind::TemplateMiddle => 2, Kind::NoSubstitutionTemplate | Kind::TemplateTail => 1, _ => unreachable!(), @@ -393,7 +393,7 @@ impl<'a> Parser<'a> { // cooked = None when template literal has invalid escape sequence let cooked = self.cur_atom().map(Clone::clone); - let raw = &self.cur_src()[1..self.cur_src().len() - end_offset]; + let raw = &self.cur_src()[1..self.cur_src().len() - end_offset as usize]; let raw = Atom::from(if cooked.is_some() && raw.contains('\r') { self.ast.new_str(raw.replace("\r\n", "\n").replace('\r', "\n").as_str()) } else { @@ -407,7 +407,7 @@ impl<'a> Parser<'a> { node.end -= end_offset; if !tagged && cooked.is_none() { - self.error(Diagnostic::TemplateLiteral(node.range())); + self.error(Diagnostic::TemplateLiteral(node)); } let tail = matches!(cur_kind, Kind::TemplateTail | Kind::NoSubstitutionTemplate); @@ -475,7 +475,7 @@ impl<'a> Parser<'a> { // SuperCall: // super ( Arguments ) if !matches!(self.cur_kind(), Kind::Dot | Kind::LBrack | Kind::LParen) { - self.error(Diagnostic::UnexpectedSuper(node.range())); + self.error(Diagnostic::UnexpectedSuper(node)); } self.ast.super_(node) @@ -605,13 +605,13 @@ impl<'a> Parser<'a> { }; if matches!(callee, Expression::ImportExpression(_)) { - self.error(Diagnostic::NewDynamicImport(self.end_node(rhs_node).range())); + self.error(Diagnostic::NewDynamicImport(self.end_node(rhs_node))); } let node = self.end_node(node); if optional { - self.error(Diagnostic::NewOptionalChain(node.range())); + self.error(Diagnostic::NewOptionalChain(node)); } Ok(self.ast.new_expression(node, callee, arguments, type_parameter)) diff --git a/crates/oxc_parser/src/js/function.rs b/crates/oxc_parser/src/js/function.rs index 48d604773..8322c54e2 100644 --- a/crates/oxc_parser/src/js/function.rs +++ b/crates/oxc_parser/src/js/function.rs @@ -155,13 +155,15 @@ impl<'a> Parser<'a> { let decl = self.parse_function_impl(func_kind)?; if stmt_ctx.is_single_statement() { if decl.r#async { - self.error(Diagnostic::AsyncFunctionDeclaration( - decl.node.start..decl.params.node.end, - )); + self.error(Diagnostic::AsyncFunctionDeclaration(Node::new( + decl.node.start, + decl.params.node.end, + ))); } else if decl.generator { - self.error(Diagnostic::GeneratorFunctionDeclaration( - decl.node.start..decl.params.node.end, - )); + self.error(Diagnostic::GeneratorFunctionDeclaration(Node::new( + decl.node.start, + decl.params.node.end, + ))); } } @@ -318,7 +320,7 @@ impl<'a> Parser<'a> { self.ctx = ctx; if kind.is_id_required() && id.is_none() { - self.error(Diagnostic::ExpectFunctionName(self.cur_token().range())); + self.error(Diagnostic::ExpectFunctionName(self.cur_token().node())); } id @@ -431,7 +433,7 @@ impl<'a> Parser<'a> { self.ctx = self.ctx.and_await(has_await); if self.cur_token().is_on_new_line { - self.error(Diagnostic::LineterminatorBeforeArrow(self.cur_token().range())); + self.error(Diagnostic::LineterminatorBeforeArrow(self.cur_token().node())); } self.expect(Kind::Arrow)?; diff --git a/crates/oxc_parser/src/js/grammar.rs b/crates/oxc_parser/src/js/grammar.rs index 75ea5920e..d523f0879 100644 --- a/crates/oxc_parser/src/js/grammar.rs +++ b/crates/oxc_parser/src/js/grammar.rs @@ -45,7 +45,7 @@ impl<'a> CoverGrammar<'a, Expression<'a>> for SimpleAssignmentTarget<'a> { let node = expr.node; match expr.unbox().expression { Expression::ObjectExpression(_) | Expression::ArrayExpression(_) => { - Err(Diagnostic::InvalidAssignment(node.range())) + Err(Diagnostic::InvalidAssignment(node)) } expr => SimpleAssignmentTarget::cover(expr, p), } @@ -55,7 +55,7 @@ impl<'a> CoverGrammar<'a, Expression<'a>> for SimpleAssignmentTarget<'a> { Ok(SimpleAssignmentTarget::TSNonNullExpression(expr)) } Expression::TSTypeAssertion(expr) => Ok(SimpleAssignmentTarget::TSTypeAssertion(expr)), - expr => Err(Diagnostic::InvalidAssignment(expr.node().range())), + expr => Err(Diagnostic::InvalidAssignment(expr.node())), } } } @@ -77,10 +77,10 @@ impl<'a> CoverGrammar<'a, ArrayExpression<'a>> for ArrayAssignmentTarget<'a> { if i == len - 1 { rest = Some(AssignmentTarget::cover(elem.unbox().argument, p)?); if let Some(node) = expr.trailing_comma { - p.error(Diagnostic::RestElementTraillingComma(node.range())); + p.error(Diagnostic::RestElementTraillingComma(node)); } } else { - return Err(Diagnostic::SpreadLastElement(elem.node.range())); + return Err(Diagnostic::SpreadLastElement(elem.node)); } } } @@ -135,7 +135,7 @@ impl<'a> CoverGrammar<'a, ObjectExpression<'a>> for ObjectAssignmentTarget<'a> { if i == len - 1 { rest = Some(AssignmentTarget::cover(spread.unbox().argument, p)?); } else { - return Err(Diagnostic::SpreadLastElement(spread.node.range())); + return Err(Diagnostic::SpreadLastElement(spread.node)); } } } @@ -166,7 +166,7 @@ impl<'a> CoverGrammar<'a, Property<'a>> for AssignmentTargetProperty<'a> { let binding = match property.value { PropertyValue::Expression(expr) => AssignmentTargetMaybeDefault::cover(expr, p)?, PropertyValue::Pattern(_) => { - return Err(Diagnostic::InvalidAssignment(property.value.node().range())); + return Err(Diagnostic::InvalidAssignment(property.value.node())); } }; let target = AssignmentTargetPropertyProperty { diff --git a/crates/oxc_parser/src/js/list.rs b/crates/oxc_parser/src/js/list.rs index 91285af0b..b5e637dfe 100644 --- a/crates/oxc_parser/src/js/list.rs +++ b/crates/oxc_parser/src/js/list.rs @@ -65,7 +65,7 @@ impl<'a> SeparatedList<'a> for ObjectPatternProperties<'a> { let rest_element = p.parse_rest_element()?; if !matches!(rest_element.argument.kind, BindingPatternKind::BindingIdentifier(_)) { - p.error(Diagnostic::InvalidRestArgument(rest_element.node.range())); + p.error(Diagnostic::InvalidRestArgument(rest_element.node)); } ObjectPatternProperty::RestElement(rest_element) @@ -291,7 +291,7 @@ impl<'a> SeparatedList<'a> for AssertEntries<'a> { }; if let Some(old_node) = self.keys.get(&key.as_atom()) { - p.error(Diagnostic::Redeclaration(key.as_atom(), old_node.range(), key.node().range())); + p.error(Diagnostic::Redeclaration(key.as_atom(), *old_node, key.node())); } else { self.keys.insert(key.as_atom(), key.node()); } @@ -396,8 +396,8 @@ impl<'a> ClassElements<'a> { { p.error(Diagnostic::Redeclaration( private_ident.name.clone(), - existed.node.range(), - private_ident.node.range(), + existed.node, + private_ident.node, )); } } diff --git a/crates/oxc_parser/src/js/module.rs b/crates/oxc_parser/src/js/module.rs index 40a9097b1..d612594cb 100644 --- a/crates/oxc_parser/src/js/module.rs +++ b/crates/oxc_parser/src/js/module.rs @@ -255,7 +255,7 @@ impl<'a> Parser<'a> { self.error(Diagnostic::ExportNamedString( literal.value.clone(), specifier.local.name().clone(), - literal.node.range(), + literal.node, )); } } @@ -384,7 +384,7 @@ impl<'a> Parser<'a> { // ModuleExportName : StringLiteral // It is a Syntax Error if IsStringWellFormedUnicode(the SV of StringLiteral) is false. if !literal.is_string_well_formed_unicode() { - self.error(Diagnostic::ExportLoneSurrogate(literal.node.range())); + self.error(Diagnostic::ExportLoneSurrogate(literal.node)); }; Ok(ModuleExportName::StringLiteral(literal)) } diff --git a/crates/oxc_parser/src/js/object.rs b/crates/oxc_parser/src/js/object.rs index 7cd855183..48952dfac 100644 --- a/crates/oxc_parser/src/js/object.rs +++ b/crates/oxc_parser/src/js/object.rs @@ -216,7 +216,7 @@ impl<'a> Parser<'a> { let method = self.parse_method(false, false)?; if !method.params.is_empty() { - self.error(Diagnostic::GetterParameters(method.params.node.range())); + self.error(Diagnostic::GetterParameters(method.params.node)); } let value = PropertyValue::Expression(self.ast.function_expression(method)); @@ -240,12 +240,12 @@ impl<'a> Parser<'a> { let method = self.parse_method(false, false)?; if method.params.items.len() != 1 { - self.error(Diagnostic::SetterParameters(method.params.node.range())); + self.error(Diagnostic::SetterParameters(method.params.node)); } if method.params.items.len() == 1 { if let BindingPatternKind::RestElement(elem) = &method.params.items[0].pattern.kind { - self.error(Diagnostic::SetterParametersRestPattern(elem.node.range())); + self.error(Diagnostic::SetterParametersRestPattern(elem.node)); } } diff --git a/crates/oxc_parser/src/js/statement.rs b/crates/oxc_parser/src/js/statement.rs index e4178a2b5..39c60dfca 100644 --- a/crates/oxc_parser/src/js/statement.rs +++ b/crates/oxc_parser/src/js/statement.rs @@ -50,7 +50,8 @@ impl<'a> Parser<'a> { if expecting_diretives { if let Statement::ExpressionStatement(expr) = &stmt { if let Expression::StringLiteral(string) = &expr.expression { - let src = &self.source[string.node.start + 1..string.node.end - 1]; + let src = &self.source + [string.node.start as usize + 1..string.node.end as usize - 1]; let directive = self.ast.directive(expr.node, (*string).clone(), src); directives.push(directive); @@ -192,7 +193,7 @@ impl<'a> Parser<'a> { ))?; if stmt_ctx.is_single_statement() && decl.kind.is_lexical() { - self.error(Diagnostic::LexicalDeclarationSingleStatement(decl.node.range())); + self.error(Diagnostic::LexicalDeclarationSingleStatement(decl.node)); } Ok(Statement::Declaration(Declaration::VariableDeclaration(decl))) @@ -297,18 +298,15 @@ impl<'a> Parser<'a> { // for (a.b in ...), for ([a] in ..), for ({a} in ..) if self.at(Kind::In) || self.at(Kind::Of) { let target = AssignmentTarget::cover(init_expression, self) - .map_err(|_| Diagnostic::UnexpectedToken(self.end_node(expression_node).range()))?; + .map_err(|_| Diagnostic::UnexpectedToken(self.end_node(expression_node)))?; let for_stmt_left = ForStatementLeft::AssignmentTarget(target); if !r#await && is_async_of { - self.error(Diagnostic::ForLoopAsyncOf(self.end_node(expression_node).range())); + self.error(Diagnostic::ForLoopAsyncOf(self.end_node(expression_node))); } if is_let_of { - self.error(Diagnostic::UnexpectedKeyword( - "let", - self.end_node(expression_node).range(), - )); + self.error(Diagnostic::UnexpectedKeyword("let", self.end_node(expression_node))); } return self.parse_for_in_or_of_loop(node, r#await, for_stmt_left); @@ -330,7 +328,7 @@ impl<'a> Parser<'a> { self.expect(Kind::RParen)?; if r#await { - self.error(Diagnostic::ForAwait(self.end_node(node).range())); + self.error(Diagnostic::ForAwait(self.end_node(node))); } let body = self.parse_statement_list_item(StatementContext::For)?; @@ -354,7 +352,7 @@ impl<'a> Parser<'a> { self.expect(Kind::RParen)?; if r#await && is_for_in { - self.error(Diagnostic::ForAwait(self.end_node(node).range())); + self.error(Diagnostic::ForAwait(self.end_node(node))); } let body = self.parse_statement_list_item(StatementContext::For)?; @@ -454,8 +452,8 @@ impl<'a> Parser<'a> { if self.cur_token().is_on_new_line { self.error(Diagnostic::IllegalNewline( "throw", - self.end_node(node).range(), - self.cur_token().range(), + self.end_node(node), + self.cur_token().node(), )); } let argument = self.parse_expression()?; @@ -474,8 +472,7 @@ impl<'a> Parser<'a> { let finalizer = self.eat(Kind::Finally).then(|| self.parse_block()).transpose()?; - #[allow(clippy::range_plus_one)] - let range = self.prev_token_end..self.prev_token_end + 1; + let range = Node::new(self.prev_token_end, self.prev_token_end + 1); if handler.is_none() && finalizer.is_none() { self.error(Diagnostic::ExpectCatchFinally(range)); } diff --git a/crates/oxc_parser/src/lexer/mod.rs b/crates/oxc_parser/src/lexer/mod.rs index 687bfcba0..497a0988c 100644 --- a/crates/oxc_parser/src/lexer/mod.rs +++ b/crates/oxc_parser/src/lexer/mod.rs @@ -21,7 +21,7 @@ use constants::{ pub use kind::Kind; use number::{parse_big_int, parse_float, parse_int}; use oxc_allocator::{Allocator, String}; -use oxc_ast::{Atom, SourceType, Span}; +use oxc_ast::{Atom, Node, SourceType}; use oxc_diagnostics::{Diagnostic, Diagnostics}; use simd::{SkipMultilineComment, SkipWhitespace}; use string_builder::AutoCow; @@ -205,7 +205,7 @@ impl<'a> Lexer<'a> { } /// Expand the current token for `JSXIdentifier` - pub fn next_jsx_identifier(&mut self, prev_len: usize) -> Token { + pub fn next_jsx_identifier(&mut self, prev_len: u32) -> Token { let kind = self.read_jsx_identifier(prev_len); self.lookahead.clear(); self.finish_next(kind) @@ -219,7 +219,7 @@ impl<'a> Lexer<'a> { _ => unreachable!(), }; self.current.token.start = self.offset() - offset; - self.current.chars = self.source[self.current.token.start + 1..].chars(); + self.current.chars = self.source[self.current.token.start as usize + 1..].chars(); let kind = Kind::LAngle; self.lookahead.clear(); self.finish_next(kind) @@ -234,7 +234,7 @@ impl<'a> Lexer<'a> { _ => unreachable!(), }; self.current.token.start = self.offset() - offset; - self.current.chars = self.source[self.current.token.start + 1..].chars(); + self.current.chars = self.source[self.current.token.start as usize + 1..].chars(); let kind = Kind::RAngle; self.lookahead.clear(); self.finish_next(kind) @@ -247,13 +247,14 @@ impl<'a> Lexer<'a> { /// Get the length offset from the source, in UTF-8 bytes #[inline] - fn offset(&self) -> usize { - self.source.len() - self.current.chars.as_str().len() + #[allow(clippy::cast_possible_truncation)] + fn offset(&self) -> u32 { + (self.source.len() - self.current.chars.as_str().len()) as u32 } /// Get the current unterminated token range - fn unterminated_range(&self) -> Span { - self.current.token.start..self.offset() + fn unterminated_range(&self) -> Node { + Node::new(self.current.token.start, self.offset()) } /// Peek the next char without advancing the position @@ -279,9 +280,9 @@ impl<'a> Lexer<'a> { matched } - fn current_offset(&self) -> std::ops::Range { + fn current_offset(&self) -> Node { let offset = self.offset(); - offset..offset + Node::new(offset, offset) } /// Return `IllegalCharacter` Error or `UnexpectedEnd` if EOF @@ -316,7 +317,10 @@ impl<'a> Lexer<'a> { match value { Ok(value) => self.current.token.value = value, Err(err) => { - self.error(Diagnostic::InvalidNumber(err, self.current.token.start..self.offset())); + self.error(Diagnostic::InvalidNumber( + err, + Node::new(self.current.token.start, self.offset()), + )); self.current.token.value = TokenValue::Number(std::f64::NAN); } }; @@ -710,11 +714,11 @@ impl<'a> Lexer<'a> { self.identifier_unicode_escape_sequence(&mut builder, true); } Some(c) => { - self.error(Diagnostic::InvalidCharacter(c, start..self.offset() - 1)); + self.error(Diagnostic::InvalidCharacter(c, Node::new(start, self.offset() - 1))); return Kind::Undetermined; } None => { - self.error(Diagnostic::UnexpectedEnd(start..self.offset() - 1)); + self.error(Diagnostic::UnexpectedEnd(Node::new(start, self.offset() - 1))); return Kind::Undetermined; } } @@ -931,7 +935,7 @@ impl<'a> Lexer<'a> { break; } } - self.error(Diagnostic::InvalidNumberEnd(offset..self.offset())); + self.error(Diagnostic::InvalidNumberEnd(Node::new(offset, self.offset()))); Kind::Undetermined } @@ -958,7 +962,7 @@ impl<'a> Lexer<'a> { let mut is_valid_escape_sequence = true; self.read_string_escape_sequence(text, false, &mut is_valid_escape_sequence); if !is_valid_escape_sequence { - let range = start..self.offset(); + let range = Node::new(start, self.offset()); self.error(Diagnostic::InvalidEscapeSequence(range)); } } @@ -1080,8 +1084,8 @@ impl<'a> Lexer<'a> { /// `IdentifierStart` /// `JSXIdentifier` `IdentifierPart` /// `JSXIdentifier` [no `WhiteSpace` or Comment here] - - fn read_jsx_identifier(&mut self, prev_len: usize) -> Kind { - let prev_str = &self.source[prev_len..self.offset()]; + fn read_jsx_identifier(&mut self, prev_len: u32) -> Kind { + let prev_str = &self.source[prev_len as usize..self.offset() as usize]; let mut builder = AutoCow::new(self); loop { @@ -1185,7 +1189,7 @@ impl<'a> Lexer<'a> { ) { let start = self.offset(); if self.current.chars.next() != Some('u') { - let range = start..self.offset(); + let range = Node::new(start, self.offset()); self.error(Diagnostic::UnicodeEscapeSequence(range)); return; } @@ -1196,7 +1200,7 @@ impl<'a> Lexer<'a> { }; let Some(value) = value else { - let range = start..self.offset(); + let range = Node::new(start,self.offset()); self.error(Diagnostic::UnicodeEscapeSequence(range)); return; }; @@ -1204,7 +1208,7 @@ impl<'a> Lexer<'a> { // For Identifiers, surrogate pair is an invalid grammar, e.g. `var \uD800\uDEA7`. let ch = match value { SurrogatePair::Astral(..) | SurrogatePair::HighLow(..) => { - let range = start..self.offset(); + let range = Node::new(start, self.offset()); self.error(Diagnostic::UnicodeEscapeSequence(range)); return; } @@ -1212,7 +1216,7 @@ impl<'a> Lexer<'a> { if let Ok(ch) = char::try_from(code_point) { ch } else { - let range = start..self.offset(); + let range = Node::new(start, self.offset()); self.error(Diagnostic::UnicodeEscapeSequence(range)); return; } diff --git a/crates/oxc_parser/src/lexer/token.rs b/crates/oxc_parser/src/lexer/token.rs index de2918840..5ec9bcb6a 100644 --- a/crates/oxc_parser/src/lexer/token.rs +++ b/crates/oxc_parser/src/lexer/token.rs @@ -1,9 +1,7 @@ //! Token -use std::ops::Range; - use num_bigint::BigUint; -use oxc_ast::Atom; +use oxc_ast::{Atom, Node}; use super::kind::Kind; @@ -13,10 +11,10 @@ pub struct Token { pub kind: Kind, /// Start offset in source - pub start: usize, + pub start: u32, /// End offset in source - pub end: usize, + pub end: u32, /// Indicates the token is on a newline pub is_on_new_line: bool, @@ -29,8 +27,8 @@ pub struct Token { impl Token { #[must_use] - pub const fn range(&self) -> Range { - self.start..self.end + pub const fn node(&self) -> Node { + Node::new(self.start, self.end) } } diff --git a/crates/oxc_parser/src/lib.rs b/crates/oxc_parser/src/lib.rs index 180595868..80cd5d244 100644 --- a/crates/oxc_parser/src/lib.rs +++ b/crates/oxc_parser/src/lib.rs @@ -46,7 +46,7 @@ pub struct Parser<'a> { token: Token, /// The end range of the previous token - prev_token_end: usize, + prev_token_end: u32, /// Parser state state: ParserState<'a>, @@ -102,6 +102,7 @@ impl<'a> Parser<'a> { ParserReturn { program, errors: self.errors.borrow().clone() } } + #[allow(clippy::cast_possible_truncation)] fn parse_program(&mut self) -> Result> { // initialize cur_token and prev_token by moving onto the first token self.bump_any(); @@ -109,7 +110,7 @@ impl<'a> Parser<'a> { let (directives, statements) = self.parse_directives_and_statements(/* is_top_level */ true)?; - let node = Node::new(0, self.source.len()); + let node = Node::new(0, self.source.len() as u32); Ok(self.ast.program(node, directives, statements, self.source_type)) } @@ -119,7 +120,7 @@ impl<'a> Parser<'a> { if self.source_type.is_javascript() && (self.source.starts_with("// @flow") || self.source.starts_with("/* @flow */")) { - return Some(Diagnostic::Flow(0..8)); + return Some(Diagnostic::Flow(Node::new(0, 8))); } None } diff --git a/crates/oxc_parser/src/state.rs b/crates/oxc_parser/src/state.rs index b6271ed61..3121b7239 100644 --- a/crates/oxc_parser/src/state.rs +++ b/crates/oxc_parser/src/state.rs @@ -5,7 +5,7 @@ use oxc_ast::ast::Decorator; #[derive(Default)] pub struct ParserState<'a> { - pub not_parenthesized_arrow: HashSet, + pub not_parenthesized_arrow: HashSet, pub decorators: Option>>, } diff --git a/crates/oxc_parser/src/ts/types.rs b/crates/oxc_parser/src/ts/types.rs index 509b0b379..91d317e18 100644 --- a/crates/oxc_parser/src/ts/types.rs +++ b/crates/oxc_parser/src/ts/types.rs @@ -877,7 +877,7 @@ impl<'a> Parser<'a> { self.bump(Kind::Comma); self.bump(Kind::Semicolon); if !params.is_empty() { - self.error(Diagnostic::GetterParameters(params.node.range())); + self.error(Diagnostic::GetterParameters(params.node)); } Ok(self.ast.ts_method_signature( self.end_node(node), @@ -900,12 +900,10 @@ impl<'a> Parser<'a> { self.bump(Kind::Comma); self.bump(Kind::Semicolon); if params.items.len() != 1 { - self.error(Diagnostic::SetterParameters(params.node.range())); + self.error(Diagnostic::SetterParameters(params.node)); } if let Some(return_type) = return_type.as_ref() { - self.error(Diagnostic::ASetAccessorCannotHaveAReturnTypeAnnotation( - return_type.node.range(), - )); + self.error(Diagnostic::ASetAccessorCannotHaveAReturnTypeAnnotation(return_type.node)); } Ok(self.ast.ts_method_signature( self.end_node(node),