use facet::Facet;
use indexmap::IndexMap;
#[cfg(feature = "json-import")]
use crate::diagnostic::{ImportError, JsonDocumentKind};
#[cfg(feature = "json-import")]
use crate::source::{PackageRoot, SourceFile};
type OrderedMap<V> = IndexMap<String, V, std::hash::RandomState>;
#[derive(Debug, Clone, Facet, PartialEq, Eq)]
pub struct RawGrammarFile {
pub raw: String,
pub grammar: RawGrammarJson,
}
impl RawGrammarFile {
#[cfg(feature = "json-import")]
pub fn from_source_file(
root: &PackageRoot,
source_file: SourceFile<String>,
) -> Result<SourceFile<Self>, ImportError> {
let path = root.join(&source_file.path);
let source_id = source_file.id;
let package_path = source_file.path.clone();
let grammar =
facet_json::from_str(&source_file.body).map_err(|source| ImportError::Json {
package_root: Some(root.as_path().to_owned()),
path: Some(path),
source_id: Some(source_id),
package_path: Some(package_path),
document: JsonDocumentKind::Grammar,
phase: "decode raw grammar JSON",
source,
})?;
Ok(source_file.map(|raw| Self { raw, grammar }))
}
}
#[derive(Debug, Clone, Facet, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct LanguageName(String);
impl LanguageName {
pub fn new(name: impl Into<String>) -> Self {
Self(name.into())
}
pub fn as_str(&self) -> &str {
&self.0
}
}
#[derive(Debug, Clone, Facet, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct RuleName(String);
impl RuleName {
pub fn new(name: impl Into<String>) -> Self {
Self(name.into())
}
pub fn as_str(&self) -> &str {
&self.0
}
}
#[derive(Debug, Clone, Default, Facet, PartialEq, Eq)]
#[facet(transparent)]
pub struct RuleTable(OrderedMap<RawRuleJson>);
impl RuleTable {
pub fn len(&self) -> usize {
self.0.len()
}
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
pub fn start_rule(&self) -> Option<(RuleName, &RawRuleJson)> {
self.0
.first()
.map(|(name, rule)| (RuleName::new(name.clone()), rule))
}
pub fn get(&self, name: &str) -> Option<&RawRuleJson> {
self.0.get(name)
}
pub fn get_index(&self, index: usize) -> Option<(RuleName, &RawRuleJson)> {
self.0
.get_index(index)
.map(|(name, rule)| (RuleName::new(name.clone()), rule))
}
pub fn iter(&self) -> impl Iterator<Item = (RuleName, &RawRuleJson)> {
self.0
.iter()
.map(|(name, rule)| (RuleName::new(name.clone()), rule))
}
}
#[derive(Debug, Clone, Default, Facet, PartialEq, Eq)]
#[facet(transparent)]
pub struct ReservedSetTable(OrderedMap<Vec<RawRuleJson>>);
impl ReservedSetTable {
pub fn len(&self) -> usize {
self.0.len()
}
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
pub fn get_index(&self, index: usize) -> Option<(&str, &[RawRuleJson])> {
self.0
.get_index(index)
.map(|(name, rules)| (name.as_str(), rules.as_slice()))
}
pub fn iter(&self) -> impl Iterator<Item = (&str, &[RawRuleJson])> {
self.0
.iter()
.map(|(name, rules)| (name.as_str(), rules.as_slice()))
}
}
#[derive(Debug, Clone, Facet, PartialEq, Eq)]
pub struct RawGrammarJson {
#[facet(rename = "$schema")]
pub schema: Option<String>,
pub inherits: Option<String>,
pub name: String,
pub rules: RuleTable,
#[facet(default)]
pub extras: Vec<RawRuleJson>,
#[facet(default)]
pub precedences: Vec<Vec<PrecedenceEntryJson>>,
#[facet(default)]
pub conflicts: Vec<Vec<String>>,
#[facet(default)]
pub externals: Vec<RawRuleJson>,
#[facet(default)]
pub inline: Vec<String>,
#[facet(default)]
pub supertypes: Vec<String>,
pub word: Option<String>,
#[facet(default)]
pub reserved: ReservedSetTable,
}
impl RawGrammarJson {
#[cfg(feature = "json-import")]
pub fn from_tree_sitter_json_str(input: &str) -> Result<Self, ImportError> {
facet_json::from_str(input).map_err(|source| ImportError::Json {
package_root: None,
path: None,
source_id: None,
package_path: None,
document: JsonDocumentKind::Grammar,
phase: "decode raw grammar JSON",
source,
})
}
pub fn start_rule(&self) -> Option<(RuleName, &RawRuleJson)> {
self.rules.start_rule()
}
pub fn rule(&self, name: &str) -> Option<&RawRuleJson> {
self.rules.get(name)
}
pub fn language_name(&self) -> LanguageName {
LanguageName::new(self.name.clone())
}
}
#[derive(Debug, Clone, Facet, PartialEq, Eq)]
#[facet(untagged)]
#[repr(u8)]
pub enum PrecedenceEntryJson {
Name(String),
Symbol(PrecedenceSymbolJson),
}
#[derive(Debug, Clone, Facet, PartialEq, Eq)]
pub struct PrecedenceSymbolJson {
#[facet(rename = "type")]
pub kind: String,
pub name: String,
}
#[derive(Debug, Clone, Facet, PartialEq, Eq)]
#[facet(tag = "type", rename_all = "SCREAMING_SNAKE_CASE")]
#[repr(u8)]
pub enum RawRuleJson {
Alias {
content: Box<RawRuleJson>,
named: bool,
value: String,
},
Blank,
String {
value: String,
},
Pattern {
value: String,
flags: Option<String>,
},
Symbol {
name: String,
},
Choice {
members: Vec<RawRuleJson>,
},
Field {
name: String,
content: Box<RawRuleJson>,
},
Seq {
members: Vec<RawRuleJson>,
},
Repeat {
content: Box<RawRuleJson>,
},
Repeat1 {
content: Box<RawRuleJson>,
},
PrecDynamic {
value: i32,
content: Box<RawRuleJson>,
},
PrecLeft {
value: PrecedenceValue,
content: Box<RawRuleJson>,
},
PrecRight {
value: PrecedenceValue,
content: Box<RawRuleJson>,
},
Prec {
value: PrecedenceValue,
content: Box<RawRuleJson>,
},
Token {
content: Box<RawRuleJson>,
},
ImmediateToken {
content: Box<RawRuleJson>,
},
Reserved {
context_name: String,
content: Box<RawRuleJson>,
},
}
#[derive(Debug, Clone, Facet, PartialEq, Eq)]
#[facet(untagged)]
#[repr(u8)]
pub enum PrecedenceValue {
Integer(i32),
Name(String),
}