From 83b6010461a0696adb7718f0355681706c71f38f Mon Sep 17 00:00:00 2001 From: ObserverOfTime Date: Sun, 14 Apr 2024 10:40:59 +0300 Subject: [PATCH] feat(grammar): add "inherits" field if available --- cli/src/generate/dsl.js | 13 ++++++++++++- cli/src/generate/grammar-schema.json | 6 ++++++ cli/src/generate/mod.rs | 16 ++++++++-------- 3 files changed, 26 insertions(+), 9 deletions(-) diff --git a/cli/src/generate/dsl.js b/cli/src/generate/dsl.js index 7c376c80..2deafd65 100644 --- a/cli/src/generate/dsl.js +++ b/cli/src/generate/dsl.js @@ -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') { diff --git a/cli/src/generate/grammar-schema.json b/cli/src/generate/grammar-schema.json index 59aa209c..1ed83959 100644 --- a/cli/src/generate/grammar-schema.json +++ b/cli/src/generate/grammar-schema.json @@ -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": { diff --git a/cli/src/generate/mod.rs b/cli/src/generate/mod.rs index e9f2bfee..bf9c28dc 100644 --- a/cli/src/generate/mod.rs +++ b/cli/src/generate/mod.rs @@ -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}")), } }