tree-sitter/cli/src/generate/rules.rs

239 lines
5.5 KiB
Rust
Raw Normal View History

2019-08-13 10:08:58 -07:00
use std::collections::HashMap;
2018-12-05 12:50:12 -08:00
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
2018-12-06 22:11:52 -08:00
pub(crate) enum SymbolType {
2018-12-05 12:50:12 -08:00
External,
End,
2018-12-05 12:50:12 -08:00
Terminal,
NonTerminal,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
2018-12-06 22:11:52 -08:00
pub(crate) enum Associativity {
2018-12-05 12:50:12 -08:00
Left,
2018-12-18 16:05:36 -08:00
Right,
2018-12-05 12:50:12 -08:00
}
#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
2018-12-06 22:11:52 -08:00
pub(crate) struct Alias {
pub value: String,
pub is_named: bool,
2018-12-05 12:50:12 -08:00
}
2018-12-06 22:11:52 -08:00
pub(crate) type AliasMap = HashMap<Symbol, Alias>;
2018-12-05 12:50:12 -08:00
#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)]
2018-12-06 22:11:52 -08:00
pub(crate) struct MetadataParams {
pub precedence: Option<i32>,
pub dynamic_precedence: i32,
pub associativity: Option<Associativity>,
pub is_token: bool,
pub is_string: bool,
pub is_active: bool,
pub is_main_token: bool,
pub alias: Option<Alias>,
2019-02-07 12:29:20 -08:00
pub field_name: Option<String>,
2018-12-05 12:50:12 -08:00
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
2018-12-06 22:11:52 -08:00
pub(crate) struct Symbol {
pub kind: SymbolType,
pub index: usize,
2018-12-05 12:50:12 -08:00
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
2018-12-06 22:11:52 -08:00
pub(crate) enum Rule {
2018-12-05 12:50:12 -08:00
Blank,
String(String),
Pattern(String),
NamedSymbol(String),
Symbol(Symbol),
2018-12-08 23:35:48 -08:00
Choice(Vec<Rule>),
2018-12-05 12:50:12 -08:00
Metadata {
params: MetadataParams,
2018-12-08 23:35:48 -08:00
rule: Box<Rule>,
2018-12-05 12:50:12 -08:00
},
2018-12-08 23:35:48 -08:00
Repeat(Box<Rule>),
Seq(Vec<Rule>),
2018-12-05 12:50:12 -08:00
}
impl Rule {
2019-02-07 12:29:20 -08:00
pub fn field(name: String, content: Rule) -> Self {
add_metadata(content, move |params| {
2019-02-07 12:29:20 -08:00
params.field_name = Some(name);
})
}
pub fn alias(content: Rule, value: String, is_named: bool) -> Self {
add_metadata(content, move |params| {
2019-01-17 17:16:04 -08:00
params.alias = Some(Alias { is_named, value });
})
}
2018-12-05 12:50:12 -08:00
pub fn token(content: Rule) -> Self {
add_metadata(content, |params| {
params.is_token = true;
})
}
pub fn immediate_token(content: Rule) -> Self {
add_metadata(content, |params| {
params.is_token = true;
params.is_main_token = true;
})
}
pub fn prec(value: i32, content: Rule) -> Self {
add_metadata(content, |params| {
params.precedence = Some(value);
})
}
pub fn prec_left(value: i32, content: Rule) -> Self {
add_metadata(content, |params| {
params.associativity = Some(Associativity::Left);
params.precedence = Some(value);
})
}
pub fn prec_right(value: i32, content: Rule) -> Self {
add_metadata(content, |params| {
params.associativity = Some(Associativity::Right);
params.precedence = Some(value);
})
}
2018-12-11 12:14:34 -08:00
pub fn prec_dynamic(value: i32, content: Rule) -> Self {
add_metadata(content, |params| {
params.dynamic_precedence = value;
})
}
2018-12-05 12:50:12 -08:00
pub fn repeat(rule: Rule) -> Self {
2018-12-08 23:35:48 -08:00
Rule::Repeat(Box::new(rule))
2018-12-05 12:50:12 -08:00
}
pub fn choice(rules: Vec<Rule>) -> Self {
let mut elements = Vec::with_capacity(rules.len());
for rule in rules {
choice_helper(&mut elements, rule);
}
2018-12-08 23:35:48 -08:00
Rule::Choice(elements)
2018-12-05 12:50:12 -08:00
}
pub fn seq(rules: Vec<Rule>) -> Self {
2018-12-08 23:35:48 -08:00
Rule::Seq(rules)
2018-12-05 12:50:12 -08:00
}
2019-01-02 12:34:40 -08:00
}
2018-12-05 12:50:12 -08:00
2019-01-02 12:34:40 -08:00
#[cfg(test)]
impl Rule {
2018-12-05 12:50:12 -08:00
pub fn terminal(index: usize) -> Self {
Rule::Symbol(Symbol::terminal(index))
}
pub fn non_terminal(index: usize) -> Self {
Rule::Symbol(Symbol::non_terminal(index))
}
pub fn external(index: usize) -> Self {
Rule::Symbol(Symbol::external(index))
}
pub fn named(name: &'static str) -> Self {
Rule::NamedSymbol(name.to_string())
}
pub fn string(value: &'static str) -> Self {
Rule::String(value.to_string())
}
2018-12-06 22:11:52 -08:00
pub fn pattern(value: &'static str) -> Self {
Rule::Pattern(value.to_string())
}
2018-12-05 12:50:12 -08:00
}
impl Symbol {
2018-12-18 16:05:36 -08:00
pub fn is_terminal(&self) -> bool {
self.kind == SymbolType::Terminal
}
2018-12-06 22:11:52 -08:00
pub fn is_non_terminal(&self) -> bool {
2018-12-18 16:05:36 -08:00
self.kind == SymbolType::NonTerminal
2018-12-06 22:11:52 -08:00
}
pub fn is_external(&self) -> bool {
2018-12-18 16:05:36 -08:00
self.kind == SymbolType::External
2018-12-06 22:11:52 -08:00
}
2019-01-03 10:31:14 -08:00
pub fn is_eof(&self) -> bool {
self.kind == SymbolType::End
}
2018-12-05 12:50:12 -08:00
pub fn non_terminal(index: usize) -> Self {
2018-12-18 16:05:36 -08:00
Symbol {
kind: SymbolType::NonTerminal,
index,
}
2018-12-05 12:50:12 -08:00
}
pub fn terminal(index: usize) -> Self {
2018-12-18 16:05:36 -08:00
Symbol {
kind: SymbolType::Terminal,
index,
}
2018-12-05 12:50:12 -08:00
}
pub fn external(index: usize) -> Self {
2018-12-18 16:05:36 -08:00
Symbol {
kind: SymbolType::External,
index,
}
2018-12-05 12:50:12 -08:00
}
pub fn end() -> Self {
Symbol {
kind: SymbolType::End,
index: 0,
}
}
2018-12-05 12:50:12 -08:00
}
impl From<Symbol> for Rule {
fn from(symbol: Symbol) -> Self {
Rule::Symbol(symbol)
}
}
fn add_metadata<T: FnOnce(&mut MetadataParams)>(input: Rule, f: T) -> Rule {
2018-12-05 12:50:12 -08:00
match input {
Rule::Metadata { rule, mut params } => {
f(&mut params);
Rule::Metadata { rule, params }
2018-12-18 16:05:36 -08:00
}
2018-12-05 12:50:12 -08:00
_ => {
let mut params = MetadataParams::default();
f(&mut params);
2018-12-18 16:05:36 -08:00
Rule::Metadata {
rule: Box::new(input),
params,
}
2018-12-05 12:50:12 -08:00
}
}
}
fn choice_helper(result: &mut Vec<Rule>, rule: Rule) {
match rule {
2018-12-08 23:35:48 -08:00
Rule::Choice(elements) => {
2018-12-05 12:50:12 -08:00
for element in elements {
choice_helper(result, element);
}
2018-12-18 16:05:36 -08:00
}
2018-12-05 12:50:12 -08:00
_ => {
if !result.contains(&rule) {
result.push(rule);
}
}
}
}