feat(generate): place file APIs behind a feature flag
This commit is contained in:
parent
e659dddad1
commit
27e5147a5f
3 changed files with 43 additions and 6 deletions
|
|
@ -19,6 +19,10 @@ path = "src/generate.rs"
|
|||
[lints]
|
||||
workspace = true
|
||||
|
||||
[features]
|
||||
default = ["load"]
|
||||
load = ["dep:semver", "dep:url"]
|
||||
|
||||
[dependencies]
|
||||
anyhow.workspace = true
|
||||
heck.workspace = true
|
||||
|
|
@ -28,7 +32,7 @@ log.workspace = true
|
|||
regex.workspace = true
|
||||
regex-syntax.workspace = true
|
||||
rustc-hash.workspace = true
|
||||
semver.workspace = true
|
||||
semver = { workspace = true, optional = true }
|
||||
serde.workspace = true
|
||||
serde_json.workspace = true
|
||||
smallbitvec.workspace = true
|
||||
|
|
@ -38,4 +42,4 @@ topological-sort.workspace = true
|
|||
tree-sitter.workspace = true
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
url.workspace = true
|
||||
url = { workspace = true, optional = true }
|
||||
|
|
|
|||
|
|
@ -1,18 +1,21 @@
|
|||
use std::{collections::HashMap, sync::LazyLock};
|
||||
#[cfg(feature = "load")]
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
env, fs,
|
||||
io::Write,
|
||||
path::{Path, PathBuf},
|
||||
process::{Command, Stdio},
|
||||
sync::LazyLock,
|
||||
};
|
||||
|
||||
use anyhow::Result;
|
||||
use node_types::VariableInfo;
|
||||
use regex::{Regex, RegexBuilder};
|
||||
use rules::{Alias, Symbol};
|
||||
#[cfg(feature = "load")]
|
||||
use semver::Version;
|
||||
use serde::{Deserialize, Serialize};
|
||||
#[cfg(feature = "load")]
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
use thiserror::Error;
|
||||
|
||||
mod build_tables;
|
||||
|
|
@ -45,6 +48,7 @@ static JSON_COMMENT_REGEX: LazyLock<Regex> = LazyLock::new(|| {
|
|||
});
|
||||
|
||||
struct JSONStageOutput {
|
||||
#[cfg(feature = "load")]
|
||||
node_types_json: String,
|
||||
syntax_grammar: SyntaxGrammar,
|
||||
lexical_grammar: LexicalGrammar,
|
||||
|
|
@ -55,6 +59,7 @@ struct JSONStageOutput {
|
|||
|
||||
struct GeneratedParser {
|
||||
c_code: String,
|
||||
#[cfg(feature = "load")]
|
||||
node_types_json: String,
|
||||
}
|
||||
|
||||
|
|
@ -69,6 +74,7 @@ pub enum GenerateError {
|
|||
GrammarPath(String),
|
||||
#[error("{0}")]
|
||||
IO(String),
|
||||
#[cfg(feature = "load")]
|
||||
#[error(transparent)]
|
||||
LoadGrammarFile(#[from] LoadGrammarError),
|
||||
#[error(transparent)]
|
||||
|
|
@ -79,6 +85,7 @@ pub enum GenerateError {
|
|||
VariableInfo(#[from] VariableInfoError),
|
||||
#[error(transparent)]
|
||||
BuildTables(#[from] ParseTableBuilderError),
|
||||
#[cfg(feature = "load")]
|
||||
#[error(transparent)]
|
||||
ParseVersion(#[from] ParseVersionError),
|
||||
#[error(transparent)]
|
||||
|
|
@ -91,8 +98,10 @@ impl From<std::io::Error> for GenerateError {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "load")]
|
||||
pub type LoadGrammarFileResult<T> = Result<T, LoadGrammarError>;
|
||||
|
||||
#[cfg(feature = "load")]
|
||||
#[derive(Debug, Error, Serialize)]
|
||||
pub enum LoadGrammarError {
|
||||
#[error("Path to a grammar file with `.js` or `.json` extension is required")]
|
||||
|
|
@ -105,12 +114,14 @@ pub enum LoadGrammarError {
|
|||
FileExtension(PathBuf),
|
||||
}
|
||||
|
||||
#[cfg(feature = "load")]
|
||||
impl From<std::io::Error> for LoadGrammarError {
|
||||
fn from(value: std::io::Error) -> Self {
|
||||
Self::IO(value.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "load")]
|
||||
#[derive(Debug, Error, Serialize)]
|
||||
pub enum ParseVersionError {
|
||||
#[error("{0}")]
|
||||
|
|
@ -121,8 +132,10 @@ pub enum ParseVersionError {
|
|||
IO(String),
|
||||
}
|
||||
|
||||
#[cfg(feature = "load")]
|
||||
pub type JSResult<T> = Result<T, JSError>;
|
||||
|
||||
#[cfg(feature = "load")]
|
||||
#[derive(Debug, Error, Serialize)]
|
||||
pub enum JSError {
|
||||
#[error("Failed to run `{runtime}` -- {error}")]
|
||||
|
|
@ -139,24 +152,28 @@ pub enum JSError {
|
|||
Serialzation(String),
|
||||
}
|
||||
|
||||
#[cfg(feature = "load")]
|
||||
impl From<std::io::Error> for JSError {
|
||||
fn from(value: std::io::Error) -> Self {
|
||||
Self::IO(value.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "load")]
|
||||
impl From<serde_json::Error> for JSError {
|
||||
fn from(value: serde_json::Error) -> Self {
|
||||
Self::Serialzation(value.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "load")]
|
||||
impl From<semver::Error> for JSError {
|
||||
fn from(value: semver::Error) -> Self {
|
||||
Self::Semver(value.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "load")]
|
||||
pub fn generate_parser_in_directory<T, U, V>(
|
||||
repo_path: T,
|
||||
out_path: Option<U>,
|
||||
|
|
@ -268,6 +285,8 @@ fn generate_node_types_from_grammar(
|
|||
prepare_grammar(input_grammar)?;
|
||||
let variable_info =
|
||||
node_types::get_variable_info(&syntax_grammar, &lexical_grammar, &simple_aliases)?;
|
||||
|
||||
#[cfg(feature = "load")]
|
||||
let node_types_json = node_types::generate_node_types_json(
|
||||
&syntax_grammar,
|
||||
&lexical_grammar,
|
||||
|
|
@ -275,6 +294,7 @@ fn generate_node_types_from_grammar(
|
|||
&variable_info,
|
||||
)?;
|
||||
Ok(JSONStageOutput {
|
||||
#[cfg(feature = "load")]
|
||||
node_types_json: serde_json::to_string_pretty(&node_types_json).unwrap(),
|
||||
syntax_grammar,
|
||||
lexical_grammar,
|
||||
|
|
@ -296,6 +316,7 @@ fn generate_parser_for_grammar_with_opts(
|
|||
inlines,
|
||||
simple_aliases,
|
||||
variable_info,
|
||||
#[cfg(feature = "load")]
|
||||
node_types_json,
|
||||
} = generate_node_types_from_grammar(input_grammar)?;
|
||||
let supertype_symbol_map =
|
||||
|
|
@ -320,6 +341,7 @@ fn generate_parser_for_grammar_with_opts(
|
|||
);
|
||||
Ok(GeneratedParser {
|
||||
c_code,
|
||||
#[cfg(feature = "load")]
|
||||
node_types_json,
|
||||
})
|
||||
}
|
||||
|
|
@ -329,6 +351,7 @@ fn generate_parser_for_grammar_with_opts(
|
|||
/// If the file is not found in the current directory or any of its parent directories, this will
|
||||
/// return `None` to maintain backwards compatibility. If the file is found but the version cannot
|
||||
/// be parsed as semver, this will return an error.
|
||||
#[cfg(feature = "load")]
|
||||
fn read_grammar_version(repo_path: &Path) -> Result<Option<Version>, ParseVersionError> {
|
||||
#[derive(Deserialize)]
|
||||
struct TreeSitterJson {
|
||||
|
|
@ -373,6 +396,7 @@ fn read_grammar_version(repo_path: &Path) -> Result<Option<Version>, ParseVersio
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "load")]
|
||||
pub fn load_grammar_file(
|
||||
grammar_path: &Path,
|
||||
js_runtime: Option<&str>,
|
||||
|
|
@ -387,6 +411,7 @@ pub fn load_grammar_file(
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "load")]
|
||||
fn load_js_grammar_file(grammar_path: &Path, js_runtime: Option<&str>) -> JSResult<String> {
|
||||
let grammar_path = fs::canonicalize(grammar_path)?;
|
||||
|
||||
|
|
@ -481,6 +506,7 @@ fn load_js_grammar_file(grammar_path: &Path, js_runtime: Option<&str>) -> JSResu
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "load")]
|
||||
pub fn write_file(path: &Path, body: impl AsRef<[u8]>) -> GenerateResult<()> {
|
||||
fs::write(path, body)
|
||||
.map_err(|e| GenerateError::IO(format!("Failed to write {:?} -- {e}", path.file_name())))
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ pub struct VariableInfo {
|
|||
}
|
||||
|
||||
#[derive(Debug, Serialize, PartialEq, Eq, Default, PartialOrd, Ord)]
|
||||
#[cfg(feature = "load")]
|
||||
pub struct NodeInfoJSON {
|
||||
#[serde(rename = "type")]
|
||||
kind: String,
|
||||
|
|
@ -47,6 +48,7 @@ pub struct NodeInfoJSON {
|
|||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
#[cfg(feature = "load")]
|
||||
pub struct NodeTypeJSON {
|
||||
#[serde(rename = "type")]
|
||||
kind: String,
|
||||
|
|
@ -54,6 +56,7 @@ pub struct NodeTypeJSON {
|
|||
}
|
||||
|
||||
#[derive(Debug, Serialize, PartialEq, Eq, PartialOrd, Ord)]
|
||||
#[cfg(feature = "load")]
|
||||
pub struct FieldInfoJSON {
|
||||
multiple: bool,
|
||||
required: bool,
|
||||
|
|
@ -67,6 +70,7 @@ pub struct ChildQuantity {
|
|||
multiple: bool,
|
||||
}
|
||||
|
||||
#[cfg(feature = "load")]
|
||||
impl Default for FieldInfoJSON {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
|
|
@ -441,6 +445,7 @@ pub fn get_supertype_symbol_map(
|
|||
supertype_symbol_map
|
||||
}
|
||||
|
||||
#[cfg(feature = "load")]
|
||||
pub type SuperTypeCycleResult<T> = Result<T, SuperTypeCycleError>;
|
||||
|
||||
#[derive(Debug, Error, Serialize)]
|
||||
|
|
@ -462,6 +467,7 @@ impl std::fmt::Display for SuperTypeCycleError {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "load")]
|
||||
pub fn generate_node_types_json(
|
||||
syntax_grammar: &SyntaxGrammar,
|
||||
lexical_grammar: &LexicalGrammar,
|
||||
|
|
@ -783,6 +789,7 @@ pub fn generate_node_types_json(
|
|||
Ok(result)
|
||||
}
|
||||
|
||||
#[cfg(feature = "load")]
|
||||
fn process_supertypes(info: &mut FieldInfoJSON, subtype_map: &[(NodeTypeJSON, Vec<NodeTypeJSON>)]) {
|
||||
for (supertype, subtypes) in subtype_map {
|
||||
if info.types.contains(supertype) {
|
||||
|
|
@ -829,7 +836,7 @@ where
|
|||
})
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[cfg(all(test, feature = "load"))]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue