Files
doslang-mirror/grammar.js
T
정시원andgithub-actions[bot] 83ce26c209 add minimal Zed syntax highlighting for Ferro (#2)
* add minimal Ferro tree-sitter grammar

* add temporary tree-sitter generation workflow

* generate Ferro tree-sitter parser

* drop custom grammar in favor of Rust grammar reuse

* remove temporary tree-sitter generation workflow

* add Zed extension manifest for Ferro

* configure Ferro files for Zed

* add Ferro syntax highlighting queries

* remove generated custom tree-sitter parser

* remove generated custom tree-sitter node types

* tighten Ferro Zed highlight queries

* add minimal Ferro tree-sitter grammar

* point Zed at Ferro grammar

* refresh Ferro highlights

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-08-16 18:50:19 +09:00

103 lines
2.5 KiB
JavaScript

// Minimal Tree-sitter grammar for Ferro syntax highlighting in Zed.
// This intentionally models lexical structure rather than full Ferro semantics.
module.exports = grammar({
name: "ferro",
extras: $ => [
/[\s\uFEFF\u2060\u200B]/,
],
rules: {
source_file: $ => repeat(choice(
$.line_comment,
$.block_comment,
$.string_literal,
$.char_literal,
$.integer_literal,
$.builtin,
$.builtin_type,
$.keyword,
$.identifier,
$.operator,
$.punctuation,
)),
line_comment: _ => token(seq("//", /[^\n]*/)),
// Ferro block comments may nest. Keeping this rule recursive makes syntax
// highlighting follow the compiler lexer instead of flattening nested /* */.
block_comment: $ => seq(
"/*",
repeat(choice(
$.block_comment,
/[^*/]+/,
/\*[^/]/,
/\/[^*]/,
)),
"*/",
),
string_literal: _ => token(seq(
'"',
repeat(choice(
/[^"\\\n\r]/,
/\\(x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4}|[nrt\\'"0])/,
)),
'"',
)),
char_literal: _ => token(seq(
"'",
choice(
/[^'\\\n\r]/,
/\\(x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4}|[nrt\\'"0])/,
),
"'",
)),
integer_literal: _ => token(prec(2, choice(
/0[xX][0-9A-Fa-f_]+/,
/0[bB][01_]+/,
/0[oO][0-7_]+/,
/[0-9][0-9_]*/,
))),
builtin: _ => token(prec(3, /@[A-Za-z_][A-Za-z0-9_]*/)),
builtin_type: _ => token(prec(3, choice(
"i8", "i16", "i32",
"u8", "u16", "u32",
"usize", "isize",
"bool", "char", "void", "str",
))),
keyword: _ => token(prec(3, choice(
"unit", "import", "pub", "fn", "struct", "packed", "enum", "error",
"const", "static", "var", "let", "mut",
"if", "else", "while", "for", "in", "match",
"return", "break", "continue", "defer",
"unsafe", "critical", "shared", "atomic", "comptime", "asm",
"try", "catch", "orelse", "as", "extern",
"interrupt", "interrupt_safe", "far",
"true", "false", "null", "undefined",
"self", "Self", "type",
"and", "or", "not",
))),
identifier: _ => /[A-Za-z_][A-Za-z0-9_]*/,
operator: _ => token(choice(
"<<=", ">>=",
"+=", "-=", "*=", "/=", "%=", "&=", "|=", "^=",
"==", "!=", "<=", ">=", "<<", ">>", "->", "=>", "..",
"+%", "-%", "*%",
"+", "-", "*", "/", "%", "=", "<", ">", "&", "|", "^", "~", "!", "?",
)),
punctuation: _ => token(choice(
"(", ")", "{", "}", "[", "]", ",", ";", ":", ".",
)),
},
});