feat(grammar): add "inherits" field if available

This commit is contained in:
ObserverOfTime 2024-04-14 10:40:59 +03:00 committed by Amaan Qureshi
parent 159c34fdff
commit 83b6010461
3 changed files with 26 additions and 9 deletions

View file

@ -223,6 +223,8 @@ function RuleBuilder(ruleMap) {
}
function grammar(baseGrammar, options) {
let inherits = null;
if (!options) {
options = baseGrammar;
baseGrammar = {
@ -237,6 +239,7 @@ function grammar(baseGrammar, options) {
};
} else {
baseGrammar = baseGrammar.grammar;
inherits = baseGrammar.name;
}
let externals = baseGrammar.externals;
@ -279,6 +282,14 @@ function grammar(baseGrammar, options) {
throw new Error("Grammar's 'name' property must not start with a digit and cannot contain non-word characters.");
}
if (inherits && typeof inherits !== "string") {
throw new Error("Base grammar's 'name' property must be a string.");
}
if (inherits && !/^[a-zA-Z_]\w*$/.test(name)) {
throw new Error("Base grammar's 'name' property must not start with a digit and cannot contain non-word characters.");
}
const rules = Object.assign({}, baseGrammar.rules);
if (options.rules) {
if (typeof options.rules !== "object") {
@ -407,7 +418,7 @@ function grammar(baseGrammar, options) {
throw new Error("Grammar must have at least one rule.");
}
return { grammar: { name, word, rules, extras, conflicts, precedences, externals, inline, supertypes } };
return { grammar: { name, inherits, word, rules, extras, conflicts, precedences, externals, inline, supertypes } };
}
function checkArguments(args, ruleCount, caller, callerName, suffix = '', argType = 'rule') {

View file

@ -14,6 +14,12 @@
"pattern": "^[a-zA-Z_]\\w*"
},
"inherits": {
"description": "the name of the parent grammar",
"type": "string",
"pattern": "^[a-zA-Z_]\\w*"
},
"rules": {
"type": "object",
"patternProperties": {

View file

@ -199,7 +199,7 @@ fn load_js_grammar_file(grammar_path: &Path, js_runtime: Option<&str>) -> Result
let mut node_stdin = node_process
.stdin
.take()
.with_context(|| "Failed to open stdin for node")?;
.with_context(|| format!("Failed to open stdin for {js_runtime}"))?;
let cli_version = Version::parse(env!("CARGO_PKG_VERSION"))
.with_context(|| "Could not parse this package's version as semver.")?;
write!(
@ -209,20 +209,20 @@ fn load_js_grammar_file(grammar_path: &Path, js_runtime: Option<&str>) -> Result
global.TREE_SITTER_CLI_VERSION_PATCH = {};",
cli_version.major, cli_version.minor, cli_version.patch,
)
.with_context(|| "Failed to write tree-sitter version to node's stdin")?;
.with_context(|| format!("Failed to write tree-sitter version to {js_runtime}'s stdin"))?;
let javascript_code = include_bytes!("./dsl.js");
node_stdin
.write(javascript_code)
.with_context(|| "Failed to write grammar dsl to node's stdin")?;
.with_context(|| format!("Failed to write grammar dsl to {js_runtime}'s stdin"))?;
drop(node_stdin);
let output = node_process
.wait_with_output()
.with_context(|| "Failed to read output from node")?;
.with_context(|| format!("Failed to read output from {js_runtime}"))?;
match output.status.code() {
None => panic!("Node process was killed"),
None => panic!("{js_runtime} process was killed"),
Some(0) => {
let stdout =
String::from_utf8(output.stdout).with_context(|| "Got invalid UTF8 from node")?;
let stdout = String::from_utf8(output.stdout)
.with_context(|| format!("Got invalid UTF8 from {js_runtime}"))?;
let mut grammar_json = &stdout[..];
@ -244,7 +244,7 @@ fn load_js_grammar_file(grammar_path: &Path, js_runtime: Option<&str>) -> Result
.with_context(|| "Failed to serialize grammar JSON")?
+ "\n")
}
Some(code) => Err(anyhow!("Node process exited with status {code}")),
Some(code) => Err(anyhow!("{js_runtime} process exited with status {code}")),
}
}