Skip to content

Commit ddfbbe4

Browse files
committed
refactor(grammar): build from yaml
1 parent ee2ead3 commit ddfbbe4

7 files changed

Lines changed: 2209 additions & 15 deletions

File tree

package-lock.json

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -593,14 +593,15 @@
593593
},
594594
"scripts": {
595595
"release-elixir-ls": "cd elixir-ls && mix elixir_ls.release2 -o ../elixir-ls-release",
596-
"vscode:prepublish": "npm-run-all release-elixir-ls esbuild-release",
596+
"vscode:prepublish": "npm-run-all build-grammar release-elixir-ls esbuild-release",
597597
"mixcompile": "mix compile",
598598
"mixcompile-esbuild": "npm-run-all mixcompile esbuild",
599599
"clean": "rimraf ./out",
600600
"compile": "tsc -b",
601601
"watch": "tsc -b -w",
602602
"update-vscode": "node ./node_modules/vscode/bin/install",
603-
"pretest": "npm-run-all clean compile",
603+
"pretest": "npm-run-all build-grammar clean compile",
604+
"build-grammar": "node ./scripts/buildGrammar.js",
604605
"test": "node ./out/test/runTest.js",
605606
"lint": "biome check",
606607
"fix-formatting": "biome format --write",
@@ -618,6 +619,7 @@
618619
"@vscode/test-electron": "^2.5.2",
619620
"esbuild": "^0.25.4",
620621
"glob": "^11.0.2",
622+
"js-yaml": "^4.1.0",
621623
"mocha": "^11.5.0",
622624
"npm-run-all": "^4.1.5",
623625
"rimraf": "^6.0.1",

scripts/buildGrammar.js

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
#!/usr/bin/env node
2+
const fs = require("node:fs");
3+
const path = require("node:path");
4+
const yaml = require("js-yaml");
5+
6+
function loadYaml(relPath) {
7+
return yaml.load(fs.readFileSync(path.join(__dirname, relPath), "utf8"));
8+
}
9+
10+
function escapeChar(ch) {
11+
const specials = [
12+
"{",
13+
"}",
14+
"[",
15+
"]",
16+
"<",
17+
">",
18+
"(",
19+
")",
20+
"/",
21+
"\\",
22+
'"',
23+
"'",
24+
"|",
25+
];
26+
return specials.includes(ch) ? `\\${ch}` : ch;
27+
}
28+
29+
function buildSigils(conf) {
30+
const patterns = [];
31+
for (const h of conf.interpolated.heredocs) {
32+
patterns.push({
33+
begin: `~[a-z](?>${h.delim})`,
34+
beginCaptures: {
35+
0: { name: "punctuation.definition.string.begin.elixir" },
36+
},
37+
comment: "Double-quoted heredocs sigils",
38+
end: `^\\s*${h.delim}`,
39+
endCaptures: { 0: { name: "punctuation.definition.string.end.elixir" } },
40+
name: h.name,
41+
patterns: [
42+
{ include: "#interpolated_elixir" },
43+
{ include: "#escaped_char" },
44+
],
45+
});
46+
}
47+
for (const d of conf.interpolated.delimiters) {
48+
patterns.push({
49+
begin: `~[a-z]\\${escapeChar(d.open)}`,
50+
beginCaptures: {
51+
0: { name: "punctuation.definition.string.begin.elixir" },
52+
},
53+
comment: "sigil (allow for interpolation)",
54+
end: `\\${escapeChar(d.close)}[a-z]*`,
55+
endCaptures: { 0: { name: "punctuation.definition.string.end.elixir" } },
56+
name: "string.quoted.double.interpolated.elixir",
57+
patterns: [
58+
{ include: "#interpolated_elixir" },
59+
{ include: "#escaped_char" },
60+
...(d.nest ? [{ include: d.nest }] : []),
61+
],
62+
});
63+
}
64+
for (const h of conf.literal.heredocs) {
65+
patterns.push({
66+
begin: `~[A-Z][A-Z0-9]*(?>${h.delim})`,
67+
beginCaptures: {
68+
0: { name: "punctuation.definition.string.begin.elixir" },
69+
},
70+
comment: "Double-quoted heredocs sigils",
71+
end: `^\\s*${h.delim}`,
72+
endCaptures: { 0: { name: "punctuation.definition.string.end.elixir" } },
73+
name: h.name,
74+
});
75+
}
76+
for (const d of conf.literal.delimiters) {
77+
const pat = {
78+
begin: `~[A-Z][A-Z0-9]*\\${escapeChar(d.open)}`,
79+
beginCaptures: {
80+
0: { name: "punctuation.definition.string.begin.elixir" },
81+
},
82+
comment: "sigil (without interpolation)",
83+
end: `\\${escapeChar(d.close)}[a-z]*`,
84+
endCaptures: { 0: { name: "punctuation.definition.string.end.elixir" } },
85+
name: "string.quoted.double.literal.elixir",
86+
};
87+
if (d.nest) pat.patterns = [{ include: d.nest }];
88+
patterns.push(pat);
89+
}
90+
return { patterns };
91+
}
92+
93+
const base = loadYaml("../syntaxes/yaml/elixir.yml");
94+
const sigils = loadYaml("../syntaxes/yaml/sigils.yml");
95+
const modules = loadYaml("../syntaxes/yaml/modules.yml");
96+
97+
base.patterns = modules.concat(base.patterns);
98+
base.repository.sigils = buildSigils(sigils);
99+
100+
fs.writeFileSync(
101+
path.join(__dirname, "../syntaxes/elixir.json"),
102+
JSON.stringify(base, null, 2),
103+
);

0 commit comments

Comments
 (0)