0
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2025-02-14 17:47:35 -05:00
denoland-deno/cli/tools/lint/ast_buf.rs
2024-12-13 00:33:44 +01:00

636 lines
12 KiB
Rust

use deno_ast::{
swc::common::{Span, DUMMY_SP},
view::AssignOp,
};
use indexmap::IndexMap;
pub enum Flag {
ProgramModule,
FnAsync,
FnGenerator,
FnDeclare,
FnOptional,
MemberComputed,
MemberOptional,
PropShorthand,
PropComputed,
PropGetter,
PropSetter,
PropMethod,
VarVar,
VarConst,
VarLet,
VarDeclare,
ExportType,
TplTail,
ForAwait,
LogicalOr,
LogicalAnd,
LogicalNullishCoalescin,
JSXSelfClosing,
BinEqEq,
BinNotEq,
BinEqEqEq,
BinNotEqEq,
BinLt,
BinLtEq,
BinGt,
BinGtEq,
BinLShift,
BinRShift,
BinZeroFillRShift,
BinAdd,
BinSub,
BinMul,
BinDiv,
BinMod,
BinBitOr,
BinBitXor,
BinBitAnd,
BinIn,
BinInstanceOf,
BinExp,
UnaryMinus,
UnaryPlus,
UnaryBang,
UnaryTilde,
UnaryTypeOf,
UnaryVoid,
UnaryDelete,
UpdatePrefix,
UpdatePlusPlus,
UpdateMinusMinus,
YieldDelegate,
ParamOptional,
ClassDeclare,
ClassAbstract,
ClassConstructor,
ClassMethod,
ClassPublic,
ClassProtected,
ClassPrivate,
TsDeclare,
TsConst,
TsTrue,
TsPlus,
TsMinus,
TsReadonly,
}
pub fn assign_op_to_flag(m: AssignOp) -> u8 {
match m {
AssignOp::Assign => 0,
AssignOp::AddAssign => 1,
AssignOp::SubAssign => 2,
AssignOp::MulAssign => 3,
AssignOp::DivAssign => 4,
AssignOp::ModAssign => 5,
AssignOp::LShiftAssign => 6,
AssignOp::RShiftAssign => 7,
AssignOp::ZeroFillRShiftAssign => 8,
AssignOp::BitOrAssign => 9,
AssignOp::BitXorAssign => 10,
AssignOp::BitAndAssign => 11,
AssignOp::ExpAssign => 12,
AssignOp::AndAssign => 13,
AssignOp::OrAssign => 14,
AssignOp::NullishAssign => 15,
}
}
impl From<Flag> for u8 {
fn from(m: Flag) -> u8 {
match m {
Flag::ProgramModule => 0b00000001,
Flag::FnAsync => 0b00000001,
Flag::FnGenerator => 0b00000010,
Flag::FnDeclare => 0b00000100,
Flag::FnOptional => 0b00001000,
Flag::MemberComputed => 0b00000001,
Flag::MemberOptional => 0b00000010,
Flag::PropShorthand => 0b00000001,
Flag::PropComputed => 0b00000010,
Flag::PropGetter => 0b00000100,
Flag::PropSetter => 0b00001000,
Flag::PropMethod => 0b00010000,
Flag::VarVar => 0b00000001,
Flag::VarConst => 0b00000010,
Flag::VarLet => 0b00000100,
Flag::VarDeclare => 0b00001000,
Flag::ExportType => 0b000000001,
Flag::TplTail => 0b000000001,
Flag::ForAwait => 0b000000001,
Flag::LogicalOr => 0b000000001,
Flag::LogicalAnd => 0b000000010,
Flag::LogicalNullishCoalescin => 0b000000100,
Flag::JSXSelfClosing => 0b000000001,
Flag::BinEqEq => 1,
Flag::BinNotEq => 2,
Flag::BinEqEqEq => 3,
Flag::BinNotEqEq => 4,
Flag::BinLt => 5,
Flag::BinLtEq => 6,
Flag::BinGt => 7,
Flag::BinGtEq => 8,
Flag::BinLShift => 9,
Flag::BinRShift => 10,
Flag::BinZeroFillRShift => 11,
Flag::BinAdd => 12,
Flag::BinSub => 13,
Flag::BinMul => 14,
Flag::BinDiv => 15,
Flag::BinMod => 16,
Flag::BinBitOr => 17,
Flag::BinBitXor => 18,
Flag::BinBitAnd => 19,
Flag::BinIn => 20,
Flag::BinInstanceOf => 21,
Flag::BinExp => 22,
Flag::UnaryMinus => 1,
Flag::UnaryPlus => 2,
Flag::UnaryBang => 3,
Flag::UnaryTilde => 4,
Flag::UnaryTypeOf => 5,
Flag::UnaryVoid => 6,
Flag::UnaryDelete => 7,
Flag::UpdatePrefix => 0b000000001,
Flag::UpdatePlusPlus => 0b000000010,
Flag::UpdateMinusMinus => 0b000000100,
Flag::YieldDelegate => 1,
Flag::ParamOptional => 1,
Flag::ClassDeclare => 0b000000001,
Flag::ClassAbstract => 0b000000010,
Flag::ClassConstructor => 0b000000100,
Flag::ClassMethod => 0b000001000,
Flag::ClassPublic => 0b001000000,
Flag::ClassProtected => 0b010000000,
Flag::ClassPrivate => 0b10000000,
Flag::TsDeclare => 0b000000001,
Flag::TsConst => 0b000000010,
Flag::TsTrue => 0b000000100,
Flag::TsPlus => 0b000001000,
Flag::TsMinus => 0b000010000,
Flag::TsReadonly => 0b000100000,
}
}
}
// Keep in sync with JS
pub enum AstNode {
Invalid,
//
Program,
// Module declarations
Import,
ImportDecl,
ExportDecl,
ExportNamedDeclaration,
ExportDefaultDecl,
ExportDefaultExpr,
ExportAll,
TsImportEquals,
TsExportAssignment,
TsNamespaceExport,
// Decls
ClassDeclaration,
Fn,
Var,
Using,
TSInterface,
TsTypeAlias,
TSEnumDeclaration,
TsModule,
// Statements
Block,
Empty,
Debugger,
With,
Return,
Labeled,
Break,
Continue,
IfStatement,
Switch,
SwitchCase,
Throw,
TryStatement,
While,
DoWhileStatement,
ForStatement,
ForInStatement,
ForOfStatement,
Decl,
ExpressionStatement,
// Expressions
This,
Array,
Object,
FunctionExpression,
Unary,
UpdateExpression,
BinaryExpression,
Assign,
MemberExpression,
Super,
Cond,
CallExpression,
New,
Paren,
SequenceExpression,
Identifier,
TemplateLiteral,
TaggedTemplateExpression,
ArrowFunctionExpression,
ClassExpr,
YieldExpression,
MetaProp,
AwaitExpression,
LogicalExpression,
TSTypeAssertion,
TsConstAssertion,
TSNonNullExpression,
TSAsExpression,
TsInstantiation,
TSSatisfiesExpression,
PrivateIdentifier,
ChainExpression,
// Literals
StringLiteral,
Bool,
Null,
NumericLiteral,
BigIntLiteral,
RegExpLiteral,
// Custom
EmptyExpr,
Spread,
Property,
VariableDeclarator,
CatchClause,
RestElement,
ExportSpecifier,
TemplateElement,
MethodDefinition,
// Patterns
ArrayPattern,
AssignmentPattern,
ObjectPattern,
// JSX
JSXAttribute,
JSXClosingElement,
JSXClosingFragment,
JSXElement,
JSXEmptyExpression,
JSXExpressionContainer,
JSXFragment,
JSXIdentifier,
JSXMemberExpression,
JSXNamespacedName,
JSXOpeningElement,
JSXOpeningFragment,
JSXSpreadAttribute,
JSXSpreadChild,
JSXText,
TSTypeAnnotation,
TSTypeParameterDeclaration,
TSTypeParameter,
TSEnumMember,
TSInterfaceBody,
TSInterfaceHeritage,
TSTypeReference,
TSThisType,
TSLiteralType,
TSInferType,
TSConditionalType,
TSUnionType,
TSIntersectionType,
TSMappedType,
TSTypeQuery,
TSTupleType,
TSFunctionType,
TsCallSignatureDeclaration,
TSAnyKeyword,
TSBigIntKeyword,
TSBooleanKeyword,
TSIntrinsicKeyword,
TSNeverKeyword,
TSNullKeyword,
TSNumberKeyword,
TSObjectKeyword,
TSStringKeyword,
TSSymbolKeyword,
TSUndefinedKeyword,
TSUnknownKeyword,
TSVoidKeyword,
}
impl From<AstNode> for u8 {
fn from(m: AstNode) -> u8 {
m as u8
}
}
pub enum AstProp {
// Base
Parent,
Range,
Type,
_InternalFlags, // Private
// Node
Alternate,
Argument,
Arguments,
Async,
Attributes,
Await,
Block,
Body,
Callee,
Cases,
Children,
ClosingElement,
ClosingFragment,
Computed,
Consequent,
Cooked,
Declarations,
Declare,
Definite,
Delegate,
Discriminant,
Elements,
ElementTypes,
Expression,
Expressions,
Exported,
Finalizer,
Flags,
Generator,
Handler,
Id,
Init,
Key,
Kind,
Label,
Left,
Local,
Members,
Meta,
Method,
Name,
Namespace,
Object,
OpeningElement,
OpeningFragment,
Operator,
Optional,
Param,
Params,
Pattern,
Prefix,
Properties,
Property,
Quasi,
Quasis,
Raw,
ReturnType,
Right,
SelfClosing,
Shorthand,
Source,
Specifiers,
Tag,
Tail,
Test,
TypeAnnotation,
TypeArguments,
TypeParameters,
Types,
Update,
Value,
}
impl From<AstProp> for u8 {
fn from(m: AstProp) -> u8 {
m as u8
}
}
const MASK_U32_1: u32 = 0b11111111_00000000_00000000_00000000;
const MASK_U32_2: u32 = 0b00000000_11111111_00000000_00000000;
const MASK_U32_3: u32 = 0b00000000_00000000_11111111_00000000;
const MASK_U32_4: u32 = 0b00000000_00000000_00000000_11111111;
pub fn append_u32(result: &mut Vec<u8>, value: u32) {
let v1: u8 = ((value & MASK_U32_1) >> 24) as u8;
let v2: u8 = ((value & MASK_U32_2) >> 16) as u8;
let v3: u8 = ((value & MASK_U32_3) >> 8) as u8;
let v4: u8 = (value & MASK_U32_4) as u8;
result.push(v1);
result.push(v2);
result.push(v3);
result.push(v4);
}
pub fn append_usize(result: &mut Vec<u8>, value: usize) {
let raw = u32::try_from(value).unwrap();
append_u32(result, raw);
}
pub fn write_usize(result: &mut [u8], value: usize, idx: usize) {
let raw = u32::try_from(value).unwrap();
let v1: u8 = ((raw & MASK_U32_1) >> 24) as u8;
let v2: u8 = ((raw & MASK_U32_2) >> 16) as u8;
let v3: u8 = ((raw & MASK_U32_3) >> 8) as u8;
let v4: u8 = (raw & MASK_U32_4) as u8;
result[idx] = v1;
result[idx + 1] = v2;
result[idx + 2] = v3;
result[idx + 3] = v4;
}
#[derive(Debug, Clone)]
pub struct FlagValue(u8);
impl FlagValue {
pub fn new() -> Self {
Self(0)
}
pub fn set(&mut self, flag: Flag) {
let value: u8 = flag.into();
self.0 |= value;
}
}
#[derive(Debug)]
pub struct StringTable {
id: usize,
table: IndexMap<String, usize>,
}
impl StringTable {
pub fn new() -> Self {
Self {
id: 0,
table: IndexMap::new(),
}
}
pub fn insert(&mut self, s: &str) -> usize {
if let Some(id) = self.table.get(s) {
return *id;
}
let id = self.id;
self.id += 1;
self.table.insert(s.to_string(), id);
id
}
pub fn serialize(&mut self) -> Vec<u8> {
let mut result: Vec<u8> = vec![];
append_u32(&mut result, self.table.len() as u32);
// Assume that it's sorted by id
for (s, _id) in &self.table {
let bytes = s.as_bytes();
append_u32(&mut result, bytes.len() as u32);
result.append(&mut bytes.to_vec());
}
// eprintln!("Serialized string table: {:#?}", result);
result
}
}
#[derive(Debug)]
pub struct SerializeCtx {
pub id: usize,
pub id_to_offset: IndexMap<usize, usize>,
pub buf: Vec<u8>,
pub str_table: StringTable,
}
impl SerializeCtx {
pub fn new() -> Self {
let mut ctx = Self {
id: 0,
id_to_offset: IndexMap::new(),
buf: vec![],
str_table: StringTable::new(),
};
ctx.str_table.insert("");
// Placeholder node
ctx.push_node(AstNode::Invalid, 0, &DUMMY_SP);
ctx
}
pub fn next_id(&mut self) -> usize {
let id = self.id;
self.id += 1;
id
}
pub fn write_u8(&mut self, value: u8) {
self.buf.push(value);
}
pub fn write_node(
&mut self,
id: usize,
kind: AstNode,
parent_id: usize,
span: &Span,
prop_count: usize,
) {
self.id_to_offset.insert(id, self.buf.len());
let kind_value: u8 = kind.into();
self.buf.push(kind_value);
append_usize(&mut self.buf, parent_id);
// Span
append_u32(&mut self.buf, span.lo.0);
append_u32(&mut self.buf, span.hi.0);
// No node has more than <10 properties
self.buf.push(prop_count as u8);
}
pub fn write_ids<I>(&mut self, prop: AstProp, ids: I)
where
I: IntoIterator<Item = usize>,
{
self.buf.push(prop.into());
let mut count = 0;
let idx = self.buf.len();
append_usize(&mut self.buf, 0);
for id in ids {
append_usize(&mut self.buf, id);
count += 1;
}
write_usize(&mut self.buf, count, idx);
}
pub fn write_id(&mut self, id: usize) {
append_usize(&mut self.buf, id);
}
pub fn write_flags(&mut self, flags: &FlagValue) {
self.buf.push(AstProp::_InternalFlags.into());
self.buf.push(flags.0)
}
pub fn write_prop(&mut self, prop: AstProp, id: usize) {
self.buf.push(prop.into());
append_usize(&mut self.buf, id);
}
pub fn push_node(
&mut self,
kind: AstNode,
parent_id: usize,
span: &Span,
) -> usize {
let id = self.id;
self.id_to_offset.insert(id, self.buf.len());
self.id += 1;
self.write_node(id, kind, parent_id, span, 0);
id
}
}