Finch/editors/vscode/test/grammar.js
Claude 68a9493572
Vector types (SIMD): f32x8, i8x32, f64x4 and the rest; --cpu native
- fNxM / iNxM / uNxM up to 512 bits, as LLVM vectors (<8 x float>): LLVM picks SSE, AVX2,
  AVX-512 or NEON for them
- f32x8(x) in every lane, f32x8(a, ..., h), f32x8(list, i) loads, f32x8(i32x8 v) converts
- + - * / and the bit operators lane by lane, with a plain number on either side counting for every lane;
  v[i], v[i] = x, v.len, == / != (every lane), print and str
- methods: sum min max dot abs sqrt floor ceil round fma store; min/max/abs/clamp lane by lane
- wide vectors (and structs holding them) are loaded and stored with align 16, what malloc and the stack give
- --cpu <name> (and cpu = "..." in finch.toml): native, x86-64-v3, apple-m1, ...
- debug info shows vectors; the language server completes their methods; Kate and VS Code highlight them
- f32 x = -1.5 works: a minus in front of a float written in the code keeps it such a number

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Psc42moPLwP43Cmb9oZqSR
2026-11-01 13:50:35 +00:00

70 lines
3.6 KiB
JavaScript

// Tokenizes Finch code with the same engine VS Code uses and checks the scopes.
const fs = require('fs'), path = require('path');
const vsctm = require('vscode-textmate'), oniguruma = require('vscode-oniguruma');
const grammarPath = path.join(__dirname, "..", "syntaxes", "finch.tmLanguage.json");
const wasm = fs.readFileSync(require.resolve("vscode-oniguruma/release/onig.wasm")).buffer;
const onigLib = oniguruma.loadWASM(wasm).then(() => ({
createOnigScanner: (s) => new oniguruma.OnigScanner(s),
createOnigString: (s) => new oniguruma.OnigString(s),
}));
const registry = new vsctm.Registry({ onigLib, loadGrammar: async () => vsctm.parseRawGrammar(fs.readFileSync(grammarPath, 'utf8'), grammarPath) });
const code = [
'import "stdio.h"',
'import shapes',
'struct Point {',
' int x = 0x1F',
'}',
'fn add(int a, float b) -> int {',
' s := "hi\\n" + str(a) // note',
' for i in 0..10 { print(i, \'c\', 3.5, true, null) }',
' p := Point(x: 1)',
' return a + p.x',
'}',
'fn Point.move(int dx) -> int! {',
' map[str]int m',
' n := try parse(s) or 0',
' self.x += dx',
' return error("no")',
'}',
'test "lives \\(hp + f(1)) left" {',
' assert(clamp(x, 0, 9) == 3)',
'}',
'fn dot(f32x8 a, i8x32 b) {',
];
const expect = [ // [line, token text, scope that must be present]
[0, 'import', 'keyword.control.import'], [0, '"stdio.h"', 'string.quoted.double'],
[1, 'shapes', 'entity.name.namespace'],
[2, 'struct', 'storage.type.struct'], [2, 'Point', 'entity.name.type.struct'],
[3, 'int', 'storage.type.primitive'], [3, '0x1F', 'constant.numeric.hex'],
[5, 'fn', 'storage.type.function'], [5, 'add', 'entity.name.function'], [5, 'float', 'storage.type.primitive'], [5, '->', 'keyword.operator.arrow'],
[6, ':=', 'keyword.operator.assignment'], [6, '\\n', 'constant.character.escape'], [6, '// note', 'comment.line'], [6, 'str', 'storage.type.primitive'],
[7, 'for', 'keyword.control'], [7, 'in', 'keyword.control'], [7, '..', 'keyword.operator.range'], [7, 'print', 'support.function.builtin'],
[7, 'c', 'string.quoted.single'], [7, '3.5', 'constant.numeric.float'], [7, 'true', 'constant.language'], [7, 'null', 'constant.language'],
[8, 'Point', 'entity.name.type'],
[9, 'return', 'keyword.control'],
[11, 'Point', 'entity.name.type'], [11, 'move', 'entity.name.function'], [11, '!', 'keyword.operator'],
[12, 'map', 'storage.type.primitive'],
[13, 'try', 'keyword.control'], [13, 'or', 'keyword.control'],
[14, 'self', 'variable.language.self'],
[15, 'error', 'support.function.builtin'],
[17, 'test', 'keyword.other.test'], [17, '\\(', 'punctuation.section.embedded.begin'], [17, 'hp', 'meta.embedded.line'],
[17, 'f', 'meta.embedded.line'], [17, 'left', 'string.quoted.double'],
[18, 'assert', 'support.function.builtin'], [18, 'clamp', 'support.function.builtin'],
[20, 'f32x8', 'storage.type.primitive'], [20, 'i8x32', 'storage.type.primitive'],
];
registry.loadGrammar('source.finch').then((g) => {
let state = vsctm.INITIAL, toks = [];
code.forEach((line, i) => {
const r = g.tokenizeLine(line, state);
r.tokens.forEach((t) => toks.push([i, line.substring(t.startIndex, t.endIndex), t.scopes.join(' ')]));
state = r.ruleStack;
});
let bad = 0;
for (const [line, text, scope] of expect) {
const hit = toks.find((t) => t[0] === line && t[1].trim() === text);
const ok = hit && hit[2].includes(scope);
if (!ok) { bad++; console.log('FAIL', line, JSON.stringify(text), 'wanted', scope, 'got', hit ? hit[2] : '(no token)'); }
}
console.log(bad ? `grammar: ${bad} failed` : `grammar: all ${expect.length} ok`);
process.exit(bad ? 1 : 0);
});