]> gitweb.fperrin.net Git - DictionaryPC.git/blob - src/com/hughes/android/dictionary/parser/enwiktionary/FunctionCallbacksDefault.java
Changed ordering of FormOf, handling of FormOf, handing of Encoding.
[DictionaryPC.git] / src / com / hughes / android / dictionary / parser / enwiktionary / FunctionCallbacksDefault.java
1 // Copyright 2012 Google Inc. All Rights Reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 package com.hughes.android.dictionary.parser.enwiktionary;
16
17 import java.util.Arrays;
18 import java.util.LinkedHashMap;
19 import java.util.LinkedHashSet;
20 import java.util.List;
21 import java.util.Map;
22 import java.util.Set;
23 import java.util.logging.Logger;
24
25 import com.hughes.android.dictionary.engine.EntryTypeName;
26 import com.hughes.android.dictionary.engine.IndexBuilder;
27 import com.hughes.android.dictionary.parser.WikiTokenizer;
28 import com.hughes.util.ListUtil;
29
30 public final class FunctionCallbacksDefault {
31   
32   static final Logger LOG = Logger.getLogger(EnWiktionaryXmlParser.class.getName());
33   
34   static final Map<String,FunctionCallback> DEFAULT = new LinkedHashMap<String, FunctionCallback>();
35   
36   static {
37     FunctionCallback callback = new TranslationCallback();
38     DEFAULT.put("t", callback);
39     DEFAULT.put("t+", callback);
40     DEFAULT.put("t-", callback);
41     DEFAULT.put("tø", callback);
42     DEFAULT.put("apdx-t", callback);
43     
44     callback = new EncodingCallback();
45     Set<String> encodings = new LinkedHashSet<String>(Arrays.asList(
46         "zh-ts", "zh-tsp",
47         "sd-Arab", "ku-Arab", "Arab", "unicode", "Laoo", "ur-Arab", "Thai", 
48         "fa-Arab", "Khmr", "Cyrl", "IPAchar", "ug-Arab", "ko-inline", 
49         "Jpan", "Kore", "Hebr", "rfscript", "Beng", "Mong", "Knda", "Cyrs",
50         "yue-tsj", "Mlym", "Tfng", "Grek", "yue-yue-j"));
51     for (final String encoding : encodings) {
52       DEFAULT.put(encoding, callback);
53     }
54     
55     callback = new l_term();
56     DEFAULT.put("l", callback);
57     DEFAULT.put("term", callback);
58
59     callback = new Gender();
60     DEFAULT.put("m", callback);
61     DEFAULT.put("f", callback);
62     DEFAULT.put("n", callback);
63     DEFAULT.put("p", callback);
64     DEFAULT.put("g", callback);
65     
66     callback = new AppendArg0();
67
68     callback = new Ignore();
69     DEFAULT.put("trreq", callback);
70     DEFAULT.put("t-image", callback);
71     DEFAULT.put("defn", callback);
72     DEFAULT.put("rfdef", callback);
73     DEFAULT.put("rfdate", callback);
74     DEFAULT.put("rfex", callback);
75     DEFAULT.put("rfquote", callback);
76     DEFAULT.put("attention", callback);
77     DEFAULT.put("zh-attention", callback);
78
79
80     callback = new FormOf();
81     DEFAULT.put("form of", callback);
82     DEFAULT.put("conjugation of", callback);
83     DEFAULT.put("participle of", callback);
84     DEFAULT.put("present participle of", callback);
85     DEFAULT.put("past participle of", callback);
86     DEFAULT.put("feminine past participle of", callback);
87     DEFAULT.put("gerund of", callback);
88     DEFAULT.put("feminine of", callback);
89     DEFAULT.put("plural of", callback);
90     DEFAULT.put("feminine plural of", callback);
91     DEFAULT.put("inflected form of", callback);
92     DEFAULT.put("alternative form of", callback);
93     DEFAULT.put("dated form of", callback);
94     DEFAULT.put("apocopic form of", callback);
95     
96     callback = new InflOrHead();
97     DEFAULT.put("infl", callback);
98     DEFAULT.put("head", callback);
99     
100     callback = new AppendName();
101     DEFAULT.put("...", callback);
102     
103     DEFAULT.put("qualifier", new QualifierCallback());
104     DEFAULT.put("italbrac", new italbrac());
105     DEFAULT.put("gloss", new gloss());
106     DEFAULT.put("not used", new not_used());
107     DEFAULT.put("wikipedia", new wikipedia());
108   }
109
110   
111   static final class NameAndArgs implements FunctionCallback {
112     @Override
113     public boolean onWikiFunction(final WikiTokenizer wikiTokenizer, final String name, final List<String> args,
114         final Map<String, String> namedArgs, final EnWiktionaryXmlParser parser,
115         final AppendAndIndexWikiCallback appendAndIndexWikiCallback) {
116       
117       appendAndIndexWikiCallback.builder.append(name);
118       for (int i = 0; i < args.size(); ++i) {
119         if (args.get(i).length() > 0) {
120           appendAndIndexWikiCallback.builder.append("|");
121           appendAndIndexWikiCallback.dispatch(args.get(i), null, null);
122         }
123       }
124       appendNamedArgs(namedArgs, appendAndIndexWikiCallback);
125       return true;
126     }
127   }
128   static NameAndArgs NAME_AND_ARGS = new NameAndArgs();
129
130   private static void appendNamedArgs(final Map<String, String> namedArgs,
131       final AppendAndIndexWikiCallback appendAndIndexWikiCallback) {
132     for (final Map.Entry<String, String> entry : namedArgs.entrySet()) {
133       appendAndIndexWikiCallback.builder.append("|");
134       appendAndIndexWikiCallback.dispatch(entry.getKey(), null, null);
135       appendAndIndexWikiCallback.builder.append("=");
136       appendAndIndexWikiCallback.dispatch(entry.getValue(), null, null);
137     }
138   }
139
140   // ------------------------------------------------------------------
141
142   static final class TranslationCallback implements FunctionCallback {
143     @Override
144     public boolean onWikiFunction(final WikiTokenizer wikiTokenizer, final String name, final List<String> args,
145         final Map<String, String> namedArgs, final EnWiktionaryXmlParser parser,
146         final AppendAndIndexWikiCallback appendAndIndexWikiCallback) {
147
148       final String transliteration = namedArgs.remove("tr");
149       namedArgs.keySet().removeAll(EnWiktionaryXmlParser.USELESS_WIKI_ARGS);
150       if (args.size() < 2) {
151         LOG.warning("{{t...}} with wrong args: title=" + parser.title);
152         return false;
153       }
154       final String langCode = ListUtil.get(args, 0);
155       final String word = ListUtil.get(args, 1);
156       final String gender = ListUtil.get(args, 2);
157       // TODO: deal with second (and third...) gender, and alt.
158       
159       appendAndIndexWikiCallback.dispatch(word, EntryTypeName.WIKTIONARY_TITLE_MULTI);
160       
161       if (gender != null) {
162         appendAndIndexWikiCallback.builder.append(String.format(" {%s}", gender));
163       }
164       if (transliteration != null) {
165         appendAndIndexWikiCallback.builder.append(" (");
166         appendAndIndexWikiCallback.dispatch(transliteration, EntryTypeName.WIKTIONARY_TRANSLITERATION);
167         appendAndIndexWikiCallback.builder.append(")");
168       }
169       return true;
170     }
171     
172   }
173
174   // ------------------------------------------------------------------
175   
176   static final class QualifierCallback implements FunctionCallback {
177     @Override
178     public boolean onWikiFunction(final WikiTokenizer wikiTokenizer, final String name, final List<String> args,
179         final Map<String, String> namedArgs,
180         final EnWiktionaryXmlParser parser,
181         final AppendAndIndexWikiCallback appendAndIndexWikiCallback) {
182       if (args.size() != 1 || !namedArgs.isEmpty()) {
183         LOG.warning("weird qualifier: ");
184         return false;
185       }
186       String qualifier = args.get(0);
187       appendAndIndexWikiCallback.builder.append("(");
188       appendAndIndexWikiCallback.dispatch(qualifier, null);
189       appendAndIndexWikiCallback.builder.append(")");
190       return true;
191     }
192   }
193
194   // ------------------------------------------------------------------
195   
196   static final class EncodingCallback implements FunctionCallback {
197     @Override
198     public boolean onWikiFunction(final WikiTokenizer wikiTokenizer, final String name, final List<String> args,
199         final Map<String, String> namedArgs,
200         final EnWiktionaryXmlParser parser,
201         final AppendAndIndexWikiCallback appendAndIndexWikiCallback) {
202       if (!namedArgs.isEmpty()) {
203         LOG.warning("weird encoding: " + wikiTokenizer.token());
204       }
205       if (args.size() == 0) {
206         // Things like "{{Jpan}}" exist.
207         return true;
208       }
209       
210       for (int i = 0; i < args.size(); ++i) {
211         if (i > 0) {
212           appendAndIndexWikiCallback.builder.append(", ");
213         }
214         final String arg = args.get(i);
215 //        if (arg.equals(parser.title)) {
216 //          parser.titleAppended = true;
217 //        }
218         appendAndIndexWikiCallback.dispatch(arg, appendAndIndexWikiCallback.entryTypeName);
219       }
220       
221       return true;
222     }
223   }
224
225   // ------------------------------------------------------------------
226   
227   static final class Gender implements FunctionCallback {
228     @Override
229     public boolean onWikiFunction(final WikiTokenizer wikiTokenizer, final String name, final List<String> args,
230         final Map<String, String> namedArgs,
231         final EnWiktionaryXmlParser parser,
232         final AppendAndIndexWikiCallback appendAndIndexWikiCallback) {
233       if (!namedArgs.isEmpty()) {
234         return false;
235       }
236       appendAndIndexWikiCallback.builder.append("{");
237       appendAndIndexWikiCallback.builder.append(name);
238       for (int i = 0; i < args.size(); ++i) {
239         appendAndIndexWikiCallback.builder.append("|").append(args.get(i));
240       }
241       appendAndIndexWikiCallback.builder.append("}");
242       return true;
243     }
244   }
245
246   // ------------------------------------------------------------------
247   
248   static final class l_term implements FunctionCallback {
249     @Override
250     public boolean onWikiFunction(final WikiTokenizer wikiTokenizer, final String name, final List<String> args,
251         final Map<String, String> namedArgs,
252         final EnWiktionaryXmlParser parser,
253         final AppendAndIndexWikiCallback appendAndIndexWikiCallback) {
254       
255       // for {{l}}, lang is arg 0, but not for {{term}}
256       if (name.equals("term")) {
257         args.add(0, "");
258       }
259       
260       final EntryTypeName entryTypeName;
261       switch (parser.state) {
262       case TRANSLATION_LINE: entryTypeName = EntryTypeName.WIKTIONARY_TRANSLATION_OTHER_TEXT; break;
263       case ENGLISH_DEF_OF_FOREIGN: entryTypeName = EntryTypeName.WIKTIONARY_ENGLISH_DEF_WIKI_LINK; break;
264       default: throw new IllegalStateException("Invalid enum value: " + parser.state);
265       }
266       
267       final String langCode = args.get(0);
268       final IndexBuilder indexBuilder;
269       if ("".equals(langCode)) {
270         indexBuilder = parser.foreignIndexBuilder;
271       } else if ("en".equals(langCode)) {
272         indexBuilder = parser.enIndexBuilder;
273       } else {
274         indexBuilder = parser.foreignIndexBuilder;
275       }
276       
277       String displayText = ListUtil.get(args, 2, "");
278       if (displayText.equals("")) {
279         displayText = ListUtil.get(args, 1, null);
280       }
281       
282       if (displayText != null) {
283         appendAndIndexWikiCallback.dispatch(displayText, indexBuilder, entryTypeName);
284       } else {
285         LOG.warning("no display text: " + wikiTokenizer.token());
286       }
287       
288       final String tr = namedArgs.remove("tr");
289       if (tr != null) {
290         appendAndIndexWikiCallback.builder.append(" (");
291         appendAndIndexWikiCallback.dispatch(tr, indexBuilder, EntryTypeName.WIKTIONARY_TRANSLITERATION);
292         appendAndIndexWikiCallback.builder.append(")");
293       }
294       
295       final String gloss = ListUtil.get(args, 3, "");
296       if (!gloss.equals("")) {
297         appendAndIndexWikiCallback.builder.append(" (");
298         appendAndIndexWikiCallback.dispatch(gloss, parser.enIndexBuilder, EntryTypeName.WIKTIONARY_ENGLISH_DEF);
299         appendAndIndexWikiCallback.builder.append(")");
300       }
301       
302       namedArgs.keySet().removeAll(EnWiktionaryXmlParser.USELESS_WIKI_ARGS);
303       if (!namedArgs.isEmpty()) {
304         appendAndIndexWikiCallback.builder.append(" {").append(name);
305         appendNamedArgs(namedArgs, appendAndIndexWikiCallback);
306         appendAndIndexWikiCallback.builder.append("}");
307       }
308
309       return true;
310     }
311   }
312
313   // ------------------------------------------------------------------
314   
315   static final class AppendArg0 implements FunctionCallback {
316     @Override
317     public boolean onWikiFunction(final WikiTokenizer wikiTokenizer, final String name, final List<String> args,
318         final Map<String, String> namedArgs,
319         final EnWiktionaryXmlParser parser,
320         final AppendAndIndexWikiCallback appendAndIndexWikiCallback) {
321       if (args.size() != 1 || !namedArgs.isEmpty()) {
322         return false;
323       }
324       appendAndIndexWikiCallback.dispatch(args.get(0), EntryTypeName.WIKTIONARY_TRANSLATION_OTHER_TEXT);
325       // TODO: transliteration
326       return true;
327     }
328   }
329
330   // ------------------------------------------------------------------
331   
332   static final class italbrac implements FunctionCallback {
333     @Override
334     public boolean onWikiFunction(final WikiTokenizer wikiTokenizer, final String name, final List<String> args,
335         final Map<String, String> namedArgs,
336         final EnWiktionaryXmlParser parser,
337         final AppendAndIndexWikiCallback appendAndIndexWikiCallback) {
338       if (args.size() != 1 || !namedArgs.isEmpty()) {
339         return false;
340       }
341       appendAndIndexWikiCallback.builder.append("(");
342       appendAndIndexWikiCallback.dispatch(args.get(0), EntryTypeName.WIKTIONARY_TRANSLATION_OTHER_TEXT);
343       appendAndIndexWikiCallback.builder.append(")");
344       return true;
345     }
346   }
347
348   // ------------------------------------------------------------------
349   
350   static final class gloss implements FunctionCallback {
351     @Override
352     public boolean onWikiFunction(final WikiTokenizer wikiTokenizer, final String name, final List<String> args,
353         final Map<String, String> namedArgs,
354         final EnWiktionaryXmlParser parser,
355         final AppendAndIndexWikiCallback appendAndIndexWikiCallback) {
356       if (args.size() != 1 || !namedArgs.isEmpty()) {
357         return false;
358       }
359       appendAndIndexWikiCallback.builder.append("(");
360       appendAndIndexWikiCallback.dispatch(args.get(0), EntryTypeName.WIKTIONARY_TRANSLATION_OTHER_TEXT);
361       appendAndIndexWikiCallback.builder.append(")");
362       return true;
363     }
364   }
365   
366   // ------------------------------------------------------------------
367   
368   static final class Ignore implements FunctionCallback {
369     @Override
370     public boolean onWikiFunction(final WikiTokenizer wikiTokenizer, final String name, final List<String> args,
371         final Map<String, String> namedArgs,
372         final EnWiktionaryXmlParser parser,
373         final AppendAndIndexWikiCallback appendAndIndexWikiCallback) {
374       return true;
375     }
376   }
377
378   // ------------------------------------------------------------------
379   
380   static final class not_used implements FunctionCallback {
381     @Override
382     public boolean onWikiFunction(final WikiTokenizer wikiTokenizer, final String name, final List<String> args,
383         final Map<String, String> namedArgs,
384         final EnWiktionaryXmlParser parser,
385         final AppendAndIndexWikiCallback appendAndIndexWikiCallback) {
386       appendAndIndexWikiCallback.builder.append("(not used)");
387       return true;
388     }
389   }
390
391
392   // ------------------------------------------------------------------
393   
394   static final class AppendName implements FunctionCallback {
395     @Override
396     public boolean onWikiFunction(final WikiTokenizer wikiTokenizer, final String name, final List<String> args,
397         final Map<String, String> namedArgs,
398         final EnWiktionaryXmlParser parser,
399         final AppendAndIndexWikiCallback appendAndIndexWikiCallback) {
400       if (!args.isEmpty() || !namedArgs.isEmpty()) {
401         return false;
402       }
403       appendAndIndexWikiCallback.builder.append(name);
404       return true;
405     }
406   }
407
408   // --------------------------------------------------------------------
409   // --------------------------------------------------------------------
410   
411
412   static final class FormOf implements FunctionCallback {
413     @Override
414     public boolean onWikiFunction(final WikiTokenizer wikiTokenizer, final String name, final List<String> args,
415         final Map<String, String> namedArgs,
416         final EnWiktionaryXmlParser parser,
417         final AppendAndIndexWikiCallback appendAndIndexWikiCallback) {
418       parser.entryIsFormOfSomething = true;
419       String formName = name;
420       if (name.equals("form of")) {
421         formName = ListUtil.remove(args, 0, null);
422       }
423       if (formName == null) {
424         LOG.warning("Missing form name: " + parser.title);
425         formName = "form of";
426       }
427       String baseForm = ListUtil.get(args, 1, "");
428       if ("".equals(baseForm)) {
429         baseForm = ListUtil.get(args, 0, null);
430         ListUtil.remove(args, 1, "");
431       } else {
432         ListUtil.remove(args, 0, null);
433       }
434       namedArgs.keySet().removeAll(EnWiktionaryXmlParser.USELESS_WIKI_ARGS);
435       
436       appendAndIndexWikiCallback.builder.append("{");
437       NAME_AND_ARGS.onWikiFunction(wikiTokenizer, formName, args, namedArgs, parser, appendAndIndexWikiCallback);
438       appendAndIndexWikiCallback.builder.append("}");
439       if (baseForm != null && appendAndIndexWikiCallback.indexedEntry != null) {
440         parser.foreignIndexBuilder.addEntryWithString(appendAndIndexWikiCallback.indexedEntry, baseForm, EntryTypeName.WIKTIONARY_BASE_FORM_MULTI);
441       } else {
442         // null baseForm happens in Danish.
443         LOG.warning("Null baseform: " + parser.title);
444       }
445       return true;
446     }
447   }
448   
449   static final FormOf FORM_OF = new FormOf();
450   
451
452   // --------------------------------------------------------------------
453   // --------------------------------------------------------------------
454   
455   static final class wikipedia implements FunctionCallback {
456     @Override
457     public boolean onWikiFunction(final WikiTokenizer wikiTokenizer, final String name, final List<String> args,
458         final Map<String, String> namedArgs,
459         final EnWiktionaryXmlParser parser,
460         final AppendAndIndexWikiCallback appendAndIndexWikiCallback) {
461       namedArgs.remove("lang");
462       if (args.size() > 1 || !namedArgs.isEmpty()) {
463         // Unindexed!
464         return false;
465       } else if (args.size() == 1) {
466         return false;
467       } else {
468         return true;
469       }
470     }
471   }
472
473   static final class InflOrHead implements FunctionCallback {
474     @Override
475     public boolean onWikiFunction(final WikiTokenizer wikiTokenizer, final String name, final List<String> args,
476         final Map<String, String> namedArgs,
477         final EnWiktionaryXmlParser parser,
478         final AppendAndIndexWikiCallback appendAndIndexWikiCallback) {
479       // See: http://en.wiktionary.org/wiki/Template:infl
480       final String langCode = ListUtil.get(args, 0);
481       String head = namedArgs.remove("head");
482       if (head == null) {
483         head = namedArgs.remove("title"); // Bug
484       }
485       if (head == null) {
486         head = parser.title;
487       }
488       parser.titleAppended = true;
489       
490       namedArgs.keySet().removeAll(EnWiktionaryXmlParser.USELESS_WIKI_ARGS);
491
492       final String tr = namedArgs.remove("tr");
493       String g = namedArgs.remove("g");
494       if (g == null) {
495         g = namedArgs.remove("gender");
496       }
497       final String g2 = namedArgs.remove("g2");
498       final String g3 = namedArgs.remove("g3");
499
500       appendAndIndexWikiCallback.dispatch(head, EntryTypeName.WIKTIONARY_TITLE_MULTI);
501
502       if (g != null) {
503         appendAndIndexWikiCallback.builder.append(" {").append(g);
504         if (g2 != null) {
505           appendAndIndexWikiCallback.builder.append("|").append(g2);
506         }
507         if (g3 != null) {
508           appendAndIndexWikiCallback.builder.append("|").append(g3);
509         }
510         appendAndIndexWikiCallback.builder.append("}");
511       }
512
513       if (tr != null) {
514         appendAndIndexWikiCallback.builder.append(" (");
515         appendAndIndexWikiCallback.dispatch(tr, EntryTypeName.WIKTIONARY_TITLE_MULTI);
516         appendAndIndexWikiCallback.builder.append(")");
517         parser.wordForms.add(tr);
518       }
519
520       final String pos = ListUtil.get(args, 1);
521       if (pos != null) {
522         appendAndIndexWikiCallback.builder.append(" (").append(pos).append(")");
523       }
524       for (int i = 2; i < args.size(); i += 2) {
525         final String inflName = ListUtil.get(args, i);
526         final String inflValue = ListUtil.get(args, i + 1);
527         appendAndIndexWikiCallback.builder.append(", ");
528         appendAndIndexWikiCallback.dispatch(inflName, null, null);
529         if (inflValue != null && inflValue.length() > 0) {
530           appendAndIndexWikiCallback.builder.append(": ");
531           appendAndIndexWikiCallback.dispatch(inflValue, null, null);
532           parser.wordForms.add(inflValue);
533         }
534       }
535       for (final String key : namedArgs.keySet()) {
536         final String value = WikiTokenizer.toPlainText(namedArgs.get(key));
537         appendAndIndexWikiCallback.builder.append(" ");
538         appendAndIndexWikiCallback.dispatch(key, null, null);
539         appendAndIndexWikiCallback.builder.append("=");
540         appendAndIndexWikiCallback.dispatch(value, null, null);
541         parser.wordForms.add(value);
542       }
543       return true;
544     }
545   }
546   
547
548   static {
549     DEFAULT.put("it-noun", new it_noun());
550   } 
551   static final class it_noun implements FunctionCallback {
552     @Override
553     public boolean onWikiFunction(final WikiTokenizer wikiTokenizer, final String name, final List<String> args,
554         final Map<String, String> namedArgs,
555         final EnWiktionaryXmlParser parser,
556         final AppendAndIndexWikiCallback appendAndIndexWikiCallback) {
557       parser.titleAppended = true;
558       final String base = ListUtil.get(args, 0);
559       final String gender = ListUtil.get(args, 1);
560       final String singular = base + ListUtil.get(args, 2, null);
561       final String plural = base + ListUtil.get(args, 3, null);
562       appendAndIndexWikiCallback.builder.append(" ");
563       appendAndIndexWikiCallback.dispatch(singular, null, null);
564       appendAndIndexWikiCallback.builder.append(" {").append(gender).append("}, ");
565       appendAndIndexWikiCallback.dispatch(plural, null, null);
566       appendAndIndexWikiCallback.builder.append(" {pl}");
567       parser.wordForms.add(singular);
568       parser.wordForms.add(plural);
569       if (!namedArgs.isEmpty() || args.size() > 4) {
570         LOG.warning("Invalid it-noun: " + wikiTokenizer.token());
571       }
572       return true;
573     }
574   }
575
576   static {
577     DEFAULT.put("it-proper noun", new it_proper_noun());
578   } 
579   static final class it_proper_noun implements FunctionCallback {
580     @Override
581     public boolean onWikiFunction(final WikiTokenizer wikiTokenizer, final String name, final List<String> args,
582         final Map<String, String> namedArgs,
583         final EnWiktionaryXmlParser parser,
584         final AppendAndIndexWikiCallback appendAndIndexWikiCallback) {
585       return false;
586     }
587   }
588
589 }