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;
pub(super) type MidParseResult = NarseseOptions<Budget, Term, Punctuation, Stamp, Truth>;
#[derive(Parser)] #[grammar = "src/cin_implements/opennars/dialect_opennars.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("无效的中间结果"),
}
}
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(())
}
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)
}
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)
}
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}"),
}
}
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 })
}
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_operation => {
let mut pairs = pair.into_inner();
let predicate = fold_pest_term(pairs.next().unwrap())?;
let mut subject_terms = vec![];
for pair in pairs {
subject_terms.push(fold_pest_term(pair)?);
}
Ok(Term::Statement {
copula: FORMAT_ASCII.statement.copula_inheritance.into(),
subject: Box::new(Term::Compound {
connecter: FORMAT_ASCII.compound.connecter_product.into(),
terms: subject_terms,
}),
predicate: Box::new(predicate),
})
}
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}"),
}
}
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 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 形式有变的 = vec![];
let narseses = "
_
__
___
<(&|,(^want,{SELF},$1,FALSE),(^anticipate,{SELF},$1)) =|> <(*,{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>,(^lighter,{SELF},$1)) =/> <$1 --> [heated]>>.
<<$1 --> [heated]> =/> <$1 --> [melted]>>.
<<$1 --> [melted]> <|> <$1 --> [pliable]>>.
<(&/,<$1 --> [pliable]>,(^reshape,{SELF},$1)) =/> <$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>. :|:
<(&|,(^want,{SELF},$1,FALSE),(^anticipate,{SELF},$1)) =|> <(*,{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>,(^lighter,{SELF},$1)) =/> <$1 --> [heated]>>.
<<$1 --> [heated]> =/> <$1 --> [melted]>>.
<<$1 --> [melted]> <|> <$1 --> [pliable]>>.
<(&/,<$1 --> [pliable]>,(^reshape,{SELF},$1)) =/> <$1 --> [hardened]>>.
<<$1 --> [hardened]> =|> <$1 --> [unscrewing]>>.
(&&,<#1 --> object>,<#1 --> [unscrewing]>)!
"
.split('\n')
.map(str::trim)
.filter(|l| !l.is_empty());
let 去掉空格 = |s: &str| s.chars().filter(|c| !c.is_whitespace()).collect::<String>();
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,
_ => 形式有变的.push((去掉空格(narsese), 去掉空格(&parsed_str))),
}
}
println!("✅直接相等的个数:{直接相等的个数}");
println!("✅删去空格后相等的个数:{删去空格后相等的个数}");
println!("⚠️形式有变的个数:{}", 形式有变的.len());
for (n, (narsese, parsed_str)) in 形式有变的.iter().enumerate() {
println!(" {n}:\n\t{narsese:?}\n =?>\t{:?}", parsed_str);
}
println!("测试完毕!");
}
}