tamer: asg: Add basic Doc support (for @desc)
This introduces a new `Doc` object that can be owned by `Expr` (only atm) and contain what it describes as a concise independent clause. This construction is not enforced, and is only really obvious today via the Summary Pages. There's a lot of latent and unrealized potential in TAME's documentation philosophy that was never realized, so this will certainly evolve over time. But for now, the primary purpose was to get `@desc` working on things like classifications so that `xmli` output can compile for certain packages. DEV-13708main
parent
0163391498
commit
9cb6195046
|
@ -73,9 +73,6 @@ BEGINFILE {
|
|||
found_rels = 0
|
||||
}
|
||||
|
||||
# Skip comments.
|
||||
/^ *\/+/ { next }
|
||||
|
||||
# Predicates will be reset for each line,
|
||||
# allowing the remainder of the script to be read more declaratively.
|
||||
{ in_block = in_block_subexpr = 0 }
|
||||
|
@ -100,6 +97,15 @@ block_src && /}/ {
|
|||
print ""
|
||||
}
|
||||
|
||||
# "// empty" means that the lack of edges is intentional.
|
||||
block_src && /^ *\/\/ empty$/ {
|
||||
# Suppress error from the edge check below.
|
||||
found_rels++
|
||||
}
|
||||
|
||||
# Skip comments.
|
||||
/^ *\/+/ { next }
|
||||
|
||||
# For each target object,
|
||||
# output a relation.
|
||||
#
|
||||
|
|
|
@ -40,6 +40,8 @@ use super::{
|
|||
Asg, AsgError, Expr, Ident, ObjectIndex,
|
||||
};
|
||||
use crate::{
|
||||
diagnose::Annotate,
|
||||
diagnostic_todo,
|
||||
parse::{prelude::*, StateStack},
|
||||
span::{Span, UNKNOWN_SPAN},
|
||||
sym::SymbolId,
|
||||
|
@ -161,18 +163,30 @@ impl ParseState for AirAggregate {
|
|||
Transition(Empty).incomplete()
|
||||
}
|
||||
|
||||
// TODO: We don't support package ids yet
|
||||
// Packages are identified by their paths.
|
||||
(st @ Toplevel(..), AirBind(BindIdent(id))) => {
|
||||
Transition(st).err(AsgError::InvalidBindContext(id))
|
||||
}
|
||||
|
||||
(Toplevel(oi_pkg), tok @ AirDoc(..)) => {
|
||||
diagnostic_todo!(
|
||||
vec![
|
||||
oi_pkg.note("for this package"),
|
||||
tok.internal_error(
|
||||
"this package-level documentation is not yet supported"
|
||||
)
|
||||
],
|
||||
"package-level documentation is not yet supported by TAMER",
|
||||
)
|
||||
}
|
||||
|
||||
// Package import
|
||||
(Toplevel(oi_pkg), AirBind(RefIdent(pathspec))) => {
|
||||
oi_pkg.import(ctx.asg_mut(), pathspec);
|
||||
Transition(Toplevel(oi_pkg)).incomplete()
|
||||
}
|
||||
|
||||
// Note: We unfortunately can't match on `AirExpr | AirBind`
|
||||
// Note: We unfortunately can't match on `AirExpr | AirBind | ...`
|
||||
// and delegate in the same block
|
||||
// (without having to duplicate type checks and then handle
|
||||
// unreachable paths)
|
||||
|
@ -182,6 +196,7 @@ impl ParseState for AirAggregate {
|
|||
}
|
||||
(PkgExpr(expr), AirExpr(etok)) => ctx.proxy(expr, etok),
|
||||
(PkgExpr(expr), AirBind(etok)) => ctx.proxy(expr, etok),
|
||||
(PkgExpr(expr), AirDoc(etok)) => ctx.proxy(expr, etok),
|
||||
|
||||
// Template parsing.
|
||||
(st @ (Toplevel(_) | PkgExpr(_)), tok @ AirTpl(..)) => {
|
||||
|
@ -189,6 +204,7 @@ impl ParseState for AirAggregate {
|
|||
}
|
||||
(PkgTpl(tplst), AirTpl(ttok)) => ctx.proxy(tplst, ttok),
|
||||
(PkgTpl(tplst), AirBind(ttok)) => ctx.proxy(tplst, ttok),
|
||||
(PkgTpl(tplst), AirDoc(ttok)) => ctx.proxy(tplst, ttok),
|
||||
|
||||
(Empty, AirPkg(PkgEnd(span))) => {
|
||||
Transition(Empty).err(AsgError::InvalidPkgEndContext(span))
|
||||
|
@ -205,9 +221,10 @@ impl ParseState for AirAggregate {
|
|||
}
|
||||
}
|
||||
|
||||
(Empty, tok @ (AirExpr(..) | AirBind(..) | AirTpl(..))) => {
|
||||
Transition(Empty).err(AsgError::PkgExpected(tok.span()))
|
||||
}
|
||||
(
|
||||
Empty,
|
||||
tok @ (AirExpr(..) | AirBind(..) | AirTpl(..) | AirDoc(..)),
|
||||
) => Transition(Empty).err(AsgError::PkgExpected(tok.span())),
|
||||
|
||||
(Empty, AirIdent(IdentDecl(name, kind, src))) => ctx
|
||||
.asg_mut()
|
||||
|
|
|
@ -85,7 +85,7 @@ impl ParseState for AirExprAggregate {
|
|||
tok: Self::Token,
|
||||
ctx: &mut Self::Context,
|
||||
) -> crate::parse::TransitionResult<Self::Super> {
|
||||
use super::ir::{AirBind::*, AirExpr::*};
|
||||
use super::ir::{AirBind::*, AirDoc::*, AirExpr::*};
|
||||
use AirBindableExpr::*;
|
||||
use AirExprAggregate::*;
|
||||
|
||||
|
@ -143,12 +143,19 @@ impl ParseState for AirExprAggregate {
|
|||
.incomplete()
|
||||
}
|
||||
|
||||
(BuildingExpr(es, oi), AirDoc(DocIndepClause(clause))) => {
|
||||
oi.desc_short(ctx.asg_mut(), clause);
|
||||
Transition(BuildingExpr(es, oi)).incomplete()
|
||||
}
|
||||
|
||||
(st @ Ready(..), AirExpr(ExprEnd(span))) => {
|
||||
Transition(st).err(AsgError::UnbalancedExpr(span))
|
||||
}
|
||||
|
||||
// The binding may refer to a parent context.
|
||||
(st @ Ready(..), tok @ AirBind(..)) => Transition(st).dead(tok),
|
||||
// Token may refer to a parent context.
|
||||
(st @ Ready(..), tok @ (AirBind(..) | AirDoc(..))) => {
|
||||
Transition(st).dead(tok)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ use crate::asg::{
|
|||
test::{asg_from_toks, parse_as_pkg_body},
|
||||
Air, AirAggregate,
|
||||
},
|
||||
graph::object::{expr::ExprRel, ObjectRel},
|
||||
graph::object::{expr::ExprRel, Doc, ObjectRel},
|
||||
ExprOp, Ident,
|
||||
};
|
||||
use crate::span::dummy::*;
|
||||
|
@ -861,3 +861,29 @@ fn idents_share_defining_pkg() {
|
|||
oi_foo.src_pkg(&asg).map(|pkg| pkg.resolve(&asg).span())
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn expr_doc_short_desc() {
|
||||
let id_expr = SPair("foo".into(), S2);
|
||||
let clause = SPair("short desc".into(), S3);
|
||||
|
||||
#[rustfmt::skip]
|
||||
let toks = vec![
|
||||
Air::ExprStart(ExprOp::Sum, S1),
|
||||
Air::BindIdent(id_expr),
|
||||
Air::DocIndepClause(clause),
|
||||
Air::ExprEnd(S4),
|
||||
];
|
||||
|
||||
let asg = asg_from_toks(toks);
|
||||
|
||||
let oi_expr = asg.expect_ident_oi::<Expr>(id_expr);
|
||||
let oi_docs = oi_expr
|
||||
.edges_filtered::<Doc>(&asg)
|
||||
.map(ObjectIndex::cresolve(&asg));
|
||||
|
||||
assert_eq!(
|
||||
vec![&Doc::new_indep_clause(clause)],
|
||||
oi_docs.collect::<Vec<_>>(),
|
||||
);
|
||||
}
|
||||
|
|
|
@ -768,14 +768,45 @@ sum_ir! {
|
|||
display: |f| write!(f, "end template definition and expand it"),
|
||||
},
|
||||
}
|
||||
|
||||
enum AirDoc {
|
||||
/// Describe the active object using an independent clause.
|
||||
///
|
||||
/// This is like a "subject line",
|
||||
/// but is intended to be used when generating documentation
|
||||
/// in various different contexts.
|
||||
/// Users should think of this as taking place of an identifier
|
||||
/// name when used in a sentence,
|
||||
/// and phrase these clauses relative to the semantic
|
||||
/// properties of the object being described.
|
||||
/// The description should be able to stand on its own as a
|
||||
/// simple sentence, and should be able to be used to make
|
||||
/// compound sentences.
|
||||
///
|
||||
/// For example,
|
||||
/// predicates should make sense when being used to describe
|
||||
/// other objects,
|
||||
/// and should make sense when concatenated together using
|
||||
/// conjunctives and disjunctives.
|
||||
/// Calculations should make sense with and without those
|
||||
/// predicates.
|
||||
DocIndepClause(text: SPair) => {
|
||||
span: text,
|
||||
display: |f| write!(
|
||||
f,
|
||||
"documentation describing the active object as a subject \
|
||||
in a sentence",
|
||||
),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// Expressions that are able to be bound to identifiers.
|
||||
///
|
||||
/// This is the primary token set when parsing packages,
|
||||
/// since most everything in TAMER is an expression.
|
||||
pub sum enum AirBindableExpr = AirExpr | AirBind;
|
||||
pub sum enum AirBindableExpr = AirExpr | AirBind | AirDoc;
|
||||
|
||||
/// Tokens that may be used to define or apply templates.
|
||||
pub sum enum AirBindableTpl = AirTpl | AirBind;
|
||||
pub sum enum AirBindableTpl = AirTpl | AirBind | AirDoc;
|
||||
}
|
||||
|
|
|
@ -206,6 +206,19 @@ impl ParseState for AirTplAggregate {
|
|||
Transition(Toplevel(tpl)).incomplete()
|
||||
}
|
||||
|
||||
(Toplevel(tpl), tok @ AirDoc(..)) => {
|
||||
diagnostic_todo!(
|
||||
vec![
|
||||
tpl.oi().note("in this template"),
|
||||
tok.internal_error(
|
||||
"this template-level documentation is not \
|
||||
yet supported"
|
||||
)
|
||||
],
|
||||
"template-level documentation is not yet supported by TAMER",
|
||||
)
|
||||
}
|
||||
|
||||
(Toplevel(tpl), AirTpl(TplMetaStart(span))) => {
|
||||
let oi_meta = ctx.asg_mut().create(Meta::new_required(span));
|
||||
Transition(TplMeta(tpl, oi_meta)).incomplete()
|
||||
|
@ -242,6 +255,21 @@ impl ParseState for AirTplAggregate {
|
|||
diagnostic_todo!(vec![tok.note("this token")], "AirTpl variant")
|
||||
}
|
||||
|
||||
(TplMeta(tpl, oi_meta), tok @ AirDoc(..)) => {
|
||||
diagnostic_todo!(
|
||||
vec![
|
||||
tpl.oi().note("in this template"),
|
||||
oi_meta.note("this metavariable"),
|
||||
tok.internal_error(
|
||||
"this metavariable-level documentation is not \
|
||||
yet supported"
|
||||
)
|
||||
],
|
||||
"metavariable-level documentation is not yet supported \
|
||||
by TAMER",
|
||||
)
|
||||
}
|
||||
|
||||
(Toplevel(..), tok @ AirTpl(TplMetaEnd(..))) => {
|
||||
diagnostic_todo!(
|
||||
vec![tok.note("this token")],
|
||||
|
@ -299,7 +327,7 @@ impl ParseState for AirTplAggregate {
|
|||
Transition(Ready).err(AsgError::UnbalancedTpl(span))
|
||||
}
|
||||
|
||||
(st @ (Ready | Done), tok @ AirBind(..)) => {
|
||||
(st @ (Ready | Done), tok @ (AirBind(..) | AirDoc(..))) => {
|
||||
Transition(st).dead(tok)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -132,6 +132,7 @@ use std::{
|
|||
#[macro_use]
|
||||
mod rel;
|
||||
|
||||
pub mod doc;
|
||||
pub mod expr;
|
||||
pub mod ident;
|
||||
pub mod meta;
|
||||
|
@ -139,6 +140,7 @@ pub mod pkg;
|
|||
pub mod root;
|
||||
pub mod tpl;
|
||||
|
||||
pub use doc::Doc;
|
||||
pub use expr::Expr;
|
||||
pub use ident::Ident;
|
||||
pub use meta::Meta;
|
||||
|
@ -330,6 +332,9 @@ object_gen! {
|
|||
|
||||
/// Metasyntactic variable (metavariable).
|
||||
Meta,
|
||||
|
||||
/// Documentation.
|
||||
Doc,
|
||||
}
|
||||
|
||||
impl Object<OnlyObjectInner> {
|
||||
|
@ -341,6 +346,7 @@ impl Object<OnlyObjectInner> {
|
|||
Self::Expr(expr) => expr.span(),
|
||||
Self::Tpl(tpl) => tpl.span(),
|
||||
Self::Meta(meta) => meta.span(),
|
||||
Self::Doc(doc) => doc.span(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,75 @@
|
|||
// Documentation represented on the ASG
|
||||
//
|
||||
// Copyright (C) 2014-2023 Ryan Specialty, LLC.
|
||||
//
|
||||
// This file is part of TAME.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Documentation on the ASG.
|
||||
//!
|
||||
//! TODO: Document TAME's stance on documentation and literate programming,
|
||||
//! much of which hasn't been able to be realized over the years.
|
||||
|
||||
use super::prelude::*;
|
||||
use crate::{
|
||||
parse::{util::SPair, Token},
|
||||
span::Span,
|
||||
};
|
||||
use std::fmt::Display;
|
||||
|
||||
/// Documentation string.
|
||||
///
|
||||
/// TODO: This presently serves as a subject line,
|
||||
/// e.g. a description or label,
|
||||
/// but will evolve in the future.
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub enum Doc {
|
||||
/// An (ideally) concise independent clause describing an object.
|
||||
IndepClause(SPair),
|
||||
}
|
||||
|
||||
impl Display for Doc {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
write!(f, "documentation string")
|
||||
}
|
||||
}
|
||||
|
||||
impl Doc {
|
||||
/// Document an object using what is ideally a concise independent
|
||||
/// clause.
|
||||
pub fn new_indep_clause(clause: SPair) -> Self {
|
||||
Self::IndepClause(clause)
|
||||
}
|
||||
|
||||
pub fn indep_clause(&self) -> Option<SPair> {
|
||||
match self {
|
||||
Self::IndepClause(spair) => Some(*spair),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn span(&self) -> Span {
|
||||
match self {
|
||||
Self::IndepClause(spair) => spair.span(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object_rel! {
|
||||
/// Templates may expand into nearly any context,
|
||||
/// and must therefore be able to contain just about anything.
|
||||
Doc -> {
|
||||
// empty
|
||||
}
|
||||
}
|
|
@ -19,15 +19,14 @@
|
|||
|
||||
//! Expressions on the ASG.
|
||||
|
||||
use std::fmt::Display;
|
||||
|
||||
use super::{prelude::*, Ident, Tpl};
|
||||
use super::{prelude::*, Doc, Ident, Tpl};
|
||||
use crate::{
|
||||
f::Functor,
|
||||
num::Dim,
|
||||
parse::{util::SPair, Token},
|
||||
span::Span,
|
||||
};
|
||||
use std::fmt::Display;
|
||||
|
||||
#[cfg(doc)]
|
||||
use super::ObjectKind;
|
||||
|
@ -222,6 +221,7 @@ object_rel! {
|
|||
Expr -> {
|
||||
cross Ident,
|
||||
tree Expr,
|
||||
tree Doc,
|
||||
|
||||
// Template application
|
||||
tree Tpl,
|
||||
|
@ -253,4 +253,15 @@ impl ObjectIndex<Expr> {
|
|||
let identi = asg.lookup_global_or_missing(ident);
|
||||
self.add_edge_to(asg, identi, Some(ident.span()))
|
||||
}
|
||||
|
||||
/// Describe this expression using a short independent clause.
|
||||
///
|
||||
/// This is intended to be a concise description for use either as a
|
||||
/// simple sentence or as part of a compound sentence.
|
||||
/// There should only be one such clause for any given object,
|
||||
/// but that is not enforced here.
|
||||
pub fn desc_short(&self, asg: &mut Asg, clause: SPair) -> Self {
|
||||
let oi_doc = asg.create(Doc::new_indep_clause(clause));
|
||||
self.add_edge_to(asg, oi_doc, None)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,8 +22,8 @@
|
|||
//! See (parent module)[super] for more information.
|
||||
|
||||
use super::{
|
||||
Expr, Ident, Meta, Object, ObjectIndex, ObjectKind, OiPairObjectInner, Pkg,
|
||||
Root,
|
||||
Doc, Expr, Ident, Meta, Object, ObjectIndex, ObjectKind, OiPairObjectInner,
|
||||
Pkg, Root,
|
||||
};
|
||||
use crate::{
|
||||
asg::{graph::object::Tpl, Asg},
|
||||
|
@ -317,7 +317,7 @@ impl<S> DynObjectRel<S, ObjectIndex<Object>> {
|
|||
}
|
||||
}
|
||||
|
||||
ty_cross_edge!(Root, Pkg, Ident, Expr, Tpl, Meta)
|
||||
ty_cross_edge!(Root, Pkg, Ident, Expr, Tpl, Meta, Doc)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
//! or observing template expansions.
|
||||
|
||||
use super::object::{
|
||||
DynObjectRel, Expr, Meta, Object, ObjectIndex, ObjectRelTy,
|
||||
Doc, DynObjectRel, Expr, Meta, Object, ObjectIndex, ObjectRelTy,
|
||||
OiPairObjectInner, Pkg, Tpl,
|
||||
};
|
||||
use crate::{
|
||||
|
@ -210,6 +210,10 @@ impl<'a> TreeContext<'a> {
|
|||
self.emit_tpl_arg(meta, *oi_meta, depth)
|
||||
}
|
||||
|
||||
Object::Doc((doc, oi_doc)) => {
|
||||
self.emit_doc(doc, *oi_doc, paired_rel.source())
|
||||
}
|
||||
|
||||
Object::Root(..) => diagnostic_unreachable!(
|
||||
vec![],
|
||||
"tree walk is not expected to emit Root",
|
||||
|
@ -285,10 +289,11 @@ impl<'a> TreeContext<'a> {
|
|||
ExprOp::Eq => Some(self.emit_match(expr, oi_expr, depth)),
|
||||
_ => Some(expr_ele(expr, oi_expr, depth)),
|
||||
},
|
||||
// TODO: Perhaps errors for Root and Meta?
|
||||
Object::Root(_) | Object::Pkg(_) | Object::Meta(_) => {
|
||||
Some(expr_ele(expr, oi_expr, depth))
|
||||
}
|
||||
// TODO: Perhaps errors for Root, Meta, and Doc?
|
||||
Object::Root(_)
|
||||
| Object::Pkg(_)
|
||||
| Object::Meta(_)
|
||||
| Object::Doc(_) => Some(expr_ele(expr, oi_expr, depth)),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -474,6 +479,30 @@ impl<'a> TreeContext<'a> {
|
|||
))
|
||||
}
|
||||
|
||||
/// Emit short documentation strings.
|
||||
///
|
||||
/// This derives e.g. `@desc`.
|
||||
fn emit_doc(
|
||||
&mut self,
|
||||
doc: &Doc,
|
||||
oi_doc: ObjectIndex<Doc>,
|
||||
src: &Object<OiPairObjectInner>,
|
||||
) -> Option<Xirf> {
|
||||
match src {
|
||||
// TODO: Non-stmt exprs should use `@label` instead.
|
||||
Object::Expr(..) => doc.indep_clause().map(attr_desc),
|
||||
|
||||
_ => {
|
||||
diagnostic_todo!(
|
||||
vec![oi_doc.internal_error(
|
||||
"this documentation is not supported in XIRF output"
|
||||
)],
|
||||
"unsupported documentation",
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn push(&mut self, tok: Xirf) {
|
||||
if self.stack.is_full() {
|
||||
diagnostic_panic!(
|
||||
|
@ -541,6 +570,10 @@ fn attr_value(val: SPair) -> Xirf {
|
|||
Xirf::attr(QN_VALUE, val, (val.span(), val.span()))
|
||||
}
|
||||
|
||||
fn attr_desc(desc: SPair) -> Xirf {
|
||||
Xirf::attr(QN_DESC, desc, (desc.span(), desc.span()))
|
||||
}
|
||||
|
||||
fn expr_ele(expr: &Expr, oi_expr: ObjectIndex<Expr>, depth: Depth) -> Xirf {
|
||||
use ExprOp::*;
|
||||
|
||||
|
|
|
@ -238,7 +238,11 @@ impl ParseState for NirToAir {
|
|||
Transition(Ready).ok(Air::RefIdent(spair))
|
||||
}
|
||||
|
||||
(Ready, Todo | TodoAttr(..) | Desc(..)) => {
|
||||
(Ready, Desc(clause)) => {
|
||||
Transition(Ready).ok(Air::DocIndepClause(clause))
|
||||
}
|
||||
|
||||
(Ready, Todo | TodoAttr(..)) => {
|
||||
Transition(Ready).ok(Air::Todo(UNKNOWN_SPAN))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -122,6 +122,33 @@ fn logic_exprs() {
|
|||
);
|
||||
}
|
||||
|
||||
// @desc becomes an independent clause,
|
||||
// intended for short summary documentation.
|
||||
#[test]
|
||||
fn desc_as_indep_clause() {
|
||||
let id = SPair("class".into(), S2);
|
||||
let desc = SPair("class desc".into(), S3);
|
||||
|
||||
#[rustfmt::skip]
|
||||
let toks = vec![
|
||||
Open(Classify, S1),
|
||||
BindIdent(id),
|
||||
Desc(desc),
|
||||
Close(Classify, S4),
|
||||
];
|
||||
|
||||
assert_eq!(
|
||||
#[rustfmt::skip]
|
||||
Ok(vec![
|
||||
O(Air::ExprStart(ExprOp::Conj, S1)),
|
||||
O(Air::BindIdent(id)),
|
||||
O(Air::DocIndepClause(desc)),
|
||||
O(Air::ExprEnd(S4)),
|
||||
]),
|
||||
Sut::parse(toks.into_iter()).collect(),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tpl_with_name() {
|
||||
let name = SPair("_tpl_name_".into(), S2);
|
||||
|
|
|
@ -392,7 +392,7 @@ ele_parse! {
|
|||
ClassifyStmt := QN_CLASSIFY(_, ospan) {
|
||||
@ {
|
||||
QN_AS => BindIdent,
|
||||
QN_DESC => TodoAttr,
|
||||
QN_DESC => Desc,
|
||||
QN_ANY => TodoAttr,
|
||||
QN_YIELDS => TodoAttr,
|
||||
QN_SYM => TodoAttr,
|
||||
|
|
|
@ -3,9 +3,9 @@
|
|||
xmlns:c="http://www.lovullo.com/calc"
|
||||
xmlns:t="http://www.lovullo.com/rater/apply-template">
|
||||
|
||||
<classify as="always" />
|
||||
<classify as="always" desc="Always" />
|
||||
|
||||
<classify as="sometimes">
|
||||
<classify as="sometimes" desc="Sometimes">
|
||||
<any>
|
||||
<all />
|
||||
<any />
|
||||
|
@ -14,11 +14,15 @@
|
|||
<any />
|
||||
</classify>
|
||||
|
||||
<classify as="short-match-implicit-eq-implicit-true">
|
||||
<classify as="short-match-implicit-eq-implicit-true"
|
||||
desc="Short match with implicit eq and
|
||||
an implicit value">
|
||||
<match on="foo" value="TRUE" />
|
||||
</classify>
|
||||
|
||||
<classify as="short-match-implicit-eq-explicit-value">
|
||||
<classify as="short-match-implicit-eq-explicit-value"
|
||||
desc="Short match with an implicit eq and
|
||||
an explicit value">
|
||||
<match on="foo" value="bar" />
|
||||
</classify>
|
||||
</package>
|
||||
|
|
|
@ -3,9 +3,9 @@
|
|||
xmlns:c="http://www.lovullo.com/calc"
|
||||
xmlns:t="http://www.lovullo.com/rater/apply-template">
|
||||
|
||||
<classify as="always" />
|
||||
<classify as="always" desc="Always" />
|
||||
|
||||
<classify as="sometimes">
|
||||
<classify as="sometimes" desc="Sometimes">
|
||||
<any>
|
||||
<all />
|
||||
<any />
|
||||
|
@ -14,11 +14,15 @@
|
|||
<any />
|
||||
</classify>
|
||||
|
||||
<classify as="short-match-implicit-eq-implicit-true">
|
||||
<classify as="short-match-implicit-eq-implicit-true"
|
||||
desc="Short match with implicit eq and
|
||||
an implicit value">
|
||||
<match on="foo" />
|
||||
</classify>
|
||||
|
||||
<classify as="short-match-implicit-eq-explicit-value">
|
||||
<classify as="short-match-implicit-eq-explicit-value"
|
||||
desc="Short match with an implicit eq and
|
||||
an explicit value">
|
||||
<match on="foo" value="bar" />
|
||||
</classify>
|
||||
</package>
|
||||
|
|
Loading…
Reference in New Issue