]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.databoard/src/org/simantics/databoard/parser/repository/DataTypeRepository.java
Fixed all line endings of the repository
[simantics/platform.git] / bundles / org.simantics.databoard / src / org / simantics / databoard / parser / repository / DataTypeRepository.java
1 /*******************************************************************************
2  *  Copyright (c) 2010 Association for Decentralized Information Management in
3  *  Industry THTH ry.
4  *  All rights reserved. This program and the accompanying materials
5  *  are made available under the terms of the Eclipse Public License v1.0
6  *  which accompanies this distribution, and is available at
7  *  http://www.eclipse.org/legal/epl-v10.html
8  *
9  *  Contributors:
10  *      VTT Technical Research Centre of Finland - initial API and implementation
11  *******************************************************************************/
12 package org.simantics.databoard.parser.repository;
13
14 import java.io.IOException;
15 import java.io.InputStream;
16 import java.io.StringReader;
17 import java.util.HashMap;
18 import java.util.List;
19 import java.util.Map;
20 import java.util.Map.Entry;
21 import java.util.Set;
22 import java.util.TreeMap;
23
24 import org.simantics.databoard.Datatypes;
25 import org.simantics.databoard.parser.DataParser;
26 import org.simantics.databoard.parser.ParseException;
27 import org.simantics.databoard.parser.ast.type.AstArrayType;
28 import org.simantics.databoard.parser.ast.type.AstAttribute;
29 import org.simantics.databoard.parser.ast.type.AstComponent;
30 import org.simantics.databoard.parser.ast.type.AstRecordType;
31 import org.simantics.databoard.parser.ast.type.AstTupleType;
32 import org.simantics.databoard.parser.ast.type.AstType;
33 import org.simantics.databoard.parser.ast.type.AstTypeDefinition;
34 import org.simantics.databoard.parser.ast.type.AstTypeReference;
35 import org.simantics.databoard.parser.ast.type.AstUnionType;
36 import org.simantics.databoard.parser.unparsing.DataTypePrinter;
37 import org.simantics.databoard.type.ArrayType;
38 import org.simantics.databoard.type.Component;
39 import org.simantics.databoard.type.DataTypeDefinition;
40 import org.simantics.databoard.type.Datatype;
41 import org.simantics.databoard.type.DoubleType;
42 import org.simantics.databoard.type.FloatType;
43 import org.simantics.databoard.type.IntegerType;
44 import org.simantics.databoard.type.LongType;
45 import org.simantics.databoard.type.MapType;
46 import org.simantics.databoard.type.OptionalType;
47 import org.simantics.databoard.type.RecordType;
48 import org.simantics.databoard.type.StringType;
49 import org.simantics.databoard.type.UnionType;
50 import org.simantics.databoard.util.Limit;
51 import org.simantics.databoard.util.Range;
52
53 /**
54  * Type repository maintains a mapping from strings to
55  * data types. It can also convert abstract syntax trees
56  * to data types.
57  * 
58  * @author Hannu Niemistö
59  */
60 public class DataTypeRepository {
61
62         Map<String, Datatype> dataTypes =  new TreeMap<String, Datatype>();
63         Map<String, Datatype> dataTypesConstruction =  new HashMap<String, Datatype>();
64         Map<String, AstType> untranslatedTypes = new TreeMap<String, AstType>();
65         Map<Datatype, String> typeNames = new HashMap<Datatype, String>();
66         
67         /**
68          * Adds a type to the repository.
69          * 
70          * @param name Name of the type
71          * @param type Type to be added
72          */
73         public void add(String name, Datatype type) {
74                 //System.out.println("add(" + name + ", " + type.toSingleLineString() + ")");
75                 //Datatype oldType = dataTypes.get(name);
76                 //String oldName = typeNames.get(type);
77                 /*if (oldType!=null && !oldType.equals(type)) throw new RuntimeException("name = "+type+" is already mapped in the repository to "+oldType);
78                 if (oldName!=null && !oldName.equals(name)) throw new RuntimeException("name = "+type+" is already mapped in the repository to "+oldName);
79                 */dataTypes.put(name, type);
80                 typeNames.put(type, name);
81         }
82         
83         void addTemp(String name, Datatype type) {
84                 Datatype oldType = dataTypesConstruction.get(name);
85                 if (oldType!=null && oldType!=type) throw new RuntimeException("name = "+type+" is already mapped in the repository to "+oldType);
86                 dataTypesConstruction.put(name, type);
87         }       
88         
89         void finishType(String name) {
90                 Datatype type = dataTypesConstruction.remove(name);
91                 if (type==null) throw new RuntimeException("X");
92                 dataTypes.put(name, type);
93                 typeNames.put(type, name);
94         }
95
96         
97         /**
98          * Gets a data type in the repository.
99          * 
100          * @param name
101          * @return the data type
102          */
103         public Datatype get(String name) {
104                 Datatype res1 = dataTypesConstruction.get(name);
105                 if (res1!=null) return res1;
106                 Datatype res2 = dataTypes.get(name); 
107                 return res2;
108         }
109         
110         public String get(Datatype type) {
111                 return typeNames.get(type);
112         }
113         
114         public boolean contains(String name) {
115                 return dataTypes.containsKey(name);
116         }
117         
118         public boolean contains(Datatype type) {
119                 return typeNames.containsKey(type);
120         }
121         
122         
123         /** 
124          * @return a view of all data types defined in this repository.
125          */
126         public Set<String> getTypeNames() {
127                 return dataTypes.keySet();
128         }
129         
130         /**
131          * Add a type definitions to the repository.
132          * 
133          * @param defs type definitions
134          */
135         public void addDefinitions(DataTypeDefinition...defs) {
136                 for (DataTypeDefinition def : defs) {
137                         add(def.getName(), def.getDataType());
138                 }
139         }
140
141         /**
142          * Add a type definition to the repository.
143          * 
144          * @param def type definition
145          */
146         public void addDefinition(DataTypeDefinition def) {
147                 add(def.getName(), def.getDataType());
148         }
149         
150         
151         /**
152          * Adds a type to the repository.
153          * 
154          * @param name Name of the type
155          * @param ast Abstract syntax tree of the type to be added
156          * @return Translated data type
157          * @throws DataTypeSyntaxError 
158          */
159         public Datatype add(String name, AstType ast) throws DataTypeSyntaxError {
160                 if (name!=null) {
161                         Datatype t = get(name);
162                         if (t!=null) return t;
163                 }
164                 
165                 if(ast instanceof AstTypeReference) {
166                         AstTypeReference named = (AstTypeReference)ast;
167                         Datatype type = null;
168                         if (dataTypesConstruction.containsKey(named.name))
169                                 return dataTypesConstruction.get(named.name);
170                         if (dataTypes.containsKey(named.name))
171                                 return dataTypes.get(named.name);
172                         
173                         if(untranslatedTypes.containsKey(named.name))
174                                 type = add(named.name, untranslatedTypes.remove(named.name)); //?
175                         else 
176                                 type = translateBuiltin(named);
177                         if(name != null)
178                                 add(name, type);
179                         return type;
180                 }
181                 else if(ast instanceof AstArrayType) {
182                         ArrayType type = new ArrayType();
183                         if(name != null) addTemp(name, type);
184                         translate((AstArrayType)ast, type);
185                         if(name != null) finishType(name);
186                         return type;
187                 } 
188                 else if(ast instanceof AstRecordType) {
189                         RecordType type = new RecordType();
190                         if(name != null) addTemp(name, type);
191                         translate((AstRecordType)ast, type);
192                         if(name != null) finishType(name);                      
193                         return type;
194                 } 
195                 else if(ast instanceof AstTupleType) {
196                         RecordType type = new RecordType();
197                         if(name != null) addTemp(name, type);
198                         translate((AstTupleType)ast, type);
199                         if(name != null) finishType(name);                      
200                         return type;
201                 }
202                 else if(ast instanceof AstUnionType) {
203                         UnionType type = new UnionType();
204                         if(name != null) addTemp(name, type);
205                         translate((AstUnionType)ast, type);
206                         if(name != null) finishType(name);                      
207                         return type;
208                 }
209                 else
210                         throw new AssertionError("Not all syntax tree nodes covered");
211         }
212         
213         private Datatype translateBuiltin(AstTypeReference named) 
214                         throws DataTypeSyntaxError {
215                 try {
216                         if(named.name.equals("Boolean")) {
217                                 if(!named.parameters.isEmpty())
218                                         throw new DataTypeSyntaxError(named.name + " does not take type parameters.");
219                                 if(!named.attributes.isEmpty())
220                                         throw new DataTypeSyntaxError(named.name + " does not have attributes.");
221                                 return Datatypes.BOOLEAN;
222                         }
223                         else if(named.name.equals("Byte")) {
224                                 if(!named.parameters.isEmpty())
225                                         throw new DataTypeSyntaxError(named.name + " does not take type parameters.");
226                                 if(!named.attributes.isEmpty())
227                                         throw new DataTypeSyntaxError(named.name + " does not have attributes.");
228                                 return Datatypes.BYTE;
229                         }
230                         else if(named.name.equals("Integer")) {
231                                 if(!named.parameters.isEmpty())
232                                         throw new DataTypeSyntaxError(named.name + " does not take type parameters.");
233                                 if(named.attributes.isEmpty())
234                                         return Datatypes.INTEGER;
235                                 else {
236                                         IntegerType type = new IntegerType();
237                                         for(AstAttribute attribute : named.attributes) {
238                                                 String key = attribute.key;
239                                                 if(key.equals("range"))
240                                                         type.setRange( attribute.value );
241                                                 else if(key.equals("unit"))
242                                                         type.setUnit( attribute.value );
243                                                 else
244                                                         throw new DataTypeSyntaxError(named.name + " does not have attribute " + attribute.key + ".");
245                                         }
246                                         return type;
247                                 }
248                         }
249                         else if(named.name.equals("Long")) {
250                                 if(!named.parameters.isEmpty())
251                                         throw new DataTypeSyntaxError(named.name + " does not take type parameters.");
252                                 if(named.attributes.isEmpty())
253                                         return Datatypes.LONG;
254                                 else {
255                                         LongType type = new LongType();
256                                         for(AstAttribute attribute : named.attributes) {
257                                                 String key = attribute.key;
258                                                 if(key.equals("range"))
259                                                         type.setRange( attribute.value );
260                                                 else if(key.equals("unit"))
261                                                         type.setUnit( attribute.value );
262                                                 else
263                                                         throw new DataTypeSyntaxError(named.name + " does not have attribute " + attribute.key + ".");
264                                         }
265                                         return type;
266                                 }
267                         }
268                         else if(named.name.equals("Float")) {
269                                 if(!named.parameters.isEmpty())
270                                         throw new DataTypeSyntaxError(named.name + " does not take type parameters.");                  
271                                 if(named.attributes.isEmpty())
272                                         return Datatypes.FLOAT;
273                                 else {
274                                         FloatType type = new FloatType();
275                                         for(AstAttribute attribute : named.attributes) {
276                                                 String key = attribute.key;
277                                                 if(key.equals("range"))
278                                                         type.setRange( attribute.value );
279                                                 else if(key.equals("unit"))
280                                                         type.setUnit( attribute.value );
281                                                 else
282                                                         throw new DataTypeSyntaxError(named.name + " does not have attribute " + attribute.key + ".");
283                                         }
284                                         return type;
285                                 }
286                         }
287                         else if(named.name.equals("Double")) {
288                                 if(!named.parameters.isEmpty())
289                                         throw new DataTypeSyntaxError(named.name + " does not take type parameters.");
290                                 if(named.attributes.isEmpty())
291                                         return Datatypes.DOUBLE;
292                                 else {
293                                         DoubleType type = new DoubleType();
294                                         for(AstAttribute attribute : named.attributes) {
295                                                 String key = attribute.key;
296                                                 if(key.equals("range"))
297                                                         type.setRange( attribute.value );                                       
298                                                 else if(key.equals("unit"))
299                                                         type.setUnit( attribute.value );
300                                                 else
301                                                         throw new DataTypeSyntaxError(named.name + " does not have attribute " + attribute.key + ".");
302                                         }
303                                         return type;
304                                 }
305                         }
306                         else if(named.name.equals("String")) {
307                                 if(!named.parameters.isEmpty())
308                                         throw new DataTypeSyntaxError(named.name + " does not take type parameters.");
309                                 if(named.attributes.isEmpty())
310                                         return Datatypes.STRING;
311                                 else {
312                                         StringType type = new StringType();
313                                         for(AstAttribute attribute : named.attributes) {
314                                                 String key = attribute.key;
315                                                 if(key.equals("mimeType"))
316                                                         type.setMimeType( attribute.value );
317                                                 else if(key.equals("pattern")) 
318                                                         type.setPattern( attribute.value );
319                                                 else if(key.equals("length"))
320                                                         type.setLength( attribute.value );                                      
321                                                 else
322                                                         throw new DataTypeSyntaxError(named.name + " does not have attribute " + attribute.key + ".");
323                                         }
324                                         return type;
325                                 }
326                         }
327                         else if(named.name.equals("Optional")) {
328                                 if(named.parameters.size() != 1)
329                                         throw new DataTypeSyntaxError(
330                                                         "Optional takes one type parameter not " + named.parameters.size() + ".");
331                                 if(!named.attributes.isEmpty())
332                                         throw new DataTypeSyntaxError(named.name + " does not have attributes.");
333                                 OptionalType type = new OptionalType();
334                                 type.componentType = translate(named.parameters.get(0));
335                                 return type;
336                         }
337                         else if(named.name.equals("Variant")) {
338                                 if(!named.parameters.isEmpty())
339                                         throw new DataTypeSyntaxError(named.name + " does not take type parameters.");
340                                 return Datatypes.VARIANT;
341                         }
342                         else if(named.name.equals("Map")) {
343                                 if(named.parameters.size() != 2)
344                                         throw new DataTypeSyntaxError(
345                                                         "Map takes two type parameters not " + named.parameters.size() + ".");
346                                 return new MapType(
347                                                 translate(named.parameters.get(0)), 
348                                                 translate(named.parameters.get(1))
349                                         );
350                         }
351                         else
352                                 throw new DataTypeSyntaxError("Undefined type " + named.name);
353                 } 
354                 catch(IllegalArgumentException e) {
355                         throw new DataTypeSyntaxError(e);
356                 }
357         }
358
359         private void translate(AstArrayType ast, ArrayType type) throws DataTypeSyntaxError {
360                 type.componentType = translate(ast.componentType);
361                 if(ast.minLength == null) {
362                         if(ast.maxLength == null) {
363                                 type.setLength( (String) null );
364                         } else {
365                                 type.setLength( new Range(
366                                                 Limit.nolimit(),
367                                                 Limit.inclusive(ast.maxLength)
368                                                 ));
369                         }
370                 } else {
371                         if(ast.maxLength == null) {
372                                 type.setLength( new Range(
373                                                 Limit.inclusive(ast.minLength),
374                                                 Limit.nolimit()
375                                                 ));
376                         } else {
377                                 type.setLength( new Range(
378                                                 Limit.inclusive(ast.minLength),
379                                                 Limit.inclusive(ast.maxLength)
380                                                 ));
381                         }
382                 }
383         }
384         
385         private void translate(AstRecordType ast, RecordType type) throws DataTypeSyntaxError {
386                 Component[] components = new Component[ast.components.size()];
387                 for(int i=0;i<ast.components.size();++i) {
388                         AstComponent astComponent = ast.components.get(i);
389                         components[i] = new Component(
390                                         astComponent.name,
391                                         translate(astComponent.type)
392                                         );                      
393                 } 
394                 type.setReferable( ast.referable );
395                 type.setComponents( components );
396         }
397         
398         private void translate(AstTupleType ast, RecordType type) throws DataTypeSyntaxError {
399                 Component[] components = new Component[ast.components.size()];
400                 components = new Component[ast.components.size()];
401                 for(int i=0;i<ast.components.size();++i) {
402                         components[i] = new Component(
403                                         Integer.toString(i),
404                                         translate(ast.components.get(i))
405                                         );
406                 }
407                 type.setComponents( components );
408         }
409         
410         private void translate(AstUnionType ast, UnionType type) throws DataTypeSyntaxError {
411                 type.components = new Component[ast.components.size()];
412                 for(int i=0;i<ast.components.size();++i) {
413                         AstComponent astComponent = ast.components.get(i);
414                         type.components[i] = new Component(
415                                         astComponent.name,
416                                         add(astComponent.name, astComponent.type) //translate(astComponent.type)
417                                         );
418                 } 
419         }
420         
421         /**
422          * Adds all type definitions to the repository.
423          * @param definitions Abstract syntax trees of the definitions
424          * @throws DataTypeSyntaxError 
425          */
426         public void add(List<AstTypeDefinition> definitions) throws DataTypeSyntaxError {
427                 for(AstTypeDefinition def : definitions)
428                         untranslatedTypes.put(def.name, def.type);
429                 for(AstTypeDefinition def : definitions)
430                         if(untranslatedTypes.containsKey(def.name))
431                                 add(def.name, untranslatedTypes.remove(def.name));
432         }
433         
434         /**
435          * Parses and adds type definitions to the repository.
436          * 
437          * @param definitions Definitions in textual format.
438          */
439         public void addDefinitions(String definitions) throws DataTypeSyntaxError {
440                 try {
441                         List<AstTypeDefinition> typeDefinitions = 
442                                 new DataParser(new StringReader(definitions)).typeDefinitions();
443                         add(typeDefinitions);
444                 } catch (ParseException e) {
445                         throw new DataTypeSyntaxError(e);
446                 }
447         }
448         
449         public void addDefinitions(InputStream definitions) throws IOException, DataTypeSyntaxError {
450                 try {
451                         List<AstTypeDefinition> typeDefinitions = 
452                                 new DataParser(definitions).typeDefinitions();
453                         add(typeDefinitions);
454                 } catch (ParseException e) {
455                         throw new DataTypeSyntaxError(e);
456                 }
457         }
458         
459         /**
460          * Translates an unnamed data type.
461          * @param ast Abstract syntax tree of the type to be translated
462          * @return Translated data type
463          * @throws DataTypeSyntaxError 
464          */
465         public Datatype translate(AstType ast) throws DataTypeSyntaxError {
466                 return add(null, ast);
467         }
468         
469         /**
470          * Parses an unnamed data type.
471          * 
472          * @param typeString The textual representation of the type to be translated
473          * @return Translated data type
474          * @throws DataTypeSyntaxError 
475          */
476         public Datatype translate(String typeString) throws DataTypeSyntaxError {
477                 try {
478                         AstType type =
479                                 new DataParser(new StringReader(typeString)).type();
480                         return add(null, type);
481                 } catch (ParseException e) {
482                         throw new DataTypeSyntaxError(e);
483                 }
484         }
485         
486         @Override
487         public String toString() {
488                 StringBuilder sb = new StringBuilder();
489                 DataTypePrinter printer = new DataTypePrinter( sb );
490                 printer.setLinefeed( true );
491                 
492                 for (Entry<String, Datatype> e : dataTypes.entrySet()) {
493                         String name = e.getKey();
494                         Datatype type = e.getValue();                   
495                         sb.append("type ");
496                         sb.append( name );
497                         sb.append(" = ");
498                         printer.print( type );
499                         sb.append("\n");
500                 }
501                 
502                 return sb.toString();
503         }
504         
505 }