use std::collections::HashMap;
use pest::iterators::Pair;
use crate::common::{FileId, Span};
use crate::parser::error::{ParseError, grammar_bug};
use crate::parser::logic::{FlowLogRule, Head, apply_indices_to_rule, parse_plan_indices};
use crate::parser::{Lexeme, Rule, span_of, type_ref_name};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum RawTypeOp {
Alias,
Subtype,
}
#[derive(Debug, Clone)]
pub(crate) struct CompDecl {
pub(crate) name: String,
pub(crate) type_params: Vec<String>,
pub(crate) supertype: Option<SuperRef>,
pub(crate) body: Vec<RawItem>,
pub(crate) span: Span,
}
#[derive(Debug, Clone)]
pub(crate) struct SuperRef {
pub(crate) name: String,
pub(crate) args: Vec<String>,
pub(crate) span: Span,
}
#[derive(Debug, Clone)]
pub(crate) struct InitDecl {
pub(crate) instance: String,
pub(crate) comp: String,
pub(crate) args: Vec<String>,
pub(crate) span: Span,
}
#[derive(Debug, Clone)]
pub(crate) enum RawItem {
Decl(RawRelation),
TypeAlias {
name: String,
op: RawTypeOp,
parent: String,
span: Span,
},
Rule(FlowLogRule),
Fact(FlowLogRule),
Input {
name: String,
params: HashMap<String, String>,
span: Span,
},
Output {
name: String,
params: HashMap<String, String>,
span: Span,
},
Printsize {
name: String,
span: Span,
},
Init(InitDecl),
Comp(CompDecl),
Override {
name: String,
span: Span,
},
}
#[derive(Debug, Clone)]
pub(crate) struct RawRelation {
pub(crate) name: String,
pub(crate) attrs: Vec<(String, String)>,
pub(crate) overridable: bool,
pub(crate) span: Span,
}
impl CompDecl {
pub(crate) fn from_parsed_rule(
parsed_rule: Pair<Rule>,
file: FileId,
) -> Result<Self, ParseError> {
debug_assert_eq!(parsed_rule.as_rule(), Rule::comp_decl);
let span = span_of(&parsed_rule, file);
let mut inner = parsed_rule.into_inner();
let name = inner
.next()
.ok_or_else(|| grammar_bug("comp_decl missing name"))?
.as_str()
.to_string();
let mut type_params = Vec::new();
let mut supertype: Option<SuperRef> = None;
let mut body: Vec<RawItem> = Vec::new();
let mut plan_target_start: Option<usize> = None;
for node in inner {
match node.as_rule() {
Rule::comp_type_params => {
type_params.extend(node.into_inner().map(|p| p.as_str().to_string()));
}
Rule::comp_supertype => {
supertype = Some(SuperRef::from_parsed_rule(node, file)?);
}
Rule::comp_body_item => {
let inner_kind = node.clone().into_inner().peek().map(|p| p.as_rule());
if matches!(inner_kind, Some(Rule::plan_directive)) {
let plan_pair = node
.into_inner()
.next()
.ok_or_else(|| grammar_bug("comp_body_item missing inner"))?;
let start =
plan_target_start
.take()
.ok_or_else(|| ParseError::PlanOrphan {
span: span_of(&plan_pair, file),
})?;
let (span, raw_indices) = parse_plan_indices(plan_pair, file)?;
for item in &mut body[start..] {
let RawItem::Rule(rule) = item else {
return Err(grammar_bug(
"plan_target_start should only ever point at RawItem::Rule items",
));
};
apply_indices_to_rule(rule, span, &raw_indices)?;
}
} else {
let items = RawItem::from_parsed_rule(node, file)?;
plan_target_start =
matches!(items.first(), Some(RawItem::Rule(_))).then_some(body.len());
body.extend(items);
}
}
other => {
return Err(grammar_bug(format!(
"unexpected child of comp_decl: {other:?}"
)));
}
}
}
Ok(Self {
name,
type_params,
supertype,
body,
span,
})
}
}
impl SuperRef {
fn from_parsed_rule(node: Pair<Rule>, file: FileId) -> Result<Self, ParseError> {
debug_assert_eq!(node.as_rule(), Rule::comp_supertype);
let span = span_of(&node, file);
let mut inner = node.into_inner();
let name = inner
.next()
.ok_or_else(|| grammar_bug("comp_supertype missing name"))?
.as_str()
.to_string();
let args = parse_comp_type_args(inner.next())?;
Ok(Self { name, args, span })
}
}
impl InitDecl {
pub(crate) fn from_parsed_rule(
parsed_rule: Pair<Rule>,
file: FileId,
) -> Result<Self, ParseError> {
debug_assert_eq!(parsed_rule.as_rule(), Rule::init_decl);
let span = span_of(&parsed_rule, file);
let mut inner = parsed_rule.into_inner();
let instance = inner
.next()
.ok_or_else(|| grammar_bug("init_decl missing instance name"))?
.as_str()
.to_string();
let comp = inner
.next()
.ok_or_else(|| grammar_bug("init_decl missing component name"))?
.as_str()
.to_string();
let args = parse_comp_type_args(inner.next())?;
Ok(Self {
instance,
comp,
args,
span,
})
}
}
fn parse_comp_type_args(node: Option<Pair<Rule>>) -> Result<Vec<String>, ParseError> {
let Some(node) = node else {
return Ok(Vec::new());
};
debug_assert_eq!(node.as_rule(), Rule::comp_type_args);
Ok(node.into_inner().map(|p| type_ref_name(&p)).collect())
}
impl RawItem {
pub(crate) fn from_parsed_rule(
parsed_rule: Pair<Rule>,
file: FileId,
) -> Result<Vec<Self>, ParseError> {
debug_assert_eq!(parsed_rule.as_rule(), Rule::comp_body_item);
let inner = parsed_rule
.into_inner()
.next()
.ok_or_else(|| grammar_bug("comp_body_item missing inner"))?;
let item = match inner.as_rule() {
Rule::declaration => RawItem::Decl(RawRelation::from_parsed_rule(inner, file)?),
Rule::type_alias_decl => {
let (name, op, parent, span) = split_type_alias(inner, file)?;
RawItem::TypeAlias {
name,
op,
parent,
span,
}
}
Rule::rule => return parse_raw_rule(inner, file),
Rule::fact => parse_raw_fact(inner, file)?,
Rule::input_directive => {
let (name, params, span) = parse_io_parts(inner, file)?;
RawItem::Input { name, params, span }
}
Rule::output_directive => {
let (name, params, span) = parse_io_parts(inner, file)?;
RawItem::Output { name, params, span }
}
Rule::printsize_directive => parse_raw_printsize(inner, file)?,
Rule::comp_decl => RawItem::Comp(CompDecl::from_parsed_rule(inner, file)?),
Rule::init_decl => RawItem::Init(InitDecl::from_parsed_rule(inner, file)?),
Rule::override_directive => parse_raw_override(inner, file)?,
other => {
return Err(grammar_bug(format!(
"unexpected rule inside comp_body_item: {other:?}"
)));
}
};
Ok(vec![item])
}
}
pub(crate) fn split_type_alias(
node: Pair<Rule>,
file: FileId,
) -> Result<(String, RawTypeOp, String, Span), ParseError> {
debug_assert_eq!(node.as_rule(), Rule::type_alias_decl);
let span = span_of(&node, file);
let mut inner = node.into_inner();
let name = inner
.next()
.ok_or_else(|| grammar_bug("type_alias_decl missing name"))?
.as_str()
.to_string();
let op_inner = inner
.next()
.ok_or_else(|| grammar_bug("type_alias_decl missing operator"))?
.into_inner()
.next()
.ok_or_else(|| grammar_bug("type_decl_op missing inner op"))?;
let op = match op_inner.as_rule() {
Rule::subtype_op => RawTypeOp::Subtype,
Rule::alias_op => RawTypeOp::Alias,
other => return Err(grammar_bug(format!("unexpected type op: {other:?}"))),
};
let parent = type_ref_name(
&inner
.next()
.ok_or_else(|| grammar_bug("type_alias_decl missing parent"))?,
);
Ok((name, op, parent, span))
}
fn parse_raw_rule(node: Pair<Rule>, file: FileId) -> Result<Vec<RawItem>, ParseError> {
Ok(FlowLogRule::expand_from_parsed_rule(node, file)?
.into_iter()
.map(RawItem::Rule)
.collect())
}
fn parse_raw_fact(node: Pair<Rule>, file: FileId) -> Result<RawItem, ParseError> {
let head_node = node
.into_inner()
.next()
.ok_or_else(|| grammar_bug("fact missing head"))?;
let head = Head::from_parsed_rule(head_node, file)?;
Ok(RawItem::Fact(FlowLogRule::new(head, vec![])))
}
fn parse_io_parts(
node: Pair<Rule>,
file: FileId,
) -> Result<(String, HashMap<String, String>, Span), ParseError> {
let span = span_of(&node, file);
let mut inner = node.into_inner();
let name = inner
.next()
.ok_or_else(|| grammar_bug("io directive missing relation name"))?
.as_str()
.to_string();
let params = match inner.next() {
Some(params_node) => super::directive::parse_io_params_node(params_node)?,
None => HashMap::new(),
};
Ok((name, params, span))
}
fn parse_raw_printsize(node: Pair<Rule>, file: FileId) -> Result<RawItem, ParseError> {
let span = span_of(&node, file);
let name = node
.into_inner()
.next()
.ok_or_else(|| grammar_bug("printsize missing relation name"))?
.as_str()
.to_string();
Ok(RawItem::Printsize { name, span })
}
fn parse_raw_override(node: Pair<Rule>, file: FileId) -> Result<RawItem, ParseError> {
let span = span_of(&node, file);
let name = node
.into_inner()
.next()
.ok_or_else(|| grammar_bug("override directive missing relation name"))?
.as_str()
.to_string();
Ok(RawItem::Override { name, span })
}
impl RawRelation {
pub(crate) fn from_parsed_rule(
parsed_rule: Pair<Rule>,
file: FileId,
) -> Result<Self, ParseError> {
debug_assert_eq!(parsed_rule.as_rule(), Rule::declaration);
let span = span_of(&parsed_rule, file);
let mut inner = parsed_rule.into_inner();
let name = inner
.next()
.ok_or_else(|| grammar_bug("relation missing name"))?
.as_str()
.to_string();
let mut attrs = Vec::new();
let mut overridable = false;
for node in inner {
match node.as_rule() {
Rule::attributes_decl => {
for attr in node.into_inner() {
let mut parts = attr.into_inner();
let aname = parts
.next()
.ok_or_else(|| grammar_bug("attribute missing name"))?
.as_str()
.to_string();
let type_name = type_ref_name(
&parts
.next()
.ok_or_else(|| grammar_bug("attribute missing type_ref"))?,
);
attrs.push((aname, type_name));
}
}
Rule::overridable_kw => {
overridable = true;
}
_ => {}
}
}
Ok(Self {
name,
attrs,
overridable,
span,
})
}
}