use crate::runtimes::TranslateError;
use anyhow::{Ok, Result};
use narsese::{
api::NarseseOptions,
conversion::string::impl_enum::format_instances::FORMAT_ASCII,
lexical::{Budget, Narsese, Punctuation, Stamp, Term, Truth},
};
use pest::{iterators::Pair, Parser};
use pest_derive::Parser;
type MidParseResult = NarseseOptions<Budget, Term, Punctuation, Stamp, Truth>;
#[derive(Parser)] #[grammar = "src/cin_implements/ona/dialect_ona.pest"]
pub struct DialectParser;
pub fn parse(input: &str) -> Result<Narsese> {
let pair = DialectParser::parse(Rule::narsese, input)?.next().unwrap();
let folded = fold_pest(pair)?;
Ok(folded)
}
fn fold_pest(pest_parsed: Pair<Rule>) -> Result<Narsese> {
let mut mid_result = MidParseResult {
budget: None,
term: None,
punctuation: None,
stamp: None,
truth: None,
};
fold_pest_procedural(pest_parsed, &mut mid_result)?;
match mid_result.fold() {
Some(narsese) => Ok(narsese),
None => TranslateError::err_anyhow("无效的中间结果"),
}
}
pub(super) fn fold_pest_procedural(pair: Pair<Rule>, result: &mut MidParseResult) -> Result<()> {
match pair.as_rule() {
Rule::WHITESPACE | Rule::narsese | Rule::budget_content | Rule::term => {
unreachable!("规则{:?}不会被匹配到!{pair:?}", pair.as_rule())
}
Rule::task => {
for pair in pair.into_inner() {
fold_pest_procedural(pair, result)?;
}
}
Rule::budget => result.budget = Some(fold_pest_budget(pair)?),
Rule::sentence => {
for pair in pair.into_inner() {
fold_pest_procedural(pair, result)?;
}
}
Rule::statement => result.term = Some(fold_pest_statement(pair)?),
Rule::compound => result.term = Some(fold_pest_compound(pair)?),
Rule::atom => result.term = Some(fold_pest_atom(pair)?),
Rule::punctuation => result.punctuation = Some(pair.as_str().into()),
Rule::stamp => result.stamp = Some(pair.as_str().into()),
Rule::truth => result.truth = Some(fold_pest_truth(pair)?),
_ => unreachable!("仅出现在内部解析的不可达规则!{:?}{pair}", pair.as_rule()),
}
Ok(())
}
pub(super) fn fold_pest_truth(pair: Pair<Rule>) -> Result<Truth> {
let mut v = Truth::new();
for pair_value_str in pair.into_inner() {
v.push(pair_value_str.as_str().to_string());
}
Ok(v)
}
pub(super) fn fold_pest_budget(pair: Pair<Rule>) -> Result<Budget> {
let mut v = Budget::new();
for pair_value_str in pair.into_inner() {
v.push(pair_value_str.as_str().to_string());
}
Ok(v)
}
pub(super) fn fold_pest_term(pair: Pair<Rule>) -> Result<Term> {
match pair.as_rule() {
Rule::atom => fold_pest_atom(pair),
Rule::compound => fold_pest_compound(pair),
Rule::statement => fold_pest_statement(pair),
_ => unreachable!("词项只有可能是原子、复合与陈述 | {pair}"),
}
}
pub(super) fn fold_pest_atom(pair: Pair<Rule>) -> Result<Term> {
let mut prefix = String::new();
let mut name = String::new();
for pair in pair.into_inner() {
let pair_str = pair.as_str();
match pair.as_rule() {
Rule::atom_prefix => prefix.push_str(pair_str),
Rule::atom_content => name.push_str(pair_str),
Rule::placeholder => {
prefix.push('_');
if pair_str.len() > 1 {
name.push_str(&pair_str[1..]);
}
}
_ => unreachable!("原子词项只可能有「占位符」或「前缀+名称(内容)」两种 | {pair}"),
}
}
Ok(Term::Atom { prefix, name })
}
pub(super) fn fold_pest_compound(pair: Pair<Rule>) -> Result<Term> {
let pair = pair.into_inner().next().unwrap();
match pair.as_rule() {
Rule::compound_common => {
let mut pairs = pair.into_inner();
let connecter = pairs.next().unwrap().as_str().into();
let mut terms = vec![];
for pair in pairs {
terms.push(fold_pest_term(pair)?);
}
Ok(Term::Compound { connecter, terms })
}
Rule::compound_binary => {
let mut pairs = pair.into_inner();
let left = fold_pest_term(pairs.next().unwrap())?;
let connecter = pairs.next().unwrap().as_str().to_string();
let right = fold_pest_term(pairs.next().unwrap())?;
Ok(Term::Compound {
connecter,
terms: vec![left, right],
})
}
Rule::ext_set => {
let mut terms = vec![];
for pair in pair.into_inner() {
terms.push(fold_pest_term(pair)?);
}
Ok(Term::Set {
left_bracket: FORMAT_ASCII.compound.brackets_set_extension.0.into(),
terms,
right_bracket: FORMAT_ASCII.compound.brackets_set_extension.1.into(),
})
}
Rule::int_set => {
let mut terms = vec![];
for pair in pair.into_inner() {
terms.push(fold_pest_term(pair)?);
}
Ok(Term::Set {
left_bracket: FORMAT_ASCII.compound.brackets_set_intension.0.into(),
terms,
right_bracket: FORMAT_ASCII.compound.brackets_set_intension.1.into(),
})
}
_ => unreachable!("复合词项只可能是「通用」「操作」「外延集」「内涵集」四种 | {pair}"),
}
}
pub(super) fn fold_pest_statement(pair: Pair<Rule>) -> Result<Term> {
let mut pairs = pair.into_inner();
let subject = fold_pest_term(pairs.next().unwrap())?;
let copula = pairs.next().unwrap().as_str();
let predicate = fold_pest_term(pairs.next().unwrap())?;
Ok(Term::new_statement(copula, subject, predicate))
}
#[cfg(test)]
mod tests {
use std::collections::HashSet;
use super::*;
use nar_dev_utils::first;
use narsese::conversion::string::impl_lexical::format_instances::FORMAT_ASCII;
#[test]
fn test_dialect_parser() {
let mut 直接相等的个数: usize = 0;
let mut 删去空格与分隔符后相等的个数: usize = 0;
let mut 去掉空格与分隔符_字符重排后相等的个数: usize = 0; let mut 形式有变的 = vec![];
let narseses = "
(* {SELF})
({SELF} * x)
<(&|,<(*,{SELF},$1,FALSE)-->^want>,<(*,{SELF},$1)-->^anticipate>) =|> <(*,{SELF},$1) --> afraid_of>>.
<A --> B>.
{A, B}
<{tim} --> (/,livingIn,_,{graz})>. %0%
<<(*,$1,sunglasses) --> own> ==> <$1 --> [aggressive]>>.
<(*,{tom},sunglasses) --> own>.
<<$1 --> [aggressive]> ==> <$1 --> murder>>.
<<$1 --> (/,livingIn,_,{graz})> ==> <$1 --> murder>>.
<{?who} --> murder>?
<{tim} --> (/,livingIn,_,{graz})>.
<{tim} --> (/,livingIn,_,{graz})>. %0%
<<(*,$1,sunglasses) --> own> ==> <$1 --> [aggressive]>>.
<(*,{tom},(&,[black],glasses)) --> own>.
<<$1 --> [aggressive]> ==> <$1 --> murder>>.
<<$1 --> (/,livingIn,_,{graz})> ==> <$1 --> murder>>.
<sunglasses --> (&,[black],glasses)>.
<{?who} --> murder>?
<(*,toothbrush,plastic) --> made_of>.
<(&/,<(*,$1,plastic) --> made_of>,<(*,{SELF},$1)-->^lighter>) =/> <$1 --> [heated]>>.
<<$1 --> [heated]> =/> <$1 --> [melted]>>.
<<$1 --> [melted]> <|> <$1 --> [pliable]>>.
<(&/,<$1 --> [pliable]>,<(*,{SELF},$1)-->^reshape>) =/> <$1 --> [hardened]>>.
<<$1 --> [hardened]> =|> <$1 --> [unscrewing]>>.
<toothbrush --> object>.
(&&,<#1 --> object>,<#1 --> [unscrewing]>)!
<{SELF} --> [hurt]>! %0%
<{SELF} --> [hurt]>. :|: %0%
<(&/,<(*,{SELF},wolf) --> close_to>,+1000) =/> <{SELF} --> [hurt]>>.
<(*,{SELF},wolf) --> close_to>. :|:
<(&|,<(*,{SELF},$1,FALSE)-->^want>,<(*,{SELF},$1)-->^anticipate>) =|> <(*,{SELF},$1) --> afraid_of>>.
<(*,{SELF},?what) --> afraid_of>?
<a --> A>. :|: %1.00;0.90%
<b --> B>. :|: %1.00;0.90%
<c --> C>. :|: %1.00;0.90%
<a --> A>. :|: %1.00;0.90%
<b --> B>. :|: %1.00;0.90%
<?1 =/> <c --> C>>?
<(*,cup,plastic) --> made_of>.
<cup --> object>.
<cup --> [bendable]>.
<toothbrush --> [bendable]>.
<toothbrush --> object>.
<(&/,<(*,$1,plastic) --> made_of>,<(*,{SELF},$1)-->^lighter>) =/> <$1 --> [heated]>>.
<<$1 --> [heated]> =/> <$1 --> [melted]>>.
<<$1 --> [melted]> <|> <$1 --> [pliable]>>.
<(&/,<$1 --> [pliable]>,<(*,{SELF},$1)-->^reshape>) =/> <$1 --> [hardened]>>.
<<$1 --> [hardened]> =|> <$1 --> [unscrewing]>>.
(&&,<#1 --> object>,<#1 --> [unscrewing]>)!
<{redInst} |-> [red]>. :|: %1.0%
<{redInst} |-> [green]>. :|: %0.0%
<{redInst} |-> [blue]>. :|: %0.0%
<{greenInst} |-> [red]>. :|: %0.0%
<{greenInst} |-> [green]>. :|: %1.0%
<{greenInst} |-> [blue]>. :|: %0.0%
<{blueInst} |-> [red]>. :|: %0.0%
<{blueInst} |-> [green]>. :|: %0.0%
<{blueInst} |-> [blue]>. :|: %1.0%
<{newColor} |-> [red]>. :|: %0.0%
<{newColor} |-> [green]>. :|: %0.0%
<{newColor} |-> [blue]>. :|: %0.1%
<{?what} <-> {newColor}>? :|:
<{blueInst} <-> {newColor}>. :|: %1.000000;0.810000%
<({blueInst} * {newColor}) --> (+ blue)>? :|:
<({blueInst} * {newColor}) --> (+ blue)>. :|: %1.000000;0.810000%
<{cat} --> [meowing]>. :|: %0.6%
<{cat} --> [barking]>. :|: %0.0%
<(<({#1} ~ {#2}) --> [meowing]> &/ <({SELF} * #1) --> ^say>) =/> G>.
G! :|:
<{dog} --> [barking]>. :|: %1.0%
<{dog} --> [meowing]>. :|: %0.3%
<({cat} ~ {dog}) --> [meowing]>? :|:
<({cat} ~ {dog}) --> [meowing]>. :|: %1.000000;0.810000%
G! :|:
({SELF} * cat)
<(<obstacle --> [left]> &/ ^right) =/> <obstacle --> [free]>>.
<(<obstacle --> [right]> &/ ^left) =/> <obstacle --> [free]>>.
<(<obstacle --> [front]> &/ ^left) =/> <obstacle --> [free]>>.
<((<gripper --> [open]> &/ <obstacle --> [free]>) &/ ^forward) =/> G>.
<(<gripper --> [hold]> &/ <({SELF} * $obj) --> ^goto>) =/> <$obj --> [left]>>.
<(<gripper --> [hold]> &/ <({SELF} * $obj) --> ^goto>) =/> <$obj --> [front]>>.
<(<gripper --> [hold]> &/ <({SELF} * $obj) --> ^goto>) =/> <$obj --> [right]>>.
<((<gripper --> [open]> &/ <bottle --> [left]>) &/ <({SELF} * bottle) --> ^pick>) =/> G>.
<((<gripper --> [open]> &/ <bottle --> [front]>) &/ <({SELF} * bottle) --> ^pick>) =/> G>.
<((<gripper --> [open]> &/ <bottle --> [right]>) &/ <({SELF} * bottle) --> ^pick>) =/> G>.
<((<gripper --> [hold]> &/ <person --> [left]>) &/ ^drop) =/> G>.
<((<gripper --> [hold]> &/ <person --> [front]>) &/ ^drop) =/> G>.
<((<gripper --> [hold]> &/ <person --> [right]>) &/ ^drop) =/> G>.
"
.split('\n')
.map(str::trim)
.filter(|l| !l.is_empty());
let 去掉空格与分隔符 = |s: &str| {
s.chars()
.filter(|c| !c.is_whitespace() && *c != ',')
.collect::<String>()
};
let 去掉空格与分隔符_字符集合 = |s: &str| {
s.chars()
.filter(|c| !c.is_whitespace() && *c != ',')
.collect::<HashSet<_>>()
};
for narsese in narseses {
let parsed = parse(narsese).expect("pest解析失败!");
let parsed_str = FORMAT_ASCII.format_narsese(&parsed);
println!(" {narsese:?}\n => {:?}", parsed_str);
first! {
narsese == parsed_str => 直接相等的个数 += 1,
去掉空格与分隔符(narsese) == 去掉空格与分隔符(&parsed_str) => 删去空格与分隔符后相等的个数 += 1,
去掉空格与分隔符_字符集合(narsese) == 去掉空格与分隔符_字符集合(&parsed_str) => 去掉空格与分隔符_字符重排后相等的个数 += 1,
_ => 形式有变的.push((去掉空格与分隔符(narsese), 去掉空格与分隔符(&parsed_str), parsed)),
}
}
println!("✅直接相等的个数:{直接相等的个数}");
println!("✅删去空格与分隔符后相等的个数:{删去空格与分隔符后相等的个数}");
println!(
"✅去掉空格与分隔符_字符重排后相等的个数:{去掉空格与分隔符_字符重排后相等的个数}"
);
println!("⚠️形式有变的个数:{}", 形式有变的.len());
for (n, (narsese, parsed_str, parsed)) in 形式有变的.iter().enumerate() {
println!(" {n}:\n\t{narsese:?}\n =?>\t{:?}", parsed_str);
let len_diff = parsed_str.len().abs_diff(narsese.len());
if len_diff as f64 / narsese.len() as f64 > 0.5 {
println!("❗长度有较大变化( 变化量={len_diff} ):{parsed:#?}");
}
}
assert!(形式有变的.is_empty(), "❌出现形式有变的解析结果!");
println!("测试完毕!");
}
}