0
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2025-02-08 07:16:56 -05:00
This commit is contained in:
Marvin Hagemeister 2025-01-04 22:04:27 +01:00
parent 113c2e844a
commit d773c32e0a
2 changed files with 94 additions and 231 deletions

View file

@ -18,8 +18,8 @@ const {
// Keep these in sync with Rust // Keep these in sync with Rust
const AST_IDX_INVALID = 0; const AST_IDX_INVALID = 0;
const AST_TYPE_REF_ARRAY = 1; const AST_GROUP_TYPE = 1;
const AST_NODE_SIZE = 1 + 4 + 4 + 4; const NODE_SIZE = 1 + 4 + 4 + 4;
// Keep in sync with Rust // Keep in sync with Rust
// These types are expected to be present on every node. Note that this // These types are expected to be present on every node. Note that this
@ -314,26 +314,11 @@ function findPropOffset(buf, offset, search) {
if (skip === 0 && prop === search) return maybe; if (skip === 0 && prop === search) return maybe;
if (skip > 0) skip--; if (skip > 0) skip--;
if (kind === PropFlags.Ref) { if (kind === PropFlags.Obj) {
offset += 4;
} else if (kind === PropFlags.RefArr) {
const len = readU32(buf, offset); const len = readU32(buf, offset);
offset += 4 + (len * 4); offset += len * (1 + 1 + 4);
} else if (kind === PropFlags.Obj) {
const len = readU32(buf, offset);
skip += len;
offset += 4;
} else if (
kind === PropFlags.String || kind === PropFlags.Number ||
kind === PropFlags.Regex
) {
offset += 4;
} else if (kind === PropFlags.Bool) {
offset++;
} else if (kind === PropFlags.Null || kind === PropFlags.Undefined) {
// No value
} else { } else {
offset++; offset += 4;
} }
} }
@ -341,7 +326,7 @@ function findPropOffset(buf, offset, search) {
} }
const INTERNAL_CTX = Symbol("ctx"); const INTERNAL_CTX = Symbol("ctx");
const INTERNAL_OFFSET = Symbol("offset"); const INTERNAL_IDX = Symbol("offset");
// This class is a facade for all materialized nodes. Instead of creating a // This class is a facade for all materialized nodes. Instead of creating a
// unique class per AST node, we have one class with getters for every // unique class per AST node, we have one class with getters for every
@ -349,15 +334,15 @@ const INTERNAL_OFFSET = Symbol("offset");
// only when they are needed. // only when they are needed.
class FacadeNode { class FacadeNode {
[INTERNAL_CTX]; [INTERNAL_CTX];
[INTERNAL_OFFSET]; [INTERNAL_IDX];
/** /**
* @param {AstContext} ctx * @param {AstContext} ctx
* @param {number} offset * @param {number} idx
*/ */
constructor(ctx, offset) { constructor(ctx, idx) {
this[INTERNAL_CTX] = ctx; this[INTERNAL_CTX] = ctx;
this[INTERNAL_OFFSET] = offset; this[INTERNAL_IDX] = idx;
} }
/** /**
@ -373,12 +358,12 @@ class FacadeNode {
* @returns {string} * @returns {string}
*/ */
[Symbol.for("Deno.customInspect")](_, options) { [Symbol.for("Deno.customInspect")](_, options) {
const json = toJsValue(this[INTERNAL_CTX], this[INTERNAL_OFFSET]); const json = toJsValue(this[INTERNAL_CTX], this[INTERNAL_IDX]);
return Deno.inspect(json, options); return Deno.inspect(json, options);
} }
[Symbol.for("Deno.lint.toJsValue")]() { [Symbol.for("Deno.lint.toJsValue")]() {
return toJsValue(this[INTERNAL_CTX], this[INTERNAL_OFFSET]); return toJsValue(this[INTERNAL_CTX], this[INTERNAL_IDX]);
} }
} }
@ -401,7 +386,7 @@ function setNodeGetters(ctx) {
Object.defineProperty(FacadeNode.prototype, name, { Object.defineProperty(FacadeNode.prototype, name, {
get() { get() {
return readValue(this[INTERNAL_CTX], this[INTERNAL_OFFSET], i); return readValue(this[INTERNAL_CTX], this[INTERNAL_IDX], i);
}, },
}); });
} }
@ -410,16 +395,16 @@ function setNodeGetters(ctx) {
/** /**
* Serialize a node recursively to plain JSON * Serialize a node recursively to plain JSON
* @param {AstContext} ctx * @param {AstContext} ctx
* @param {number} offset * @param {number} idx
* @returns {*} * @returns {*}
*/ */
function toJsValue(ctx, offset) { function toJsValue(ctx, idx) {
const { buf } = ctx; const { buf } = ctx;
/** @type {Record<string, any>} */ /** @type {Record<string, any>} */
const node = { const node = {
type: readValue(ctx, offset, AST_PROP_TYPE), type: readValue(ctx, idx, AST_PROP_TYPE),
range: readValue(ctx, offset, AST_PROP_RANGE), range: readValue(ctx, idx, AST_PROP_RANGE),
}; };
/** @type {Record<string, any>} */ /** @type {Record<string, any>} */
@ -427,12 +412,12 @@ function toJsValue(ctx, offset) {
let skip = 0; let skip = 0;
// type + parentId + SpanLo + SpanHi // type + parentId + SpanLo + SpanHi
offset += 1 + 4 + 4 + 4; idx += 1 + 4 + 4 + 4;
const count = buf[offset++]; const count = buf[idx++];
for (let i = 0; i < count; i++) { for (let i = 0; i < count; i++) {
const prop = buf[offset++]; const prop = buf[idx++];
const kind = buf[offset++]; const kind = buf[idx++];
const name = getString(ctx.strTable, ctx.strByProp[prop]); const name = getString(ctx.strTable, ctx.strByProp[prop]);
if (skip > 0) { if (skip > 0) {
skip--; skip--;
@ -443,34 +428,34 @@ function toJsValue(ctx, offset) {
} }
if (kind === PropFlags.Ref) { if (kind === PropFlags.Ref) {
const v = readU32(buf, offset); const v = readU32(buf, idx);
offset += 4; idx += 4;
out[name] = v === 0 ? null : toJsValue(ctx, v); out[name] = v === 0 ? null : toJsValue(ctx, v);
} else if (kind === PropFlags.RefArr) { } else if (kind === PropFlags.RefArr) {
const len = readU32(buf, offset); const len = readU32(buf, idx);
offset += 4; idx += 4;
const nodes = new Array(len); const nodes = new Array(len);
for (let i = 0; i < len; i++) { for (let i = 0; i < len; i++) {
const v = readU32(buf, offset); const v = readU32(buf, idx);
if (v === 0) continue; if (v === 0) continue;
nodes[i] = toJsValue(ctx, v); nodes[i] = toJsValue(ctx, v);
offset += 4; idx += 4;
} }
out[name] = nodes; out[name] = nodes;
} else if (kind === PropFlags.Bool) { } else if (kind === PropFlags.Bool) {
const v = buf[offset++]; const v = buf[idx++];
out[name] = v === 1; out[name] = v === 1;
} else if (kind === PropFlags.String) { } else if (kind === PropFlags.String) {
const v = readU32(buf, offset); const v = readU32(buf, idx);
offset += 4; idx += 4;
out[name] = getString(ctx.strTable, v); out[name] = getString(ctx.strTable, v);
} else if (kind === PropFlags.Number) { } else if (kind === PropFlags.Number) {
const v = readU32(buf, offset); const v = readU32(buf, idx);
offset += 4; idx += 4;
out[name] = Number(getString(ctx.strTable, v)); out[name] = Number(getString(ctx.strTable, v));
} else if (kind === PropFlags.Regex) { } else if (kind === PropFlags.Regex) {
const v = readU32(buf, offset); const v = readU32(buf, idx);
offset += 4; idx += 4;
out[name] = readRegex(ctx.strTable, v); out[name] = readRegex(ctx.strTable, v);
} else if (kind === PropFlags.Null) { } else if (kind === PropFlags.Null) {
@ -478,9 +463,9 @@ function toJsValue(ctx, offset) {
} else if (kind === PropFlags.Undefined) { } else if (kind === PropFlags.Undefined) {
out[name] = undefined; out[name] = undefined;
} else if (kind === PropFlags.Obj) { } else if (kind === PropFlags.Obj) {
const v = readU32(buf, offset); const v = readU32(buf, idx);
skip += v; skip += v;
offset += 4; idx += 4;
const obj = {}; const obj = {};
out = obj; out = obj;
out[name] = obj; out[name] = obj;
@ -632,67 +617,6 @@ function getString(strTable, id) {
return name; return name;
} }
/**
* @param {AstContext["buf"]} buf
* @param {number} child
* @returns {null | [number, number]}
*/
function findChildOffset(buf, child) {
let offset = readU32(buf, child + 1);
// type + parentId + SpanLo + SpanHi
offset += 1 + 4 + 4 + 4;
const propCount = buf[offset++];
for (let i = 0; i < propCount; i++) {
const _prop = buf[offset++];
const kind = buf[offset++];
switch (kind) {
case PropFlags.Ref: {
const start = offset;
const value = readU32(buf, offset);
offset += 4;
if (value === child) {
return [start, -1];
}
break;
}
case PropFlags.RefArr: {
const start = offset;
const len = readU32(buf, offset);
offset += 4;
for (let j = 0; j < len; j++) {
const value = readU32(buf, offset);
offset += 4;
if (value === child) {
return [start, j];
}
}
break;
}
case PropFlags.Number:
case PropFlags.String:
case PropFlags.Regex:
offset += 4;
break;
case PropFlags.Bool:
offset++;
break;
case PropFlags.Null:
case PropFlags.Undefined:
break;
case PropFlags.Obj:
break;
}
}
return null;
}
/** @implements {MatchContext} */ /** @implements {MatchContext} */
class MatchCtx { class MatchCtx {
/** /**
@ -707,18 +631,21 @@ class MatchCtx {
} }
/** /**
* @param {number} offset * @param {number} idx
* @returns {number} * @returns {number}
*/ */
getParent(offset) { getParent(idx) {
return readU32(this.buf, offset + 1); let offset = idx * NODE_SIZE;
offset += 1 + 4 + 4;
return readU32(this.buf, offset);
} }
/** /**
* @param {number} offset * @param {number} idx
* @returns {number} * @returns {number}
*/ */
getType(offset) { getType(idx) {
const offset = idx * NODE_SIZE;
return this.buf[offset]; return this.buf[offset];
} }
@ -835,133 +762,70 @@ class MatchCtx {
} }
/** /**
* @param {number} offset * @param {number} idx
* @returns {number} * @returns {number}
*/ */
getFirstChild(offset) { getFirstChild(idx) {
const { buf } = this; let offset = idx * NODE_SIZE;
offset += 1;
// type + parentId + SpanLo + SpanHi return readU32(this.buf, offset);
offset += 1 + 4 + 4 + 4;
const count = buf[offset++];
for (let i = 0; i < count; i++) {
const _prop = buf[offset++];
const kind = buf[offset++];
switch (kind) {
case PropFlags.Ref: {
const v = readU32(buf, offset);
offset += 4;
return v;
}
case PropFlags.RefArr: {
const len = readU32(buf, offset);
offset += 4;
for (let j = 0; j < len; j++) {
const v = readU32(buf, offset);
offset += 4;
return v;
}
return len;
}
case PropFlags.Number:
case PropFlags.String:
case PropFlags.Regex:
offset += 4;
break;
case PropFlags.Bool:
offset++;
break;
case PropFlags.Null:
case PropFlags.Undefined:
break;
}
}
return -1;
} }
/** /**
* @param {number} offset * @param {number} idx
* @returns {number} * @returns {number}
*/ */
getLastChild(offset) { getLastChild(idx) {
const { buf } = this; let offset = idx * NODE_SIZE;
offset += 1;
// type + parentId + SpanLo + SpanHi let childId = readU32(this.buf, offset);
offset += 1 + 4 + 4 + 4; if (childId <= AST_IDX_INVALID) return -1;
let last = -1; while (childId > AST_IDX_INVALID) {
let offset = childId * NODE_SIZE;
offset += 1 + 4;
const count = buf[offset++]; const nextId = readU32(this.buf, offset);
for (let i = 0; i < count; i++) { if (nextId <= AST_IDX_INVALID) break;
const _prop = buf[offset++];
const kind = buf[offset++];
switch (kind) { childId = nextId;
case PropFlags.Ref: {
const v = readU32(buf, offset);
offset += 4;
last = v;
break;
}
case PropFlags.RefArr: {
const len = readU32(buf, offset);
offset += 4;
for (let j = 0; j < len; j++) {
const v = readU32(buf, offset);
last = v;
offset += 4;
}
break;
}
case PropFlags.String:
case PropFlags.Number:
case PropFlags.Regex:
offset += 4;
break;
case PropFlags.Bool:
offset++;
break;
case PropFlags.Null:
case PropFlags.Undefined:
break;
}
} }
return last; return childId;
} }
/** /**
* @param {number} id * @param {number} idx
* @returns {number[]} * @returns {number[]}
*/ */
getSiblings(id) { getSiblings(idx) {
// TODO(@marvinhagemeister): We can rewrite this to not
// use array allocation now.
const { buf } = this; const { buf } = this;
const result = findChildOffset(buf, id); let offset = idx * NODE_SIZE;
// Happens for program nodes offset += 1 + 4 + 4;
if (result === null) return []; const parentIdx = readU32(buf, offset);
if (result[1] === -1) { const pOffset = parentIdx * NODE_SIZE;
return [id]; const pType = buf[pOffset + 1];
}
let offset = result[0];
const count = readU32(buf, offset);
offset += 4;
/** @type {number[]} */ /** @type {number[]} */
const out = []; const out = [];
for (let i = 0; i < count; i++) {
const v = readU32(buf, offset); if (pType !== AST_GROUP_TYPE) {
offset += 4; return out;
out.push(v); }
let childId = readU32(buf, pOffset + 1);
while (childId > AST_IDX_INVALID) {
out.push(childId);
const nextId = readU32(buf, pOffset + 1 + 4);
if (nextId <= AST_IDX_INVALID) break;
childId = nextId;
} }
return out; return out;
@ -989,9 +853,7 @@ function createAstContext(buf) {
const stringCount = readU32(buf, offset); const stringCount = readU32(buf, offset);
offset += 4; offset += 4;
// TODO(@marvinhagemeister): We could lazily decode the strings on an as needed basis. let strId = 0;
// Not sure if this matters much in practice though.
let id = 0;
for (let i = 0; i < stringCount; i++) { for (let i = 0; i < stringCount; i++) {
const len = readU32(buf, offset); const len = readU32(buf, offset);
offset += 4; offset += 4;
@ -999,8 +861,8 @@ function createAstContext(buf) {
const strBytes = buf.slice(offset, offset + len); const strBytes = buf.slice(offset, offset + len);
offset += len; offset += len;
const s = DECODER.decode(strBytes); const s = DECODER.decode(strBytes);
strTable.set(id, s); strTable.set(strId, s);
id++; strId++;
} }
if (strTable.size !== stringCount) { if (strTable.size !== stringCount) {
@ -1206,14 +1068,14 @@ function traverse(ctx, visitors, idx, cancellationToken) {
const { buf } = ctx; const { buf } = ctx;
let offset = idx * AST_NODE_SIZE; let offset = idx * NODE_SIZE;
const nodeType = buf[offset++]; const nodeType = buf[offset++];
/** @type {VisitorFn[] | null} */ /** @type {VisitorFn[] | null} */
let exits = null; let exits = null;
// Only visit if it's an actual node // Only visit if it's an actual node
if (nodeType !== AST_TYPE_REF_ARRAY) { if (nodeType !== AST_GROUP_TYPE) {
// Loop over visitors and check if any selector matches // Loop over visitors and check if any selector matches
for (let i = 0; i < visitors.length; i++) { for (let i = 0; i < visitors.length; i++) {
const v = visitors[i]; const v = visitors[i];

View file

@ -357,15 +357,16 @@ impl SerializeCtx {
} }
/// Allocate an undefined field /// Allocate an undefined field
pub fn write_null<P>(&mut self, prop: P) -> usize pub fn write_null<P>(&mut self, prop: P)
where where
P: Into<u8> + Display + Clone, P: Into<u8> + Display + Clone,
{ {
self.field_header(prop, PropFlags::Null) self.field_header(prop, PropFlags::Null);
append_u32(&mut self.field_buf, 0);
} }
/// Allocate a number field /// Allocate a number field
pub fn write_num<P>(&mut self, prop: P, value: &str) -> usize pub fn write_num<P>(&mut self, prop: P, value: &str)
where where
P: Into<u8> + Display + Clone, P: Into<u8> + Display + Clone,
{ {
@ -395,7 +396,7 @@ impl SerializeCtx {
self.field_header(prop, PropFlags::Bool); self.field_header(prop, PropFlags::Bool);
let n = if value { 1 } else { 0 }; let n = if value { 1 } else { 0 };
self.field_buf.push(n); append_u32(&mut self.field_buf, n);
} }
/// Replace the placeholder of a reference field with the actual offset /// Replace the placeholder of a reference field with the actual offset