tamer: NIR->xmli: Initial classify, any, all support

Just as `rate` is a `sum`, `classify` is an `all` by default.  The `@any`
attribute will change that interpretation, though I only intend to recognize
that in parsing later on, not emit that in XMLI.

DEV-13708
main
Mike Gerwitz 2023-02-24 23:01:02 -05:00
parent d5cf276de2
commit 98fcb115da
8 changed files with 151 additions and 36 deletions

View File

@ -90,8 +90,14 @@ impl Display for Expr {
/// as was the original plan with TAMER.
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum ExprOp {
// Summation (+)
Sum,
// Product (×)
Product,
// Logical conjunction (∧)
Conj,
// Logical disjunction ()
Disj,
}
impl Display for ExprOp {
@ -99,8 +105,10 @@ impl Display for ExprOp {
use ExprOp::*;
match self {
Sum => write!(f, "sum"),
Product => write!(f, "product"),
Sum => write!(f, "sum (+)"),
Product => write!(f, "product (×)"),
Conj => write!(f, "conjunctive (∧)"),
Disj => write!(f, "disjunctive ()"),
}
}
}

View File

@ -36,11 +36,11 @@ use super::object::{
use crate::{
asg::{
visit::{Depth, TreeWalkRel},
Asg, ExprOp,
Asg, ExprOp, Ident,
},
diagnose::Annotate,
diagnostic_panic, diagnostic_unreachable,
parse::{prelude::*, util::SPair, Transitionable},
parse::{prelude::*, Transitionable},
span::{Span, UNKNOWN_SPAN},
sym::{
st::{URI_LV_CALC, URI_LV_RATER, URI_LV_TPL},
@ -230,13 +230,39 @@ impl<'a> TreeContext<'a> {
) -> Option<Xirf> {
match src {
Object::Ident((ident, _)) => {
self.push(yields(ident.name(), expr.span()));
Some(stmt(expr, depth))
self.emit_expr_ident(expr, ident, depth)
}
_ => Some(expr_ele(expr, depth)),
}
}
/// Emit an identified expression.
///
/// Legacy TAME is only able to bind certain identifiers via statements
/// such as `rate` and `classify`.
fn emit_expr_ident(
&mut self,
expr: &Expr,
ident: &Ident,
depth: Depth,
) -> Option<Xirf> {
let (qname, ident_qname) = match expr.op() {
ExprOp::Sum => (QN_RATE, QN_YIELDS),
ExprOp::Conj => (QN_CLASSIFY, QN_AS),
ExprOp::Product | ExprOp::Disj => todo!("stmt: {expr:?}"),
};
let ispan = ident.span();
self.push(Xirf::attr(ident_qname, ident.name(), (ispan, ispan)));
Some(Xirf::open(
qname,
OpenSpan::without_name_span(expr.span()),
depth,
))
}
fn push(&mut self, tok: Xirf) {
if self.stack.is_full() {
diagnostic_panic!(
@ -292,24 +318,14 @@ fn ns(qname: QName, uri: UriStaticSymbolId, span: Span) -> Xirf {
Xirf::attr(qname, uri, (span, span))
}
fn stmt(expr: &Expr, depth: Depth) -> Xirf {
match expr.op() {
ExprOp::Sum => {
Xirf::open(QN_RATE, OpenSpan::without_name_span(expr.span()), depth)
}
_ => todo!("stmt: {expr:?}"),
}
}
fn yields(name: SPair, span: Span) -> Xirf {
Xirf::attr(QN_YIELDS, name, (span, name))
}
fn expr_ele(expr: &Expr, depth: Depth) -> Xirf {
use ExprOp::*;
let qname = match expr.op() {
ExprOp::Sum => QN_C_SUM,
ExprOp::Product => QN_C_PRODUCT,
Sum => QN_C_SUM,
Product => QN_C_PRODUCT,
Conj => QN_ALL,
Disj => QN_ANY,
};
Xirf::open(qname, OpenSpan::without_name_span(expr.span()), depth)

View File

@ -183,12 +183,18 @@ pub enum NirEntity {
/// Rate (verb) block,
/// representing a calculation with a scalar result.
Rate,
/// Summation (Σ) expression.
Sum,
/// Product (Π) expression.
Product,
// Classification.
Classify,
/// Conjunctive (∧) expression.
All,
/// Disjunctive () expression.
Any,
/// Template parameter (metavariable).
TplParam,
}
@ -209,9 +215,15 @@ impl Display for NirEntity {
match self {
Package => write!(f, "package"),
Rate => write!(f, "rate block"),
Sum => write!(f, "sum (∑) expression"),
Product => write!(f, "product (Π) expression"),
Classify => write!(f, "classification"),
All => write!(f, "conjunctive (∧) expression"),
Any => write!(f, "disjunctive () expression"),
TplParam => write!(f, "template param (metavariable)"),
}
}

View File

@ -80,11 +80,22 @@ impl ParseState for NirToAir {
(Ready, Nir::Open(NirEntity::Product, span)) => {
Transition(Ready).ok(Air::ExprOpen(ExprOp::Product, span))
}
(Ready, Nir::Open(NirEntity::Classify | NirEntity::All, span)) => {
Transition(Ready).ok(Air::ExprOpen(ExprOp::Conj, span))
}
(Ready, Nir::Open(NirEntity::Any, span)) => {
Transition(Ready).ok(Air::ExprOpen(ExprOp::Disj, span))
}
(
Ready,
Nir::Close(
NirEntity::Rate | NirEntity::Sum | NirEntity::Product,
NirEntity::Rate
| NirEntity::Sum
| NirEntity::Product
| NirEntity::Classify
| NirEntity::All
| NirEntity::Any,
span,
),
) => Transition(Ready).ok(Air::ExprClose(span)),

View File

@ -76,3 +76,43 @@ fn calc_exprs() {
Sut::parse(toks.into_iter()).collect(),
);
}
#[test]
fn classify_to_conj_expr() {
let id = SPair("always".into(), S2);
let toks = vec![
Nir::Open(NirEntity::Classify, S1),
Nir::BindIdent(id),
Nir::Close(NirEntity::Classify, S3),
];
assert_eq!(
Ok(vec![
O(Air::ExprOpen(ExprOp::Conj, S1)),
O(Air::ExprIdent(id)),
O(Air::ExprClose(S3)),
]),
Sut::parse(toks.into_iter()).collect(),
);
}
#[test]
fn logic_exprs() {
let toks = vec![
Nir::Open(NirEntity::All, S1),
Nir::Open(NirEntity::Any, S2),
Nir::Close(NirEntity::Any, S3),
Nir::Close(NirEntity::All, S4),
];
assert_eq!(
Ok(vec![
O(Air::ExprOpen(ExprOp::Conj, S1)),
O(Air::ExprOpen(ExprOp::Disj, S2)),
O(Air::ExprClose(S3)),
O(Air::ExprClose(S4)),
]),
Sut::parse(toks.into_iter()).collect(),
);
}

View File

@ -389,15 +389,16 @@ ele_parse! {
/// A classification is a logic expression yielding a boolean result
/// with the dimensionality matching the largest dimensionality of its
/// inputs.
ClassifyStmt := QN_CLASSIFY {
ClassifyStmt := QN_CLASSIFY(_, ospan) {
@ {
QN_AS => TodoAttr,
QN_AS => BindIdent,
QN_DESC => TodoAttr,
QN_ANY => TodoAttr,
QN_YIELDS => TodoAttr,
QN_SYM => TodoAttr,
QN_TERMINATE => TodoAttr,
} => Todo,
} => NirEntity::Classify.open(ospan),
/(cspan) => NirEntity::Classify.close(cspan),
LogExpr,
};
@ -595,8 +596,9 @@ ele_parse! {
///
/// This represents an expression that matches when _any_ of its inner
/// [`LogExpr`] expressions match.
AnyExpr := QN_ANY {
@ {} => Todo,
AnyExpr := QN_ANY(_, ospan) {
@ {} => NirEntity::Any.open(ospan),
/(cspan) => NirEntity::Any.close(cspan),
LogExpr,
};
@ -605,8 +607,9 @@ ele_parse! {
///
/// This represents an expression that matches when _all_ of its inner
/// [`LogExpr`] expressions match.
AllExpr := QN_ALL {
@ {} => Todo,
AllExpr := QN_ALL(_, ospan) {
@ {} => NirEntity::All.open(ospan),
/(cspan) => NirEntity::All.close(cspan),
LogExpr,
};

View File

@ -11,12 +11,24 @@
<rate yields="rateBaz">
<c:sum>
<c:product />
<c:sum />
</c:sum>
<c:sum>
<c:product>
<c:sum />
<c:product />
<c:sum />
</c:sum>
</c:product>
</rate>
</package>
<classify as="always" />
<classify as="sometimes">
<any>
<all />
<any />
<all />
</any>
<any />
</classify>
</package>

View File

@ -15,12 +15,25 @@
<rate yields="rateBaz">
<c:sum>
<c:product />
<c:sum />
</c:sum>
<c:sum>
<c:product>
<c:sum />
<c:product />
<c:sum />
</c:sum>
</c:product>
</rate>
<classify as="always" />
<classify as="sometimes">
<any>
<all />
<any />
<all />
</any>
<any />
</classify>
</package>