]> matita.cs.unibo.it Git - helm.git/blob - helm/DEVEL/mathml_editor/src/TDictionary.cc
ocaml 3.09 transition
[helm.git] / helm / DEVEL / mathml_editor / src / TDictionary.cc
1 /* This file is part of EdiTeX, an editor of mathematical
2  * expressions based on TeX syntax.
3  * 
4  * Copyright (C) 2002-2003 Luca Padovani <lpadovan@cs.unibo.it>,
5  *                    2003 Paolo Marinelli <pmarinel@cs.unibo.it>.
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  *
21  * For more information, please visit the project's home page
22  * http://helm.cs.unibo.it/editex/
23  * or send an email to <lpadovan@cs.unibo.it>
24  */
25
26 #include <sstream>
27 #include <cassert>
28
29 #include "dom.hh"
30 #include "config.dirs"
31 #include "TDictionary.hh"
32 #include "TTokenizer.hh"
33 #include "CLoggerConsole.hh"
34
35 static TDictionary::Entry undefinedEntry;
36
37 static std::string
38 getURIBase(const std::string& uri)
39 {
40   std::string::size_type slash = uri.rfind('/');
41   if (slash != std::string::npos) return uri.substr(0, slash + 1);
42   else return "";
43 }
44
45 static std::string
46 getURIName(const std::string& uri)
47 {
48   std::string::size_type slash = uri.rfind('/');
49   if (slash != std::string::npos) return uri.substr(slash + 1, uri.size());
50   else return uri;
51 }
52
53 std::string
54 TDictionary::getDefaultDictionaryPath()
55 {
56   return PKGDATADIR"/dictionary-tex.xml";
57 }
58
59 void
60 TDictionary::load(const std::string& uri)
61 {
62   load(getURIName(uri), getURIBase(uri));
63 }
64
65 void
66 TDictionary::load(const std::string& name, const std::string& base)
67 {
68   logger.debug("Dictionary: loading `" + base + name + "'");
69
70   DOM::DOMImplementation di;
71   DOM::Document doc = di.createDocumentFromURI((base + name).c_str());
72   assert(doc);
73   load(doc, base);
74 }
75
76 void
77 TDictionary::load(const DOM::Document& doc, const std::string& base)
78 {
79   assert(doc);
80
81   DOM::Element root = doc.get_documentElement();
82   assert(root);
83
84   CLoggerConsole logger;
85   TTokenizer tokenizer(logger);
86
87   for (DOM::Node p = root.get_firstChild(); p; p = p.get_nextSibling())
88     if (p.get_nodeType() == DOM::Node::ELEMENT_NODE && p.get_nodeName() == "include")
89       {
90         DOM::Element el = p;
91         assert(el);
92         if (el.hasAttribute("href"))
93           {
94             // WARNING: this may result into an infinite loop!
95             std::string href = el.getAttribute("href");
96             std::string newBase = getURIBase(href);
97             std::string newName = getURIName(href);
98             if (newBase != "") load(newName, newBase);
99             else load(newName, base);
100           }
101         else
102           logger.warning("Dictionary: include statement with no href attribute (ignored)");
103       }
104     else if (p.get_nodeType() == DOM::Node::ELEMENT_NODE && p.get_nodeName() == "entry")
105       {
106         DOM::Element el = p;
107         assert(el);
108         assert(el.hasAttribute("name"));
109
110         std::string name = el.getAttribute("name");
111         if (entries.find(name) != entries.end())
112           logger.info("Dictionary: `" + name + "' is being redefined");
113
114         Entry entry;
115
116         if (el.hasAttribute("class"))
117           {
118             std::string cls = el.getAttribute("class");
119             if (cls == "o") entry.cls = OPERATOR;
120             else if (cls == "i") entry.cls = IDENTIFIER;
121             else if (cls == "n") entry.cls == NUMBER;
122             else entry.cls = MACRO;
123           }
124         else
125           entry.cls = MACRO;
126
127         if (el.hasAttribute("val"))
128           {
129             entry.value = el.getAttribute("val");
130             if (entry.cls == MACRO)
131               logger.warning("Dictionary: `" + name + "' has a specified value, but is classified as macro");
132           }
133
134         if (el.hasAttribute("pattern"))
135           {
136             if (entry.cls != MACRO)
137               logger.warning("Dictionary: `" + name + "' has a specified pattern, but is not classified as macro");
138
139             std::string pattern = el.getAttribute("pattern");
140             if (pattern == "{}")
141               entry.leftOpen = entry.rightOpen = 1;
142             else if (pattern == "{")
143               entry.leftOpen = 1;
144             else if (pattern == "}")
145               entry.rightOpen = 1;
146             else
147               entry.pattern = tokenizer.tokenize(pattern);
148           }
149
150 #if 0
151         if (el.hasAttribute("infix"))
152           {
153             std::istringstream is(el.getAttribute("infix"));
154             unsigned infix;
155             is >> infix;
156             entry.infix = infix;
157             if (!el.hasAttribute("prefix")) entry.prefix = infix;
158             if (!el.hasAttribute("postfix")) entry.postfix = infix;
159           }
160
161         if (el.hasAttribute("prefix"))
162           {
163             std::istringstream is(el.getAttribute("prefix"));
164             unsigned prefix;
165             is >> prefix;
166             entry.prefix = prefix;
167             if (!el.hasAttribute("infix"))
168               {
169                 entry.infix = prefix;
170                 if (!el.hasAttribute("postfix")) entry.postfix = prefix;
171               }
172           }
173
174         if (el.hasAttribute("postfix"))
175           {
176             std::istringstream is(el.getAttribute("postfix"));
177             unsigned postfix;
178             is >> postfix;
179             entry.postfix = postfix;
180             if (!el.hasAttribute("infix"))
181               {
182                 entry.infix = postfix;
183                 if (!el.hasAttribute("prefix")) entry.prefix = postfix;
184               }
185           }
186 #endif
187
188         if (el.hasAttribute("limits"))
189           {
190             std::istringstream is(el.getAttribute("limits"));
191             unsigned limits;
192             is >> limits;
193             entry.limits = limits;
194           }
195
196         if (el.hasAttribute("embellishment"))
197           {
198             std::istringstream is(el.getAttribute("embellishment"));
199             unsigned embellishment;
200             is >> embellishment;
201             entry.embellishment = embellishment;
202           }
203
204         if (el.hasAttribute("delimiter"))
205           {
206             if (entry.cls != OPERATOR && !entry.embellishment)
207               logger.warning("Dictionary: `" + name + "' delimiter ignored for non-operator");
208
209             std::istringstream is(el.getAttribute("delimiter"));
210             unsigned delimiter;
211             is >> delimiter;
212             entry.delimiter = delimiter;
213           }
214
215         if (el.hasAttribute("table"))
216           {
217             if (entry.cls != MACRO)
218               logger.warning("Dictionary: `" + name + "' table ignored for non-macro");
219
220             std::istringstream is(el.getAttribute("table"));
221             unsigned table;
222             is >> table;
223             entry.table = table;
224           }
225
226         entries[name] = entry;
227       }
228 }
229
230 const TDictionary::Entry&
231 TDictionary::find(const std::string& name) const
232 {
233   Dictionary::const_iterator p = entries.find(name);
234   if (p != entries.end()) return (*p).second;
235   else
236     {
237       logger.warning("unknown entry `" + name + "'");
238       return undefinedEntry;
239     }
240 }
241
242 std::string
243 TDictionary::complete(const std::string prefix, std::list<std::string>& complete_list) const
244 {
245   bool no_match = true;
246   std::string new_prefix = "";
247   for (Dictionary::const_iterator i = entries.begin(); i != entries.end(); i++)
248     {
249       if ((*i).first.find(prefix) == 0)
250         {
251           complete_list.push_front((*i).first);
252           if (no_match)
253             {
254               // it's the first match
255               no_match = false;
256               new_prefix = (*i).first;
257             }
258           else
259             {
260               // in this case, new_prefix has been set yet.
261               std::string s1 = (*i).first.substr(prefix.length()); // s1 is the high part of the matching string
262               std::string s2 = new_prefix.substr(prefix.length()); // s2 is the high part of new_prefix
263 #if 0
264               long j = 0; // it's the number of common characters
265               while (s1[j] == s2[j]) j++;
266 #endif
267               std::string::const_iterator i1 = s1.begin();
268               std::string::const_iterator i2 = s2.begin();
269               while (i1 != s1.end() && i2 != s2.end() && *i1 == *i2) i1++, i2++;
270               new_prefix = prefix + s1.substr(0, i1 - s1.begin());
271               //new_prefix = (j) ? prefix + s1.substr(0, i1 - s1.begin()) : prefix;
272             }
273         }
274     }
275
276   return new_prefix;
277 }
278
279 bool
280 TDictionary::Entry::paramDelimited(unsigned i) const
281 {
282   assert(i < pattern.size());
283   assert(pattern[i].category == TToken::PARAMETER);
284   // a parameter is delimited if it is NOT the last one
285   // AND the next argument is not a parameter
286   return i + 1 < pattern.size() && pattern[i + 1].category != TToken::PARAMETER;
287 }
288
289 bool
290 TDictionary::Entry::lastDelimiter(unsigned i) const
291 {
292   assert(i < pattern.size());
293   assert(pattern[i].category != TToken::PARAMETER);
294   // a token is the last delimiter if it is the last token 
295   // of the pattern or if the next token is a parameter)
296   return i + 1 == pattern.size() || pattern[i + 1].category == TToken::PARAMETER;
297 }
298
299 unsigned
300 TDictionary::Entry::previousParam(unsigned i) const
301 {
302   // this method return the position in the pattern of the 
303   // parameter placed in a position preceding i.
304   // If no preceding i parameter present, the method return
305   // pattern.size().
306   // To know the position of the last parameter, call this 
307   // method with i == pattern.size()
308   unsigned j = i - 1;
309
310   while (pattern[j].category != TToken::PARAMETER)
311     {
312       if (j) j--;
313       else return pattern.size();
314     }
315   return j;
316 }