mirror of
https://github.com/denoland/deno.git
synced 2025-02-01 12:16:11 -05:00
WIP
This commit is contained in:
parent
8fc684c126
commit
2da8eee932
4 changed files with 147 additions and 153 deletions
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue