use crate::idl::types::{
AbstractString, AbstractWString, BasicType, BasicTypeKind, BoundedSequence, BoundedString,
BoundedWString, IdlType, NamedType, NamespacedType, UnboundedSequence, UnboundedString,
UnboundedWString,
};
use crate::idl::values::IdlValue;
use pest::{Parser, iterators::Pair};
#[derive(Debug, Clone, PartialEq)]
pub enum IdlDefinition {
Module(IdlModule),
Constant(IdlConstant),
Struct(IdlStruct),
Enum(IdlEnum),
Union(IdlUnion),
Typedef(IdlTypedef),
}
#[derive(Debug, Clone, PartialEq)]
pub struct IdlTypedef {
pub annotations: Vec<IdlAnnotation>,
pub base_type: IdlType,
pub name: String,
pub array_sizes: Vec<u32>,
}
#[derive(Debug, Clone, PartialEq)]
pub struct IdlModule {
pub annotations: Vec<IdlAnnotation>,
pub name: String,
pub definitions: Vec<IdlDefinition>,
}
#[derive(Debug, Clone, PartialEq)]
pub struct IdlConstant {
pub annotations: Vec<IdlAnnotation>,
pub const_type: IdlType,
pub name: String,
pub value: IdlValue,
}
#[derive(Debug, Clone, PartialEq)]
pub struct IdlStruct {
pub annotations: Vec<IdlAnnotation>,
pub name: String,
pub fields: Vec<IdlField>,
}
#[derive(Debug, Clone, PartialEq)]
pub struct IdlEnum {
pub annotations: Vec<IdlAnnotation>,
pub name: String,
pub values: Vec<IdlEnumValue>,
}
#[derive(Debug, Clone, PartialEq)]
pub struct IdlEnumValue {
pub annotations: Vec<IdlAnnotation>,
pub name: String,
}
#[derive(Debug, Clone, PartialEq)]
pub struct IdlUnion {
pub annotations: Vec<IdlAnnotation>,
pub name: String,
pub switch_type: IdlType,
pub cases: Vec<IdlUnionCase>,
}
#[derive(Debug, Clone, PartialEq)]
pub struct IdlUnionCase {
pub labels: Vec<IdlCaseLabel>,
pub element: IdlField,
}
#[derive(Debug, Clone, PartialEq)]
pub enum IdlCaseLabel {
Case(IdlValue),
Default,
}
#[derive(Debug, Clone, PartialEq)]
pub struct IdlField {
pub annotations: Vec<IdlAnnotation>,
pub field_type: IdlType,
pub name: String,
}
#[derive(Debug, Clone, PartialEq)]
pub struct IdlAnnotation {
pub name: String,
pub params: Vec<(String, IdlValue)>,
}
#[derive(Debug, Clone, PartialEq)]
pub struct IdlFile {
pub definitions: Vec<IdlDefinition>,
pub includes: Vec<String>,
}
#[allow(missing_docs)]
mod parser_impl {
use pest_derive::Parser;
#[derive(Parser)]
#[grammar = "idl.pest"]
pub(super) struct IdlParser;
}
use parser_impl::{IdlParser, Rule};
#[derive(Debug, thiserror::Error)]
pub enum ParseError {
#[error("Pest parsing error: {0}")]
Pest(#[from] Box<pest::error::Error<Rule>>),
#[error("Semantic error: {0}")]
Semantic(String),
}
pub type ParseResult<T> = Result<T, ParseError>;
pub fn parse_idl(input: &str) -> ParseResult<IdlFile> {
let pairs =
IdlParser::parse(Rule::specification, input).map_err(|e| ParseError::Pest(Box::new(e)))?;
let mut definitions = Vec::new();
let mut includes = Vec::new();
for pair in pairs {
if pair.as_rule() == Rule::specification {
for definition_pair in pair.into_inner() {
match definition_pair.as_rule() {
Rule::include_directive => {
if let Some(include) = parse_include_directive(definition_pair) {
includes.push(include);
}
}
Rule::definition => {
if let Some(def) = parse_definition(definition_pair)? {
definitions.push(def);
}
}
Rule::EOI => break,
_ => {}
}
}
}
}
Ok(IdlFile {
definitions,
includes,
})
}
fn parse_include_directive(pair: Pair<'_, Rule>) -> Option<String> {
for inner_pair in pair.into_inner() {
match inner_pair.as_rule() {
Rule::string_literal => {
let s = inner_pair.as_str();
return Some(s[1..s.len() - 1].to_string());
}
Rule::angle_bracket_include => {
let s = inner_pair.as_str();
return Some(s[1..s.len() - 1].to_string());
}
_ => {}
}
}
None
}
fn parse_definition(pair: Pair<'_, Rule>) -> ParseResult<Option<IdlDefinition>> {
for inner_pair in pair.into_inner() {
match inner_pair.as_rule() {
Rule::module => return Ok(Some(parse_module(inner_pair)?)),
Rule::const_dcl => return Ok(Some(parse_const_dcl(inner_pair)?)),
Rule::struct_type => return Ok(Some(parse_struct_type(inner_pair)?)),
Rule::enum_type => return Ok(Some(parse_enum_type(inner_pair)?)),
Rule::union_type => return Ok(Some(parse_union_type(inner_pair)?)),
Rule::type_dcl => {
for type_inner in inner_pair.into_inner() {
match type_inner.as_rule() {
Rule::typedef_dcl => return Ok(Some(parse_typedef_dcl(type_inner)?)),
Rule::struct_type => return Ok(Some(parse_struct_type(type_inner)?)),
Rule::enum_type => return Ok(Some(parse_enum_type(type_inner)?)),
Rule::union_type => return Ok(Some(parse_union_type(type_inner)?)),
_ => {}
}
}
}
_ => {}
}
}
Ok(None)
}
fn parse_typedef_dcl(pair: Pair<'_, Rule>) -> ParseResult<IdlDefinition> {
let mut annotations = Vec::new();
let mut base_type = IdlType::Basic(BasicType::from_kind(BasicTypeKind::Int));
let mut name = String::new();
let mut array_sizes = Vec::new();
for inner in pair.into_inner() {
match inner.as_rule() {
Rule::annotation => {
annotations.push(parse_annotation(inner)?);
}
Rule::type_declarator => {
for decl_inner in inner.into_inner() {
match decl_inner.as_rule() {
Rule::type_spec => {
base_type = parse_type_spec(decl_inner)?;
}
Rule::declarators => {
for decl in decl_inner.into_inner() {
if decl.as_rule() == Rule::declarator {
let (parsed_name, sizes) = parse_declarator_with_array(decl)?;
name = parsed_name;
array_sizes = sizes;
break; }
}
}
_ => {}
}
}
}
_ => {}
}
}
Ok(IdlDefinition::Typedef(IdlTypedef {
annotations,
base_type,
name,
array_sizes,
}))
}
fn parse_module(pair: Pair<'_, Rule>) -> ParseResult<IdlDefinition> {
let mut name = String::new();
let mut definitions = Vec::new();
let mut annotations = Vec::new();
for inner in pair.into_inner() {
match inner.as_rule() {
Rule::annotation => {
annotations.push(parse_annotation(inner)?);
}
Rule::identifier => {
name = inner.as_str().to_string();
}
Rule::definition => {
if let Some(def) = parse_definition(inner)? {
definitions.push(def);
}
}
_ => {}
}
}
Ok(IdlDefinition::Module(IdlModule {
annotations,
name,
definitions,
}))
}
fn parse_annotation(pair: Pair<'_, Rule>) -> ParseResult<IdlAnnotation> {
let mut name = String::new();
let mut params = Vec::new();
for inner in pair.into_inner() {
match inner.as_rule() {
Rule::scoped_name => {
name = inner.as_str().trim().to_string();
}
Rule::annotation_appl_params => {
params = parse_annotation_params(inner)?;
}
_ => {}
}
}
Ok(IdlAnnotation { name, params })
}
fn parse_annotation_params(pair: Pair<'_, Rule>) -> ParseResult<Vec<(String, IdlValue)>> {
let mut params = Vec::new();
for inner in pair.into_inner() {
match inner.as_rule() {
Rule::annotation_appl_param => {
let (name, value) = parse_annotation_param(inner)?;
params.push((name, value));
}
Rule::const_expr => {
let value = parse_const_expr(inner)?;
params.push((String::new(), value));
}
_ => {}
}
}
Ok(params)
}
fn parse_annotation_param(pair: Pair<'_, Rule>) -> ParseResult<(String, IdlValue)> {
let mut name = String::new();
let mut value = IdlValue::String(String::new());
for inner in pair.into_inner() {
match inner.as_rule() {
Rule::identifier => {
name = inner.as_str().to_string();
}
Rule::const_expr => {
value = parse_const_expr(inner)?;
}
_ => {}
}
}
Ok((name, value))
}
fn parse_const_dcl(pair: Pair<'_, Rule>) -> ParseResult<IdlDefinition> {
let mut annotations = Vec::new();
let mut const_type = IdlType::Basic(BasicType::from_kind(BasicTypeKind::Int));
let mut name = String::new();
let mut value = IdlValue::Int64(0);
for inner in pair.into_inner() {
match inner.as_rule() {
Rule::annotation => {
annotations.push(parse_annotation(inner)?);
}
Rule::const_type => {
const_type = parse_const_type(inner)?;
}
Rule::identifier => {
name = inner.as_str().to_string();
}
Rule::const_expr => {
value = parse_const_expr(inner)?;
}
_ => {}
}
}
if let IdlType::String(AbstractString::Unbounded(_)) = &const_type
&& let IdlValue::String(s) = &value
{
const_type = IdlType::String(AbstractString::Bounded(BoundedString {
maximum_size: s.len().try_into().unwrap_or_default(),
}));
}
if let IdlType::WString(AbstractWString::Unbounded(_)) = &const_type
&& let IdlValue::String(s) = &value
{
const_type = IdlType::WString(AbstractWString::Bounded(BoundedWString {
maximum_size: s.len().try_into().unwrap_or_default(),
}));
}
Ok(IdlDefinition::Constant(IdlConstant {
annotations,
const_type,
name,
value,
}))
}
fn parse_struct_type(pair: Pair<'_, Rule>) -> ParseResult<IdlDefinition> {
let mut annotations = Vec::new();
let mut name = String::new();
let mut fields = Vec::new();
for inner in pair.into_inner() {
match inner.as_rule() {
Rule::annotation => {
annotations.push(parse_annotation(inner)?);
}
Rule::identifier => {
name = inner.as_str().to_string();
}
Rule::member => {
fields.push(parse_member(inner)?);
}
_ => {}
}
}
Ok(IdlDefinition::Struct(IdlStruct {
annotations,
name,
fields,
}))
}
fn parse_member(pair: Pair<'_, Rule>) -> ParseResult<IdlField> {
let mut annotations = Vec::new();
let mut field_type = IdlType::Basic(BasicType::from_kind(BasicTypeKind::Int));
let mut name = String::new();
let mut array_sizes: Vec<u32> = Vec::new();
for inner in pair.into_inner() {
match inner.as_rule() {
Rule::annotation => {
annotations.push(parse_annotation(inner)?);
}
Rule::type_spec => {
field_type = parse_type_spec(inner)?;
}
Rule::declarator => {
let (parsed_name, sizes) = parse_declarator_with_array(inner)?;
name = parsed_name;
array_sizes = sizes;
}
_ => {}
}
}
for size in array_sizes.into_iter().rev() {
field_type = IdlType::Array(super::types::Array::new(field_type, size));
}
Ok(IdlField {
annotations,
field_type,
name,
})
}
fn parse_enum_type(pair: Pair<'_, Rule>) -> ParseResult<IdlDefinition> {
let mut annotations = Vec::new();
let mut name = String::new();
let mut values = Vec::new();
for inner in pair.into_inner() {
match inner.as_rule() {
Rule::annotation => {
annotations.push(parse_annotation(inner)?);
}
Rule::identifier => {
name = inner.as_str().to_string();
}
Rule::enumerator => {
values.push(parse_enumerator(inner)?);
}
_ => {}
}
}
Ok(IdlDefinition::Enum(IdlEnum {
annotations,
name,
values,
}))
}
fn parse_enumerator(pair: Pair<'_, Rule>) -> ParseResult<IdlEnumValue> {
let mut annotations = Vec::new();
let mut name = String::new();
for inner in pair.into_inner() {
match inner.as_rule() {
Rule::annotation => {
annotations.push(parse_annotation(inner)?);
}
Rule::identifier => {
name = inner.as_str().to_string();
}
_ => {}
}
}
Ok(IdlEnumValue { annotations, name })
}
fn parse_union_type(pair: Pair<'_, Rule>) -> ParseResult<IdlDefinition> {
let mut annotations = Vec::new();
let mut name = String::new();
let mut switch_type = IdlType::Basic(BasicType::from_kind(BasicTypeKind::Int));
let mut cases = Vec::new();
for inner in pair.into_inner() {
match inner.as_rule() {
Rule::annotation => {
annotations.push(parse_annotation(inner)?);
}
Rule::identifier => {
name = inner.as_str().to_string();
}
Rule::switch_type_spec => {
switch_type = parse_switch_type_spec(inner)?;
}
Rule::case => {
cases.push(parse_case(inner)?);
}
_ => {}
}
}
Ok(IdlDefinition::Union(IdlUnion {
annotations,
name,
switch_type,
cases,
}))
}
fn parse_switch_type_spec(pair: Pair<'_, Rule>) -> ParseResult<IdlType> {
for inner in pair.into_inner() {
match inner.as_rule() {
Rule::integer_type => return Ok(parse_integer_type(inner)),
Rule::char_type => {
return Ok(IdlType::Basic(BasicType::from_kind(BasicTypeKind::Char)));
}
Rule::boolean_type => {
return Ok(IdlType::Basic(BasicType::from_kind(BasicTypeKind::Boolean)));
}
Rule::scoped_name => return Ok(parse_scoped_name_as_type(inner.as_str())),
_ => {}
}
}
Err(ParseError::Semantic("Invalid switch type".to_string()))
}
fn parse_case(pair: Pair<'_, Rule>) -> ParseResult<IdlUnionCase> {
let mut labels = Vec::new();
let mut element = IdlField {
annotations: Vec::new(),
field_type: IdlType::Basic(BasicType::from_kind(BasicTypeKind::Int)),
name: String::new(),
};
for inner in pair.into_inner() {
match inner.as_rule() {
Rule::case_label => {
labels.push(parse_case_label(inner)?);
}
Rule::element_spec => {
element = parse_element_spec(inner)?;
}
_ => {}
}
}
Ok(IdlUnionCase { labels, element })
}
fn parse_case_label(pair: Pair<'_, Rule>) -> ParseResult<IdlCaseLabel> {
for inner in pair.into_inner() {
if inner.as_rule() == Rule::const_expr {
let value = parse_const_expr(inner)?;
return Ok(IdlCaseLabel::Case(value));
}
}
Ok(IdlCaseLabel::Default)
}
fn parse_element_spec(pair: Pair<'_, Rule>) -> ParseResult<IdlField> {
let mut annotations = Vec::new();
let mut field_type = IdlType::Basic(BasicType::from_kind(BasicTypeKind::Int));
let mut name = String::new();
for inner in pair.into_inner() {
match inner.as_rule() {
Rule::annotation => {
annotations.push(parse_annotation(inner)?);
}
Rule::type_spec => {
field_type = parse_type_spec(inner)?;
}
Rule::declarator => {
name = parse_declarator_name(inner)?;
}
_ => {}
}
}
Ok(IdlField {
annotations,
field_type,
name,
})
}
fn parse_const_type(pair: Pair<'_, Rule>) -> ParseResult<IdlType> {
for inner in pair.into_inner() {
match inner.as_rule() {
Rule::integer_type => return Ok(parse_integer_type(inner)),
Rule::char_type => {
return Ok(IdlType::Basic(BasicType::from_kind(BasicTypeKind::Char)));
}
Rule::boolean_type => {
return Ok(IdlType::Basic(BasicType::from_kind(BasicTypeKind::Boolean)));
}
Rule::floating_pt_type => return Ok(parse_floating_pt_type(&inner)),
Rule::string_type => return Ok(parse_string_type(inner)),
Rule::scoped_name => return Ok(parse_scoped_name_as_type(inner.as_str())),
Rule::octet_type => {
return Ok(IdlType::Basic(BasicType::from_kind(BasicTypeKind::Octet)));
}
_ => {}
}
}
Err(ParseError::Semantic("Invalid const type".to_string()))
}
fn parse_type_spec(pair: Pair<'_, Rule>) -> ParseResult<IdlType> {
for inner in pair.into_inner() {
match inner.as_rule() {
Rule::simple_type_spec => return parse_simple_type_spec(inner),
Rule::constr_type_spec => return parse_constr_type_spec(inner),
_ => {}
}
}
Err(ParseError::Semantic("Invalid type spec".to_string()))
}
fn parse_simple_type_spec(pair: Pair<'_, Rule>) -> ParseResult<IdlType> {
for inner in pair.into_inner() {
match inner.as_rule() {
Rule::base_type_spec => return parse_base_type_spec(inner),
Rule::template_type_spec => return parse_template_type_spec(inner),
Rule::scoped_name => return Ok(parse_scoped_name_as_type(inner.as_str())),
_ => {}
}
}
Err(ParseError::Semantic("Invalid simple type spec".to_string()))
}
fn parse_scoped_name_as_type(scoped_name: &str) -> IdlType {
let scoped_name = scoped_name.trim();
let parts: Vec<&str> = scoped_name.split("::").collect();
if parts.len() == 1 {
IdlType::Named(NamedType {
name: parts[0].to_string(),
})
} else {
let namespaces: Vec<String> = parts[..parts.len() - 1]
.iter()
.map(ToString::to_string)
.collect();
let name = parts[parts.len() - 1].to_string();
IdlType::Namespaced(NamespacedType { namespaces, name })
}
}
fn parse_base_type_spec(pair: Pair<'_, Rule>) -> ParseResult<IdlType> {
for inner in pair.into_inner() {
match inner.as_rule() {
Rule::floating_pt_type => return Ok(parse_floating_pt_type(&inner)),
Rule::integer_type => return Ok(parse_integer_type(inner)),
Rule::char_type => {
return Ok(IdlType::Basic(BasicType::from_kind(BasicTypeKind::Char)));
}
Rule::boolean_type => {
return Ok(IdlType::Basic(BasicType::from_kind(BasicTypeKind::Boolean)));
}
Rule::octet_type => {
return Ok(IdlType::Basic(BasicType::from_kind(BasicTypeKind::Octet)));
}
_ => {}
}
}
Err(ParseError::Semantic("Invalid base type spec".to_string()))
}
fn parse_template_type_spec(pair: Pair<'_, Rule>) -> ParseResult<IdlType> {
for inner in pair.into_inner() {
match inner.as_rule() {
Rule::sequence_type => return parse_sequence_type(inner),
Rule::string_type => return Ok(parse_string_type(inner)),
Rule::wide_string_type => return Ok(parse_wide_string_type(inner)),
_ => {}
}
}
Err(ParseError::Semantic(
"Invalid template type spec".to_string(),
))
}
fn parse_constr_type_spec(pair: Pair<'_, Rule>) -> ParseResult<IdlType> {
for inner in pair.into_inner() {
match inner.as_rule() {
Rule::struct_type => return Ok(IdlType::Named(NamedType::new("struct"))),
Rule::union_type => return Ok(IdlType::Named(NamedType::new("union"))),
Rule::enum_type => return Ok(IdlType::Named(NamedType::new("enum"))),
_ => {}
}
}
Err(ParseError::Semantic(
"Invalid constructed type spec".to_string(),
))
}
fn parse_floating_pt_type(pair: &Pair<'_, Rule>) -> IdlType {
let type_str = pair.as_str();
let kind = BasicTypeKind::parse(type_str)
.expect("floating_pt_type should always be a valid BasicTypeKind");
IdlType::Basic(BasicType::from_kind(kind))
}
fn parse_integer_type(pair: Pair<'_, Rule>) -> IdlType {
for inner in pair.into_inner() {
match inner.as_rule() {
Rule::signed_int | Rule::unsigned_int => {
let kind = BasicTypeKind::parse(inner.as_str())
.expect("integer_type should always be a valid BasicTypeKind");
return IdlType::Basic(BasicType::from_kind(kind));
}
_ => {}
}
}
IdlType::Basic(BasicType::from_kind(BasicTypeKind::Int))
}
fn parse_sequence_type(pair: Pair<'_, Rule>) -> ParseResult<IdlType> {
let mut element_type = IdlType::Basic(BasicType::from_kind(BasicTypeKind::Octet));
let mut max_size: Option<u32> = None;
for inner in pair.into_inner() {
match inner.as_rule() {
Rule::type_spec => {
element_type = parse_type_spec(inner)?;
}
Rule::positive_int_const => {
max_size = inner.as_str().parse::<u32>().ok();
}
_ => {}
}
}
if let Some(size) = max_size {
Ok(IdlType::BoundedSequence(BoundedSequence::new(
element_type,
size,
)))
} else {
Ok(IdlType::UnboundedSequence(UnboundedSequence::new(
element_type,
)))
}
}
fn parse_string_type(pair: Pair<'_, Rule>) -> IdlType {
for inner in pair.into_inner() {
if inner.as_rule() == Rule::positive_int_const
&& let Ok(max_size) = inner.as_str().parse::<u32>()
{
return IdlType::String(AbstractString::Bounded(BoundedString {
maximum_size: max_size,
}));
}
}
IdlType::String(AbstractString::Unbounded(UnboundedString))
}
fn parse_wide_string_type(pair: Pair<'_, Rule>) -> IdlType {
for inner in pair.into_inner() {
if inner.as_rule() == Rule::positive_int_const
&& let Ok(max_size) = inner.as_str().parse::<u32>()
{
return IdlType::WString(AbstractWString::Bounded(BoundedWString {
maximum_size: max_size,
}));
}
}
IdlType::WString(AbstractWString::Unbounded(UnboundedWString))
}
fn parse_declarator_with_array(pair: Pair<'_, Rule>) -> ParseResult<(String, Vec<u32>)> {
for inner in pair.into_inner() {
match inner.as_rule() {
Rule::pointer_declarator => {
return parse_declarator_with_array(inner);
}
Rule::direct_declarator => {
let mut name = String::new();
let mut array_sizes = Vec::new();
for direct_inner in inner.into_inner() {
match direct_inner.as_rule() {
Rule::identifier => {
name = direct_inner.as_str().to_string();
}
Rule::positive_int_const => {
if let Ok(IdlValue::Int32(size)) =
parse_const_expr_value(direct_inner.clone())
{
array_sizes.push(size.try_into().unwrap_or_default());
} else if let Ok(size) = direct_inner.as_str().trim().parse::<u32>() {
array_sizes.push(size);
}
}
_ => {}
}
}
return Ok((name, array_sizes));
}
_ => {}
}
}
Err(ParseError::Semantic("Invalid declarator".to_string()))
}
fn parse_declarator_name(pair: Pair<'_, Rule>) -> ParseResult<String> {
for inner in pair.into_inner() {
match inner.as_rule() {
Rule::pointer_declarator => {
return parse_declarator_name(inner);
}
Rule::direct_declarator => {
for direct_inner in inner.into_inner() {
if direct_inner.as_rule() == Rule::identifier {
return Ok(direct_inner.as_str().to_string());
}
}
}
_ => {}
}
}
Err(ParseError::Semantic("Invalid declarator".to_string()))
}
fn parse_const_expr_value(pair: Pair<'_, Rule>) -> ParseResult<IdlValue> {
let pair_str = pair.as_str();
for inner in pair.into_inner() {
if inner.as_rule() == Rule::const_expr {
return parse_const_expr(inner);
}
}
if let Ok(val) = pair_str.trim().parse::<i32>() {
return Ok(IdlValue::Int32(val));
}
Err(ParseError::Semantic(
"Invalid positive int const".to_string(),
))
}
fn parse_const_expr(pair: Pair<'_, Rule>) -> ParseResult<IdlValue> {
for inner in pair.into_inner() {
if inner.as_rule() == Rule::or_expr {
return parse_or_expr(inner);
}
}
Err(ParseError::Semantic("Invalid const expression".to_string()))
}
fn parse_or_expr(pair: Pair<'_, Rule>) -> ParseResult<IdlValue> {
for inner in pair.into_inner() {
if inner.as_rule() == Rule::xor_expr {
return parse_xor_expr(inner);
}
}
Err(ParseError::Semantic("Invalid or expression".to_string()))
}
fn parse_xor_expr(pair: Pair<'_, Rule>) -> ParseResult<IdlValue> {
for inner in pair.into_inner() {
if inner.as_rule() == Rule::and_expr {
return parse_and_expr(inner);
}
}
Err(ParseError::Semantic("Invalid xor expression".to_string()))
}
fn parse_and_expr(pair: Pair<'_, Rule>) -> ParseResult<IdlValue> {
for inner in pair.into_inner() {
if inner.as_rule() == Rule::shift_expr {
return parse_shift_expr(inner);
}
}
Err(ParseError::Semantic("Invalid and expression".to_string()))
}
fn parse_shift_expr(pair: Pair<'_, Rule>) -> ParseResult<IdlValue> {
for inner in pair.into_inner() {
if inner.as_rule() == Rule::add_expr {
return parse_add_expr(inner);
}
}
Err(ParseError::Semantic("Invalid shift expression".to_string()))
}
fn parse_add_expr(pair: Pair<'_, Rule>) -> ParseResult<IdlValue> {
for inner in pair.into_inner() {
if inner.as_rule() == Rule::mult_expr {
return parse_mult_expr(inner);
}
}
Err(ParseError::Semantic("Invalid add expression".to_string()))
}
fn parse_mult_expr(pair: Pair<'_, Rule>) -> ParseResult<IdlValue> {
for inner in pair.into_inner() {
if inner.as_rule() == Rule::unary_expr {
return parse_unary_expr(inner);
}
}
Err(ParseError::Semantic("Invalid mult expression".to_string()))
}
fn parse_unary_expr(pair: Pair<'_, Rule>) -> ParseResult<IdlValue> {
let mut unary_op: Option<&str> = None;
let mut inner_expr: Option<Pair<'_, Rule>> = None;
for inner in pair.into_inner() {
match inner.as_rule() {
Rule::unary_operator => {
unary_op = Some(inner.as_str());
}
Rule::primary_expr => {
inner_expr = Some(inner);
}
Rule::unary_expr => {
let value = parse_unary_expr(inner)?;
if let Some(op) = unary_op {
return apply_unary_op(op, value);
}
return Ok(value);
}
_ => {}
}
}
if let Some(op) = unary_op
&& let Some(expr) = inner_expr
{
let value = parse_primary_expr(expr)?;
return apply_unary_op(op, value);
}
if let Some(expr) = inner_expr {
return parse_primary_expr(expr);
}
Err(ParseError::Semantic("Invalid unary expression".to_string()))
}
fn apply_unary_op(op: &str, value: IdlValue) -> ParseResult<IdlValue> {
match op {
"-" => match value {
IdlValue::Int8(i) => Ok(IdlValue::Int8(-i)),
IdlValue::Int16(i) => Ok(IdlValue::Int16(-i)),
IdlValue::Int32(i) => Ok(IdlValue::Int32(-i)),
IdlValue::Int64(i) => Ok(IdlValue::Int64(-i)),
IdlValue::Float32(f) => Ok(IdlValue::Float32(-f)),
IdlValue::Float64(f) => Ok(IdlValue::Float64(-f)),
_ => Err(ParseError::Semantic(format!(
"Cannot apply unary minus to {value:?}"
))),
},
"+" => Ok(value), "~" => match value {
IdlValue::Int8(i) => Ok(IdlValue::Int8(!i)),
IdlValue::UInt8(i) => Ok(IdlValue::UInt8(!i)),
IdlValue::Int16(i) => Ok(IdlValue::Int16(!i)),
IdlValue::UInt16(i) => Ok(IdlValue::UInt16(!i)),
IdlValue::Int32(i) => Ok(IdlValue::Int32(!i)),
IdlValue::UInt32(i) => Ok(IdlValue::UInt32(!i)),
IdlValue::Int64(i) => Ok(IdlValue::Int64(!i)),
IdlValue::UInt64(i) => Ok(IdlValue::UInt64(!i)),
_ => Err(ParseError::Semantic(format!(
"Cannot apply bitwise NOT to {value:?}"
))),
},
_ => Err(ParseError::Semantic(format!(
"Unknown unary operator: {op}"
))),
}
}
fn parse_primary_expr(pair: Pair<'_, Rule>) -> ParseResult<IdlValue> {
for inner in pair.into_inner() {
match inner.as_rule() {
Rule::literal => {
return parse_literal(inner);
}
Rule::scoped_name => {
return Ok(IdlValue::String(inner.as_str().to_string()));
}
Rule::const_expr => {
return parse_const_expr(inner);
}
_ => {}
}
}
Err(ParseError::Semantic(
"Invalid primary expression".to_string(),
))
}
fn parse_literal(pair: Pair<'_, Rule>) -> ParseResult<IdlValue> {
let pair_str = pair.as_str().to_string();
for inner in pair.into_inner() {
match inner.as_rule() {
Rule::integer_literal => return parse_integer_literal(inner),
Rule::floating_pt_literal => return parse_floating_pt_literal(inner),
Rule::character_literal => return parse_character_literal(inner),
Rule::string_literal => return parse_string_literal(inner),
Rule::string_concat => {
let mut result = String::new();
for str_part in inner.into_inner() {
if let Ok(IdlValue::String(s)) = parse_string_literal(str_part) {
result.push_str(&s);
}
}
return Ok(IdlValue::String(result));
}
Rule::boolean_literal => return parse_boolean_literal(inner),
_ => {}
}
}
Err(ParseError::Semantic(format!("Invalid literal: {pair_str}")))
}
fn parse_integer_literal(pair: Pair<'_, Rule>) -> ParseResult<IdlValue> {
if let Some(inner) = pair.into_inner().next() {
let value_str = inner.as_str();
return Ok(IdlValue::Int64(match inner.as_rule() {
Rule::decimal_literal => value_str.parse::<i64>().unwrap_or(0),
Rule::hex_literal => i64::from_str_radix(&value_str[2..], 16).unwrap_or(0),
Rule::octal_literal => i64::from_str_radix(&value_str[1..], 8).unwrap_or(0),
_ => 0,
}));
}
Err(ParseError::Semantic("Invalid integer literal".to_string()))
}
fn parse_floating_pt_literal(pair: Pair<'_, Rule>) -> ParseResult<IdlValue> {
for inner in pair.into_inner() {
if inner.as_rule() == Rule::float_literal {
let value_str = inner.as_str();
return Ok(IdlValue::Float64(value_str.parse::<f64>().unwrap_or(0.0)));
}
}
Err(ParseError::Semantic(
"Invalid floating point literal".to_string(),
))
}
fn parse_character_literal(pair: Pair<'_, Rule>) -> ParseResult<IdlValue> {
for inner in pair.into_inner() {
if inner.as_rule() == Rule::char_literal {
let s = inner.as_str();
let char_content = &s[1..s.len() - 1];
return Ok(IdlValue::Char(char_content.chars().next().unwrap_or('\0')));
}
}
Err(ParseError::Semantic(
"Invalid character literal".to_string(),
))
}
fn process_escape_sequences(s: &str) -> String {
let mut result = String::with_capacity(s.len());
let mut chars = s.chars().peekable();
while let Some(c) = chars.next() {
if c == '\\' {
match chars.next() {
Some('n') => result.push('\n'),
Some('r') => result.push('\r'),
Some('t') => result.push('\t'),
Some('\\') | None => result.push('\\'),
Some('"') => result.push('"'),
Some('\'') => result.push('\''),
Some('0') => result.push('\0'),
Some(other) => {
result.push('\\');
result.push(other);
}
}
} else {
result.push(c);
}
}
result
}
fn parse_string_literal(pair: Pair<'_, Rule>) -> ParseResult<IdlValue> {
if pair.as_rule() == Rule::string_literal {
let s = pair.as_str();
let string_content = &s[1..s.len() - 1];
return Ok(IdlValue::String(process_escape_sequences(string_content)));
}
for inner in pair.into_inner() {
if inner.as_rule() == Rule::string_literal {
let s = inner.as_str();
let string_content = &s[1..s.len() - 1];
return Ok(IdlValue::String(process_escape_sequences(string_content)));
}
}
Err(ParseError::Semantic("Invalid string literal".to_string()))
}
fn parse_boolean_literal(pair: Pair<'_, Rule>) -> ParseResult<IdlValue> {
for inner in pair.into_inner() {
match inner.as_rule() {
Rule::KW_TRUE => return Ok(IdlValue::Bool(true)),
Rule::KW_FALSE => return Ok(IdlValue::Bool(false)),
_ => {}
}
}
Err(ParseError::Semantic("Invalid boolean literal".to_string()))
}