1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2025-01-21 13:00:36 -05:00

fix: sibling selectors

This commit is contained in:
Marvin Hagemeister 2024-12-18 11:31:11 +01:00
parent 8d9f9ce5e2
commit 321a1fe57e
5 changed files with 203 additions and 53 deletions

View file

@ -217,6 +217,63 @@ function readValue(ctx, offset, search) {
throw new Error(`Unknown prop kind: ${kind}`);
}
/**
* @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.String:
offset += 4;
break;
case PropFlags.Bool:
offset++;
break;
case PropFlags.Null:
case PropFlags.Undefined:
break;
}
}
return null;
}
/**
* @param {AstContext} ctx
* @param {number} offset
@ -386,9 +443,8 @@ class MatchCtx {
const { buf } = this;
offset = findPropOffset(buf, offset, propIds[idx]);
// console.log("attr value", offset, propIds, idx);
if (offset === -1) return undefined;
const prop = buf[offset++];
const _prop = buf[offset++];
const kind = buf[offset++];
if (kind === PropFlags.Ref) {
@ -398,7 +454,7 @@ class MatchCtx {
return this.getAttrPathValue(value, propIds, idx + 1);
} else if (kind === PropFlags.RefArr) {
// FIXME
const count = readU32(buf, offset);
const _count = readU32(buf, offset);
offset += 4;
}
@ -452,22 +508,133 @@ class MatchCtx {
return true;
}
getFirstChild() {
// FIXME
return 0;
/**
* @param {number} offset
* @returns {number}
*/
getFirstChild(offset) {
const { buf } = this;
// type + parentId + SpanLo + SpanHi
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.String:
offset += 4;
break;
case PropFlags.Bool:
offset++;
break;
case PropFlags.Null:
case PropFlags.Undefined:
break;
}
}
return -1;
}
getLastChild() {
// FIXME
return 0;
/**
* @param {number} offset
* @returns {number}
*/
getLastChild(offset) {
const { buf } = this;
// type + parentId + SpanLo + SpanHi
offset += 1 + 4 + 4 + 4;
let last = -1;
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;
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:
offset += 4;
break;
case PropFlags.Bool:
offset++;
break;
case PropFlags.Null:
case PropFlags.Undefined:
break;
}
}
return last;
}
getSiblingBefore() {
// FIXME
return 0;
}
getSiblings() {
// FIXME
return [];
/**
* @param {number} id
* @returns {number[]}
*/
getSiblings(id) {
const { buf } = this;
const result = findChildOffset(buf, id);
// Happens for program nodes
if (result === null) return [];
if (result[1] === -1) {
return [id];
}
let offset = result[0];
const count = readU32(buf, offset);
offset += 4;
/** @type {number[]} */
const out = [];
for (let i = 0; i < count; i++) {
const v = readU32(buf, offset);
offset += 4;
out.push(v);
}
return out;
}
}
@ -623,8 +790,6 @@ export function runPluginsForFile(fileName, serializedAst) {
try {
fn(node);
} catch (err) {
// FIXME: console here doesn't support error cause
console.log(err);
throw new Error(`Visitor "${name}" of plugin "${id}" errored`, {
cause: err,
});
@ -734,7 +899,6 @@ function traverse(ctx, visitors, offset) {
const propCount = buf[offset];
offset += 1;
// console.log({ propCount });
for (let i = 0; i < propCount; i++) {
const kind = buf[offset + 1];

View file

@ -900,12 +900,12 @@ function matchChild(next) {
*/
function matchAdjacent(next) {
return (ctx, id) => {
const parent = ctx.getParent(id);
if (parent < 0) return false;
const siblings = ctx.getSiblings(id);
const idx = siblings.indexOf(id) - 1;
const prev = ctx.getSiblingBefore(parent, id);
if (prev < 0) return false;
if (idx < 0) return false;
const prev = siblings[idx];
return next(ctx, prev);
};
}
@ -916,16 +916,14 @@ function matchAdjacent(next) {
*/
function matchFollowing(next) {
return (ctx, id) => {
const parent = ctx.getParent(id);
if (parent < 0) return false;
const siblings = ctx.getSiblings(id);
const idx = siblings.indexOf(id) - 1;
let prev = ctx.getSiblingBefore(parent, id);
while (prev > -1) {
if (next(ctx, prev)) {
return true;
}
if (idx < 0) return false;
prev = ctx.getSiblingBefore(parent, prev);
for (let i = idx; i >= 0; i--) {
const sib = siblings[i];
if (next(ctx, sib)) return true;
}
return false;

View file

@ -116,6 +116,14 @@ Deno.test("Lexer - Relation ~", () => {
{ token: Token.Op, value: "~" },
{ token: Token.Word, value: "Bar" },
]);
expect(testLexer("Foo Bar ~ Bar")).toEqual([
{ token: Token.Word, value: "Foo" },
{ token: Token.Space, value: "" },
{ token: Token.Word, value: "Bar" },
{ token: Token.Op, value: "~" },
{ token: Token.Word, value: "Bar" },
]);
});
Deno.test("Lexer - Attr", () => {

View file

@ -147,6 +147,7 @@ class FakeContext implements MatchCtx {
} else if (
first === -1 && prop.value !== null && typeof prop.value === "object"
) {
// @ts-ignore loosely typed
first = prop.value;
}
}
@ -164,6 +165,7 @@ class FakeContext implements MatchCtx {
if (prop.value.length === 0) return -1;
return prop.value.at(-1);
} else if (prop.value !== null && typeof prop.value !== "object") {
// @ts-ignore loosely typed
last = prop.value;
}
}
@ -176,27 +178,6 @@ class FakeContext implements MatchCtx {
return node.parentId;
}
getSiblingBefore(parentId: number, sib: number): number {
const node = this.ids.get(parentId);
if (node === undefined) return -1;
let prev = -1;
for (const prop of node.props) {
if (prop.value === sib) return prev;
if (Array.isArray(prop.value)) {
for (const id of prop.value) {
if (id === sib) return prev;
prev = id;
}
} else {
prev = prop.value;
}
}
return -1;
}
getSiblings(id: number): number[] {
const parent = this.getParent(id);
const node = this.ids.get(parent);

View file

@ -102,7 +102,6 @@ export interface ILexer {
export interface MatchContext {
getFirstChild(id: number): number;
getLastChild(id: number): number;
getSiblingBefore(parentId: number, sib: number): number;
getSiblings(id: number): number[];
getParent(id: number): number;
getType(id: number): number;