commit 35ba1a129fce413a3d43e944134f4a818df062b6 Author: rowan Date: Wed Apr 16 22:21:46 2025 -0500 add some stuffs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d570088 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +node_modules/ + diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..601ddbf --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "vendor/kuebiko"] + path = vendor/kuebiko + url = git@git.kitsu.cafe:rowan/kuebiko.git diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..e17efc2 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,22 @@ +{ + "name": "wgsl-reflect", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "wgsl-reflect", + "version": "1.0.0", + "license": "ISC", + "devDependencies": { + "folktest": "git+https://git.kitsu.cafe/rowan/folktest.git" + } + }, + "node_modules/folktest": { + "version": "1.0.0", + "resolved": "git+https://git.kitsu.cafe/rowan/folktest.git#708d44f1215be33fcceba426029f44b4f963dbe5", + "dev": true, + "license": "GPL-3.0-or-later" + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..9cc17c1 --- /dev/null +++ b/package.json @@ -0,0 +1,16 @@ +{ + "name": "wgsl-reflect", + "version": "1.0.0", + "main": "index.js", + "type": "module", + "scripts": { + "test": "./tests/index.js" + }, + "keywords": [], + "author": "", + "license": "ISC", + "description": "", + "devDependencies": { + "folktest": "git+https://git.kitsu.cafe/rowan/folktest.git" + } +} diff --git a/src/index.js b/src/index.js new file mode 100644 index 0000000..073466d --- /dev/null +++ b/src/index.js @@ -0,0 +1,77 @@ +const shader = `// A fragment shader which lights textured geometry with point lights. + +// Lights from a storage buffer binding. +struct PointLight { + position : vec3f, + color : vec3f, +} + +struct LightStorage { + pointCount : u32, + point : array, +} +@group(0) @binding(0) var lights : LightStorage; + +// Texture and sampler. +@group(1) @binding(0) var baseColorSampler : sampler; +@group(1) @binding(1) var baseColorTexture : texture_2d; + +// Function arguments are values from the vertex shader. +@fragment +fn fragmentMain(@location(0) worldPos : vec3f, + @location(1) normal : vec3f, + @location(2) uv : vec2f) -> @location(0) vec4f { + // Sample the base color of the surface from a texture. + let baseColor = textureSample(baseColorTexture, baseColorSampler, uv); + + let N = normalize(normal); + var surfaceColor = vec3f(0); + + // Loop over the scene point lights. + for (var i = 0u; i < lights.pointCount; i++) { + let worldToLight = lights.point[i].position - worldPos; + let dist = length(worldToLight); + let dir = normalize(worldToLight); + + // Determine the contribution of this light to the surface color. + let radiance = lights.point[i].color * (1 / pow(dist, 2)); + let nDotL = max(dot(N, dir), 0); + + // Accumulate light contribution to the surface color. + surfaceColor += baseColor.rgb * radiance * nDotL; + } + + // Return the accumulated surface color. + return vec4(surfaceColor, baseColor.a); +}` + +/** + * + 3.1 Parsing + Remove comments: + + Replace the first comment with a space code point (U+0020). + + Repeat until no comments remain. + + Find template lists, using the algorithm in § 3.9 Template Lists. + + Parse the whole text, attempting to match the translation_unit grammar rule. Parsing uses a LALR(1) parser (one token of lookahead) [DeRemer1969], with the following customization: + + Tokenization is interleaved with parsing, and is context-aware. When the parser requests the next token: + + Consume and ignore an initial sequence of blankspace code points. + + If the next code point is the start of a template list, consume it and return _template_args_start. + + If the next code point is the end of a template list, consume it and return _template_args_end. + + Otherwise: + + A token candidate is any WGSL token formed from the non-empty prefix of the remaining unconsumed code points. + + The token returned is the longest token candidate that is also a valid lookahead token for the current parser state. [VanWyk2007] + + + */ + diff --git a/src/parser/comments.js b/src/parser/comments.js new file mode 100644 index 0000000..478a1ce --- /dev/null +++ b/src/parser/comments.js @@ -0,0 +1,16 @@ +import { char, until } from '../../vendor/kuebiko/src/index.js' + +// https://www.w3.org/TR/WGSL/#comments +const slash = char('\u002f') +const asterisk = char('\u002a') + +const comment = seq(slash, slash) + +const blockCommentStart = seq(slash, asterisk) +const blockCommentEnd = seq(asterisk, slash) + +const blockComment = seq( + blockCommentStart, + until(blockCommentEnd) +) + diff --git a/src/parser/keyword.js b/src/parser/keyword.js new file mode 100644 index 0000000..ab8ee77 --- /dev/null +++ b/src/parser/keyword.js @@ -0,0 +1,188 @@ +import { any, anyChar, char, many, not, seq, str, until } from '../../vendor/kuebiko/src/index.js' + +export const ident = seq( + not(any( + char('_'), + seq(str('__'), many(anyChar)), + )), + until(' ') +) + +const Keyword = [ + 'alias', + 'break', + 'case', + 'const', + 'const_assert', + 'continue', + 'continuing', + 'default', + 'diagnostic', + 'discard', + 'else', + 'enable', + 'false', + 'fn', + 'for', + 'if', + 'let', + 'loop', + 'override', + 'requires', + 'return', + 'struct', + 'switch', + 'true', + 'var', + 'while' +] + +const Reserved = [ + 'NULL', + 'Self', + 'abstract', + 'active', + 'alignas', + 'alignof', + 'as', + 'asm', + 'asm_fragment', + 'async', + 'attribute', + 'auto', + 'await', + 'become', + 'cast', + 'catch', + 'class', + 'co_await', + 'co_return', + 'co_yield', + 'coherent', + 'column_major', + 'common', + 'compile', + 'compile_fragment', + 'concept', + 'const_cast', + 'consteval', + 'constexpr', + 'constinit', + 'crate', + 'debugger', + 'decltype', + 'delete', + 'demote', + 'demote_to_helper', + 'do', + 'dynamic_cast', + 'enum', + 'explicit', + 'export', + 'extends', + 'extern', + 'external', + 'fallthrough', + 'filter', + 'final', + 'finally', + 'friend', + 'from', + 'fxgroup', + 'get', + 'goto', + 'groupshared', + 'highp', + 'impl', + 'implements', + 'import', + 'inline', + 'instanceof', + 'interface', + 'layout', + 'lowp', + 'macro', + 'macro_rules', + 'match', + 'mediump', + 'meta', + 'mod', + 'module', + 'move', + 'mut', + 'mutable', + 'namespace', + 'new', + 'nil', + 'noexcept', + 'noinline', + 'nointerpolation', + 'non_coherent', + 'noncoherent', + 'noperspective', + 'null', + 'nullptr', + 'of', + 'operator', + 'package', + 'packoffset', + 'partition', + 'pass', + 'patch', + 'pixelfragment', + 'precise', + 'precision', + 'premerge', + 'priv', + 'protected', + 'pub', + 'public', + 'readonly', + 'ref', + 'regardless', + 'register', + 'reinterpret_cast', + 'require', + 'resource', + 'restrict', + 'self', + 'set', + 'shared', + 'sizeof', + 'smooth', + 'snorm', + 'static', + 'static_assert', + 'static_cast', + 'std', + 'subroutine', + 'super', + 'target', + 'template', + 'this', + 'thread_local', + 'throw', + 'trait', + 'try', + 'type', + 'typedef', + 'typeid', + 'typename', + 'typeof', + 'union', + 'unless', + 'unorm', + 'unsafe', + 'unsized', + 'use', + 'using', + 'varying', + 'virtual', + 'volatile', + 'wgsl', + 'where', + 'with', + 'writeonly', + 'yield' +] + diff --git a/src/parser/literal.js b/src/parser/literal.js new file mode 100644 index 0000000..78a9f1e --- /dev/null +++ b/src/parser/literal.js @@ -0,0 +1,145 @@ +import { any, anyOf, digit, maybe, seq, str } from '../../vendor/kuebiko/src/index.js' +import { many } from '../../vendor/kuebiko/src/index.js' + + +const iu = anyOf('iu') +const decimal = char('.') +const sign = anyOf('+-') +const e = anyOf('eE') +const p = anyOf('pP') +const fh = anyOf('fh') + +export const zero = char('0') +export const digits = many(digit) + +export const booleanLiteral = any(str('true'), str('false')) +export const decimalIntLiteral = any( + zero, + seq( + not(zero), + digits, + maybe(iu) + ) +) + +const hexDigit = any(digit, anyOf('abcdef'), anyOf('ABCDEF')) + +const hexPrefix = seq(zero, anyOf('xX')) + +const hexIntLiteral = seq( + hexPrefix, + hexDigit, + maybe(iu) +) + +export const integerLiteral = any( + decimalIntLiteral, + hexIntLiteral +) + + +const nonzeroDigit = anyOf('123456789') + +const many1 = parser => seq(parser, many(parser)) + +const exponent = seq( + e, + sign, + many1(digit) +) + +const fhDecimalFloatLiteral = seq( + any( + zero, + seq( + nonzeroDigit, + digits + ) + ), + fh +) + +const eDecimalFloatLiteral = seq( + digits, + exponent, + fh +) + +const cDecimalFloatLiteral = seq( + any( + seq( + digits, + decimal, + many1(digit) + ), + + seq( + many1(digit), + decimal, + digits + ) + ), + + maybe(seq(exponent, fh)), +) + +const decimalFloatLiteral = any( + fhDecimalFloatLiteral, + eDecimalFloatLiteral, + cDecimalFloatLiteral +) + +const sHexFloatLiteral = seq( + hexPrefix, + any( + seq( + many(hexDigit), + decimal, + many1(hexDigit) + ), + + seq( + many1(hexDigit), + decimal, + many(hexDigit) + ) + ), + + maybe( + seq( + p, + maybe(sign), + many1(digit), + fh + ) + ) +) + +const zHexFloatLiteral = seq( + hexPrefix, + many1(hexDigit), + p, + maybe(sign), + many1(digit), + maybe(fh) +) +const hexFloatLiteral = any( + sHexFloatLiteral, + zHexFloatLiteral +) + +export const floatingPointLiteral = any( + decimalFloatLiteral, + hexFloatLiteral +) + + +export const numericLiteral = any( + integerLiteral, + floatingPointLiteral +) + +export const literal = any( + numericLiteral, + booleanLiteral +) diff --git a/src/parser/whitespace.js b/src/parser/whitespace.js new file mode 100644 index 0000000..97a896c --- /dev/null +++ b/src/parser/whitespace.js @@ -0,0 +1,25 @@ +import { any, char, seq } from '../../vendor/kuebiko/src/index.js' + +// https://www.w3.org/TR/WGSL/#blankspace-and-line-breaks +export const space = char('\u0020') +export const ht = char('\u0009') +export const lf = char('\u000a') +export const vt = char('\u000b') +export const ff = char('\u000c') +export const cr = char('\u000d') +export const nel = char('\u000d') +export const ltr = char('\u200e') +export const rtl = char('\u200f') +export const ls = char('\u200f') +export const ps = char('\u2029') + +export const blankspace = any( + space, ht, lf, vt, ff, + cr, nel, ltr, rtl, ls +) + + +export const linebreak = any( + lf, vt, ff, cr, nel, ls, ps +) + diff --git a/tests/index.js b/tests/index.js new file mode 100755 index 0000000..1efa8e9 --- /dev/null +++ b/tests/index.js @@ -0,0 +1,8 @@ +#!/usr/bin/env node + +import { TerminalRunner } from 'folktest' +import * as Tests from './units/index.js' + +console.log(TerminalRunner(Tests).toString()) + + diff --git a/tests/units/index.js b/tests/units/index.js new file mode 100644 index 0000000..ea6a69a --- /dev/null +++ b/tests/units/index.js @@ -0,0 +1,17 @@ +import { it, assert } from 'folktest' +import { ident } from '../../src/parser/keyword.js' + +export const Tests = [ + it('whatever', () => { + const pass1 = 'test1' + const pass2 = '_Test2' + const fail1 = '_' + const fail2 = '__test' + const fail3 = 'default' + + console.log( + ident + ) + }) +] + diff --git a/vendor/kuebiko b/vendor/kuebiko new file mode 160000 index 0000000..74bac48 --- /dev/null +++ b/vendor/kuebiko @@ -0,0 +1 @@ +Subproject commit 74bac48730187475160fe6cf3cdb4bc89c8e6c0b