summaryrefslogtreecommitdiff
path: root/support/texlab/src/citeproc/name/parser.lalrpop
diff options
context:
space:
mode:
Diffstat (limited to 'support/texlab/src/citeproc/name/parser.lalrpop')
-rw-r--r--support/texlab/src/citeproc/name/parser.lalrpop152
1 files changed, 152 insertions, 0 deletions
diff --git a/support/texlab/src/citeproc/name/parser.lalrpop b/support/texlab/src/citeproc/name/parser.lalrpop
new file mode 100644
index 0000000000..556e3bd361
--- /dev/null
+++ b/support/texlab/src/citeproc/name/parser.lalrpop
@@ -0,0 +1,152 @@
+// Ported from: https://github.com/michel-kraemer/citeproc-java/blob/master/citeproc-java/grammars/InternalName.g4
+// Michel Kraemer
+// Apache License 2.0
+use citeproc_io::{Name, PersonName};
+use itertools::Itertools;
+
+grammar;
+
+pub Names: Vec<Name> = And<Name>;
+
+And<T>: Vec<T> = {
+ <v:(<T> "and")*> <e:T?> => match e {
+ None => v,
+ Some(e) => {
+ let mut v = v;
+ v.push(e);
+ v
+ }
+ }
+};
+
+Name: Name = {
+ <np1:UWord+> <np2:Von> <fam:Last> "," <fst:First> => {
+ let (fst1, fst2) = fst;
+ let name = PersonName {
+ family: Some(fam.join(" ")),
+ given: fst2,
+ non_dropping_particle: Some(format!("{} {}", np1.join(" "), np2)),
+ dropping_particle: None,
+ suffix: fst1,
+ };
+ Name::Person(name)
+ },
+ <np:Von> <fam:Last> "," <fst:First> => {
+ let (fst1, fst2) = fst;
+ let name = PersonName {
+ family: Some(fam.join(" ")),
+ given: fst2,
+ non_dropping_particle: Some(np),
+ dropping_particle: None,
+ suffix: fst1,
+ };
+ Name::Person(name)
+ },
+ <last:Last> "," <fst:First> => {
+ let (fst1, fst2) = fst;
+ let first_text = format!(
+ "{} {}",
+ fst1.as_ref().map(|s| s.as_str()).unwrap_or_default(),
+ fst2.as_ref().map(|s| s.as_str()).unwrap_or_default(),
+ ).trim().to_owned();
+
+ let name = if first_text == "Jr." {
+ if last.len() == 1 {
+ PersonName {
+ family: Some(last.join(" ")),
+ given: None,
+ non_dropping_particle: None,
+ dropping_particle: None,
+ suffix: Some(first_text),
+ }
+ } else {
+ let mut last = last.into_iter();
+ let given = last.next().map(ToOwned::to_owned);
+ PersonName {
+ family: Some(last.join(" ")),
+ given,
+ non_dropping_particle: None,
+ dropping_particle: None,
+ suffix: Some(first_text),
+ }
+ }
+ } else {
+ PersonName {
+ family: Some(last.join(" ")),
+ given: fst2,
+ non_dropping_particle: None,
+ dropping_particle: None,
+ suffix: fst1,
+ }
+ };
+ Name::Person(name)
+ },
+ <np:Von> <fam:Last> => {
+ let name = PersonName {
+ family: Some(fam.join(" ")),
+ given: None,
+ non_dropping_particle: Some(np),
+ dropping_particle: None,
+ suffix: None,
+ };
+ Name::Person(name)
+ },
+ <giv:UWord+> <np:Von> <fam:Last> => {
+ let name = PersonName {
+ family: Some(fam.join(" ")),
+ given: Some(giv.join(" ")),
+ non_dropping_particle: Some(np),
+ dropping_particle: None,
+ suffix: None,
+ };
+ Name::Person(name)
+ },
+ <giv:UWord+> <fam:Word> => {
+ let name = PersonName {
+ family: Some(fam.into()),
+ given: Some(giv.join(" ")),
+ non_dropping_particle: None,
+ dropping_particle: None,
+ suffix: None,
+ };
+ Name::Person(name)
+ },
+ <fam:Word> => {
+ let name = PersonName {
+ family: Some(fam.into()),
+ given: None,
+ non_dropping_particle: None,
+ dropping_particle: None,
+ suffix: None,
+ };
+ Name::Person(name)
+ },
+};
+
+First: (Option<String>, Option<String>) = {
+ <a:Word*> "," <b:Word*> => (Some(a.join(" ")), Some(b.join(" "))),
+ <a:Word*> => (None, Some(a.join(" "))),
+};
+
+Last: Vec<&'input str> = {
+ LWord => vec![(<>)],
+ UWord+ => (<>),
+};
+
+Von: String = {
+ LWord => String::from(<>),
+ <a:Von> <b:LWord> => format!("{} {}", a, b),
+ <a:Von> <b:UWord+> <c:LWord> => format!("{} {} {}", a, b.join(" "), c),
+};
+
+Word: &'input str = {
+ UWord => (<>),
+ LWord => (<>),
+};
+
+UWord: &'input str = r"[A-Z\u00C0-\uFFFF(?][A-Z\u00C0-\uFFFF(?a-z\-)&/.]+" => (<>);
+
+LWord: &'input str = r"[a-z\-)&/.][A-Z\u00C0-\uFFFF(?a-z\-)&/.]+" => (<>);
+
+
+