NCL Composer  0.1.5
 All Classes Functions Variables Pages
NCLStructure.cpp
1 /* Copyright (c) 2011 Telemidia/PUC-Rio.
2  * All rights reserved. This program and the accompanying materials
3  * are made available under the terms of the Eclipse Public License v1.0
4  * which accompanies this distribution, and is available at
5  * http://www.eclipse.org/legal/epl-v10.html
6  *
7  * Contributors:
8  * Telemidia/PUC-Rio - initial API and implementation
9  */
10 #include "NCLStructure.h"
11 
12 namespace composer {
13 namespace language{
14 
15 INIT_SINGLETON(NCLStructure)
16 
17 NCLStructure::NCLStructure()
18 {
19  attributes = new map <QString, map <QString, bool > * > ();
20  attributes_ordered = new map<QString, deque <QString> * > ();
21  nesting = new map <QString, map <QString, char > * > ();
22  dataTypes = new map <QString, QString> ();
23  dataTypeDefaultSuggestions = new map <QString, QStringList>();
24  attributesDatatype = new map <QString, map<QString, QString> *> ();
25  references = new QMultiMap <QString, AttributeReferences*> ();
26 
27  loadStructure();
28 }
29 
30 NCLStructure::~NCLStructure()
31 {
32  //TODO: Destructor
33  map <QString, map <QString, bool> *>::iterator it;
34  for(it = attributes->begin(); it != attributes->end(); ++it)
35  {
36  map <QString, bool> *content = it->second;
37  content->clear();
38  delete content;
39  }
40  attributes->clear();
41  delete attributes;
42 
43  map <QString, map <QString, char> *>::iterator it2;
44  for(it2 = nesting->begin(); it2 != nesting->end(); ++it2)
45  {
46  map <QString, char> *content = it2->second;
47  content->clear();
48  delete content;
49  }
50  nesting->clear();
51  delete nesting;
52 
53  dataTypes->clear();
54  delete dataTypes;
55 
56  dataTypeDefaultSuggestions->clear();
57  delete dataTypeDefaultSuggestions;
58 
59  map <QString, map<QString, QString> *>::iterator it3;
60  for(it3 = attributesDatatype->begin(); it3 != attributesDatatype->end();
61  ++it3)
62  {
63  map<QString, QString> *content = it3->second;
64  content->clear();
65  delete content;
66  }
67  attributesDatatype->clear();
68  delete attributesDatatype;
69 
70  //TODO: DELETE EACH INTERNAL POINTER
71  references->clear();
72 }
73 
74 // TODO: This function should be based on lex and yacc to a better
75 // implementation.
76 void NCLStructure::loadStructure(){
77  QFile fInput ( NCLSTRUCTURE_FILE );
78  if(!fInput.open(QIODevice::ReadOnly)){
79  qErrnoWarning("Should not open the NCL_STRUCTURE file.");
80  return;
81  }
82 
83  QTextStream in (&fInput);
84  while(!in.atEnd()){
85  QString line = in.readLine();
86  vector <QString> tokens = parseLine(line);
87 
88  //this is a commentary
89  if(tokens.size() == 0)
90  continue;
91 
92  if(tokens[0].toLower() == "datatype")
93  {
94  bool error = false;
95  if(tokens.size() >= 3)
96  {
97  qDebug() << "I'm reading a new DATATYPE element " << tokens[0]
98  << tokens[1] << " " << tokens[2];
99  addDatatype(tokens[1], tokens[2]);
100  if (tokens.size() >= 4)
101  {
102  addDatatypeDefaultSuggestions(tokens[1], tokens[3]);
103  }
104  }
105  else error = true;
106  if (error)
107  {
108  qErrnoWarning("element primitive must have exactly 2 or 3 \
109  arguments (NAME, REGEX, DEFAULT_SUGGESTIONS)");
110  }
111  }
112  else if(tokens[0].toLower() == "element")
113  {
114  // qDebug() << "I'm reading a new ELEMENT element";
115  // qDebug() << "Adding Element -- " << tokens[1];
116 
117  if(tokens.size() == 5)
118  {
119  bool define_scope = false;
120  if(tokens[4].toLower() == "true")
121  define_scope = true;
122  addElement(tokens[1], tokens[2], 0, define_scope);
123  }
124  else
125  {
126  qErrnoWarning("element primitive must have exactly 3 arguments \
127  (ELEMENT NAME, ELEMENT FATHER, CARDINALITY)");
128  }
129 
130  }
131  else if(tokens[0].toLower() == "attribute")
132  {
133  // qDebug() << "I'm reading a new ATTRIBUTE element" << endl;
134 
135  if(tokens.size() == 5)
136  {
137  bool required = false;
138  if(tokens[3].toLower() == "true")
139  required = true;
140 
141  addAttribute(tokens[1], tokens[2], tokens[4], required);
142  }
143  else
144  {
145  qErrnoWarning("attribute primitive must be exactly 4 arguments \
146  (ELEMENT NAME, ATTR NAME, ATTR TYPE, REQUIRED)");
147  }
148 
149  }
150  else if(tokens[0].toLower() == "scope")
151  {
152  qDebug() << "I'm reading a new SCOPE element - This is not supported yet"
153  << endl;
154  }
155  else if(tokens[0].toLower() == "reference")
156  {
157  // qDebug() << "I'm reading a new REFERENCE element" << endl;
158  addReference(tokens[1], tokens[2], tokens[3], tokens[4], tokens[5]);
159 
160  }
161  //qDebug() << line << endl;
162  }
163  fInput.close();
164 }
165 
166 // TODO: This function should be based on lex and yacc to a better
167 // implementation.
168 vector <QString> NCLStructure::parseLine(QString line)
169 {
170  vector <QString> ret;
171  QChar ch;
172  int size = line.size(), i = 0;
173  QString token;
174  bool reading_attributes = false, readingstring = false;
175 
176  while (i < line.size()) {
177  ch = line.at(i);
178  if(!readingstring){
179  if (ch == '/') {
180  if (i+1 < size && line[i+1] == '/') {
181  // comment was found, it will ignore the remaining
182  // caracteres in the line
183  token = "//";
184  break;
185  }
186  }
187  else if (ch == '\"')
188  {
189  readingstring = true;
190  }
191  else if(ch == '(') {
192  if(token != "")
193  ret.push_back(token);
194  token = "";
195  reading_attributes = true;
196  }
197  else if(ch == ',') {
198  if(reading_attributes && token != "")
199  ret.push_back(token);
200  token = "";
201  }
202  else if (ch == ')') {
203  if(reading_attributes && token != "")
204  ret.push_back(token);
205  reading_attributes = false;
206  token = "";
207  }
208  else {
209  if(!ch.isSpace())
210  token.append(line.at(i));
211  }
212  }
213  else {
214  if(ch == '\"')
215  readingstring = false;
216  else
217  token.append(line.at(i));
218  }
219  i++;
220  }
221  return ret;
222 }
223 
224 //TODO: SCOPE
225 void NCLStructure::addElement(QString name, QString father, char cardinality,
226  bool define_scope)
227 {
228  if(!nesting->count(father))
229  (*nesting)[father] = new map <QString, char>();
230 
231  if(!attributes->count(name))
232  (*attributes)[name] = new map <QString, bool>();
233 
234  if(!attributesDatatype->count(name))
235  (*attributesDatatype)[name] = new map <QString, QString>();
236 
237  if(!attributes_ordered->count(name))
238  (*attributes_ordered)[name] = new deque <QString>();
239 
240  (*(*nesting)[father])[name] = cardinality;
241  this->define_scope[name] = define_scope;
242 }
243 
244 void NCLStructure::addAttribute ( QString element, QString attr, QString type,
245  bool required)
246 {
247  if(!attributes->count(element))
248  (*attributes)[element] = new map <QString, bool>();
249 
250  if(!attributesDatatype->count(element))
251  (*attributesDatatype)[element] = new map <QString, QString>();
252 
253  if(!attributes_ordered->count(element))
254  (*attributes_ordered)[element] = new deque <QString>();
255 
256 //qDebug() << "NCLStructure::addAttribute (" << element << ", " << attr << ")";
257  (*(*attributes)[element])[attr] = required;
258  (*(*attributes_ordered)[element]).push_back(attr);
259  (*(*attributesDatatype)[element])[attr] = type;
260 }
261 
262 void NCLStructure::addReference( QString element, QString attr,
263  QString ref_element, QString ref_attr,
264  QString scope)
265 {
266  AttributeReferences *ref = new AttributeReferences (element, attr,
267  ref_element, ref_attr,
268  scope);
269  references->insert(element, ref);
270 }
271 
272 void NCLStructure::addDatatype (QString name, QString regex)
273 {
274  qDebug() << "NCLStructure::addDatatype (" << name << ", " << regex << ")";
275  (*dataTypes)[name] = regex;
276 }
277 
278 void NCLStructure::addDatatypeDefaultSuggestions( QString datatype,
279  QString values)
280 {
281  // qDebug() << "NCLStructure::addDatatypeDefaultSuggestion (" << datatype
282  // << ", " << values << ")";
283  if(values != "")
284  (*dataTypeDefaultSuggestions)[datatype] = values.split(',');
285  else
286  (*dataTypeDefaultSuggestions)[datatype] = QStringList();
287 }
288 
289 QString NCLStructure::getAttributeDatatype(QString element, QString name)
290 {
291  if( attributesDatatype->count(element) &&
292  (*attributesDatatype)[element]->count(name))
293  {
294  return (*(*attributesDatatype)[element])[name];
295  }
296  return QString("Unknown");
297 }
298 
299 QStringList NCLStructure::getDatatypeDefaultSuggestions(QString datatype)
300 {
301  if( dataTypeDefaultSuggestions->count(datatype))
302  {
303  return (*dataTypeDefaultSuggestions)[datatype];
304  }
305  return QStringList();
306 }
307 
308 map <QString, bool> *NCLStructure::getAttributes(QString element)
309 {
310  if(attributes->count(element))
311  return (*attributes)[element];
312  return NULL;
313 }
314 
315 deque <QString> *NCLStructure::getAttributesOrdered(QString element)
316 {
317  if(attributes_ordered->count(element))
318  return (*attributes_ordered)[element];
319  return NULL;
320 }
321 
322 map <QString, map <QString, char> *> *NCLStructure::getNesting()
323 {
324  return this->nesting;
325 }
326 
327 map <QString, char> * NCLStructure::getChildren (QString tagname)
328 {
329  if(nesting->count(tagname))
330  return (*nesting)[tagname];
331  return NULL;
332 }
333 
334 vector <AttributeReferences*> NCLStructure::getReferences ( QString element,
335  QString attr)
336 {
337  vector <AttributeReferences *> ref;
338  foreach( AttributeReferences *value, references->values(element) )
339  {
340  if(value->getAttribute() == attr)
341  ref.push_back(value);
342  }
343  return ref;
344 }
345 
346 bool NCLStructure::defineScope(QString tagname)
347 {
348  if(define_scope.count(tagname))
349  return define_scope[tagname];
350  return false;
351 }
352 
353 } } //end namespace