#![forbid(unsafe_code)]
#![warn(missing_docs)]
mod classify;
mod error;
mod rules;
pub mod tagger;
pub mod text;
mod triple;
use std::collections::HashMap;
pub use error::ParseError;
pub use tagger::{LexiconTagger, Tagger};
pub use triple::{Predicate, Term, Triple};
use classify::classify;
use rules::{Rules, build_triple, process};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum Ambiguity {
#[default]
FirstMatch,
Error,
}
pub struct Nl3 {
rules: Rules,
tagger: Box<dyn Tagger>,
ambiguity: Ambiguity,
}
impl Nl3 {
pub fn builder() -> Nl3Builder {
Nl3Builder::default()
}
pub fn parse(&self, text: &str) -> Result<Triple, ParseError> {
if text.trim().is_empty() {
return Err(ParseError::EmptyInput);
}
let classification = classify(text, self.tagger.as_ref());
let triple = build_triple(&classification, &self.rules);
process(triple, &classification, &self.rules, self.ambiguity)
}
}
#[derive(Default)]
pub struct Nl3Builder {
grammar: Vec<String>,
vocabulary: HashMap<String, String>,
tagger: Option<Box<dyn Tagger>>,
ambiguity: Ambiguity,
}
impl Nl3Builder {
pub fn grammar<I, S>(mut self, grammar: I) -> Self
where
I: IntoIterator<Item = S>,
S: Into<String>,
{
self.grammar = grammar.into_iter().map(Into::into).collect();
self
}
pub fn vocabulary<I, K, V>(mut self, vocabulary: I) -> Self
where
I: IntoIterator<Item = (K, V)>,
K: Into<String>,
V: Into<String>,
{
self.vocabulary = vocabulary
.into_iter()
.map(|(k, v)| (k.into(), v.into()))
.collect();
self
}
pub fn tagger(mut self, tagger: impl Tagger + 'static) -> Self {
self.tagger = Some(Box::new(tagger));
self
}
pub fn ambiguity(mut self, ambiguity: Ambiguity) -> Self {
self.ambiguity = ambiguity;
self
}
pub fn build(self) -> Nl3 {
Nl3 {
rules: Rules::build(&self.grammar, self.vocabulary),
tagger: self.tagger.unwrap_or_else(|| Box::new(LexiconTagger)),
ambiguity: self.ambiguity,
}
}
}