use std::collections::BTreeMap;
use std::fmt;
use strum_macros::{Display, IntoStaticStr};
use crate::ast;
#[derive(Clone, Debug, PartialEq)]
pub struct RuleDef {
pub generic_parms: Vec<String>,
pub node: Node,
}
pub type RulesByName = BTreeMap<String, RuleDef>;
pub type RulesWithStrings = BTreeMap<String, (RuleDef, String)>;
#[derive(Debug, Copy, Clone, PartialEq, Eq, Display)]
#[allow(missing_docs)]
pub enum PreludeType {
Any,
Nil,
Bool,
Int,
Uint,
Nint,
Float,
Tstr,
Bstr,
}
#[derive(Debug, Clone, PartialEq)]
#[allow(missing_docs)]
pub enum Literal {
Bool(bool),
Int(i128),
Float(f64),
Text(String),
Bytes(Vec<u8>),
}
impl fmt::Display for Literal {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Literal::Bool(b) => write!(f, "{}", b),
Literal::Int(i) => write!(f, "{}", i),
Literal::Float(fl) => write!(f, "{}", fl),
Literal::Text(s) => write!(f, "\"{}\"", s),
Literal::Bytes(_) => write!(f, "LiteralBytes"),
}
}
}
pub fn literal_bool(b: bool) -> Node {
Node::Literal(Literal::Bool(b))
}
pub fn literal_int<T: Into<i128>>(i: T) -> Node {
Node::Literal(Literal::Int(i.into()))
}
pub fn literal_float<T: Into<f64>>(f: T) -> Node {
Node::Literal(Literal::Float(f.into()))
}
pub fn literal_text<T: Into<String>>(s: T) -> Node {
Node::Literal(Literal::Text(s.into()))
}
pub fn literal_bytes<T: Into<Vec<u8>>>(b: T) -> Node {
Node::Literal(Literal::Bytes(b.into()))
}
#[derive(Debug, Clone, PartialEq)]
#[allow(missing_docs)]
pub struct Rule {
pub name: String,
pub generic_args: Vec<Node>,
}
impl Rule {
#[doc(hidden)] pub fn new(name: &str, generic_args: Vec<Node>) -> Rule {
Rule {
name: name.to_string(),
generic_args,
}
}
#[doc(hidden)] pub fn new_name(name: &str) -> Rule {
Rule {
name: name.to_string(),
generic_args: Vec::new(),
}
}
}
#[derive(Debug, Clone, PartialEq)]
#[allow(missing_docs)]
pub struct Choice {
pub options: Vec<Node>,
}
#[derive(Clone, PartialEq)]
#[allow(missing_docs)]
pub struct KeyValue {
pub key: Box<Node>,
pub value: Box<Node>,
pub cut: IsCut,
}
pub(crate) type IsCut = bool;
impl KeyValue {
#[doc(hidden)] pub fn new(key: Node, value: Node, cut: IsCut) -> KeyValue {
KeyValue {
key: Box::new(key),
value: Box::new(value),
cut,
}
}
}
impl fmt::Display for KeyValue {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}: {}", self.key, self.value)
}
}
impl fmt::Debug for KeyValue {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut formatter = f.debug_tuple("KeyValue");
formatter.field(&self.key).field(&self.value).finish()
}
}
pub type OccurLimit = ast::Occur;
#[derive(Debug, Clone, PartialEq)]
#[allow(missing_docs)]
pub struct Occur {
pub limit: OccurLimit,
pub node: Box<Node>,
}
impl Occur {
pub fn new(limit: OccurLimit, node: Node) -> Occur {
Occur {
limit,
node: Box::new(node),
}
}
pub fn symbol(&self) -> String {
match self.limit {
OccurLimit::Optional => "?".into(),
OccurLimit::ZeroOrMore => "*".into(),
OccurLimit::OneOrMore => "+".into(),
OccurLimit::Numbered(n, m) => match (n, m) {
(0, std::usize::MAX) => format!("{}*", n),
(_, _) => format!("{}*{}", n, m),
},
}
}
pub fn limits(&self) -> (usize, usize) {
match self.limit {
OccurLimit::Optional => (0, 1),
OccurLimit::ZeroOrMore => (0, usize::MAX),
OccurLimit::OneOrMore => (1, usize::MAX),
OccurLimit::Numbered(n, m) => (n, m),
}
}
}
impl fmt::Display for Occur {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{} {}", self.symbol(), self.node)
}
}
#[derive(Debug, Clone, PartialEq)]
#[allow(missing_docs)]
pub struct Map {
pub members: Vec<Node>,
}
#[derive(Debug, Clone, PartialEq)]
#[allow(missing_docs)]
pub struct Group {
pub members: Vec<Node>,
}
#[derive(Debug, Clone, PartialEq)]
#[allow(missing_docs)]
pub struct Array {
pub members: Vec<Node>,
}
#[derive(Debug, Clone, PartialEq)]
#[allow(missing_docs)]
pub struct Range {
pub start: Box<Node>,
pub end: Box<Node>,
pub inclusive: bool,
}
impl fmt::Display for Range {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let op = if self.inclusive { ".." } else { "..." };
write!(f, "{}{}{}", self.start, op, self.end)
}
}
#[non_exhaustive]
#[derive(Debug, Clone, PartialEq)]
pub enum Control {
Size(CtlOpSize),
Lt(CtlOpLt),
Le(CtlOpLe),
Gt(CtlOpGt),
Ge(CtlOpGe),
Regexp(CtlOpRegexp),
Cbor(CtlOpCbor),
}
#[derive(Debug, Clone, PartialEq)]
pub struct CtlOpSize {
pub target: Box<Node>,
pub size: Box<Node>,
}
#[derive(Debug, Clone, PartialEq)]
pub struct CtlOpLt {
pub target: Box<Node>,
pub lt: Box<Node>,
}
#[derive(Debug, Clone, PartialEq)]
pub struct CtlOpLe {
pub target: Box<Node>,
pub le: Box<Node>,
}
#[derive(Debug, Clone, PartialEq)]
pub struct CtlOpGt {
pub target: Box<Node>,
pub gt: Box<Node>,
}
#[derive(Debug, Clone, PartialEq)]
pub struct CtlOpGe {
pub target: Box<Node>,
pub ge: Box<Node>,
}
#[derive(Debug, Clone)]
pub struct CtlOpRegexp {
pub(crate) re: regex::Regex,
}
impl PartialEq for CtlOpRegexp {
fn eq(&self, other: &Self) -> bool {
self.re.as_str() == other.re.as_str()
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct CtlOpCbor {
pub(crate) node: Box<Node>,
}
#[derive(Debug, Clone, PartialEq, IntoStaticStr)]
#[allow(missing_docs)]
pub enum Node {
Literal(Literal),
PreludeType(PreludeType),
Rule(Rule),
Choice(Choice),
Map(Map),
Array(Array),
Group(Group),
KeyValue(KeyValue),
Occur(Occur),
Unwrap(Rule),
Range(Range),
Control(Control),
Choiceify(Rule),
ChoiceifyInline(Array),
}
impl fmt::Display for Node {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Node::Literal(l) => write!(f, "{}", l),
Node::PreludeType(p) => write!(f, "{}", p),
Node::KeyValue(kv) => write!(f, "{}", kv),
_ => {
let variant: &str = self.into();
write!(f, "{}", variant)
}
}
}
}