1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160
//! A parser for CDDL, utilized for parsing in accordance with RFC 8610.
#![allow(missing_docs)] // TODO(apskhem): Temporary, to bo removed in a subsequent PR
use derive_more::{Display, From};
pub use pest::Parser;
use pest::{error::Error, iterators::Pairs};
pub mod rfc_8610 {
pub use pest::Parser;
#[derive(pest_derive::Parser)]
#[grammar = "grammar/rfc_8610.pest"]
pub struct RFC8610Parser;
}
pub mod rfc_9165 {
pub use pest::Parser;
#[derive(pest_derive::Parser)]
#[grammar = "grammar/rfc_8610.pest"]
#[grammar = "grammar/rfc_9165.pest"]
pub struct RFC8610Parser;
}
pub mod cddl {
pub use pest::Parser;
#[derive(pest_derive::Parser)]
#[grammar = "grammar/rfc_8610.pest"]
#[grammar = "grammar/rfc_9165.pest"]
#[grammar = "grammar/cddl_modules.pest"]
pub struct RFC8610Parser;
}
pub mod cddl_test {
pub use pest::Parser;
// Parser with DEBUG rules. These rules are only used in tests.
#[derive(pest_derive::Parser)]
#[grammar = "grammar/rfc_8610.pest"]
#[grammar = "grammar/rfc_9165.pest"]
#[grammar = "grammar/cddl_modules.pest"]
#[grammar = "grammar/cddl_test.pest"] // Ideally this would only be used in tests.
pub struct CDDLTestParser;
}
/// Represents different parser extensions for handling CDDL specifications.
pub enum Extension {
/// RFC8610 ONLY limited parser.
RFC8610Parser,
/// RFC8610 and RFC9165 limited parser.
RFC9165Parser,
/// RFC8610, RFC9165, and CDDL modules.
CDDLParser,
}
// CDDL Standard Postlude - read from an external file
pub const POSTLUDE: &str = include_str!("grammar/postlude.cddl");
/// Abstract Syntax Tree (AST) representing parsed CDDL syntax.
// TODO: this is temporary. need to add more pragmatic nodes
#[derive(Debug)]
pub enum AST<'a> {
/// Represents the AST for RFC 8610 CDDL rules.
RFC8610(Pairs<'a, rfc_8610::Rule>),
/// Represents the AST for RFC 9165 CDDL rules.
RFC9165(Pairs<'a, rfc_9165::Rule>),
/// Represents the AST for CDDL Modules rules.
CDDL(Pairs<'a, cddl::Rule>),
}
/// Represents different types of errors related to different types of extension.
#[derive(Display, Debug)]
pub enum CDDLErrorType {
/// An error related to RFC 8610 extension.
RFC8610(Error<rfc_8610::Rule>),
/// An error related to RFC 9165 extension.
RFC9165(Error<rfc_9165::Rule>),
/// An error related to CDDL modules extension.
CDDL(Error<cddl::Rule>),
}
/// Represents an error that may occur during CDDL parsing.
#[derive(thiserror::Error, Debug, From)]
#[error("{0}")]
pub struct CDDLError(CDDLErrorType);
/// Parses and checks semantically a CDDL input string.
///
/// # Arguments
///
/// * `input` - A string containing the CDDL input to be parsed.
///
/// # Returns
///
/// Returns `Ok(())` if parsing is successful, otherwise returns an `Err` containing
/// a boxed `CDDLError` indicating the parsing error.
///
/// # Errors
///
/// This function may return an error in the following cases:
///
/// - If there is an issue with parsing the CDDL input.
///
/// # Examples
///
/// ```rs
/// use cbork_cddl_parser::{parse_cddl, Extension};
/// use std:fs;
///
/// let mut input = fs::read_to_string("path/to/your/file.cddl").unwrap();
/// let result = parse_cddl(&mut input, &Extension::CDDLParser);
/// assert!(result.is_ok());
/// ```
pub fn parse_cddl<'a>(
input: &'a mut String, extension: &Extension,
) -> Result<AST<'a>, Box<CDDLError>> {
input.push_str("\n\n");
input.push_str(POSTLUDE);
let result = match extension {
Extension::RFC8610Parser => {
rfc_8610::RFC8610Parser::parse(rfc_8610::Rule::cddl, input)
.map(AST::RFC8610)
.map_err(CDDLErrorType::RFC8610)
},
Extension::RFC9165Parser => {
rfc_9165::RFC8610Parser::parse(rfc_9165::Rule::cddl, input)
.map(AST::RFC9165)
.map_err(CDDLErrorType::RFC9165)
},
Extension::CDDLParser => {
cddl::RFC8610Parser::parse(cddl::Rule::cddl, input)
.map(AST::CDDL)
.map_err(CDDLErrorType::CDDL)
},
};
result.map_err(|e| Box::new(CDDLError::from(e)))
}
#[cfg(test)]
mod tests {
use crate::*;
#[test]
fn it_works() {
let mut input = String::new();
let result = parse_cddl(&mut input, &Extension::CDDLParser);
match result {
Ok(c) => println!("{c:?}"),
Err(e) => {
println!("{e:?}");
println!("{e}");
},
}
}
}