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