pub mod kw {
#![allow(missing_docs)] pub const DOMAIN: &str = "DOMAIN";
pub const IMPORT: &str = "IMPORT";
pub const AS: &str = "AS";
pub const FACT: &str = "FACT";
pub const NOT: &str = "NOT";
pub const ASSUME: &str = "ASSUME";
pub const PREMISE: &str = "PREMISE";
pub const RULE: &str = "RULE";
pub const CHECK: &str = "CHECK";
pub const BIDIRECTIONAL: &str = "BIDIRECTIONAL";
pub const WHEN: &str = "WHEN";
pub const THEN: &str = "THEN";
pub const AND: &str = "AND";
pub const OR: &str = "OR";
pub const EXCLUSIVE: &str = "EXCLUSIVE";
pub const FORBIDS: &str = "FORBIDS";
pub const ONEOF: &str = "ONEOF";
pub const ATLEAST: &str = "ATLEAST";
}
#[derive(Clone, Copy, PartialEq, Eq)]
pub struct Card {
pub form: &'static str,
pub gloss: &'static str,
pub example: &'static str,
}
pub struct Keyword {
pub text: &'static str,
pub top_level: bool,
pub card: Card,
}
const fn card(form: &'static str, gloss: &'static str, example: &'static str) -> Card {
Card {
form,
gloss,
example,
}
}
pub const KEYWORDS: &[Keyword] = &[
Keyword {
text: kw::DOMAIN,
top_level: true,
card: card(
"DOMAIN <name>",
"declare this file's domain (required, once, first) — the namespace bare atoms fall into",
"DOMAIN physics",
),
},
Keyword {
text: kw::FACT,
top_level: true,
card: card(
"FACT [<domain>.]<Subject> <predicate> [<object>]",
"assert an atom is TRUE",
"FACT socrates is human",
),
},
Keyword {
text: kw::NOT,
top_level: true,
card: card(
"NOT <Subject> <predicate> [<object>]",
"assert an atom is FALSE",
"NOT socrates is immortal",
),
},
Keyword {
text: kw::ASSUME,
top_level: true,
card: card(
"ASSUME [NOT] <Subject> <predicate> [<object>]",
"a soft, retractable hypothesis (the solver may ask you to drop it)",
"ASSUME release is_ready",
),
},
Keyword {
text: kw::PREMISE,
top_level: true,
card: card(
"PREMISE <name>: then a list body or a WHEN ... THEN implication",
"a checked first principle (a constraint that must hold)",
"PREMISE wings:\n WHEN bird has feathers\n THEN bird can_fly",
),
},
Keyword {
text: kw::RULE,
top_level: true,
card: card(
"RULE <name>: then a WHEN ... THEN implication",
"an inference rule: when the WHEN holds, it derives the THEN as a fact",
"RULE mortal:\n WHEN x is human\n THEN x is mortal",
),
},
Keyword {
text: kw::CHECK,
top_level: true,
card: card(
"CHECK [<subject>] [BIDIRECTIONAL]",
"run the query; an optional subject narrows the report",
"CHECK socrates",
),
},
Keyword {
text: kw::IMPORT,
top_level: true,
card: card(
"IMPORT \"<path>\" [AS <alias>]",
"pull in another .vrf source for reuse; its atoms are named <domain>.<atom>",
"IMPORT \"physics.vrf\"",
),
},
Keyword {
text: kw::AS,
top_level: false,
card: card(
"IMPORT \"<path>\" AS <alias>",
"give the imported domain a local name to reference it by",
"IMPORT \"physics.vrf\" AS phys",
),
},
Keyword {
text: kw::WHEN,
top_level: false,
card: card(
"WHEN <literal> (literal = [NOT] <Subject> <predicate> [<object>])",
"the condition (if-part) of an implication; continue with AND/OR",
"WHEN motor over_100",
),
},
Keyword {
text: kw::THEN,
top_level: false,
card: card(
"THEN <literal>",
"the conclusion (then-part) of an implication; continue with AND/OR",
"THEN motor uses fast_path",
),
},
Keyword {
text: kw::AND,
top_level: false,
card: card(
"AND <literal>",
"extend the current WHEN or THEN group (all must hold); do not mix with OR",
"AND motor is reviewed",
),
},
Keyword {
text: kw::OR,
top_level: false,
card: card(
"OR <literal>",
"extend the current WHEN or THEN group (at least one holds); do not mix with AND",
"OR motor is hotfixed",
),
},
Keyword {
text: kw::EXCLUSIVE,
top_level: false,
card: card(
"EXCLUSIVE then one atom per line (>= 2 atoms)",
"at most one of the listed atoms may be TRUE",
"EXCLUSIVE\n light is on\n light is off",
),
},
Keyword {
text: kw::FORBIDS,
top_level: false,
card: card(
"FORBIDS then one atom per line (>= 2 atoms)",
"at most one may be TRUE (a synonym of EXCLUSIVE)",
"FORBIDS\n door is open\n door is locked",
),
},
Keyword {
text: kw::ONEOF,
top_level: false,
card: card(
"ONEOF then one atom per line (>= 2 atoms)",
"exactly one of the listed atoms is TRUE",
"ONEOF\n mode is idle\n mode is run",
),
},
Keyword {
text: kw::ATLEAST,
top_level: false,
card: card(
"ATLEAST then one atom per line (>= 2 atoms)",
"at least one of the listed atoms is TRUE",
"ATLEAST\n plan has tests\n plan has review",
),
},
Keyword {
text: kw::BIDIRECTIONAL,
top_level: false,
card: card(
"CHECK [<subject>] BIDIRECTIONAL",
"a CHECK modifier: also run the backward pass (finds UNDERDETERMINED)",
"CHECK BIDIRECTIONAL",
),
},
];
pub fn is_reserved(word: &str) -> bool {
KEYWORDS.iter().any(|k| k.text == word)
}
pub fn is_top_level(word: &str) -> bool {
KEYWORDS.iter().any(|k| k.top_level && k.text == word)
}
pub fn card_for(keyword: &str) -> Option<&'static Card> {
KEYWORDS.iter().find(|k| k.text == keyword).map(|k| &k.card)
}
pub fn top_level_forms() -> impl Iterator<Item = &'static Keyword> {
KEYWORDS.iter().filter(|k| k.top_level)
}
pub fn keyword_in(message: &str) -> Option<&'static str> {
message
.split(|c: char| !c.is_ascii_alphabetic())
.find_map(|w| KEYWORDS.iter().map(|k| k.text).find(|t| *t == w))
}