Skip to main content

sim_codec_javascript/
types.rs

1//! Runtime-independent public syntax and extension data.
2
3use std::fmt;
4
5/// Half-open UTF-8 byte range in the original source.
6#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
7pub struct Span {
8    /// First byte.
9    pub start: usize,
10    /// Byte after the range.
11    pub end: usize,
12}
13
14/// Script or Module syntactic goal.
15#[derive(Clone, Copy, Debug, Eq, PartialEq)]
16pub enum Goal {
17    /// Script goal.
18    Script,
19    /// Module goal (always strict).
20    Module,
21}
22
23/// Parser-selected lexical goal governing slash and template recognition.
24#[derive(Clone, Copy, Debug, Eq, PartialEq)]
25pub enum LexicalGoal {
26    /// Division or division-assignment is admitted.
27    Div,
28    /// A regular-expression literal is admitted.
29    RegExp,
30    /// A template tail follows a substitution.
31    TemplateTail,
32}
33
34/// Kind of lossless token.
35#[derive(Clone, Debug, Eq, PartialEq)]
36pub enum TokenKind {
37    /// IdentifierName, including escaped spelling.
38    Identifier,
39    /// Reserved or contextual keyword spelling.
40    Keyword,
41    /// Numeric literal.
42    Number,
43    /// String literal.
44    String,
45    /// Regular-expression literal.
46    RegExp,
47    /// No-substitution template or template segment.
48    Template,
49    /// Punctuator.
50    Punctuator,
51    /// Whitespace, line terminator, comment, or hashbang.
52    Trivia,
53    /// End marker.
54    End,
55}
56
57/// A lossless lexical token. Text is recovered using [`Token::span`].
58#[derive(Clone, Debug, Eq, PartialEq)]
59pub struct Token {
60    /// Token category.
61    pub kind: TokenKind,
62    /// Original byte range.
63    pub span: Span,
64    /// One-based line.
65    pub line: usize,
66    /// Zero-based Unicode-scalar column.
67    pub column: usize,
68    /// Lexical goal used to recognize this token.
69    pub goal: LexicalGoal,
70}
71
72/// Evidence for an explicit or automatic semicolon boundary.
73#[derive(Clone, Copy, Debug, Eq, PartialEq)]
74pub enum Asi {
75    /// Source contained a semicolon.
76    Explicit(Span),
77    /// A line terminator caused insertion.
78    LineTerminator(Span),
79    /// A closing brace caused insertion.
80    ClosingBrace(Span),
81    /// End of input caused insertion.
82    EndOfInput(Span),
83}
84
85/// Neutral concrete-tree node category, stable for downstream extensions.
86#[derive(Clone, Debug, Eq, PartialEq)]
87#[non_exhaustive]
88pub enum NodeKind {
89    /// Script root.
90    Script,
91    /// Module root.
92    Module,
93    /// Statement list.
94    StatementList,
95    /// A declaration.
96    Declaration,
97    /// A statement.
98    Statement,
99    /// Function declaration or expression.
100    Function,
101    /// Class declaration or expression.
102    Class,
103    /// Import declaration.
104    Import,
105    /// Export declaration.
106    Export,
107    /// Expression region grouped through shared Pratt precedence.
108    Expression,
109    /// Delimited or computed region.
110    Group,
111}
112
113/// A concrete node covering a contiguous token range.
114#[derive(Clone, Debug, Eq, PartialEq)]
115pub struct Node {
116    /// Node category.
117    pub kind: NodeKind,
118    /// Half-open token-index range.
119    pub tokens: std::ops::Range<usize>,
120    /// Nested structural nodes.
121    pub children: Vec<Node>,
122    /// Semicolon boundary, when applicable.
123    pub asi: Option<Asi>,
124}
125
126/// Source identity attachable by JavaScript or downstream syntax extensions.
127#[derive(Clone, Debug, Eq, PartialEq)]
128pub struct Origin {
129    /// Caller-owned source identity.
130    pub source: String,
131    /// Source byte range.
132    pub span: Span,
133    /// Optional parent origin, preserving transformation chains.
134    pub parent: Option<Box<Origin>>,
135}
136
137/// Complete lossless syntax tree.
138#[derive(Clone, Debug, Eq, PartialEq)]
139pub struct SyntaxTree {
140    source: String,
141    /// Selected root goal.
142    pub goal: Goal,
143    /// Lossless tokens, including trivia.
144    pub tokens: Vec<Token>,
145    /// Structural root.
146    pub root: Node,
147}
148impl SyntaxTree {
149    /// Returns the exact admitted input.
150    #[must_use]
151    pub fn source(&self) -> &str {
152        &self.source
153    }
154    /// Re-emits the input byte-for-byte.
155    #[must_use]
156    pub fn preserve_source(&self) -> String {
157        self.source.clone()
158    }
159    pub(crate) fn new(source: &str, goal: Goal, tokens: Vec<Token>, root: Node) -> Self {
160        Self {
161            source: source.to_owned(),
162            goal,
163            tokens,
164            root,
165        }
166    }
167}
168
169/// Resource limits shared by lexing and parsing.
170#[derive(Clone, Copy, Debug, Eq, PartialEq)]
171pub struct Limits {
172    /// Maximum source bytes.
173    pub max_bytes: usize,
174    /// Maximum emitted tokens.
175    pub max_tokens: usize,
176    /// Maximum delimiter/template/tree nesting.
177    pub max_nesting: usize,
178    /// Maximum physical lines.
179    pub max_lines: usize,
180    /// Maximum nodes.
181    pub max_nodes: usize,
182}
183impl Default for Limits {
184    fn default() -> Self {
185        Self {
186            max_bytes: 4 * 1024 * 1024,
187            max_tokens: 1_000_000,
188            max_nesting: 256,
189            max_lines: 250_000,
190            max_nodes: 1_000_000,
191        }
192    }
193}
194
195/// Stable diagnostic category.
196#[derive(Clone, Copy, Debug, Eq, PartialEq)]
197pub enum DiagnosticCode {
198    /// Configured resource bound crossed.
199    ResourceLimit,
200    /// Invalid source character.
201    InvalidCharacter,
202    /// Unterminated literal or comment.
203    UnterminatedLiteral,
204    /// Unmatched or crossed delimiter.
205    UnmatchedDelimiter,
206    /// Grammar violation.
207    InvalidSyntax,
208    /// Static-semantics early error.
209    EarlyError,
210}
211/// Deterministic located frontend failure.
212#[derive(Clone, Debug, Eq, PartialEq)]
213pub struct Diagnostic {
214    /// Stable category.
215    pub code: DiagnosticCode,
216    /// Offending source range.
217    pub span: Span,
218    /// One-based line.
219    pub line: usize,
220    /// Zero-based scalar column.
221    pub column: usize,
222    /// Stable detail.
223    pub message: String,
224}
225impl fmt::Display for Diagnostic {
226    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
227        write!(f, "{}:{}: {}", self.line, self.column, self.message)
228    }
229}
230impl std::error::Error for Diagnostic {}