1 /*******************************************************************************
\r
2 * Copyright (c) 2010 Association for Decentralized Information Management in
\r
4 * All rights reserved. This program and the accompanying materials
\r
5 * are made available under the terms of the Eclipse Public License v1.0
\r
6 * which accompanies this distribution, and is available at
\r
7 * http://www.eclipse.org/legal/epl-v10.html
\r
10 * VTT Technical Research Centre of Finland - initial API and implementation
\r
11 *******************************************************************************/
\r
12 package org.simantics.databoard.parser.repository;
14 import java.io.IOException;
\r
15 import java.io.InputStream;
\r
16 import java.io.StringReader;
\r
17 import java.util.HashMap;
\r
18 import java.util.List;
\r
19 import java.util.Map;
\r
20 import java.util.Map.Entry;
\r
21 import java.util.Set;
\r
22 import java.util.TreeMap;
\r
24 import org.simantics.databoard.Datatypes;
\r
25 import org.simantics.databoard.parser.DataParser;
\r
26 import org.simantics.databoard.parser.ParseException;
\r
27 import org.simantics.databoard.parser.ast.type.AstArrayType;
\r
28 import org.simantics.databoard.parser.ast.type.AstAttribute;
\r
29 import org.simantics.databoard.parser.ast.type.AstComponent;
\r
30 import org.simantics.databoard.parser.ast.type.AstRecordType;
\r
31 import org.simantics.databoard.parser.ast.type.AstTupleType;
\r
32 import org.simantics.databoard.parser.ast.type.AstType;
\r
33 import org.simantics.databoard.parser.ast.type.AstTypeDefinition;
\r
34 import org.simantics.databoard.parser.ast.type.AstTypeReference;
\r
35 import org.simantics.databoard.parser.ast.type.AstUnionType;
\r
36 import org.simantics.databoard.parser.unparsing.DataTypePrinter;
\r
37 import org.simantics.databoard.type.ArrayType;
\r
38 import org.simantics.databoard.type.Component;
\r
39 import org.simantics.databoard.type.DataTypeDefinition;
\r
40 import org.simantics.databoard.type.Datatype;
\r
41 import org.simantics.databoard.type.DoubleType;
\r
42 import org.simantics.databoard.type.FloatType;
\r
43 import org.simantics.databoard.type.IntegerType;
\r
44 import org.simantics.databoard.type.LongType;
\r
45 import org.simantics.databoard.type.MapType;
\r
46 import org.simantics.databoard.type.OptionalType;
\r
47 import org.simantics.databoard.type.RecordType;
\r
48 import org.simantics.databoard.type.StringType;
\r
49 import org.simantics.databoard.type.UnionType;
\r
50 import org.simantics.databoard.util.Limit;
\r
51 import org.simantics.databoard.util.Range;
\r
54 * Type repository maintains a mapping from strings to
55 * data types. It can also convert abstract syntax trees
58 * @author Hannu Niemistö
60 public class DataTypeRepository {
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>();
68 * Adds a type to the repository.
70 * @param name Name of the type
71 * @param type Type to be added
73 public void add(String name, Datatype type) {
\r
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);
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);
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);
98 * Gets a data type in the repository.
101 * @return the data type
103 public Datatype get(String name) {
104 Datatype res1 = dataTypesConstruction.get(name);
105 if (res1!=null) return res1;
106 Datatype res2 = dataTypes.get(name);
110 public String get(Datatype type) {
111 return typeNames.get(type);
114 public boolean contains(String name) {
115 return dataTypes.containsKey(name);
118 public boolean contains(Datatype type) {
119 return typeNames.containsKey(type);
124 * @return a view of all data types defined in this repository.
126 public Set<String> getTypeNames() {
127 return dataTypes.keySet();
131 * Add a type definitions to the repository.
133 * @param defs type definitions
135 public void addDefinitions(DataTypeDefinition...defs) {
136 for (DataTypeDefinition def : defs) {
137 add(def.getName(), def.getDataType());
142 * Add a type definition to the repository.
144 * @param def type definition
146 public void addDefinition(DataTypeDefinition def) {
147 add(def.getName(), def.getDataType());
152 * Adds a type to the repository.
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
159 public Datatype add(String name, AstType ast) throws DataTypeSyntaxError {
161 Datatype t = get(name);
162 if (t!=null) return t;
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);
173 if(untranslatedTypes.containsKey(named.name))
174 type = add(named.name, untranslatedTypes.remove(named.name)); //?
176 type = translateBuiltin(named);
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);
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);
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);
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);
210 throw new AssertionError("Not all syntax tree nodes covered");
213 private Datatype translateBuiltin(AstTypeReference named)
214 throws DataTypeSyntaxError {
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;
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;
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;
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 );
244 throw new DataTypeSyntaxError(named.name + " does not have attribute " + attribute.key + ".");
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;
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 );
263 throw new DataTypeSyntaxError(named.name + " does not have attribute " + attribute.key + ".");
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;
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 );
282 throw new DataTypeSyntaxError(named.name + " does not have attribute " + attribute.key + ".");
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;
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 );
301 throw new DataTypeSyntaxError(named.name + " does not have attribute " + attribute.key + ".");
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;
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 );
322 throw new DataTypeSyntaxError(named.name + " does not have attribute " + attribute.key + ".");
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));
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;
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() + ".");
347 translate(named.parameters.get(0)),
348 translate(named.parameters.get(1))
352 throw new DataTypeSyntaxError("Undefined type " + named.name);
354 catch(IllegalArgumentException e) {
355 throw new DataTypeSyntaxError(e);
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 );
365 type.setLength( new Range(
367 Limit.inclusive(ast.maxLength)
371 if(ast.maxLength == null) {
372 type.setLength( new Range(
373 Limit.inclusive(ast.minLength),
377 type.setLength( new Range(
378 Limit.inclusive(ast.minLength),
379 Limit.inclusive(ast.maxLength)
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(
391 translate(astComponent.type)
394 type.setReferable( ast.referable );
395 type.setComponents( components );
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(
404 translate(ast.components.get(i))
407 type.setComponents( components );
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(
416 add(astComponent.name, astComponent.type) //translate(astComponent.type)
422 * Adds all type definitions to the repository.
423 * @param definitions Abstract syntax trees of the definitions
424 * @throws DataTypeSyntaxError
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));
435 * Parses and adds type definitions to the repository.
437 * @param definitions Definitions in textual format.
439 public void addDefinitions(String definitions) throws DataTypeSyntaxError {
441 List<AstTypeDefinition> typeDefinitions =
442 new DataParser(new StringReader(definitions)).typeDefinitions();
443 add(typeDefinitions);
444 } catch (ParseException e) {
445 throw new DataTypeSyntaxError(e);
449 public void addDefinitions(InputStream definitions) throws IOException, DataTypeSyntaxError {
451 List<AstTypeDefinition> typeDefinitions =
452 new DataParser(definitions).typeDefinitions();
453 add(typeDefinitions);
454 } catch (ParseException e) {
455 throw new DataTypeSyntaxError(e);
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
465 public Datatype translate(AstType ast) throws DataTypeSyntaxError {
466 return add(null, ast);
470 * Parses an unnamed data type.
472 * @param typeString The textual representation of the type to be translated
473 * @return Translated data type
474 * @throws DataTypeSyntaxError
476 public Datatype translate(String typeString) throws DataTypeSyntaxError {
479 new DataParser(new StringReader(typeString)).type();
480 return add(null, type);
481 } catch (ParseException e) {
482 throw new DataTypeSyntaxError(e);
487 public String toString() {
488 StringBuilder sb = new StringBuilder();
489 DataTypePrinter printer = new DataTypePrinter( sb );
490 printer.setLinefeed( true );
492 for (Entry<String, Datatype> e : dataTypes.entrySet()) {
493 String name = e.getKey();
494 Datatype type = e.getValue();
498 printer.print( type );
502 return sb.toString();