0
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2025-02-01 12:16:11 -05:00
This commit is contained in:
Marvin Hagemeister 2025-01-06 19:04:42 +01:00
parent 8fc684c126
commit 2da8eee932
4 changed files with 147 additions and 153 deletions

View file

@ -25,6 +25,10 @@ const AST_GROUP_TYPE = 1;
/// <next idx u32>
/// <parent idx u32>
const NODE_SIZE = 1 + 4 + 4 + 4 + 4;
const PROP_OFFSET = 1;
const CHILD_OFFSET = 1 + 4;
const NEXT_OFFSET = 1 + 4 + 4;
const PARENT_OFFSET = 1 + 4 + 4 + 4;
// Span size in buffer: u32 + u32
const SPAN_SIZE = 4 + 4;
@ -285,16 +289,16 @@ export function installPlugin(plugin, exclude) {
/**
* @param {AstContext} ctx
* @param {number} idx
* @returns
* @returns {FacadeNode | null}
*/
function getNode(ctx, idx) {
if (idx === AST_IDX_INVALID) return null;
const cached = ctx.nodes.get(idx);
if (cached !== undefined) return cached;
if (cached !== undefined) return /** @type {*} */ (cached);
const node = new FacadeNode(ctx, idx);
ctx.nodes.set(idx, /** @type {*} */ (cached));
return node;
ctx.nodes.set(idx, /** @type {*} */ (node));
return /** @type {*} */ (node);
}
/**
@ -482,6 +486,15 @@ function toJsValue(ctx, idx) {
return node;
}
/**
* @param {AstContext["buf"]} buf
* @param {number} idx
* @returns {number}
*/
function readType(buf, idx) {
return buf[idx * NODE_SIZE];
}
/**
* @param {AstContext} ctx
* @param {number} idx
@ -501,10 +514,8 @@ function readSpan(ctx, idx) {
* @param {number} idx
* @returns {number}
*/
function readParent(buf, idx) {
let offset = idx * NODE_SIZE;
// type + prop offset + child + next
offset += 1 + 4 + 4 + 4;
function readPropOffset(buf, idx) {
const offset = (idx * NODE_SIZE) + PROP_OFFSET;
return readU32(buf, offset);
}
@ -513,10 +524,27 @@ function readParent(buf, idx) {
* @param {number} idx
* @returns {number}
*/
function readPropOffset(buf, idx) {
let offset = idx * NODE_SIZE;
// type + prop offset + child + next
offset += 1;
function readChild(buf, idx) {
const offset = (idx * NODE_SIZE) * CHILD_OFFSET;
return readU32(buf, offset);
}
/**
* @param {AstContext["buf"]} buf
* @param {number} idx
* @returns {number}
*/
function readNext(buf, idx) {
const offset = (idx * NODE_SIZE) * NEXT_OFFSET;
return readU32(buf, offset);
}
/**
* @param {AstContext["buf"]} buf
* @param {number} idx
* @returns {number}
*/
function readParent(buf, idx) {
const offset = (idx * NODE_SIZE) * PARENT_OFFSET;
return readU32(buf, offset);
}
@ -576,6 +604,7 @@ function readProperty(ctx, offset) {
const value = readU32(buf, offset);
return getNode(ctx, value);
} else if (kind === PropFlags.RefArr) {
// FIXME: This is broken atm
const len = readU32(buf, offset);
offset += 4;
@ -618,9 +647,8 @@ function readProperty(ctx, offset) {
function readValue(ctx, idx, search) {
const { buf } = ctx;
const type = buf[idx * NODE_SIZE];
if (search === AST_PROP_TYPE) {
const type = readType(buf, idx);
return getString(ctx.strTable, ctx.strByType[type]);
} else if (search === AST_PROP_RANGE) {
return readSpan(ctx, idx);
@ -814,9 +842,8 @@ class MatchCtx {
* @returns {number}
*/
getFirstChild(idx) {
let offset = idx * NODE_SIZE;
offset += 1;
return readU32(this.buf, offset);
const siblings = this.getSiblings(idx);
return siblings[0] ?? -1;
}
/**
@ -824,23 +851,8 @@ class MatchCtx {
* @returns {number}
*/
getLastChild(idx) {
let offset = idx * NODE_SIZE;
offset += 1;
let childId = readU32(this.buf, offset);
if (childId <= AST_IDX_INVALID) return -1;
while (childId > AST_IDX_INVALID) {
let offset = childId * NODE_SIZE;
offset += 1 + 4;
const nextId = readU32(this.buf, offset);
if (nextId <= AST_IDX_INVALID) break;
childId = nextId;
}
return childId;
const siblings = this.getSiblings(idx);
return siblings.at(-1) ?? -1;
}
/**
@ -848,32 +860,22 @@ class MatchCtx {
* @returns {number[]}
*/
getSiblings(idx) {
// TODO(@marvinhagemeister): We can rewrite this to not
// use array allocation now.
const { buf } = this;
const parent = readParent(buf, idx);
let offset = idx * NODE_SIZE;
offset += 1 + 4 + 4;
const parentIdx = readU32(buf, offset);
const pOffset = parentIdx * NODE_SIZE;
const pType = buf[pOffset + 1];
/** @type {number[]} */
const out = [];
if (pType !== AST_GROUP_TYPE) {
return out;
// Only RefArrays have siblings
const parentType = readType(buf, parent);
if (parentType !== AST_GROUP_TYPE) {
return [];
}
let childId = readU32(buf, pOffset + 1);
while (childId > AST_IDX_INVALID) {
out.push(childId);
const child = readChild(buf, parent);
const out = [child];
const nextId = readU32(buf, pOffset + 1 + 4);
if (nextId <= AST_IDX_INVALID) break;
childId = nextId;
let next = readNext(buf, child);
while (next > AST_IDX_INVALID) {
out.push(next);
next = readNext(buf, next);
}
return out;
@ -965,8 +967,6 @@ function createAstContext(buf) {
setNodeGetters(ctx);
console.log(ctx);
// DEV ONLY: Enable this to inspect the buffer message
_dump(ctx);
@ -1119,9 +1119,7 @@ function traverse(ctx, visitors, idx, cancellationToken) {
if (cancellationToken.isCancellationRequested()) return;
const { buf } = ctx;
let offset = idx * NODE_SIZE;
const nodeType = buf[offset++];
const nodeType = readType(ctx.buf, idx);
/** @type {VisitorFn[] | null} */
let exits = null;
@ -1149,16 +1147,12 @@ function traverse(ctx, visitors, idx, cancellationToken) {
}
try {
const childIdx = readU32(buf, offset);
offset += 4;
const childIdx = readChild(buf, idx);
if (childIdx > AST_IDX_INVALID) {
traverse(ctx, visitors, childIdx, cancellationToken);
}
const nextIdx = readU32(buf, offset);
offset += 4;
const nextIdx = readNext(buf, idx);
if (nextIdx > AST_IDX_INVALID) {
traverse(ctx, visitors, nextIdx, cancellationToken);
}
@ -1204,23 +1198,27 @@ function _dump(ctx) {
let idx = 0;
while (idx < (strTableOffset / NODE_SIZE)) {
const offset = idx * NODE_SIZE;
const type = buf[offset];
const name = getString(ctx.strTable, ctx.strByType[type]);
// @ts-ignore dump fn
// deno-lint-ignore no-console
console.log(`${name}, idx: ${idx}, offset: ${offset}, type: ${type}`);
const type = readType(buf, idx);
const child = readChild(buf, idx);
const next = readNext(buf, idx);
const parent = readParent(buf, idx);
// @ts-ignore dump fn
// deno-lint-ignore no-console
console.log(` parent: ${parent}`);
const range = readSpan(ctx, idx);
const name = type === AST_IDX_INVALID
? "<invalid>"
: type === AST_GROUP_TYPE
? "<group>"
: getString(ctx.strTable, ctx.strByType[type]);
// @ts-ignore dump fn
// deno-lint-ignore no-console
console.log(` range: ${JSON.stringify(range)}`);
console.log(`${name}, idx: ${idx}, type: ${type}`);
// @ts-ignore dump fn
// deno-lint-ignore no-console
console.log(` child: ${child}, next: ${next}, parent: ${parent}`);
// @ts-ignore dump fn
// deno-lint-ignore no-console
console.log(` range: ${range[0]}, ${range[1]}`);
let propOffset = readPropOffset(buf, idx);
const count = buf[propOffset++];
@ -1241,7 +1239,7 @@ function _dump(ctx) {
}
}
const v = readU32(buf, offset);
const v = readU32(buf, propOffset);
propOffset += 4;
if (kind === PropFlags.Ref) {

View file

@ -70,29 +70,11 @@ fn append_u32(result: &mut Vec<u8>, value: u32) {
result.push(v4);
}
#[inline]
fn write_u32(result: &mut [u8], value: u32, offset: usize) {
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[offset] = v1;
result[offset + 1] = v2;
result[offset + 2] = v3;
result[offset + 3] = v4;
}
fn append_usize(result: &mut Vec<u8>, value: usize) {
let raw = u32::try_from(value).unwrap();
append_u32(result, raw);
}
fn write_usize(result: &mut [u8], value: usize, offset: usize) {
let raw = u32::try_from(value).unwrap();
write_u32(result, raw, offset);
}
#[derive(Debug)]
pub struct StringTable {
id: usize,
@ -142,14 +124,27 @@ pub trait AstBufSerializer {
fn serialize(&mut self) -> Vec<u8>;
}
/// <type u8>
/// <prop offset u32>
/// <child idx u32>
/// <next idx u32>
/// <parent idx u32>
#[derive(Debug)]
struct Node {
kind: u8,
prop_offset: u32,
child: u32,
next: u32,
parent: u32,
}
#[derive(Debug)]
pub struct SerializeCtx {
id: u32,
start_buf: NodeRef,
/// Node buffer for traversal
buf: Vec<u8>,
nodes: Vec<Node>,
field_buf: Vec<u8>,
/// Vec of spans
@ -168,13 +163,6 @@ pub struct SerializeCtx {
prev_sibling_node: Option<u32>,
}
/// <type u8>
/// <prop offset u32>
/// <child idx u32>
/// <next idx u32>
/// <parent idx u32>
const NODE_SIZE: u32 = 1 + 4 + 4 + 4 + 4;
/// This is the internal context used to allocate and fill the buffer. The point
/// is to be able to write absolute offsets directly in place.
///
@ -190,7 +178,7 @@ impl SerializeCtx {
id: 0,
spans: vec![],
start_buf: NodeRef(0),
buf: vec![],
nodes: vec![],
field_buf: vec![],
str_table: StringTable::new(),
kind_name_map: vec![0; kind_size],
@ -206,7 +194,7 @@ impl SerializeCtx {
ctx.append_node(0, &DUMMY_SP);
ctx.kind_name_map[0] = empty_str;
ctx.kind_name_map[1] = empty_str;
ctx.start_buf = NodeRef(ctx.buf.len() as u32);
ctx.start_buf = NodeRef(ctx.nodes.len() as u32);
// Insert default props that are always present
let type_str = ctx.str_table.insert("type");
@ -251,11 +239,9 @@ impl SerializeCtx {
}
fn update_parent_link(&mut self, parent_id: u32, ref_id: u32) {
let offset = ref_id * NODE_SIZE;
// Update parent id of written ref
let parent_offset = offset + 1 + 4 + 4;
write_u32(&mut self.buf, parent_id, parent_offset.try_into().unwrap());
eprintln!("set parent {} for {}", parent_id, ref_id);
let node = self.nodes.get_mut(ref_id as usize).expect("Invalid id");
node.parent = parent_id;
}
fn update_ref_links(&mut self, parent_id: u32, ref_id: u32) {
@ -263,44 +249,45 @@ impl SerializeCtx {
// Update next pointer of previous sibling
if let Some(prev_id) = self.prev_sibling_node {
let prev_offset = prev_id * NODE_SIZE;
let prev_next = prev_offset + 1 + 4;
write_u32(&mut self.buf, ref_id, prev_next.try_into().unwrap());
eprintln!("set next {} for {}", ref_id, prev_id);
let node = self.nodes.get_mut(prev_id as usize).unwrap();
node.next = ref_id;
} else {
// Update parent child pointer
let parent_offset = parent_id * NODE_SIZE;
let child_offset = parent_offset + 1;
write_u32(&mut self.buf, ref_id, child_offset.try_into().unwrap());
eprintln!("set child {} for {}", ref_id, parent_id);
let node = self.nodes.get_mut(parent_id as usize).unwrap();
node.child = ref_id;
}
self.prev_sibling_node = Some(ref_id)
}
fn append_inner(
fn append_inner<K>(
&mut self,
kind: u8,
field_offset: usize,
kind: K,
prop_offset: usize,
span_lo: u32,
span_hi: u32,
) {
// type
self.buf.push(kind);
) where
K: Into<u8> + Display + Clone,
{
let kind_u8: u8 = kind.clone().into();
if let Some(v) = self.kind_name_map.get::<usize>(kind.into()) {
self.nodes.push(Node {
kind: kind_u8,
prop_offset: prop_offset as u32,
child: 0,
next: 0,
parent: 0,
});
if let Some(v) = self.kind_name_map.get::<usize>(kind_u8.into()) {
if *v == 0 {
let s_id = self.str_table.insert(&format!("{kind}"));
self.kind_name_map[kind as usize] = s_id;
self.kind_name_map[kind_u8 as usize] = s_id;
}
}
// field offset + child idx + next idx + parent idx
append_usize(&mut self.buf, field_offset);
append_usize(&mut self.buf, 0);
append_usize(&mut self.buf, 0);
append_usize(&mut self.buf, 0);
// write spans
self.spans.push(span_lo);
self.spans.push(span_hi);
@ -316,9 +303,7 @@ impl SerializeCtx {
self.field_offset = self.field_buf.len();
self.field_buf.push(0);
// type
let kind_u8 = kind.clone().into();
self.append_inner(kind_u8, self.field_offset, span.lo.0, span.hi.0);
self.append_inner(kind, self.field_offset, span.lo.0, span.hi.0);
PendingRef(id)
}
@ -411,10 +396,14 @@ impl SerializeCtx {
where
P: Into<u8> + Display + Clone,
{
eprintln!("prop: {} set parent {} for {:#?}", prop, parent.0, value);
self.field_header(prop, PropFlags::Ref);
append_u32(&mut self.field_buf, value.0);
self.update_ref_links(parent.0, value.0);
if parent.0 > 0 {
self.update_ref_links(parent.0, value.0);
}
}
/// Helper for writing optional node offsets
@ -426,12 +415,11 @@ impl SerializeCtx {
) where
P: Into<u8> + Display + Clone,
{
let ref_value = if let Some(v) = value { v.0 } else { 0 };
self.field_header(prop, PropFlags::Ref);
append_u32(&mut self.field_buf, ref_value);
self.update_ref_links(parent.0, ref_value);
if let Some(v) = value {
self.write_ref(prop, parent, v);
} else {
self.write_null(prop);
};
}
/// Write a vec of node offsets into the property. The necessary space
@ -447,10 +435,8 @@ impl SerializeCtx {
self.field_header(prop, PropFlags::RefArr);
let group_id = self.get_id();
append_u32(&mut self.field_buf, group_id);
// TODO(@marvinhagemeister) This is wrong
self.append_inner(GROUP_KIND, 0, 0, 0);
self.update_parent_link(parent.0, group_id);
@ -466,16 +452,26 @@ impl SerializeCtx {
/// <string table>
/// <node kind map> <- node kind id maps to string id
/// <node prop map> <- node property id maps to string id
/// <spans> <- List of spans, rarely needed
/// <offset spans>
/// <offset kind map>
/// <offset prop map>
/// <offset str table>
pub fn serialize(&mut self) -> Vec<u8> {
let mut buf: Vec<u8> = vec![];
eprintln!("BUFFER {:#?}", self.nodes);
// The buffer starts with the serialized AST first, because that
// contains absolute offsets. By butting this at the start of the
// message we don't have to waste time updating any offsets.
buf.append(&mut self.buf);
for node in &self.nodes {
buf.push(node.kind);
append_u32(&mut buf, node.prop_offset);
append_u32(&mut buf, node.child);
append_u32(&mut buf, node.next);
append_u32(&mut buf, node.parent);
}
// Next follows the string table. We'll keep track of the offset
// in the message of where the string table begins

View file

@ -943,7 +943,7 @@ fn serialize_member_expr(
ctx.write_member_expr(&node.span, optional, computed, obj, prop)
}
fn serialize_class_member(
fn _serialize_class_member(
ctx: &mut TsEsTreeBuilder,
member: &ClassMember,
) -> NodeRef {
@ -1314,7 +1314,7 @@ fn serialize_ts_index_sig(
// pos
}
fn accessibility_to_str(accessibility: Accessibility) -> String {
fn _accessibility_to_str(accessibility: Accessibility) -> String {
match accessibility {
Accessibility::Public => "public".to_string(),
Accessibility::Protected => "protected".to_string(),

View file

@ -304,9 +304,9 @@ impl WorkspaceLinter {
fn logger_printer(msg: &str, is_err: bool) {
if is_err {
eprintln!("{}", msg);
eprintln!("{}", msg.trim_end());
} else {
println!("{}", msg);
println!("{}", msg.trim_end());
}
}