mirror of
https://github.com/denoland/deno.git
synced 2025-01-10 16:11:13 -05:00
a844d96ee9
Addresses the review feedback in https://github.com/denoland/deno/pull/27416 . - Hoist the buffer max size variable to make it less confusing - Remove manual AST field counter in favour of an explicit "commit schema" step which writes the actual field count.
520 lines
12 KiB
Rust
520 lines
12 KiB
Rust
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
|
|
|
use std::fmt;
|
|
use std::fmt::Debug;
|
|
use std::fmt::Display;
|
|
|
|
use deno_ast::swc::common::Span;
|
|
|
|
use super::buffer::AstBufSerializer;
|
|
use super::buffer::BoolPos;
|
|
use super::buffer::FieldArrPos;
|
|
use super::buffer::FieldPos;
|
|
use super::buffer::NodeRef;
|
|
use super::buffer::NullPos;
|
|
use super::buffer::PendingNodeRef;
|
|
use super::buffer::SerializeCtx;
|
|
use super::buffer::StrPos;
|
|
use super::buffer::UndefPos;
|
|
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
pub enum AstNode {
|
|
// First node must always be the empty/invalid node
|
|
Invalid,
|
|
// Typically the
|
|
Program,
|
|
|
|
// Module declarations
|
|
ExportAllDeclaration,
|
|
ExportDefaultDeclaration,
|
|
ExportNamedDeclaration,
|
|
ImportDeclaration,
|
|
TsExportAssignment,
|
|
TsImportEquals,
|
|
TsNamespaceExport,
|
|
|
|
// Decls
|
|
ClassDeclaration,
|
|
FunctionDeclaration,
|
|
TSEnumDeclaration,
|
|
TSInterface,
|
|
TsModule,
|
|
TsTypeAlias,
|
|
Using,
|
|
VariableDeclaration,
|
|
|
|
// Statements
|
|
BlockStatement,
|
|
BreakStatement,
|
|
ContinueStatement,
|
|
DebuggerStatement,
|
|
DoWhileStatement,
|
|
EmptyStatement,
|
|
ExpressionStatement,
|
|
ForInStatement,
|
|
ForOfStatement,
|
|
ForStatement,
|
|
IfStatement,
|
|
LabeledStatement,
|
|
ReturnStatement,
|
|
SwitchCase,
|
|
SwitchStatement,
|
|
ThrowStatement,
|
|
TryStatement,
|
|
WhileStatement,
|
|
WithStatement,
|
|
|
|
// Expressions
|
|
ArrayExpression,
|
|
ArrowFunctionExpression,
|
|
AssignmentExpression,
|
|
AwaitExpression,
|
|
BinaryExpression,
|
|
CallExpression,
|
|
ChainExpression,
|
|
ClassExpression,
|
|
ConditionalExpression,
|
|
FunctionExpression,
|
|
Identifier,
|
|
ImportExpression,
|
|
LogicalExpression,
|
|
MemberExpression,
|
|
MetaProp,
|
|
NewExpression,
|
|
ObjectExpression,
|
|
PrivateIdentifier,
|
|
SequenceExpression,
|
|
Super,
|
|
TaggedTemplateExpression,
|
|
TemplateLiteral,
|
|
ThisExpression,
|
|
TSAsExpression,
|
|
TsConstAssertion,
|
|
TsInstantiation,
|
|
TSNonNullExpression,
|
|
TSSatisfiesExpression,
|
|
TSTypeAssertion,
|
|
UnaryExpression,
|
|
UpdateExpression,
|
|
YieldExpression,
|
|
|
|
// TODO: TSEsTree uses a single literal node
|
|
// Literals
|
|
StringLiteral,
|
|
Bool,
|
|
Null,
|
|
NumericLiteral,
|
|
BigIntLiteral,
|
|
RegExpLiteral,
|
|
|
|
EmptyExpr,
|
|
SpreadElement,
|
|
Property,
|
|
VariableDeclarator,
|
|
CatchClause,
|
|
RestElement,
|
|
ExportSpecifier,
|
|
TemplateElement,
|
|
MethodDefinition,
|
|
ClassBody,
|
|
|
|
// Patterns
|
|
ArrayPattern,
|
|
AssignmentPattern,
|
|
ObjectPattern,
|
|
|
|
// JSX
|
|
JSXAttribute,
|
|
JSXClosingElement,
|
|
JSXClosingFragment,
|
|
JSXElement,
|
|
JSXEmptyExpression,
|
|
JSXExpressionContainer,
|
|
JSXFragment,
|
|
JSXIdentifier,
|
|
JSXMemberExpression,
|
|
JSXNamespacedName,
|
|
JSXOpeningElement,
|
|
JSXOpeningFragment,
|
|
JSXSpreadAttribute,
|
|
JSXSpreadChild,
|
|
JSXText,
|
|
|
|
TSTypeAnnotation,
|
|
TSTypeParameterDeclaration,
|
|
TSTypeParameter,
|
|
TSTypeParameterInstantiation,
|
|
TSEnumMember,
|
|
TSInterfaceBody,
|
|
TSInterfaceHeritage,
|
|
TSTypeReference,
|
|
TSThisType,
|
|
TSLiteralType,
|
|
TSInferType,
|
|
TSConditionalType,
|
|
TSUnionType,
|
|
TSIntersectionType,
|
|
TSMappedType,
|
|
TSTypeQuery,
|
|
TSTupleType,
|
|
TSNamedTupleMember,
|
|
TSFunctionType,
|
|
TsCallSignatureDeclaration,
|
|
TSPropertySignature,
|
|
TSMethodSignature,
|
|
TSIndexSignature,
|
|
TSIndexedAccessType,
|
|
TSTypeOperator,
|
|
TSTypePredicate,
|
|
TSImportType,
|
|
TSRestType,
|
|
TSArrayType,
|
|
TSClassImplements,
|
|
|
|
TSAnyKeyword,
|
|
TSBigIntKeyword,
|
|
TSBooleanKeyword,
|
|
TSIntrinsicKeyword,
|
|
TSNeverKeyword,
|
|
TSNullKeyword,
|
|
TSNumberKeyword,
|
|
TSObjectKeyword,
|
|
TSStringKeyword,
|
|
TSSymbolKeyword,
|
|
TSUndefinedKeyword,
|
|
TSUnknownKeyword,
|
|
TSVoidKeyword,
|
|
TSEnumBody, // Last value is used for max value
|
|
}
|
|
|
|
impl Display for AstNode {
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
Debug::fmt(self, f)
|
|
}
|
|
}
|
|
|
|
impl From<AstNode> for u8 {
|
|
fn from(m: AstNode) -> u8 {
|
|
m as u8
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub enum AstProp {
|
|
// Base, these must be in sync with JS in the same order.
|
|
Invalid,
|
|
Type,
|
|
Parent,
|
|
Range,
|
|
Length, // Not used in AST, but can be used in attr selectors
|
|
|
|
// Starting from here the order doesn't matter.
|
|
// Following are all possible AST node properties.
|
|
Abstract,
|
|
Accessibility,
|
|
Alternate,
|
|
Argument,
|
|
Arguments,
|
|
Asserts,
|
|
Async,
|
|
Attributes,
|
|
Await,
|
|
Block,
|
|
Body,
|
|
Callee,
|
|
Cases,
|
|
Children,
|
|
CheckType,
|
|
ClosingElement,
|
|
ClosingFragment,
|
|
Computed,
|
|
Consequent,
|
|
Const,
|
|
Constraint,
|
|
Cooked,
|
|
Declaration,
|
|
Declarations,
|
|
Declare,
|
|
Default,
|
|
Definite,
|
|
Delegate,
|
|
Discriminant,
|
|
Elements,
|
|
ElementType,
|
|
ElementTypes,
|
|
ExprName,
|
|
Expression,
|
|
Expressions,
|
|
Exported,
|
|
Extends,
|
|
ExtendsType,
|
|
FalseType,
|
|
Finalizer,
|
|
Flags,
|
|
Generator,
|
|
Handler,
|
|
Id,
|
|
In,
|
|
IndexType,
|
|
Init,
|
|
Initializer,
|
|
Implements,
|
|
Key,
|
|
Kind,
|
|
Label,
|
|
Left,
|
|
Literal,
|
|
Local,
|
|
Members,
|
|
Meta,
|
|
Method,
|
|
Name,
|
|
Namespace,
|
|
NameType,
|
|
Object,
|
|
ObjectType,
|
|
OpeningElement,
|
|
OpeningFragment,
|
|
Operator,
|
|
Optional,
|
|
Out,
|
|
Param,
|
|
ParameterName,
|
|
Params,
|
|
Pattern,
|
|
Prefix,
|
|
Properties,
|
|
Property,
|
|
Qualifier,
|
|
Quasi,
|
|
Quasis,
|
|
Raw,
|
|
Readonly,
|
|
ReturnType,
|
|
Right,
|
|
SelfClosing,
|
|
Shorthand,
|
|
Source,
|
|
SourceType,
|
|
Specifiers,
|
|
Static,
|
|
SuperClass,
|
|
SuperTypeArguments,
|
|
Tag,
|
|
Tail,
|
|
Test,
|
|
TrueType,
|
|
TypeAnnotation,
|
|
TypeArguments,
|
|
TypeName,
|
|
TypeParameter,
|
|
TypeParameters,
|
|
Types,
|
|
Update,
|
|
Value, // Last value is used for max value
|
|
}
|
|
|
|
// TODO: Feels like there should be an easier way to iterater over an
|
|
// enum in Rust and lowercase the first letter.
|
|
impl Display for AstProp {
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
let s = match self {
|
|
AstProp::Invalid => "__invalid__", // unused
|
|
AstProp::Parent => "parent",
|
|
AstProp::Range => "range",
|
|
AstProp::Type => "type",
|
|
AstProp::Length => "length",
|
|
AstProp::Abstract => "abstract",
|
|
AstProp::Accessibility => "accessibility",
|
|
AstProp::Alternate => "alternate",
|
|
AstProp::Argument => "argument",
|
|
AstProp::Arguments => "arguments",
|
|
AstProp::Asserts => "asserts",
|
|
AstProp::Async => "async",
|
|
AstProp::Attributes => "attributes",
|
|
AstProp::Await => "await",
|
|
AstProp::Block => "block",
|
|
AstProp::Body => "body",
|
|
AstProp::Callee => "callee",
|
|
AstProp::Cases => "cases",
|
|
AstProp::Children => "children",
|
|
AstProp::CheckType => "checkType",
|
|
AstProp::ClosingElement => "closingElement",
|
|
AstProp::ClosingFragment => "closingFragment",
|
|
AstProp::Computed => "computed",
|
|
AstProp::Consequent => "consequent",
|
|
AstProp::Const => "const",
|
|
AstProp::Constraint => "constraint",
|
|
AstProp::Cooked => "cooked",
|
|
AstProp::Declaration => "declaration",
|
|
AstProp::Declarations => "declarations",
|
|
AstProp::Declare => "declare",
|
|
AstProp::Default => "default",
|
|
AstProp::Definite => "definite",
|
|
AstProp::Delegate => "delegate",
|
|
AstProp::Discriminant => "discriminant",
|
|
AstProp::Elements => "elements",
|
|
AstProp::ElementType => "elementType",
|
|
AstProp::ElementTypes => "elementTypes",
|
|
AstProp::ExprName => "exprName",
|
|
AstProp::Expression => "expression",
|
|
AstProp::Expressions => "expressions",
|
|
AstProp::Exported => "exported",
|
|
AstProp::Extends => "extends",
|
|
AstProp::ExtendsType => "extendsType",
|
|
AstProp::FalseType => "falseType",
|
|
AstProp::Finalizer => "finalizer",
|
|
AstProp::Flags => "flags",
|
|
AstProp::Generator => "generator",
|
|
AstProp::Handler => "handler",
|
|
AstProp::Id => "id",
|
|
AstProp::In => "in",
|
|
AstProp::IndexType => "indexType",
|
|
AstProp::Init => "init",
|
|
AstProp::Initializer => "initializer",
|
|
AstProp::Implements => "implements",
|
|
AstProp::Key => "key",
|
|
AstProp::Kind => "kind",
|
|
AstProp::Label => "label",
|
|
AstProp::Left => "left",
|
|
AstProp::Literal => "literal",
|
|
AstProp::Local => "local",
|
|
AstProp::Members => "members",
|
|
AstProp::Meta => "meta",
|
|
AstProp::Method => "method",
|
|
AstProp::Name => "name",
|
|
AstProp::Namespace => "namespace",
|
|
AstProp::NameType => "nameType",
|
|
AstProp::Object => "object",
|
|
AstProp::ObjectType => "objectType",
|
|
AstProp::OpeningElement => "openingElement",
|
|
AstProp::OpeningFragment => "openingFragment",
|
|
AstProp::Operator => "operator",
|
|
AstProp::Optional => "optional",
|
|
AstProp::Out => "out",
|
|
AstProp::Param => "param",
|
|
AstProp::ParameterName => "parameterName",
|
|
AstProp::Params => "params",
|
|
AstProp::Pattern => "pattern",
|
|
AstProp::Prefix => "prefix",
|
|
AstProp::Properties => "properties",
|
|
AstProp::Property => "property",
|
|
AstProp::Qualifier => "qualifier",
|
|
AstProp::Quasi => "quasi",
|
|
AstProp::Quasis => "quasis",
|
|
AstProp::Raw => "raw",
|
|
AstProp::Readonly => "readonly",
|
|
AstProp::ReturnType => "returnType",
|
|
AstProp::Right => "right",
|
|
AstProp::SelfClosing => "selfClosing",
|
|
AstProp::Shorthand => "shorthand",
|
|
AstProp::Source => "source",
|
|
AstProp::SourceType => "sourceType",
|
|
AstProp::Specifiers => "specifiers",
|
|
AstProp::Static => "static",
|
|
AstProp::SuperClass => "superClass",
|
|
AstProp::SuperTypeArguments => "superTypeArguments",
|
|
AstProp::Tag => "tag",
|
|
AstProp::Tail => "tail",
|
|
AstProp::Test => "test",
|
|
AstProp::TrueType => "trueType",
|
|
AstProp::TypeAnnotation => "typeAnnotation",
|
|
AstProp::TypeArguments => "typeArguments",
|
|
AstProp::TypeName => "typeName",
|
|
AstProp::TypeParameter => "typeParameter",
|
|
AstProp::TypeParameters => "typeParameters",
|
|
AstProp::Types => "types",
|
|
AstProp::Update => "update",
|
|
AstProp::Value => "value",
|
|
};
|
|
|
|
write!(f, "{}", s)
|
|
}
|
|
}
|
|
|
|
impl From<AstProp> for u8 {
|
|
fn from(m: AstProp) -> u8 {
|
|
m as u8
|
|
}
|
|
}
|
|
|
|
pub struct TsEsTreeBuilder {
|
|
ctx: SerializeCtx,
|
|
}
|
|
|
|
// TODO: Add a builder API to make it easier to convert from different source
|
|
// ast formats.
|
|
impl TsEsTreeBuilder {
|
|
pub fn new() -> Self {
|
|
// Max values
|
|
// TODO: Maybe there is a rust macro to grab the last enum value?
|
|
let kind_max_count: u8 = u8::from(AstNode::TSEnumBody) + 1;
|
|
let prop_max_count: u8 = u8::from(AstProp::Value) + 1;
|
|
Self {
|
|
ctx: SerializeCtx::new(kind_max_count, prop_max_count),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl AstBufSerializer<AstNode, AstProp> for TsEsTreeBuilder {
|
|
fn header(
|
|
&mut self,
|
|
kind: AstNode,
|
|
parent: NodeRef,
|
|
span: &Span,
|
|
) -> PendingNodeRef {
|
|
self.ctx.header(kind, parent, span)
|
|
}
|
|
|
|
fn commit_schema(&mut self, offset: PendingNodeRef) -> NodeRef {
|
|
self.ctx.commit_schema(offset)
|
|
}
|
|
|
|
fn ref_field(&mut self, prop: AstProp) -> FieldPos {
|
|
FieldPos(self.ctx.ref_field(prop))
|
|
}
|
|
|
|
fn ref_vec_field(&mut self, prop: AstProp, len: usize) -> FieldArrPos {
|
|
FieldArrPos(self.ctx.ref_vec_field(prop, len))
|
|
}
|
|
|
|
fn str_field(&mut self, prop: AstProp) -> StrPos {
|
|
StrPos(self.ctx.str_field(prop))
|
|
}
|
|
|
|
fn bool_field(&mut self, prop: AstProp) -> BoolPos {
|
|
BoolPos(self.ctx.bool_field(prop))
|
|
}
|
|
|
|
fn undefined_field(&mut self, prop: AstProp) -> UndefPos {
|
|
UndefPos(self.ctx.undefined_field(prop))
|
|
}
|
|
|
|
fn null_field(&mut self, prop: AstProp) -> NullPos {
|
|
NullPos(self.ctx.null_field(prop))
|
|
}
|
|
|
|
fn write_ref(&mut self, pos: FieldPos, value: NodeRef) {
|
|
self.ctx.write_ref(pos.0, value);
|
|
}
|
|
|
|
fn write_maybe_ref(&mut self, pos: FieldPos, value: Option<NodeRef>) {
|
|
self.ctx.write_maybe_ref(pos.0, value);
|
|
}
|
|
|
|
fn write_refs(&mut self, pos: FieldArrPos, value: Vec<NodeRef>) {
|
|
self.ctx.write_refs(pos.0, value);
|
|
}
|
|
|
|
fn write_str(&mut self, pos: StrPos, value: &str) {
|
|
self.ctx.write_str(pos.0, value);
|
|
}
|
|
|
|
fn write_bool(&mut self, pos: BoolPos, value: bool) {
|
|
self.ctx.write_bool(pos.0, value);
|
|
}
|
|
|
|
fn serialize(&mut self) -> Vec<u8> {
|
|
self.ctx.serialize()
|
|
}
|
|
}
|