Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
1af7cc2
Scaffolding for adding trivia to syntax tree
stefnotch Feb 20, 2025
bb9931b
Add most missing nodes
stefnotch Feb 20, 2025
8518401
Change start-end to span
stefnotch Feb 20, 2025
178a051
Remove srcModule from textElem
stefnotch Feb 20, 2025
a6ea872
wip refactor
stefnotch Feb 21, 2025
eb33305
Integrate new line wrapper and tweak module elem
stefnotch Feb 21, 2025
31af5a9
Rename expression grammar
stefnotch Feb 21, 2025
e052be9
Replace translate time feature with name elem
stefnotch Feb 21, 2025
9f9ddf0
Move expression elem
stefnotch Feb 21, 2025
a88c0cf
Add attributes to global elements
stefnotch Feb 21, 2025
ded81a2
Merge branch 'main' into feat/full-ast-temp
stefnotch Feb 21, 2025
9faa2cb
Update testsuite
stefnotch Feb 21, 2025
a291e97
Prep for full expression parsing
stefnotch Feb 21, 2025
72652e1
Parse everything
stefnotch Feb 22, 2025
f21664f
Prep for scope generation
stefnotch Feb 22, 2025
7f9916a
Bench runs again
stefnotch Feb 23, 2025
b261aa7
Implement new ASTtoString
stefnotch Feb 23, 2025
ee18a60
Tweak ASTtoString printing
stefnotch Feb 23, 2025
3b18105
Update tests
stefnotch Feb 23, 2025
704abeb
Update more test snapshots
stefnotch Feb 23, 2025
9b097de
Minor tweaks
stefnotch Feb 23, 2025
1e82d2f
Minor cleanup
stefnotch Feb 23, 2025
292fc4d
Merge branch 'main' into feat/full-ast-temp
stefnotch Feb 24, 2025
37b66b2
Post merge fix
stefnotch Feb 24, 2025
e3a54a8
Merge remote-tracking branch 'origin/main' into feat/full-ast-temp
stefnotch Feb 24, 2025
fb79188
Merge branch 'feat/error-message-integration' into feat/full-ast-temp
stefnotch Feb 28, 2025
64c97f7
Merge branch 'main' into feat/full-ast-temp
stefnotch Feb 28, 2025
a3b27e2
Add type safe syntax tree mutation
stefnotch Feb 28, 2025
b62b3dd
More changes
stefnotch Feb 28, 2025
8beb6ec
Demonstrate lazy syntax tree mutation
stefnotch Feb 28, 2025
7024a1f
Use a mutating approach instead
stefnotch Feb 28, 2025
e09940a
Implement symbols table pass
stefnotch Feb 28, 2025
c45ad52
Cleanup
stefnotch Feb 28, 2025
32ecc5d
stuff
stefnotch Mar 1, 2025
a1fe0a6
Add super cool partial condition evaluation
stefnotch Mar 2, 2025
09b8eaf
Remove partial conditions (complexity)
stefnotch Mar 2, 2025
61441f4
Minor tweaks
stefnotch Mar 2, 2025
68f2bd7
Updates
stefnotch Mar 2, 2025
cfa492c
new srcmap
stefnotch Mar 3, 2025
f24295c
Fix source map
stefnotch Mar 3, 2025
9753046
wip
stefnotch Mar 3, 2025
b22cae1
wip
stefnotch Mar 4, 2025
e76d41c
merge
stefnotch Mar 4, 2025
2265ba8
Merge branch 'main' into feat/full-ast-temp
stefnotch Mar 9, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 25 additions & 15 deletions tools/packages/bench/bin/bench.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { WGSLLinker } from "@use-gpu/shader";
import fs from "fs/promises";
import path from "node:path";
import { link, parseWESL } from "wesl";
import { link, ModulePath, parseWESL } from "wesl";
import { WgslReflect } from "wgsl_reflect";
import yargs from "yargs";

Expand Down Expand Up @@ -105,7 +105,7 @@ function runNTimes(n: number, variant: ParserVariant, file: BenchTest): void {
interface BenchTest {
name: string;
/** Path to the main file */
mainFile: string;
rootModule: ModulePath;
/** All relevant files (file paths and their contents) */
files: Map<string, string>;
}
Expand All @@ -115,34 +115,44 @@ async function loadAllFiles(): Promise<BenchTest[]> {
const reduceBuffer = await loadBench(
"reduceBuffer",
examplesDir,
"./reduceBuffer.wgsl",
["./reduceBuffer.wgsl"],
["package", "reduceBuffer"],
);
const particle = await loadBench(
"particle",
examplesDir,
["./particle.wgsl"],
["package", "particle"],
);
const particle = await loadBench("particle", examplesDir, "./particle.wgsl");
const rasterize = await loadBench(
"rasterize",
examplesDir,
"./rasterize_05_fine.wgsl",
["./rasterize_05_fine.wgsl"],
["package", "rasterize_05_fine"],
);
const boat = await loadBench(
"unity_webgpu_0000026E5689B260",
examplesDir,
"./unity_webgpu_000002B8376A5020.fs.wgsl",
["./unity_webgpu_000002B8376A5020.fs.wgsl"],
["package", "unity_webgpu_000002B8376A5020"],
);
const imports_only = await loadBench(
"imports_only",
examplesDir,
"./imports_only.wgsl",
["./imports_only.wgsl"],
["package", "imports_only"],
);
const bevy_deferred_lighting = await loadBench(
"bevy_deferred_lighting",
"./src/examples/bevy",
"./bevy_generated_deferred_lighting.wgsl",
["./bevy_generated_deferred_lighting.wgsl"],
["package", "bevy_generated_deferred_lighting"],
);
const bevy_linking = await loadBench(
"bevy_linking",
"./src/examples/naga_oil_example",
"./pbr.wgsl",
[
"./pbr.wgsl",
"./clustered_forward.wgsl",
"./mesh_bindings.wgsl",
"./mesh_types.wgsl",
Expand All @@ -156,6 +166,7 @@ async function loadAllFiles(): Promise<BenchTest[]> {
"./shadows.wgsl",
"./utils.wgsl",
],
["package", "pbr"],
);
return [
reduceBuffer,
Expand All @@ -171,18 +182,17 @@ async function loadAllFiles(): Promise<BenchTest[]> {
async function loadBench(
name: string,
cwd: string,
mainFile: string,
extraFiles: string[] = [],
filePaths: string[] = [],
rootModule: ModulePath,
): Promise<BenchTest> {
const files = new Map<string, string>();
const addFile = async (p: string) =>
files.set(p, await fs.readFile(path.join(cwd, p), { encoding: "utf8" }));

await addFile(mainFile);
for (const path of extraFiles) {
for (const path of filePaths) {
await addFile(path);
}
return { name, mainFile, files };
return { name, rootModule, files };
}

function runOnce(parserVariant: ParserVariant, test: BenchTest): void {
Expand All @@ -193,7 +203,7 @@ function runOnce(parserVariant: ParserVariant, test: BenchTest): void {
} else if (parserVariant === "wesl-link") {
link({
weslSrc: Object.fromEntries(test.files.entries()),
rootModuleName: test.mainFile,
rootModulePath: test.rootModule,
});
} else if (parserVariant === "wgsl_reflect") {
for (const [path, text] of test.files) {
Expand Down
24 changes: 2 additions & 22 deletions tools/packages/bulk-test/src/stripWgsl.ts
Original file line number Diff line number Diff line change
@@ -1,34 +1,14 @@
import { WeslStream } from "wesl";

/** Remove extra bits from WGSL for test comparisons.
*
* removes:
* . extra whitespace,
* . comments,
* . trailing commas in brackets, paren, and array containers
*/
/** Removes extra whitespace and comments from WGSL */
export function stripWesl(text: string): string {
const stream = new WeslStream(text);
const firstToken = stream.nextToken();
if (firstToken === null) return "";

let result = firstToken.text;
while (true) {
const token = stream.nextToken();
if (token === null) return result;

if (token.text === ",") {
const nextToken = stream.nextToken();
const nextText = nextToken?.text;
if (nextText === "}" || nextText === "]" || nextText === ")") {
// Ignore trailing comma
result += " ";
result += nextText;
} else {
result += ", " + (nextToken?.text ?? "");
}
} else {
result += " " + token.text;
}
result += " " + token.text;
}
}
17 changes: 0 additions & 17 deletions tools/packages/bulk-test/src/test/StripWgsl.test.ts

This file was deleted.

8 changes: 4 additions & 4 deletions tools/packages/bulk-test/src/testWgslFiles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,13 @@ export async function testWgslFiles(namedPaths: NamedPath[]) {
const config = { plugins: [bindingStructsPlugin()] };

namedPaths.forEach(({ name, filePath }) => {
const shortPath = "./" + name;
test(name, async () => {
const orig = await fs.readFile(filePath, { encoding: "utf8" });
const result = await expectNoLogAsync(() => {
const weslSrc = { [shortPath]: orig };
const rootModuleName = noSuffix(name);
return link({ weslSrc, rootModuleName, config });
const shortPath = "./" + name;
const weslSrc = { [shortPath]: text };
const rootModulePath = ["package", ...noSuffix(name).split("/")];
return link({ weslSrc, rootModulePath, config });
});
expect(stripWesl(result.dest)).toBe(stripWesl(orig));
});
Expand Down
52 changes: 51 additions & 1 deletion tools/packages/mini-parse/src/Parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ import {
tracing,
withTraceLogging,
} from "./ParserTracing.js";
import { Stream, Token, TypedToken } from "./Stream.js";
import { Span } from "./Span.js";
import { peekToken, Stream, Token, TypedToken } from "./Stream.js";

export interface AppState<C, S> {
/**
Expand Down Expand Up @@ -215,6 +216,18 @@ export class Parser<I, T> {
return map(this, fn);
}

/** map results to a new value.
*/
mapSpanned<U>(fn: (value: T, span: Span) => U): Parser<I, U> {
return mapSpanned(this, fn);
}

/** map results to a new value, or backtracks
*/
verifyMap<U>(fn: (value: T) => OptParserResult<U>): Parser<I, U> {
return verifyMap(this, fn);
}

/** Queue a function that runs later, typically to collect AST elements from the parse.
* when a commit() is parsed.
* Collection functions are dropped with parser backtracking, so
Expand Down Expand Up @@ -363,6 +376,43 @@ function map<I, T, U>(p: Parser<I, T>, fn: (value: T) => U): Parser<I, U> {
return mapParser;
}

/** return a parser that maps the current results */
function mapSpanned<I, T, U>(
p: Parser<I, T>,
fn: (value: T, span: Span) => U,
): Parser<I, U> {
const mapSpannedParser = parser(
`mapSpanned`,
function _mapSpanned(ctx: ParserContext): OptParserResult<U> {
const start = peekToken(ctx.stream)?.span?.[0] ?? null;
const result = p._run(ctx);
if (result === null) return null;
const end = ctx.stream.checkpoint();
return { value: fn(result.value, [start ?? end, end]) };
},
);

trackChildren(mapSpannedParser, p);
return mapSpannedParser;
}

function verifyMap<I, T, U>(
p: Parser<I, T>,
fn: (value: T) => OptParserResult<U>,
): Parser<I, U> {
const verifyMapParser = parser(
`verifyMap`,
function _verifyMap(ctx: ParserContext): OptParserResult<U> {
const result = p._run(ctx);
if (result === null) return null;
return fn(result.value);
},
);

trackChildren(verifyMapParser, p);
return verifyMapParser;
}

type ToParserFn<I, T, X> = (results: ParserResult<T>) => Parser<I, X> | null;

function toParser<I, T, O>(
Expand Down
51 changes: 8 additions & 43 deletions tools/packages/mini-parse/src/ParserLogging.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,13 @@
import { ParserContext } from "./Parser.js";
import { parserLog, tracePos, tracing } from "./ParserTracing.js";
import { SrcMap, SrcWithPath } from "./SrcMap.js";
import { Span } from "./Span.js";
import { log } from "./WrappedLog.js";

/** log an message along with the source line and a caret indicating the error position in the line
* @param pos is the position the source string, or if src is a SrcMap, then
* pos is the position in the dest (e.g. preprocessed) text
*/
export function srcLog(
src: string | SrcMap,
pos: number | [number, number],
...msgs: any[]
): void {
export function srcLog(src: string, pos: number | Span, ...msgs: any[]): void {
logInternal(log, src, pos, ...msgs);
}

Expand All @@ -21,7 +17,7 @@ export function quotedText(text?: string): string {

/** log a message along with src line, but only if tracing is active in the current parser */
export function srcTrace(
src: string | SrcMap,
src: string,
pos: number | [number, number],
...msgs: any[]
): void {
Expand All @@ -38,45 +34,17 @@ export function ctxLog(ctx: ParserContext, ...msgs: any[]): void {
*/
function logInternal(
log: typeof console.log,
srcOrSrcMap: string | SrcMap,
destPos: number | [number, number],
src: string,
destPos: number | Span,
...msgs: any[]
): void {
if (typeof srcOrSrcMap === "string") {
logInternalSrc(log, srcOrSrcMap, destPos, ...msgs);
return;
}
const { src, positions } = mapSrcPositions(srcOrSrcMap, destPos);

logInternalSrc(log, src.text, positions, ...msgs);
}

interface SrcPositions {
positions: number | [number, number];
src: SrcWithPath;
}

function mapSrcPositions(
srcMap: SrcMap,
destPos: number | [number, number],
): SrcPositions {
const srcPos = srcMap.mapPositions(...[destPos].flat());
const { src } = srcPos[0];

let positions: [number, number] | number;
if (srcPos[1]?.src?.path === src.path && srcPos[1]?.src?.text === src.text) {
positions = srcPos.map(p => p.position) as [number, number];
} else {
positions = srcPos[0].position;
}

return { src, positions };
logInternalSrc(log, src, destPos, ...msgs);
}

function logInternalSrc(
log: typeof console.log,
src: string,
pos: number | [number, number],
pos: number | Span,
...msgs: any[]
): void {
log(...msgs);
Expand Down Expand Up @@ -120,10 +88,7 @@ interface SrcLine {
}

/** return the line in the src containing a given character postion */
export function srcLine(
src: string,
position: number | [number, number],
): SrcLine {
export function srcLine(src: string, position: number | Span): SrcLine {
let pos: number;
let pos2: number | undefined;
if (typeof position === "number") {
Expand Down
4 changes: 4 additions & 0 deletions tools/packages/mini-parse/src/Span.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,7 @@
* An range, from start (inclusive) to end (exclusive).
*/
export type Span = readonly [number, number];

export function isSpan(span: any): span is Span {
return Array.isArray(span) && span.length === 2;
}
Loading