Download unified-engine/tests/test-kernel-frontend.js from Snapkitty/repoverse: direct link, hf CLI and curl.
- Browser
- Download file 5.81 kB
-
https://huggingface.co/Snapkitty/repoverse/resolve/main/unified-engine/tests/test-kernel-frontend.js
- Command line
-
hf download hf://Snapkitty/repoverse/unified-engine/tests/test-kernel-frontend.js
-
curl -L -o test-kernel-frontend.js https://huggingface.co/Snapkitty/repoverse/resolve/main/unified-engine/tests/test-kernel-frontend.js
5.81 kB
| import { test } from 'node:test'; | |
| import assert from 'node:assert/strict'; | |
| import { tokenize, TokenType, LexError } from '../kernel/compiler/lexer.js'; | |
| import { parse, ParseError } from '../kernel/compiler/parser.js'; | |
| const VECTOR_ADD = ` | |
| __global__ | |
| void vector_add(const float* A, const float* B, float* C, int N) | |
| { | |
| int i = blockIdx.x * blockDim.x + threadIdx.x; | |
| if (i < N) | |
| C[i] = A[i] + B[i]; | |
| } | |
| `; | |
| test('lexer: emits keywords, identifiers, numbers and punctuation', () => { | |
| const tokens = tokenize('int i = 42;'); | |
| assert.equal(tokens[0].type, TokenType.KEYWORD); | |
| assert.equal(tokens[0].value, 'int'); | |
| assert.equal(tokens[1].type, TokenType.IDENT); | |
| assert.equal(tokens[3].type, TokenType.INT); | |
| assert.equal(tokens[3].value, '42'); | |
| assert.equal(tokens.at(-1).type, TokenType.EOF); | |
| }); | |
| test('lexer: distinguishes float from int literals', () => { | |
| assert.equal(tokenize('1.5')[0].type, TokenType.FLOAT); | |
| assert.equal(tokenize('1')[0].type, TokenType.INT); | |
| assert.equal(tokenize('2.5f')[0].type, TokenType.FLOAT); | |
| assert.equal(tokenize('1e3')[0].type, TokenType.FLOAT); | |
| }); | |
| test('lexer: parses hex literals', () => { | |
| const token = tokenize('0x1F')[0]; | |
| assert.equal(token.type, TokenType.INT); | |
| assert.equal(parseInt(token.value, 16), 31); | |
| }); | |
| test('lexer: skips line and block comments', () => { | |
| const tokens = tokenize('int /* mid */ i; // trailing\n'); | |
| assert.equal(tokens.filter((t) => t.type === TokenType.IDENT).length, 1); | |
| }); | |
| test('lexer: tracks line numbers across newlines', () => { | |
| const tokens = tokenize('int a;\nint b;\nint c;'); | |
| assert.equal(tokens[0].line, 1); | |
| const cToken = tokens.find((t) => t.value === 'c'); | |
| assert.equal(cToken.line, 3); | |
| }); | |
| test('lexer: prefers the longest punctuator', () => { | |
| const values = tokenize('a += b').map((t) => t.value); | |
| assert.ok(values.includes('+=')); | |
| assert.ok(!values.includes('+=') === false); | |
| const shift = tokenize('a << b').map((t) => t.value); | |
| assert.ok(shift.includes('<<')); | |
| }); | |
| test('lexer: rejects an unterminated block comment', () => { | |
| assert.throws(() => tokenize('int a; /* never closed'), LexError); | |
| }); | |
| test('lexer: rejects an unknown character', () => { | |
| assert.throws(() => tokenize('int a = $;'), LexError); | |
| }); | |
| test('parser: produces the expected kernel signature', () => { | |
| const ast = parse(VECTOR_ADD); | |
| assert.equal(ast.name, 'vector_add'); | |
| assert.equal(ast.returnType, 'void'); | |
| assert.equal(ast.isGlobal, true); | |
| assert.equal(ast.params.length, 4); | |
| assert.deepEqual(ast.params.map((p) => p.name), ['A', 'B', 'C', 'N']); | |
| assert.deepEqual(ast.params.map((p) => p.type.kind), ['buffer', 'buffer', 'buffer', 'scalar']); | |
| assert.equal(ast.params[0].type.isConst, true); | |
| assert.equal(ast.params[2].type.isConst, false); | |
| }); | |
| test('parser: lowers thread indexing to global_id_x', () => { | |
| const ast = parse(VECTOR_ADD); | |
| const [decl] = ast.body; | |
| assert.equal(decl.kind, 'decl'); | |
| assert.equal(decl.name, 'i'); | |
| // i = blockIdx.x * blockDim.x + threadIdx.x | |
| const add = decl.init; | |
| assert.equal(add.kind, 'binary'); | |
| assert.equal(add.op, '+'); | |
| const mul = add.left; | |
| assert.equal(mul.kind, 'binary'); | |
| assert.equal(mul.op, '*'); | |
| assert.equal(mul.left.callee, 'block_id_x'); | |
| assert.equal(mul.right.callee, 'block_dim_x'); | |
| assert.equal(add.right.callee, 'local_id_x'); | |
| }); | |
| test('parser: keeps the guarded assignment as an if statement', () => { | |
| const ast = parse(VECTOR_ADD); | |
| const branch = ast.body[1]; | |
| assert.equal(branch.kind, 'if'); | |
| assert.equal(branch.cond.op, '<'); | |
| const assign = branch.then[0]; | |
| assert.equal(assign.kind, 'assign'); | |
| assert.equal(assign.target.kind, 'index'); | |
| assert.equal(assign.value.kind, 'binary'); | |
| assert.equal(assign.value.op, '+'); | |
| }); | |
| test('parser: accepts explicit casts and unary operators', () => { | |
| const ast = parse('__global__ int f(int a) { return -int(a) * 2; }'); | |
| // Unary minus binds tighter than '*', as in C: (-int(a)) * 2. | |
| const ret = ast.body[0].value; | |
| assert.equal(ret.kind, 'binary'); | |
| assert.equal(ret.op, '*'); | |
| assert.equal(ret.left.kind, 'unary'); | |
| assert.equal(ret.left.operand.kind, 'cast'); | |
| assert.equal(ret.left.operand.to, 'int'); | |
| }); | |
| test('parser: accepts C-style casts', () => { | |
| const ast = parse('__global__ float f(int a) { return (float)a / 2.0f; }'); | |
| const ret = ast.body[0].value; | |
| assert.equal(ret.op, '/'); | |
| assert.equal(ret.left.kind, 'cast'); | |
| assert.equal(ret.left.to, 'float'); | |
| assert.equal(ret.right.single, true); | |
| }); | |
| test('parser: follows C precedence for bitwise and shift operators', () => { | |
| const ast = parse('__global__ int f(int a) { return a & 1 << 2 | 3; }'); | |
| const ret = ast.body[0].value; | |
| assert.equal(ret.op, '|'); | |
| assert.equal(ret.left.op, '&'); | |
| assert.equal(ret.left.right.op, '<<'); | |
| }); | |
| test('parser: parses for loops with break and continue', () => { | |
| const ast = parse('__global__ void f(int n) { for (int i = 0; i < n; i += 1) { if (i == 2) continue; break; } }'); | |
| const loop = ast.body[0]; | |
| assert.equal(loop.kind, 'for'); | |
| assert.equal(loop.init.kind, 'decl'); | |
| assert.equal(loop.cond.op, '<'); | |
| assert.equal(loop.step.kind, 'assign'); | |
| assert.equal(loop.body[0].then[0].kind, 'continue'); | |
| assert.equal(loop.body[1].kind, 'break'); | |
| }); | |
| test('parser: rejects a kernel without __global__', () => { | |
| assert.throws(() => parse('void f() { }'), ParseError); | |
| }); | |
| test('parser: rejects an unsupported parameter type', () => { | |
| assert.throws(() => parse('__global__ void f(double2 v) { }'), ParseError); | |
| }); | |
| test('parser: rejects trailing input after the kernel', () => { | |
| assert.throws(() => parse(VECTOR_ADD + '\nint extra;'), ParseError); | |
| }); | |
| test('parser: rejects an unterminated body', () => { | |
| assert.throws(() => parse('__global__ void f() { int i = 0;'), ParseError); | |
| }); | |